Android之Input子系统事件分发流程
Android创建窗口机制,请看如下转载:
http://blog.csdn.net/sfdev/article/details/9130527
一、Android4.2系统服务侧——与View关系
1.服务端channel注册过程
frameworks/base/core/java/android/view/ViewRootImpl.java
- public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
- mInputChannel = new InputChannel();
- res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
- getHostVisibility(), mDisplay.getDisplayId(),
- mAttachInfo.mContentInsets, mInputChannel);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
- Looper.myLooper());
- }
frameworks/base/services/java/com/android/server/wm/Session.java
- public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
- int viewVisibility, int displayId, Rect outContentInsets,
- InputChannel outInputChannel) {
- return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
- outContentInsets, outInputChannel);
- }
frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
- public int addWindow(Session session, IWindow client, int seq,
- WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
- Rect outContentInsets, InputChannel outInputChannel) {
-
- String name = win.makeInputChannelName();
- InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
- win.setInputChannel(inputChannels[0]);
- inputChannels[1].transferTo(outInputChannel);
-
-
- mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
- }
frameworks/base/service/java/com/android/server/input/InputManagerService.java
- public void registerInputChannel(InputChannel inputChannel,
- InputWindowHandle inputWindowHandle) {
- nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
- }
- private static native void nativeRegisterInputChannel(int ptr, InputChannel inputChannel,
- InputWindowHandle inputWindowHandle, boolean monitor);
frameworks/base/service/jni/com_android_server_input_InputManagerService.cpp
- static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
- jint ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
- NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- status_t status = im->registerInputChannel(
- env, inputChannel, inputWindowHandle, monitor);
- }
- status_t NativeInputManager::registerInputChannel(JNIEnv* env,
- const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
- return mInputManager->getDispatcher()->registerInputChannel(
- inputChannel, inputWindowHandle, monitor);
-
-
-
-
-
-
-
-
- }
frameworks/base/services/input/InputDispatcher.cpp
- status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
- int fd = inputChannel->getFd();
- mConnectionsByFd.add(fd, connection);
-
- mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
- }
2.服务端上报过程
2.1.InputReaderThread线程从驱动读取数据并处理,如实现鼠标右键上报back键即在此处完成、以下代码将会看到
frameworks/base/services/input/InputReader.cpp
- bool InputReaderThread::threadLoop() {
- mReader->loopOnce();
- return true;
- }
- void InputReader::loopOnce() {
- size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
-
-
-
-
-
-
-
- processEventsLocked(mEventBuffer, count);
- }
- void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
- processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
- }
- void InputReader::processEventsForDeviceLocked(int32_t deviceId,
- const RawEvent* rawEvents, size_t count) {
- device->process(rawEvents, count);
- }
- void InputDevice::process(const RawEvent* rawEvents, size_t count) {
-
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
- mapper->process(rawEvent);
- }
- }
-
-
- void CursorInputMapper::process(const RawEvent* rawEvent) {
- mCursorButtonAccumulator.process(rawEvent);
- mCursorMotionAccumulator.process(rawEvent);
- mCursorScrollAccumulator.process(rawEvent);
- if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- sync(rawEvent->when);
- }
- }
-
-
-
- void CursorInputMapper::sync(nsecs_t when) {
- int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- getListener()->notifyMotion(&args);
-
- synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
- policyFlags, lastButtonState, currentButtonState);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
-
- void SingleTouchInputMapper::process(const RawEvent* rawEvent)
- TouchInputMapper::process(rawEvent);
- mSingleTouchMotionAccumulator.process(rawEvent);
- }
-
- void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
- TouchInputMapper::process(rawEvent);
- mMultiTouchMotionAccumulator.process(rawEvent);
- }
-
- void TouchInputMapper::process(const RawEvent* rawEvent) {
- mCursorButtonAccumulator.process(rawEvent);
- mCursorScrollAccumulator.process(rawEvent);
- mTouchButtonAccumulator.process(rawEvent);
- if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- sync(rawEvent->when);
- }
- }
-
- void TouchInputMapper::sync(nsecs_t when) {
- dispatchTouches(when, policyFlags);
- }
- void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
- dispatchMotion(when, policyFlags, mSource,
- AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
- AMOTION_EVENT_EDGE_FLAG_NONE,
- mCurrentCookedPointerData.pointerProperties,
- mCurrentCookedPointerData.pointerCoords,
- mCurrentCookedPointerData.idToIndex,
- currentIdBits, -1,
- mOrientedXPrecision, mOrientedYPrecision, mDownTime);
- }
- void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
- int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
- const PointerProperties* properties, const PointerCoords* coords,
- const uint32_t* idToIndex, BitSet32 idBits,
- int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
- getListener()->notifyMotion(&args);
- }
-
- void SwitchInputMapper::process(const RawEvent* rawEvent) {
- sync(rawEvent->when);
- }
- void SwitchInputMapper::sync(nsecs_t when) {
- getListener()->notifySwitch(&args);
- }
-
- void JoystickInputMapper::process(const RawEvent* rawEvent) {
- sync(rawEvent->when, false );
- }
- void JoystickInputMapper::sync(nsecs_t when, bool force) {
- getListener()->notifyMotion(&args);
- }
-
- void KeyboardInputMapper::process(const RawEvent* rawEvent) {
- processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
- }
- void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
- int32_t scanCode, uint32_t policyFlags) {
- getListener()->notifyKey(&args);
- }
2.2.InputReaderThread线程对系统层按键做处理(比较重要的是POWER键,最终在PhoneWindowManager中的interceptKeyBeforeQueueing和interceptMotionBeforeQueueingWhenScreenOff)后分发给InputDispatcherThread线程,以下分析将看到之前一个鼠标操作过程中无法待机的问题解决
以下几种情况都会唤醒InputDispatcherThread线程,即调用mLooper->wake()唤醒正在awoken()中的InputReaderThread线程:
frameworks/base/services/input/InputDispatcher.cpp
-
- void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
- ConfigurationChangedEntry* newEntry = new ConfigurationChangedEntry(args->eventTime);
- needWake = enqueueInboundEventLocked(newEntry);
- if (needWake) {
- mLooper->wake();
- }
- }
-
- void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
-
- mPolicy->interceptKeyBeforeQueueing(&event, policyFlags);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- KeyEntry* newEntry = new KeyEntry(args->eventTime,
- args->deviceId, args->source, policyFlags,
- args->action, flags, args->keyCode, args->scanCode,
- metaState, repeatCount, args->downTime);
- needWake = enqueueInboundEventLocked(newEntry);
- if (needWake) {
- mLooper->wake();
- }
- }
-
- void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
- mPolicy->interceptMotionBeforeQueueing(args->eventTime, policyFlags);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- MotionEntry* newEntry = new MotionEntry(args->eventTime,
- args->deviceId, args->source, policyFlags,
- args->action, args->flags, args->metaState, args->buttonState,
- args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
- args->displayId,
- args->pointerCount, args->pointerProperties, args->pointerCoords);
- needWake = enqueueInboundEventLocked(newEntry);
- if (needWake) {
- mLooper->wake();
- }
- }
-
- void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- DeviceResetEntry* newEntry = new DeviceResetEntry(args->eventTime, args->deviceId);
- needWake = enqueueInboundEventLocked(newEntry);
- if (needWake) {
- mLooper->wake();
- }
- }
-
- int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
- int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
- uint32_t policyFlags) {
- needWake |= enqueueInboundEventLocked(entry);
- if (needWake) {
- mLooper->wake();
- }
- }
-
-
-
-
-
-
-
-
2.3.InputDispatcherThread线程处理,根据PhoneWindowManager中的interceptKeyBeforeDispatching决定是否丢弃按键
InputDispatcherThread线程被唤醒
- bool InputDispatcherThread::threadLoop() {
- mDispatcher->dispatchOnce();
- return true;
- }
- void InputDispatcher::dispatchOnce() {
- dispatchOnceInnerLocked(&nextWakeupTime);
- mLooper->pollOnce(timeoutMillis);
- }
- void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
- if (!mPolicy->isKeyRepeatEnabled()) {
- resetKeyRepeatLocked();
- }
- switch (mPendingEvent->type) {
- case EventEntry::TYPE_CONFIGURATION_CHANGED: {
- done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
- }
- case EventEntry::TYPE_DEVICE_RESET: {
- done = dispatchDeviceResetLocked(currentTime, typedEntry);
- }
- case EventEntry::TYPE_KEY: {
- done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
- }
- case EventEntry::TYPE_MOTION: {
- done = dispatchMotionLocked(currentTime, typedEntry,
- &dropReason, nextWakeupTime);
- }
- }
- dropInboundEventLocked(mPendingEvent, dropReason);
- }
-
- bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
- DropReason* dropReason, nsecs_t* nextWakeupTime) {
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
- if (*dropReason == DROP_REASON_NOT_DROPPED) {
- *dropReason = DROP_REASON_POLICY;
- }
- }
- if (*dropReason != DROP_REASON_NOT_DROPPED) {
- setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
- ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
- return true;
- }
- dispatchEventLocked(currentTime, entry, inputTargets);
- }
- bool InputDispatcher::dispatchMotionLocked(
- nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
- dispatchEventLocked(currentTime, entry, inputTargets);
- }
2.4.InputDispatcherThread线程分发给应用程序进程
在这里解决了up事件上报两次的问题!!!!!!
frameworks/base/services/input/InputDispatcher.cpp
- void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
- EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
- pokeUserActivityLocked(eventEntry);
- ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
- sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
- prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
- }
- void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
- enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
- }
- void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
- const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- startDispatchCycleLocked(currentTime, connection);
- }
- void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
- switch (eventEntry->type) {
- case EventEntry::TYPE_KEY: {
- status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
- keyEntry->deviceId, keyEntry->source,
- dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
- keyEntry->keyCode, keyEntry->scanCode,
- keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
- keyEntry->eventTime);
- }
- case EventEntry::TYPE_MOTION: {
- status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
- motionEntry->deviceId, motionEntry->source,
- dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
- motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
- xOffset, yOffset,
- motionEntry->xPrecision, motionEntry->yPrecision,
- motionEntry->downTime, motionEntry->eventTime,
- motionEntry->pointerCount, motionEntry->pointerProperties,
- usingCoords);
- }
- }
- }
frameworks/base/libs/androidfw/InputTransport.cpp
- status_t InputPublisher::publishKeyEvent(
- uint32_t seq,
- int32_t deviceId,
- int32_t source,
- int32_t action,
- int32_t flags,
- int32_t keyCode,
- int32_t scanCode,
- int32_t metaState,
- int32_t repeatCount,
- nsecs_t downTime,
- nsecs_t eventTime) {
- return mChannel->sendMessage(&msg);
- }
- status_t InputChannel::sendMessage(const InputMessage* msg) {
- do {
- nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
- } while (nWrite == -1 && errno == EINTR);
- }
二、Android4.2系统应用程序侧——与View关系
InputManagerService也就是InputDispatcher与应用程序通信是靠looper。
说明:
InputReader从设备文件中读取的是RawEvent,在交给InputDispatcher进行分发之前,它需要先把RawEvent进行转化分类,拆分成KeyEvent、MotionEvent、TrackEvent各种类型等。
InputDispatcher获得按键事件后,根据当前设备的状况来优先消化事件(该过程交由PhoneWindowManager.java来处理);最后,剩余事件分发给ViewRoot;ViewRoot再分发给IME输入法或View、Activity。
1.应用程序View中channel注册过程
frameworks/base/core/java/android/view/ViewRootImpl.java
- public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
- mInputChannel = new InputChannel();
- res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
- getHostVisibility(), mDisplay.getDisplayId(),
- mAttachInfo.mContentInsets, mInputChannel);
- mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
- Looper.myLooper());
- }
- final class WindowInputEventReceiver extends InputEventReceiver {
- public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
- }
- @Override
- public void onInputEvent(InputEvent event) {
- enqueueInputEvent(event, this, 0, true);
- }
- }
frameworks/base/core/java/android/view/InputEventReceiver.java
- public InputEventReceiver(InputChannel inputChannel, Looper looper) {
- mReceiverPtr = nativeInit(this, inputChannel, mMessageQueue);
- }
- private static native int nativeInit(InputEventReceiver receiver,
- InputChannel inputChannel, MessageQueue messageQueue);
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
- static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
- jobject inputChannelObj, jobject messageQueueObj) {
- sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
- receiverObj, inputChannel, messageQueue);
- status_t status = receiver->initialize();
- }
- status_t NativeInputEventReceiver::initialize() {
- int receiveFd = mInputConsumer.getChannel()->getFd();
- mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL);
- return OK;
- }
frameworks/native/libs/utils/Looper.cpp
- int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
- request.callback = callback;
- }
2.应用程序View响应过程
frameworks/native/libs/utils/Looper.cpp
- int Looper::pollInner(int timeoutMillis) {
- awoken();
- int callbackResult = response.request.callback->handleEvent(fd, events, data);
- }
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
- int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
- status_t status = consumeEvents(env, false , -1);
- }
- status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
- bool consumeBatches, nsecs_t frameTime) {
- env->CallVoidMethod(mReceiverObjGlobal,
- gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
- }
frameworks/base/core/java/android/view/InputEventReceiver.java
- private void dispatchInputEvent(int seq, InputEvent event) {
- mSeqMap.put(event.getSequenceNumber(), seq);
- onInputEvent(event);
- }
frameworks/base/core/java/android/view/ViewRootImpl.java
- final class WindowInputEventReceiver extends InputEventReceiver {
- public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
- }
- @Override
- public void onInputEvent(InputEvent event) {
- enqueueInputEvent(event, this, 0, true);
- }
- }
- void enqueueInputEvent(InputEvent event,
- InputEventReceiver receiver, int flags, boolean processImmediately) {
- scheduleProcessInputEvents();
- }
/////////////////////////////////////////////////////////////
有关handler机制请看下文:
http://blog.csdn.net/itachi85/article/details/8035333
- final ViewRootHandler mHandler = new ViewRootHandler();
- private void scheduleProcessInputEvents() {
- Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
- mHandler.sendMessage(msg);
- }
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_PROCESS_INPUT_EVENTS:
- doProcessInputEvents();
- }
- }
///////////////////////////////////////////////////////
- void doProcessInputEvents() {
- deliverInputEvent(q);
- }
- private void deliverInputEvent(QueuedInputEvent q) {
- deliverKeyEvent(q);
- deliverPointerEvent(q);
- deliverTrackballEvent(q);
- deliverGenericMotionEvent(q);
- }
- private void deliverKeyEvent(QueuedInputEvent q) {
- imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
- deliverKeyEventPostIme(q);
-
-
-
-
-
- }
- private void deliverPointerEvent(QueuedInputEvent q) {
- boolean handled = mView.dispatchPointerEvent(event);
- }
- private void deliverTrackballEvent(QueuedInputEvent q) {
- imm.dispatchTrackballEvent(mView.getContext(), seq, event,
- mInputMethodCallback);
- deliverTrackballEventPostIme(q);
-
-
-
-
-
- }
- private void deliverGenericMotionEvent(QueuedInputEvent q) {
- imm.dispatchGenericMotionEvent(mView.getContext(), seq, event,
- mInputMethodCallback);
- deliverGenericMotionEventPostIme(q);
-
-
-
-
-
-
- }
分发给应用程序Activity:
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
- private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
- public boolean dispatchKeyEvent(KeyEvent event) {
- final Callback cb = getCallback();
-
- final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) : super.dispatchKeyEvent(event);
-
- }
- }
而上述应用程序中的dispatchKeyEvent一般会调用其父类的该方法,例如:
packages/apps/Launcher2/src/com/android/launcher2/Launcher.java
- public boolean dispatchKeyEvent(KeyEvent event) {
- return super.dispatchKeyEvent(event);
- }
应用程序Activity在分发给与之关联的某个View,如果这个View没有处理、最终交给该Activity自己处理。
应用程序有关View的设置:
- private Dialog mMenuWin;
- mMenuWin = new Dialog(aActivity, R.style.CameraDialog);
- mMenuWin.setContentView(mMenuLayout);
- mMenuWin.setOnClickListener();
- mMenuWin.setOnLongClickListener();
- mMenuWin.setOnTouchListener();
- mMenuWin.setOnKeyListener(new OnKeyListener() {
- public boolean onKey();
- public void onClick(View v);
- }
frameworks/base/core/java/android/app/Activity.java
- public boolean dispatchKeyEvent(KeyEvent event) {
- onUserInteraction();
- 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);
- }
- }
我们重点分析win.superDispatchKeyEvent,也就是View的处理流程:
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
- public class PhoneWindow extends Window implements MenuBuilder.Callback {
- public boolean superDispatchKeyEvent(KeyEvent event) {
- return mDecor.superDispatchKeyEvent(event);
- }
- }
- private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
- public boolean superDispatchKeyEvent(KeyEvent event) {
- super.dispatchKeyEvent(event)
- }
- }
frameworks/base/core/java/android/view/ViewGroup.java //分发给View的关键部分!!!
- public boolean dispatchKeyEvent(KeyEvent event) {
- mInputEventConsistencyVerifier.onKeyEvent(event, 1);
- super.dispatchKeyEvent(event)
- }
frameworks/base/core/java/android/view/View.java
- public boolean dispatchKeyEvent(KeyEvent event) {
- li.mOnKeyListener.onKey(this, event.getKeyCode(), event);
- event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)
-
-
-
-
-
-
-
-
- }
- public final boolean dispatchPointerEvent(MotionEvent event) {
- if (event.isTouchEvent()) {
- return dispatchTouchEvent(event);
- } else {
- return dispatchGenericMotionEvent(event);
- }
- }
- public boolean dispatchTouchEvent(MotionEvent event) {
-
- li.mOnTouchListener.onTouch(this, event)
-
- onTouchEvent(event)
-
-
-
-
-
-
- }
以下不再做分析
dispatchGenericMotionEvent
dispatchTrackballEvent
dispatchConfigurationChanged //添加或删除键盘设备Activity重启,见http://blog.csdn.net/tankai19880619/article/details/16805401
三、Input设备与Activity关系
1.InputReaderThread线程检测到设备插入删除
frameworks/base/service/input/InputReader.cpp
- void InputReader::loopOnce() {
- size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
-
-
-
-
-
-
-
- processEventsLocked(mEventBuffer, count);
- }
- void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
- case EventHubInterface::FINISHED_DEVICE_SCAN:
- handleConfigurationChangedLocked(rawEvent->when);
- }
- void InputReader::handleConfigurationChangedLocked(nsecs_t when) {
- updateGlobalMetaStateLocked();
-
- NotifyConfigurationChangedArgs args(when);
- mQueuedListener->notifyConfigurationChanged(&args);
- }
说明:有的平台需要在接入硬件键盘时Activity不需要刷新;可以在上处做屏蔽:
2.InputReaderThread线程分发给InputDispatcherThread线程
frameworks/base/service/input/InputDispatcher.cpp
- void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
- needWake = enqueueInboundEventLocked(newEntry);
- if (needWake) {
- mLooper->wake();
- }
- }
3.InputReaderThread线程收到消息并处理
frameworks/base/service/input/InputDispatcher.cpp
- bool InputDispatcherThread::threadLoop() {
- mDispatcher->dispatchOnce();
- return true;
- }
- void InputDispatcher::dispatchOnce() {
- dispatchOnceInnerLocked(&nextWakeupTime);
- }
- void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
- case EventEntry::TYPE_CONFIGURATION_CHANGED: {
- ConfigurationChangedEntry* typedEntry =
- static_cast<ConfigurationChangedEntry*>(mPendingEvent);
- done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
- }
- }
- bool InputDispatcher::dispatchConfigurationChangedLocked(
- nsecs_t currentTime, ConfigurationChangedEntry* entry) {
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyConfigurationChangedInterruptible);
- }
- void InputDispatcher::doNotifyConfigurationChangedInterruptible(
- CommandEntry* commandEntry) {
- mPolicy->notifyConfigurationChanged(commandEntry->eventTime);
- }
如上,不再做分析:
frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp
- void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyConfigurationChanged, when);
- }
frameworks/base/services/java/com/android/server/input/InputManagerService.cpp
- private void notifyConfigurationChanged(long whenNanos) {
- mWindowManagerCallbacks.notifyConfigurationChanged();
- }
如上,不再做分析:
frameworks/base/service/java/com/android/server/wm/InputMonitor.java
- public void notifyConfigurationChanged() {
- mService.sendNewConfiguration();
- }
frameworks/base/service/java/com/android/server/wm/WindowManagerService.java
- void sendNewConfiguration() {
- mActivityManager.updateConfiguration(null);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
4.交由ActivityManagerService进程处理
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
- public void updateConfiguration(Configuration values) {
- updateConfigurationLocked(values, null, false, false);
- }
- boolean updateConfigurationLocked(Configuration values,
- ActivityRecord starting, boolean persistent, boolean initLocale) {
- kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);
- public void setWindowManager(WindowManagerService wm) {
- mWindowManager = wm;
- }
- }
frameworks/base/services/java/com/android/server/am/ActivityStack.java
- final boolean ensureActivityConfigurationLocked(ActivityRecord r,
- int globalChanges) {
-
- if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {
- relaunchActivityLocked(r, r.configChangeFlags, false);
- return false;
- }
-
- r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
- }
frameworks/base/core/java/android/app/ActivityThread.java
- public void scheduleActivityConfigurationChanged(IBinder token) {
- queueOrSendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token);
- }
-
- public void handleMessage(Message msg) {
- case ACTIVITY_CONFIGURATION_CHANGED:
- handleActivityConfigurationChanged((IBinder)msg.obj);
- }
- final void handleActivityConfigurationChanged(IBinder token) {
- performConfigurationChanged(r.activity, mCompatConfiguration);
- }
- private static void performConfigurationChanged(ComponentCallbacks2 cb, Configuration config) {
- cb.onConfigurationChanged(config);
- }
四、项目问题
1.resumeTopActivity时的Activity重启。
http://blog.csdn.net/jivin_shen/article/details/6839175
操作逻辑:打开Launcher界面下的一个应用(比如播放器),完后接入USB键盘;之后退出该应用,也就是resumeTopActivity到Launcher时也引发了config配置更新导致的Activity重启。
原理以及解决部分:
frameworks/base/services/java/com/android/server/am/ActivityStack.java
- final boolean resumeTopActivityLocked(ActivityRecord prev) {
- return resumeTopActivityLocked(prev, null);
- }
- final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
- Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
- mService.mConfiguration,
- next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
- }
frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
- public Configuration updateOrientationFromAppTokens(
- Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
- config = updateOrientationFromAppTokensLocked(currentConfig,
- freezeThisOneIfNeeded);
- }
- private Configuration updateOrientationFromAppTokensLocked(
- Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
- computeScreenConfigurationLocked(mTempConfiguration)
- }
- boolean computeScreenConfigurationLocked(Configuration config) {
- if ((sources & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) {
-
- config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
-
-
- }
- else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
- && config.navigation == Configuration.NAVIGATION_NONAV) {
-
-
-
-
- }
- if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
-
-
-
-
- }
- }
2.面板设备与虚拟驱动导致的up上报两次:
drop类按键
down或up:
dispatchOnceInnerLocked>
dropInboundEventLocked>synthesizeCancelationEventsForAllConnectionsLocked-synthesizeCancelationEventsForConnectionLocked>inputState.synthesizeCancelationEvents->mKeyMementos.itemAt(i),最后上报系统(synthesizeCancelationEventsForConnectionLocked调用enqueueDispatchEntryLocked)
非drop类按键
down:
dispatchOnceInnerLocked->
dispatchKeyLocked->dispatchEventLocked->prepareDispatchCycleLocked->enqueueDispatchEntriesLocked->enqueueDispatchEntryLocked->InputState::trackKey->addKeyMemento //只在down时保存对up的处理
问题:
面板down->drop
虚拟down->非drop,保存up
面板down->drop,将虚拟保存的up送上去
虚拟up->非drop,直接上报
结果——两个虚拟的up
修改方法:
frameworks/base/service/input/InputDispatcher.cpp
- void InputDispatcher::enqueueDispatchEntryLocked(
- const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
- int32_t dispatchMode)
- {
- if (!connection->inputState.trackKey(keyEntry,
- dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags) || (dispatchEntry->resolvedFlags == 0x28))
- {
- #if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
- connection->getInputChannelName());
- #endif
- delete dispatchEntry;
- return;
- }
-
-
-
-
-
-
-
-
-
- }
3.焦点request错误导致不能响应按键
正确调用:setFocusable(true)和requestFocus()重新获取焦点
错误调用:setFocusable(false)和requestFocus()
系统侧为该应用tv.huan.deezer强制修改:
frameworks/base/core/java/android/view/View.java
- public final boolean requestFocus() {
- Log.d("TKTK","TK---->>>View.java>>>>requestFocus()");
- if(SystemProperties.get("sys.user.camera",null).equals("tv.huan.deezer"))
- {
- setFocusable(true);
- }
-
- return requestFocus(View.FOCUS_DOWN);
- }