输入事件分发的源头在WindowManagerService.java中,它创建了一个线程从KeyInputQueue.java中读取输入事件并通过Binder分发给当前聚焦的Window

// Retrieve next event, waiting only as long as the next repeat timeout. If the configuration has changed, then don't wait at all -- we'll report the change as soon as we have processed all events.

QueuedEvent ev = mQueue.getEvent(

(int)((!configChanged && curTime < nextKeyTime)

? (nextKeyTime-curTime) : 0));

读取到一个输入事件后,它会判断事件的类型,并根据类型调用相应的分发方法分发到Window。现在只支持三种类型:按键、轨迹球和触摸。例如,对于按键事件来说,它调用以下代码:

focus.mClient.dispatchKey(event);

在最底层,AndroidLinux输入设备中读取真正的事件,相应的代码在EventHub.cpp中。对按键事件来说,Android通过一个按键键盘布局映射表文件把scan code转换成key codeOEM需要根据自己的设备更改这个键盘布局映射表文件。OEM使用下面的方法找到键盘布局映射表文件:

// a more descriptive name

ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);

devname[sizeof(devname)-1] = 0;

device->name = devname;

// replace all the spaces with underscores

strcpy(tmpfn, devname);

for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))

*p = '_';

// find the .kl file we need for this device

const char* root = getenv("ANDROID_ROOT");

snprintf(keylayoutFilename, sizeof(keylayoutFilename),

"%s/usr/keylayout/%s.kl", root, tmpfn);

bool defaultKeymap = false;

if (access(keylayoutFilename, R_OK)) {

snprintf(keylayoutFilename, sizeof(keylayoutFilename),

"%s/usr/keylayout/%s", root, "qwerty.kl");

defaultKeymap = true;

}

device->layoutMap->load(keylayoutFilename);

OEM可以在Android启动时得到键盘布局映射表文件,因为Android会在启动时打印它的名字。Java层对它的包装是KeyInputQueue.java,而KeyInputQueue.java是供WindowManagerService.java使用的。KeyInputQueue.java通过JNI调用EventHub.cpp。而com_android_server_KeyInputQueue.cppJNI实现。

当一个Activity启动时,ActivityManagerService.java调用ActivityThread.java创建activity

activity.attach(appContext, this, getInstrumentation(), r.token, app,

r.intent, r.activityInfo, title, r.parent, r.embeddedID,

r.lastNonConfigurationInstance, config);

接下来,Activity.java创建一个代表这个activityPhoneWindow.java实例。Activity中每一个PhoneWindow.java包含一个DecorView.java实例作为View树的根:

mWindow = PolicyManager.makeNewWindow(this);

mWindow.setCallback(this);

activity被创建后,ActivityManagerService.java调用ActivityThread.javaresume这个activity。这时,ActivityThread.java调用WindowManagerImpl.java添加DecorView.java

r.window = r.activity.getWindow();

View decor = r.window.getDecorView();

decor.setVisibility(View.INVISIBLE);

ViewManager wm = a.getWindowManager();

WindowManager.LayoutParams l = r.window.getAttributes();

a.mDecor = decor;

l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

wm.addView(decor, l);

WindowManagerImpl.java创建了一个ViewRoot.java实例。ViewRoot有一个对每个进程初始化一次的静态成员。通过它,WindowManagerService.java可以知道,现在有一个进程被连接了:

if (!mInitialized) {

try {

sWindowSession = IWindowManager.Stub.asInterface(

ServiceManager.getService("window"))

.openSession(new Binder());

mInitialized = true;

} catch (RemoteException e) {

}

}

ViewRoot.java实例被创建后,WindowManagerImpl.java会调用它的setViewDecorView.java绑定ViewRoot.java

// do this last because it fires off messages to start doing things

root.setView(view, wparams, panelParentView);

setView中,ViewRoot.java最后会渲染DecorView.java,然后注册一个IWindow实例到WindowManagerService.java中:

res = sWindowSession.add(mWindow, attrs,

getHostVisibility(), mCoveredInsets);

接下来,WindowManagerService.java直接与ViewRoot.java中的IWindow实例通信。然后,ViewRoot.java调用View.java处理输入事件。例如,对按键事件来说,View中的dispatchKeyEvent会被调用:

public boolean dispatchKeyEvent(KeyEvent event) {

// If any attached key listener a first crack at the event.

//noinspection SimplifiableIfStatement

if (mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED

&& mOnKeyListener.onKey(this, event.getKeyCode(), event)) {

return true;

}

return event.dispatch(this);

}

View.java检查是否有按键监听器注册到了这个view。如果有的话,按键事件会被监听器处理。否则,就调用onKeyDown/onKeyUp

所有的按键监听器的实现都在/frameworks/base/core/java/android/text/method文件夹中:

MultiTapKeyListener.java:如果键盘是数字键盘的话,这个监听器可以把数字输入转化成字符。

QwertyKeyListener.java:如果键盘是QWERTY键盘的话,会使用这个监听器。

更多相关文章

  1. Android(安卓)创建activity流程-基于api28
  2. ActivityThread-activity启动分析
  3. Android(安卓)GUI更新过程
  4. Android(安卓)GCM使用
  5. Android(安卓)Studio 解析XML的三种方法
  6. Android(安卓)Intent FLAG介绍
  7. android之 h5调用系统相机和相册并显示
  8. 【Android】之【对话框(Dialog)大全】
  9. Android(安卓)自定义 attr

随机推荐

  1. 给Android(安卓)应用开发者的十个建议
  2. Android(安卓)- Socket 功能在 Service
  3. Android通过ViewPager实现左右滑动切换图
  4. 初学Android,使用Drawable资源之使用Stat
  5. WebView用法与JS交互
  6. android简单的答题游戏
  7. Android自动化编译设置AndroidManifest.x
  8. 【转】Android(安卓)用户事件输入路径(Me
  9. Android手势:单指拖动、双指缩放图片
  10. Android布局属性android:clipToPadding的