Android 源码分析鼠标事件传递
来源:互联网 发布:苹果硬盘彻底删除数据 编辑:程序博客网 时间:2024/05/24 04:17
google推出的carboard、daydream是没有usb接口的,调节全靠手机自身的sensor。而想gear vr这类VR眼镜是有USB接口的,眼镜内部是有sensor用户调节眼镜的,而且有触屏、返回键和音量调节键。是不是很像一个鼠标。
add device 1: /dev/input/event19 name: "XXXX VR, Inc. x HID"could not get driver version for /dev/input/mouse1, Not a typewriter
shell状态下输入getevent -l,/dev/input/mouse1确实是一个鼠标,证明了我们的猜想。
下面我们从设备输入的源头InputReader.cpp进行分析。
InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize();}
void InputManager::initialize() { mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher);}status_t InputManager::start() { status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputDispatcher thread due to error %d.", result); return result; } result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputReader thread due to error %d.", result); mDispatcherThread->requestExit(); return result; } return OK;}
InputReader是由InputManager生成,同时还生成了两个线程,一个用于取InputDevice输入的信息,一个负责分发事件
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) { ...... // Synthesize key down from buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, policyFlags, lastButtonState, currentButtonState); // Send motion event. if (downChanged || moved || scrolled || buttonsChanged) { int32_t metaState = mContext->getGlobalMetaState(); int32_t buttonState = lastButtonState; int32_t motionEventAction; if (downChanged) { motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; } else if (down || mPointerController == NULL) { motionEventAction = AMOTION_EVENT_ACTION_MOVE; } else { motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; } if (buttonsReleased) { BitSet32 released(buttonsReleased); while (!released.isEmpty()) { int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); buttonState &= ~actionButton; NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&releaseArgs); } } NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&args); ...... // Synthesize key up from buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, policyFlags, lastButtonState, currentButtonState); mCursorMotionAccumulator.finishSync(); mCursorScrollAccumulator.finishSync();}
InputReader管理着所有的InputDevice,针对不同的输入设备类型,对应不同的InputMapper类,鼠标类型是CursorInputMapper类,Cursor取事件的方法是process,在sync方法中进行处理。
static void synthesizeButtonKey(InputReaderContext* context, int32_t action, nsecs_t when, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState, int32_t buttonState, int32_t keyCode) { if ( (action == AKEY_EVENT_ACTION_DOWN && !(lastButtonState & buttonState) && (currentButtonState & buttonState)) || (action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) && !(currentButtonState & buttonState))) { NotifyKeyArgs args(when, deviceId, source, policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when); context->getListener()->notifyKey(&args); }}static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, nsecs_t when, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) { synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK); synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD);}
synthesizeButtonKeys对key进行合成,我们看到了熟悉的BACK键,context->getListener()->notifyKey(&key)
InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy);
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {...... int32_t keyCode = args->keyCode; if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) { int32_t newKeyCode = AKEYCODE_UNKNOWN; if (keyCode == AKEYCODE_DEL) { newKeyCode = AKEYCODE_BACK; } else if (keyCode == AKEYCODE_ENTER) { newKeyCode = AKEYCODE_HOME; } if (newKeyCode != AKEYCODE_UNKNOWN) { AutoMutex _l(mLock); struct KeyReplacement replacement = {keyCode, args->deviceId}; mReplacedKeys.add(replacement, newKeyCode); keyCode = newKeyCode; metaState &= ~AMETA_META_ON; } } else if (args->action == AKEY_EVENT_ACTION_UP) { // In order to maintain a consistent stream of up and down events, check to see if the key // going up is one we've replaced in a down event and haven't yet replaced in an up event, // even if the modifier was released between the down and the up events. AutoMutex _l(mLock); struct KeyReplacement replacement = {keyCode, args->deviceId}; ssize_t index = mReplacedKeys.indexOfKey(replacement); if (index >= 0) { keyCode = mReplacedKeys.valueAt(index); mReplacedKeys.removeItemsAt(index); metaState &= ~AMETA_META_ON; } } KeyEvent event; event.initialize(args->deviceId, args->source, args->action, flags, keyCode, args->scanCode, metaState, 0, args->downTime, args->eventTime); mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); .......}
context->getListener()取得的是针对InputDispatcher的一个封装,调用的是它的notifyKey,在InputManager构造方法中将InputDispatcher传给了InputReader。实际上调用的是
sp<InputDispatcherPolicyInterface>
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {...... if (keyEventObj) { wmActions = env->CallIntMethod(mServiceObj, gServiceClassInfo.interceptKeyBeforeQueueing, keyEventObj, policyFlags); if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) { wmActions = 0; } android_view_KeyEvent_recycle(env, keyEventObj); env->DeleteLocalRef(keyEventObj); } else { ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing."); wmActions = 0; } handleInterceptActions(wmActions, when, /*byref*/ policyFlags); } else { if (interactive) { policyFlags |= POLICY_FLAG_PASS_TO_USER; } }}
sp<InputDispatcherPolicyInterface>的interceptKeyBeforeQueueing。InputManagerService的jni部分实现了InputDispatcherPolicyInterface的接口,jni部分调用了InputManagerService.java的interceptKeyBeforeQueueing方法,这样key事件传递到了Java世界。
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags); }
public interface WindowManagerCallbacks { public void notifyConfigurationChanged(); public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered); public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle); public long notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHandle inputWindowHandle, String reason); public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags); public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags); public long interceptKeyBeforeDispatching(InputWindowHandle focus, KeyEvent event, int policyFlags); public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, KeyEvent event, int policyFlags); public int getPointerLayer(); }
package com.android.server.wm;
final class InputMonitor implements InputManagerService.WindowManagerCallbacks
key事件通过mWindowManagerCallbacks.interceptKeyBeforeQueueing传递,mWindowManagerCallbacks是InputMonitor的对象,InputMonitor是wm包里的一个类,我们离windowManagerService已经很近了。
private final WindowManagerService mService;
@Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags); }
mService就是WindowManagerService,mPolicy 就是PhoneWindowManager,最终我们来到了key值的处理和分发枢纽。
@Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { if (!mSystemBooted) { // If we have not yet booted, don't let key events do anything. return 0; } final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0; final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final boolean canceled = event.isCanceled(); final int keyCode = event.getKeyCode(); final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0; ...... switch (keyCode) { case KeyEvent.KEYCODE_BACK: { if (down) { mBackKeyHandled = false; if (hasLongPressOnBackBehavior()) { Message msg = mHandler.obtainMessage(MSG_BACK_LONG_PRESS); msg.setAsynchronous(true); mHandler.sendMessageDelayed(msg, ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); } } else { boolean handled = mBackKeyHandled; // Reset back key state cancelPendingBackKeyAction(); // Don't pass back press to app if we've already handled it if (handled) { result &= ~ACTION_PASS_TO_USER; } } break; } ...... if (useHapticFeedback) { performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); } if (isWakeKey) { wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY"); } return result; }
PhoneWindowManager对BACK按键的处理并没有什么特别的,PhoneWindowManager主要是对全局性的key进行处理,比如POWER、RECENT等,由于BACK按键对于View体系是非常重要的,事件肯定会分发到View层面进行进一步处理。把Key事件放进队列,我们回到InputDispatcher.cpp。
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {...... mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); bool needWake; { // acquire lock mLock.lock(); if (shouldSendKeyToInputFilterLocked(args)) { mLock.unlock(); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { return; // event was consumed by the filter } mLock.lock(); } int32_t repeatCount = 0; KeyEntry* newEntry = new KeyEntry(args->eventTime, args->deviceId, args->source, policyFlags, args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); } // release lock if (needWake) { mLooper->wake(); }}
将Key事件放进队列,然后呢?mLooper->wake()消费这个消息,不理解的可以看NativeMessageQueue
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry); traceInboundQueueLengthLocked();
InputDispatcher的enqueueInboundEventLocked方法将事件放进队列。
void InputReader::loopOnce() { ...... // Send out a message that the describes the changed input devices. if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); } // Flush queued events out to the listener. // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked // on another thread similarly waiting to acquire the InputReader lock thereby // resulting in a deadlock. This situation is actually quite plausible because the // listener is actually the input dispatcher, which calls into the window manager, // which occasionally calls into the input reader. mQueuedListener->flush();}
bool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); return true;}
void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); mDispatcherIsAliveCondition.broadcast(); // Run a dispatch loop if there are no pending commands. // The dispatch loop might enqueue commands to run afterwards. if (!haveCommandsLocked()) { dispatchOnceInnerLocked(&nextWakeupTime); } // Run all pending commands if there are any. // If any commands were run then force the next poll to wake up immediately. if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; } } // release lock // Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t currentTime = now(); int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); mLooper->pollOnce(timeoutMillis);}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { ...... // Inbound queue has at least one entry. mPendingEvent = mInboundQueue.dequeueAtHead(); traceInboundQueueLengthLocked(); ...... case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); if (isAppSwitchDue) { if (isAppSwitchKeyEventLocked(typedEntry)) { resetPendingAppSwitchLocked(true); isAppSwitchDue = false; } else if (dropReason == DROP_REASON_NOT_DROPPED) { dropReason = DROP_REASON_APP_SWITCH; } } if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } ......}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {...... for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);......}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) {...... while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.head; dispatchEntry->deliveryTime = currentTime; // Publish the event. status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); // Publish the key event. 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); break; }
之前我们介绍InputReader创建的时候,提到了InputManager创建了两个线程,一个是分发线程,一个是取事件的线程,在start中启动了他们,会调用到InputReader的loopOnce取得事件放入队列,放入队列的预处理之前已经分析,接下来是InputDispatcherThread循坏mDispatcher->dispatchOnce。dispatchOnce中dispatch一个消息
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) {..... InputMessage msg; msg.header.type = InputMessage::TYPE_KEY; msg.body.key.seq = seq; msg.body.key.deviceId = deviceId; msg.body.key.source = source; msg.body.key.action = action; msg.body.key.flags = flags; msg.body.key.keyCode = keyCode; msg.body.key.scanCode = scanCode; msg.body.key.metaState = metaState; msg.body.key.repeatCount = repeatCount; msg.body.key.downTime = downTime; msg.body.key.eventTime = eventTime; return mChannel->sendMessage(&msg);}
最终在InputPublisher中由mChannel->sendMessage, mChannel是某个window和InputReader的一个桥梁,这里发消息应该是发给了一个window。
class Connection : public RefBase { protected: virtual ~Connection(); public: enum Status { // Everything is peachy. STATUS_NORMAL, // An unrecoverable communication error has occurred. STATUS_BROKEN, // The input channel has been unregistered. STATUS_ZOMBIE }; Status status; sp<InputChannel> inputChannel; // never null sp<InputWindowHandle> inputWindowHandle; // may be null bool monitor; InputPublisher inputPublisher; InputState inputState; // True if the socket is full and no further events can be published until // the application consumes some of the input. bool inputPublisherBlocked; // Queue of events that need to be published to the connection. Queue<DispatchEntry> outboundQueue; // Queue of events that have been published to the connection but that have not // yet received a "finished" response from the application. Queue<DispatchEntry> waitQueue; explicit Connection(const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor); inline const char* getInputChannelName() const { return inputChannel->getName().string(); } const char* getWindowName() const; const char* getStatusLabel() const; DispatchEntry* findWaitQueueEntry(uint32_t seq); };
Connection是InputDispatcher的一个内部类,通过registerInputChannel,那么在哪里建立了这种连接呢?
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */, const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { return mInputManager->getDispatcher()->registerInputChannel( inputChannel, inputWindowHandle, monitor);}
public void registerInputChannel(InputChannel inputChannel, InputWindowHandle inputWindowHandle) { if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); } nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false); }
我找找到了InputManagerService.java这个源头
void openInputChannel(InputChannel outInputChannel) { if (mInputChannel != null) { throw new IllegalStateException("Window already has an input channel."); } String name = makeInputChannelName(); InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); mInputChannel = inputChannels[0]; mClientChannel = inputChannels[1]; mInputWindowHandle.inputChannel = inputChannels[0]; if (outInputChannel != null) { mClientChannel.transferTo(outInputChannel); mClientChannel.dispose(); mClientChannel = null; } else { // If the window died visible, we setup a dummy input channel, so that taps // can still detected by input monitor channel, and we can relaunch the app. // Create dummy event receiver that simply reports all events as handled. mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel); } mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle); }
WindowState中找到了有关调用,这个mService又是WindowsManagerService
public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) {...... final boolean openInputChannels = (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0); if (openInputChannels) { win.openInputChannel(outInputChannel); } public View addStartingWindow(IBinder appToken, String packageName, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, Configuration overrideConfig) { ...... WindowManager wm = null; View view = null; try { Context context = mContext; if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme=" + Integer.toHexString(theme)); if (theme != context.getThemeResId() || labelRes != 0) { try { context = context.createPackageContext(packageName, 0); context.setTheme(theme); } catch (PackageManager.NameNotFoundException e) { // Ignore } }...... final PhoneWindow win = new PhoneWindow(context);...... wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); view = win.getDecorView(); if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Adding starting window for " + packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null)); wm.addView(view, params);...... }
在每次addWindow的时候建立了一个连接,证实了我们的猜想。
消息系统这里不再分析,有兴趣的参考这篇文章http://www.cnblogs.com/TaigaCon/p/4750349.html
InputPublisher如何与消息系统建立联系,看一下时序图。
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {...... ViewRootImpl root; View panelParentView = null; synchronized (mLock) {...... root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); } // do this last because it fires off messages to start doing things try { root.setView(view, wparams, panelParentView); } catch (RuntimeException e) {...... }
Android View体系中,Window包含了很多View, 包括一个DecorView和一个ViewGroup,之后添加进来的View,都会创建一个ViewRootImpl对应,让我们看看ViewRootImpl是干什么的?
/** * The top of a view hierarchy, implementing the needed protocol between View * and the WindowManager. This is for the most part an internal implementation * detail of {@link WindowManagerGlobal}. * * {@hide} */@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks
ViewRootImpl是WindowManager和View之间的桥梁,管理着View除视图外其他的部分,它实际上是一个Handler,它可以向DecorView分发事件,当然,AccessibilityService的部分也在这里处理。
setView(View view...){...... if (mInputChannel != null) { if (mInputQueueCallback != null) { mInputQueue = new InputQueue(); mInputQueueCallback.onInputQueueCreated(mInputQueue); } mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); }......}
ViewRootImpl setView的时候会建立一个InputReceiver,当有inputEvent时触发。
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); } @Override public void onBatchedInputEventPending() { if (mUnbufferedInputDispatch) { super.onBatchedInputEventPending(); } else { scheduleConsumeBatchedInput(); } } @Override public void dispose() { unscheduleConsumeBatchedInput(); super.dispose(); } }
void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) {...... if (processImmediately) { doProcessInputEvents(); } else { scheduleProcessInputEvents(); } }
void doProcessInputEvents() { // Deliver all pending input events in the queue. while (mPendingInputEventHead != null) { QueuedInputEvent q = mPendingInputEventHead; mPendingInputEventHead = q.mNext; if (mPendingInputEventHead == null) { mPendingInputEventTail = null; } q.mNext = null; ...... deliverInputEvent(q); }...... }
private void deliverInputEvent(QueuedInputEvent q) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent", q.mEvent.getSequenceNumber()); if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0); } InputStage stage; if (q.shouldSendToSynthesizer()) { stage = mSyntheticInputStage; } else { stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; } if (stage != null) { stage.deliver(q); } else { finishInputEvent(q); } }
public boolean shouldSkipIme() { if ((mFlags & FLAG_DELIVER_POST_IME) != 0) { return true; } return mEvent instanceof MotionEvent && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER); }
mFirstInputStage = earlyPostInputStage;
final class ViewPostImeInputStage extends InputStage { public ViewPostImeInputStage(InputStage next) { super(next); } @Override protected int onProcess(QueuedInputEvent q) { if (q.mEvent instanceof KeyEvent) { return processKeyEvent(q); } else { final int source = q.mEvent.getSource(); if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { return processPointerEvent(q); } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { return processTrackballEvent(q); } else { return processGenericMotionEvent(q); } } } @Override protected void onDeliverToNext(QueuedInputEvent q) { if (mUnbufferedInputDispatch && q.mEvent instanceof MotionEvent && ((MotionEvent)q.mEvent).isTouchEvent() && isTerminalInputEvent(q.mEvent)) { mUnbufferedInputDispatch = false; scheduleConsumeBatchedInput(); } super.onDeliverToNext(q); } private int processKeyEvent(QueuedInputEvent q) { final KeyEvent event = (KeyEvent)q.mEvent; // Deliver the key to the view hierarchy. if (mView.dispatchKeyEvent(event)) { return FINISH_HANDLED; }
key终于传递到了View hierarchy,也就是DecorView。
1 0
- Android 源码分析鼠标事件传递
- Android事件传递机制 源码分析
- Android View事件传递机制-源码分析
- Android View事件传递机制-源码分析
- android事件传递机制---源码分析(上)
- android事件传递机制---源码分析(下)
- Android View事件传递与源码分析
- 从源码角度分析Android 事件传递流程
- Android O: 触摸事件传递流程源码分析(上)
- Android O: 触摸事件传递流程源码分析(下)
- Android事件传递机制分析
- Android事件传递机制分析
- qml鼠标事件传递
- Android源码事件传递流程剖析
- Android事件传递机制详解及最新源码分析——View篇
- Android事件分发源码分析
- Android事件分发源码分析
- Android事件分发源码分析
- c++(7)
- App首屏接口性能优化
- 桥接模式Bridge
- 表达式运算顺序引发的流水线的学习笔记
- NTFS(文件恢复)最简单情况
- Android 源码分析鼠标事件传递
- 【Bzoj2186】沙拉公主的困惑
- 基础练习 字母图形
- [大型网站系统与Java中间件实践]--分布式服务框架(RPC)
- String类的浅拷贝与深拷贝
- win10开启wifi热点
- java程序员--小心你代码中的内存泄漏
- 数组基础
- 【安装eclipse, 配置java环境教程】 编写第一个java程序