PhoneWindow类的成员函数getCallback是从父类Window继承下来的,它返回的是一个Window.Callback接口。每一个Activity组件都会实现一个Window.Callback接口,并且将这个Window.Callback接口设置到与它所关联的一个PhoneWindow对象的内部去,这样当该PhoneWindow对象接收到键盘事件的时候,可以该键盘事件分发给与它所关联的Activity组件处理。

  DecorView类的成员变量mFeatureId用来描述当前正在处理的DecorView对象的特征,当它的值小于0的时候,表示当前正在处理的一个DecorView对象是用来描述一个Activity组件窗口的顶层视图的。

  因此,当当前正在处理的DecorView对象描述的是一个Activity组件窗口的顶层视图,并且这个Activity组件实现有一个Window.Callback接口时,DecorView类的成员函数dispatchKeyEvent会调用该Window.Callback接口的成员函数dispatchKeyEvent来通知对应的Activity组件,它接收到一个键盘事件了。否则的话,参数event所描述的键盘事件会被分发给当前正在处理的DecorView对象的父对象来处理,这是通过调用DecorView类的父类View的成员函数dispatchKeyEvent来实现的。

  我们假设当前正在处理的DecorView对象描述的是一个Activity组件窗口的顶层视图,并且这个Activity组件实现有一个Window.Callback接口,那么参数event所描述的键盘事件接下来会分给该Activity组件处理。如果该Activity组件在处理完成这个键盘事件之后,希望该键盘事件还能继续分发下去给其它对象处理,那么它所实现的Window.Callback接口的成员函数dispatchKeyEvent的返回值handled会等于false,这时候DecorView类的成员函数dispatchKeyEvent会将该键盘事件分发给与当前正在处理的DecorView对象所关联的一个PhoneWindow对象的成员函数onKeyDown或者onKeyUp来处理,取决于变量isDown的值是true还是false,即当前发生的键盘事件是与按键按下有关,还是与按键松开有关。

  PhoneWindow类的成员函数onKeyDown和onKeyUp主要是有来监控一些特殊按键事件,例如电话键和音量键,以便可以执行一些对应的逻辑。例如,当按下电话键时,打开拨号程序;又如,当按下音量键时,调节音量的大小。

  接下来,我们继续分析Activity类所实现的Window.Callback接口的成员函数dispatchKeyEvent的实现,以便可以了解键盘事件在Activity组件窗口的分发过程。

  Step 7. Activity.dispatchKeyEvent

  [java] view plaincopyprint?

  public class Activity extends ContextThemeWrapper

  implements LayoutInflater.Factory,

  Window.Callback, KeyEvent.Callback,

  OnCreateContextMenuListener, ComponentCallbacks {

  ......

  public boolean dispatchKeyEvent(KeyEvent event) {

  ......

  Window win = getWindow();

  if (win.superDispatchKeyEvent(event)) {

  return true;

  }

  View decor = mDecor;

  if (decor == null) decor = win.getDecorView();

  return event.dispatch(this, decor != null

  ? decor.getKeyDispatcherState() : null, this);

  }

  ......

  }

  public class Activity extends ContextThemeWrapper

  implements LayoutInflater.Factory,

  Window.Callback, KeyEvent.Callback,

  OnCreateContextMenuListener, ComponentCallbacks {

  ......

  public boolean dispatchKeyEvent(KeyEvent event) {

  ......

  Window win = getWindow();

  if (win.superDispatchKeyEvent(event)) {

  return true;

  }

  View decor = mDecor;

  if (decor == null) decor = win.getDecorView();

  return event.dispatch(this, decor != null

  ? decor.getKeyDispatcherState() : null, this);

  }

  ......

  }

  这个函数定义在文件frameworks/base/core/java/android/app/Activity.java中。

  Activity类的成员函数getWindow返回的是与当前正处理的Activity组件所关联的一个PhoneWindow对象,Activity类的成员函数dispatchKeyEvent获得了这个PhoneWindow对象之后,会调用它的成员函数superDispatchKeyEvent,以便可以将参数event所描述的键盘事件分发给它处理。

  这个PhoneWindow对象在处理完成参数event所描述的键盘事件之后,如果希望该键盘事件能继续往下分发,那么Activity类的成员函数dispatchKeyEvent会将该键盘事件分发给当前正在处理的Activity组件处理,这是通过调用参数event所描述的一个KeyEvent对象的成员函数dispatch来实现的。

  注意,在调用event所描述的一个KeyEvent对象的成员函数dispatch的时候,第一个参数指定为当前正在处理的Activity组件所实现的一个KeyEvent.Callback接口。参数event所指向的一个KeyEvent对象的成员函数dispatch的执行的过程中,会相应地调用这个KeyEvent.Callback接口的成员函数onKeyDown、onKeyUp或者onKeyMultiple来处理它所描述的键盘事件,实际上是调用Activity类的成员函数onKeyDown、onKeyUp或者onKeyMultiple来处理参数event所描述的键盘事件。因此,我们在自定义一个Activity组件时,如果需要处理分发给该Activity组件的键盘事件,那么需要重写父类Activity的成员函数onKeyDown、onKeyUp或者onKeyMultiple。