The input event dispatch engine is in WindowManagerService.java. WindowManagerService.java creates a thread to read input event from KeyInputQueue.java and dispatches the event to the window which has current focus through binder.

// 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));

If an input event is read, it judges the input event type. Currently support three input event types: key, trackball and pointer. Then according to event type call corresponding dispatch function to the window which has current focus through binder. For example, for key event, it calls the following code.

focus.mClient.dispatchKey(event);

At the lowest level, Android reads the real input event (keyboard, mouse or touch) from Linux input device. The corresponding source code is EventHub.cpp. For key input event, Android maps scan code to key code according to a key layout map file. OEM needs customize the key layout map file to match the needs of his own device. It uses the following method to find out the key layout map file.

// 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 can get the key layout map file name during Android booting, because Android will log the name. The JAVA layer wrapper is KeyInputQueue.java which is used by WindowManagerService.java. It calls EventHub.cpp through JNI. com_android_server_KeyInputQueue.cpp is the JNI implementation.

Input Event Processing

When an activity is to be launched, ActivityManagerService.java calls ActivityThread.java for creating the activity.

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

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

r.lastNonConfigurationInstance, config);

Then Activity.java creates a PhoneWindow.java instance to represent the activity. Each PhoneWindow.java contains a DecorView.java instance as the root of any views in the activity.

mWindow = PolicyManager.makeNewWindow(this);

mWindow.setCallback(this);

After an activity is created, ActivityManagerService.java calls ActivityThread.java for resume the activity. At this time, ActivityThread.java calls WindowManagerImpl.java to add the DecorView.java instance.

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 news a ViewRoot.java instance. ViewRoot.java has a static member which will be only initialized once for each process. It’s used to let WindowManagerService.java know that there is a process linked now.

if (!mInitialized) {

try {

sWindowSession = IWindowManager.Stub.asInterface(

ServiceManager.getService("window"))

.openSession(new Binder());

mInitialized = true;

} catch (RemoteException e) {

}

}

After ViewRoot.java instance is created, WindowManagerImpl.java calls its setView API to bind the ViewRoot.java for the DecorView.java.

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

root.setView(view, wparams, panelParentView);

In setView API, ViewRoot.java finally draws the DecorView.java and registers an IWindow instance to WindowManagerService.java.

res = sWindowSession.add(mWindow, attrs,

getHostVisibility(), mCoveredInsets);

After that WindowManagerService.java directly communicates (including dispatching input event) with this IWindow instance in ViewRoot.java. Then ViewRoot.java calls View.java to process input event. For example, for key event, dispatchKeyEvent API in View.java will be called.

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 detects if any key listener is registered for this view. If so, the key event will be handled by the key listener. Otherwise, it calls OnKeyDown/OnKeyUp as usual.

All the key listener implementations are under frameworks/base/core/java/android/text/method folder.

MultiTapKeyListener.java - if the keypad is NUMERIC keypad, this listener is used to transform digit inputs to characters.

QwertyKeyListener.java – if the keypad is QWERTY keypad, this listener is used.

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. Android之项目推荐使用的第三方库,有助于
  2. Android富文本编辑器:XRichText
  3. Android中的程序安装和卸载
  4. NDK r21编译FFmpeg 4.2.2(x86、x86_64、ar
  5. 获取手机联系人数据方法
  6. android定位和地图开发实例
  7. Android状态栏通知Status Bar Notificati
  8. tabhost中setup()和setup(LocalActivityM
  9. 【Android笔记】关于Intent
  10. sendMessage&sendEmptyMessage异同