当用户触摸屏幕或者按键操作。
首先触发硬件驱动,驱动收到事件后,将相应事件写入到输入设备节点
输入系统取出内核事件,封装成为KeyEvent或MotionEvent
交付给对应的Window消费该事件。
硬件中断
物理设备将数据发送给内核是通过设备驱动
传输的,在dev/input/
目录下有几个设备文件eventX
。
其中event0
对应的就是触摸屏,当触摸屏的驱动被挂载后,驱动程序就会进行初始化。
当触发对应的硬件中断后,就会调用对应的处理方法,把对应事件写到设备节点(/dev/input/event0)
中.
IMS获取内核事件 IMS启动过程
在Android系统启动过程 有介绍系统的启动流程,其中IMS
属于system_server
,随着system_server
的启动而启动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private void startOtherServices () { ... InputManagerService inputManager = null ; ... traceBeginAndSlog("StartInputManagerService" ); inputManager = new InputManagerService(context); traceEnd(); traceBeginAndSlog("StartInputManager" ); inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); inputManager.start(); traceEnd(); }
1 2 3 4 5 6 7 8 9 10 public InputManagerService (Context context) { this .mContext = context; this .mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); ... mPtr = nativeInit(this , mContext, mHandler.getLooper().getQueue()); LocalServices.addService(InputManagerInternal.class , new LocalService ()) ; }
nativeInit()
执行在Native层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 static jlong nativeInit (JNIEnv* env, jclass , jobject serviceObj, jobject contextObj, jobject messageQueueObj) { sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); ... NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); im->incStrong(0 ); return reinterpret_cast <jlong>(im); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper), mInteractive(true ) { JNIEnv* env = jniEnv(); mContextObj = env->NewGlobalRef(contextObj); mServiceObj = env->NewGlobalRef(serviceObj); { AutoMutex _l (mLock) ; mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE; mLocked.pointerSpeed = 0 ; mLocked.pointerGesturesEnabled = true ; mLocked.showTouches = false ; mLocked.pointerCapture = false ; } mInteractive = true ; sp<EventHub> eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this , this ); }
初始EventHub
EventHub
主要用于监控设备节点是否更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 static const char *WAKE_LOCK_ID = "KeyEvents" ;static const char *DEVICE_PATH = "/dev/input" ; EventHub::EventHub(void ) : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1 ), mControllerNumbers(), mOpeningDevices(0 ), mClosingDevices(0 ), mNeedToSendFinishedDeviceScan(false ), mNeedToReopenDevices(false ), mNeedToScanDevices(true ), mPendingEventCount(0 ), mPendingEventIndex(0 ), mPendingINotify(false ) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mEpollFd = epoll_create(EPOLL_SIZE_HINT); mINotifyFd = inotify_init(); int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); struct epoll_event eventItem ; memset (&eventItem, 0 , sizeof (eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = EPOLL_ID_INOTIFY; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); int wakeFds[2 ]; result = pipe(wakeFds); mWakeReadPipeFd = wakeFds[0 ]; mWakeWritePipeFd = wakeFds[1 ]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); eventItem.data.u32 = EPOLL_ID_WAKE; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); int major, minor; getLinuxRelease(&major, &minor); mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5 ); }
EventHub
主要执行了以下几步:
初始化epoll
实例
初始化iNotify
实例,用于监控/dev/input
目录的变化。若发生变化,意味设备发生变化,需要处理。epoll
添加iNotify实例
监听
创建非阻塞模式的管道(pipe
),epoll监听管道的内容。(主要用于 唤醒InputReader线程)
1 2 3 4 5 6 7 8 9 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(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : mPolicy(policy), mPendingEvent(NULL ), mLastDropReason(DROP_REASON_NOT_DROPPED), mAppSwitchSawKeyDown(false ), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(NULL ), mDispatchEnabled(false ), mDispatchFrozen(false ), mInputFilterEnabled(false ), mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false ); mKeyRepeatState.lastKeyEntry = NULL ; policy->getDispatcherConfiguration(&mConfig); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) : mContext(this ), mEventHub(eventHub), mPolicy(policy), mGlobalMetaState(0 ), mGeneration(1 ), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0 ) { mQueuedListener = new QueuedInputListener(listener); { AutoMutex _l(mLock); refreshConfigurationLocked(0 ); updateGlobalMetaStateLocked(); } }
负责监听InputDispatcher
对象
initalize() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void InputManager::initialize() { mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher); } InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) : Thread( true ), mDispatcher(dispatcher) { } InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) : Thread( true ), mReader(reader) { }
initalize()
主要是创建两个能访问Java代码的native线程。
1.The InputReaderThread (called “InputReader”) reads and preprocesses raw input events,applies policy, and posts messages to a queue managed by the DispatcherThread.
2.The InputDispatcherThread (called “InputDispatcher”) thread waits for new events on the queue and asynchronously dispatches them to applications.
IMS启动——start()
IMS
初始化完毕就准备启动
1 2 3 4 5 6 public void start () { Slog.i(TAG, "Starting input manager" ); nativeStart(mPtr); ... }
1 2 3 4 5 6 static void nativeStart (JNIEnv* env, jclass , jlong ptr) { NativeInputManager* im = reinterpret_cast <NativeInputManager*>(ptr); status_t result = im->getInputManager()->start(); }
1 2 3 4 5 6 7 8 9 status_t InputManager::start () { status_t result = mDispatcherThread->run ("InputDispatcher" , PRIORITY_URGENT_DISPLAY) result = mReaderThread->run ("InputReader" , PRIORITY_URGENT_DISPLAY); return OK; }
IMS
启动,会带着InputDispatcherThread
和InputReaderThread
一起启动。
总结
IMS启动过程重点在于Native的初始化,分别创建以下对象:
初始化完毕上述对象后,然后启动以下线程:
InputReaderThread :从EventHub
取出事件并处理,再转发给InputDispatcher
InputDispatcherThread :接收来自InputReader
的事件,并派发事件到合适的窗口(window)去处理
内核事件转发APP进程过程 IMS
启动之后,InputDispatcherThread
与InputReaderThread
随之启动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 bool InputReaderThread::threadLoop () { mReader->loopOnce(); return true ; }void InputReader::loopOnce () { ... size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { processEventsLocked(mEventBuffer, count); } } ... mQueuedListener->flush (); }
EventHub->getEvents() 获取事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 size_t EventHub::getEvents (int timeoutMillis, RawEvent* buffer , size_t bufferSize) { RawEvent* event = buffer ; size_t capacity = bufferSize; for (;;) { ... if (mNeedToScanDevices) { mNeedToScanDevices = false ; scanDevicesLocked(); mNeedToSendFinishedDeviceScan = true ; } ... while (mOpeningDevices != NULL ) { Device* device = mOpeningDevices; ALOGV("Reporting device opened: id=%d, name=%s\n" , device->id, device->path.string ()); mOpeningDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; event->type = DEVICE_ADDED; event += 1 ; mNeedToSendFinishedDeviceScan = true ; if (--capacity == 0 ) { break ; } } ... while (mPendingEventIndex < mPendingEventCount) { ... ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32); ... Device* device = mDevices.valueAt(deviceIndex); if (eventItem.events & EPOLLIN) { ... int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; size_t count = size_t (readSize) / sizeof (struct input_event); for (size_t i = 0 ; i < count; i++) { struct input_event & iev = readBuffer [i ]; event->deviceId = deviceId; event->type = iev.type; event->code = iev.code; event->value = iev.value; event += 1 ; capacity -= 1 ; } } } ... int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); ... if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { mPendingINotify = false ; readNotifyLocked(); deviceChanged = true ; } } ... return event - buffer ; }
getEvents()
采用INotify + epoll
监听/dev/input/
目录下的设备节点,再转换deviceId + input_event
为RawEvent
1 2 3 4 5 6 7 8 struct RawEvent { nsecs_t when; int32_t deviceId; int32_t type; int32_t code; int32_t value; };
type
可以为以下几种
DEVICE_ADDED
:添加设备
DEVICE_REMOVED
:移除设备
FINISHED_DEVICE_SCAN
:扫描完成
type < FIRST_SYNTHETIC_EVENT
:其他事件
getEvents()
大概执行流程:
当设备节点(/dev/input)
发生变化时,epoll_wait()
会响应到对应的变化,然后getEvents()
可以知道对应的变化。继续从mINotifyFd
读取iNotify事件
,进行输入设备的操作,最后生成相应的RawEvent
此时,EventHub从设备节点获取到了事件,并转化为RawEvent
向下处理。
processEventsLocked() 处理事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 void InputReader::processEventsLocked (const RawEvent* rawEvents, size_t count) { for (const RawEvent* rawEvent = rawEvents; count;) { int32_t type = rawEvent->type; size_t batchSize = 1 ; if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { int32_t deviceId = rawEvent->deviceId; while (batchSize < count) { if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break ; } batchSize += 1 ; } processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break ; case EventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break ; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break ; default : ALOG_ASSERT(false ); break ; } } count -= batchSize; rawEvent += batchSize; } }
addDeviceLocked() 添加设备 1 2 3 4 5 6 7 8 9 10 11 12 13 void InputReader::addDeviceLocked (nsecs_t when, int32_t deviceId) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); device->configure(when, &mConfig, 0 ); device->reset(when); mDevices.add(deviceId, device); bumpGenerationLocked(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 InputDevice* InputReader::createDeviceLocked (int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) { InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), controllerNumber, identifier, classes); ... if (keyboardSource != 0 ) { device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); } if (classes & INPUT_DEVICE_CLASS_CURSOR) { device->addMapper(new CursorInputMapper(device)); } if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(new SingleTouchInputMapper(device)); } ... return device; }
addDeviceLocked()
主要创建InputDevice
,并且根据不同的设备类型来创建相应的InputMapper
。
根据上述代码列举对应关系:
Keyboard-like
:键盘类设备 –> KeyboardInputMapper
Cursor-like
:鼠标类设备 –> CursorInputMapper
TouchScreens
:触摸屏设备 –> MultiTouchInputMapper(多点触控) / SingleTouchInputMapper(单点触控)
processEventsForDeviceLocked() 处理设备事件 1 2 3 4 5 6 7 8 void InputReader::processEventsForDeviceLocked (int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); InputDevice* device = mDevices.valueAt(deviceIndex); device->process (rawEvents, count); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void InputDevice::process (const RawEvent* rawEvents, size_t count) { size_t numMappers = mMappers.size (); for (const RawEvent* rawEvent = rawEvents; count != 0 ; rawEvent++) { if (mDropUntilNextSync) { } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { } else { for (size_t i = 0 ; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process (rawEvent); } } --count; } }
以触摸屏为例,mapper
指向MultiTouchInputMapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 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::dispatchPointerSimple (nsecs_t when, uint32_t policyFlags, bool down, bool hovering) { ... if (mPointerSimple.down && !down) { mPointerSimple.down = false ; NotifyMotionArgs args (when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_UP, 0 , 0 , metaState, mLastRawState.buttonState, 0 , mViewport.displayId, 0 , 1 , &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime) ; getListener()->notifyMotion(&args); } if (down) { if (!mPointerSimple.down) { mPointerSimple.down = true ; mPointerSimple.downTime = when; NotifyMotionArgs args (when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0 , 0 , metaState, mCurrentRawState.buttonState, 0 , mViewport.displayId, 0 , 1 , &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime) ; getListener()->notifyMotion(&args); } NotifyMotionArgs args (when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0 , 0 , metaState, mCurrentRawState.buttonState, 0 , mViewport.displayId, 0 , 1 , &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime) ; getListener()->notifyMotion(&args); } }
getListener()
指的就是mQueuedListener
1 2 3 4 void QueuedInputListener::notifyMotion (const NotifyMotionArgs* args) { mArgsQueue.push(new NotifyMotionArgs(*args)); }
将触摸事件放入mArgsQueue
,此时事件加工完成。
1 2 3 4 5 6 7 8 9 10 void QueuedInputListener::flush () { size_t count = mArgsQueue.size (); for (size_t i = 0 ; i < count; i++) { NotifyArgs* args = mArgsQueue[i]; args->notify(mInnerListener); delete args; } mArgsQueue.clear (); }
NotifyArgs
主要有以下几类:
NotifyConfigurationChangedArgs:配置变化
NotifyKeyArgs:键盘事件
NotifyMotionArgs:触摸事件
NotifySwitchArgs:切换事件
NotifyDeviceResetArgs:设备重置事件
根据上节可知args
为NotifyMotionArgs
1 2 3 void NotifyMotionArgs::notify (const sp<InputListenerInterface>& listener) const { listener->notifyMotion(this ); }
listener
指的就是InputDispatcher
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 void InputDispatcher::notifyMotion (const NotifyMotionArgs* args) { ... if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount, args->pointerProperties)) { return ; } uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; android::base::Timer t; mPolicy->interceptMotionBeforeQueueing(args->eventTime, policyFlags); bool needWake; { mLock.lock(); if (shouldSendMotionToInputFilterLocked(args)) { mLock.unlock(); MotionEvent event; event.initialize(args->deviceId, args->source, args->action, args->actionButton, args->flags, args->edgeFlags, args->metaState, args->buttonState, 0 , 0 , args->xPrecision, args->yPrecision, args->downTime, args->eventTime, args->pointerCount, args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { return ; } mLock.lock(); } MotionEntry* newEntry = new MotionEntry(args->eventTime, args->deviceId, args->source, policyFlags, args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, args->displayId, args->pointerCount, args->pointerProperties, args->pointerCoords, 0 , 0 ); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); } if (needWake) { mLooper->wake(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 bool InputDispatcher::enqueueInboundEventLocked (EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry); traceInboundQueueLengthLocked(); switch (entry->type) { case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast <MotionEntry*>(entry); if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY && mInputTargetWaitApplicationHandle != NULL ) { int32_t displayId = motionEntry->displayId; int32_t x = int32_t (motionEntry->pointerCoords[0 ]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t (motionEntry->pointerCoords[0 ]. getAxisValue(AMOTION_EVENT_AXIS_Y)); sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); if (touchedWindowHandle != NULL && touchedWindowHandle->inputApplicationHandle != mInputTargetWaitApplicationHandle) { mNextUnblockedEvent = motionEntry; needWake = true ; } } break ; } } return needWake; }
总结
InputReaderThread
主要负责事件封装转换
EventHub.getEvents()
:通过epoll
监听iNotify实例(监听 /dev/input/ 目录)
读取事件放入mEventBuffer
,然后转换成RawEvent
processEventsLocked()
:对RawEvent
进行加工,转换成NotifyMotionArgs
flush()
:将事件NotifyMotionArgs
发送到InputDispatcher
进行处理,最后转换成MotionEntry
并写入到InputDispatcher.mInBoundQueue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 bool InputDispatcherThread::threadLoop () { mDispatcher->dispatchOnce(); return true ; }void InputDispatcher::dispatchOnce () { nsecs_t nextWakeupTime = LONG_LONG_MAX; { AutoMutex _l(mLock); mDispatcherIsAliveCondition.broadcast(); if (!haveCommandsLocked()) { dispatchOnceInnerLocked(&nextWakeupTime); } if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; } } nsecs_t currentTime = now(); int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); mLooper->pollOnce(timeoutMillis); }
dispatchOnceInnerLocked() 获取事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 void InputDispatcher::dispatchOnceInnerLocked (nsecs_t * nextWakeupTime) { nsecs_t currentTime = now(); if (! mPendingEvent) { if (mInboundQueue.isEmpty()) { ... if (!mPendingEvent) { return ; } } else { mPendingEvent = mInboundQueue.dequeueAtHead(); traceInboundQueueLengthLocked(); } ... resetANRTimeoutsLocked(); } ALOG_ASSERT(mPendingEvent != NULL ); bool done = false ; DropReason dropReason = DROP_REASON_NOT_DROPPED; if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { dropReason = DROP_REASON_POLICY; } else if (!mDispatchEnabled) { dropReason = DROP_REASON_DISABLED; } switch (mPendingEvent->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ... break ; } case EventEntry::TYPE_DEVICE_RESET: { ... break ; } case EventEntry::TYPE_KEY: { ... break ; } case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry = static_cast <MotionEntry*>(mPendingEvent); if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { 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 = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break ; } if (done) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); } mLastDropReason = dropReason; releasePendingEventLocked(); *nextWakeupTime = LONG_LONG_MIN; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 bool InputDispatcher::dispatchMotionLocked ( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t * nextWakeupTime) { bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; Vector<InputTarget> inputTargets; bool conflictingPointerActions = false ; int32_t injectionResult; if (isPointerEvent) { injectionResult = findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, &conflictingPointerActions); } else { injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); } addMonitoringTargetsLocked(inputTargets); dispatchEventLocked(currentTime, entry, inputTargets); return true ; }
InputTarget
的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 struct InputTarget { sp<InputChannel> inputChannel; int32_t flags; float xOffset, yOffset; float scaleFactor; BitSet32 pointerIds; }
dispatchEventLocked() 发送事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 void InputDispatcher::dispatchEventLocked (nsecs_t currentTime, EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) { pokeUserActivityLocked(eventEntry); 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::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) { bool wasEmpty = connection->outboundQueue.isEmpty(); ... if (wasEmpty && !connection->outboundQueue.isEmpty()) { startDispatchCycleLocked(currentTime, connection); } }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; status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast <MotionEntry*>(eventEntry); PointerCoords scaledCoords[MAX_POINTERS]; const PointerCoords* usingCoords = motionEntry->pointerCoords; float xOffset, yOffset; if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { float scaleFactor = dispatchEntry->scaleFactor; xOffset = dispatchEntry->xOffset * scaleFactor; yOffset = dispatchEntry->yOffset * scaleFactor; if (scaleFactor != 1.0f ) { for (uint32_t i = 0 ; i < motionEntry->pointerCount; i++) { scaledCoords[i] = motionEntry->pointerCoords[i]; scaledCoords[i].scale(scaleFactor); } usingCoords = scaledCoords; } } else { xOffset = 0.0f ; yOffset = 0.0f ; if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { for (uint32_t i = 0 ; i < motionEntry->pointerCount; i++) { scaledCoords[i].clear (); } usingCoords = scaledCoords; } } status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, motionEntry->source, motionEntry->displayId, dispatchEntry->resolvedAction, motionEntry->actionButton, dispatchEntry->resolvedFlags, motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, motionEntry->downTime, motionEntry->eventTime, motionEntry->pointerCount, motionEntry->pointerProperties, usingCoords); break ; } connection->outboundQueue.dequeue(dispatchEntry); traceOutboundQueueLengthLocked(connection); connection->waitQueue.enqueueAtTail(dispatchEntry); traceWaitQueueLengthLocked(connection); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 status_t InputPublisher::publishMotionEvent ( uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputMessage msg; msg.header.type = InputMessage::TYPE_MOTION; msg.body.motion.seq = seq; msg.body.motion.deviceId = deviceId; msg.body.motion.source = source; msg.body.motion.displayId = displayId; msg.body.motion.action = action; msg.body.motion.actionButton = actionButton; msg.body.motion.flags = flags; msg.body.motion.edgeFlags = edgeFlags; msg.body.motion.metaState = metaState; msg.body.motion.buttonState = buttonState; msg.body.motion.xOffset = xOffset; msg.body.motion.yOffset = yOffset; msg.body.motion.xPrecision = xPrecision; msg.body.motion.yPrecision = yPrecision; msg.body.motion.downTime = downTime; msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; for (uint32_t i = 0 ; i < pointerCount; i++) { msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]); msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]); } return mChannel->sendMessage(&msg); }
1 2 3 4 status_t InputChannel::sendMessage (const InputMessage* msg) { ... }
最终通过InputChannel.sendMessage()
发送包装好的触摸事件
TODO
handleReceiveCallback 接收事件 这一节的触发条件会在后面讲到,简单来说就是
后面Java层的事件分发结束,调用到InputEventReceiver.finishInputEvent()
,会向UI进程持有的InputChannel
写入数据,然后唤醒InputDispatcher
线程被唤醒后执行handleReceiveCallback()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 int InputDispatcher::handleReceiveCallback (int fd, int events, void * data) { ... sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex); ... for (;;) { uint32_t seq; bool handled; status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled); if (status) { break ; } d->finishDispatchCycleLocked(currentTime, connection, seq, handled); gotOne = true ; } }void InputDispatcher::finishDispatchCycleLocked (nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { connection->inputPublisherBlocked = false ; if (connection->status == Connection::STATUS_BROKEN || connection->status == Connection::STATUS_ZOMBIE) { return ; } onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); }void InputDispatcher::onDispatchCycleFinishedLocked ( nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); commandEntry->connection = connection; commandEntry->eventTime = currentTime; commandEntry->seq = seq; commandEntry->handled = handled; }void InputDispatcher::doDispatchCycleFinishedLockedInterruptible ( CommandEntry* commandEntry) { ... if (dispatchEntry == connection->findWaitQueueEntry(seq)) { connection->waitQueue.dequeue(dispatchEntry); traceWaitQueueLengthLocked(connection); } startDispatchCycleLocked(now(), connection); }
总结
InputReader
发送触摸事件到InputDispatcher
,通过findFocusedWindowTargetsLocked()
寻找触摸事件对应的窗口,如果没有找到就使用第一个Window
。把结果写入inputTargets
中,然后通过publishMotionEvent
分发触摸事件,再通过InputChannel
发送消息到UI线程。
触摸事件发送至Activity
InputDispatcher
负责分发触摸事件,最后通过InputChannel->sendMessage()
发出消息
1 2 3 4 5 6 7 8 9 10 11 12 status_t InputChannel::sendMessage (const InputMessage* msg) { const size_t msgLength = msg->size (); InputMessage cleanMsg; msg->getSanitizedCopy(&cleanMsg); ssize_t nWrite; do { nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 && errno == EINTR); return OK; }
InputChannel
通过socket
发送消息。
既然存在sendMessage()
就需要找到相对的receiveMessage()
调用的地方。
当前是InputDispatcher
调用的sendMessage()
,对应就需要去Window
找receiveMessage()
本质是SocketPair(非网络套接字)
。SocketPair
用于实现本机内的进程间通信。
SocketPair
提供方法:
socketPair()
:创建SocketPair,返回一对相互连接的fd
send()
:写入数据,可在另一个fd读取
recv()
:读取数据
非常适合用来进行进程间的交互式通讯。
InputChannel
就是SocketPair
的封装,分别分配给InputDispatcher
与Window
。
InputDispatcher
写入的事件,Window
可以从自己持有的InputChannel
获取;反向也是如此。
InputChannel
提供方法:位于InputTransport.cpp
中
openInputChannelPair()
:封装socketPair()
sendMessage()
:封装send()
receiveMessage()
:封装recv()
最后屏幕的触摸事件都需要反映到一个Activity上,然后再一步步传递到对应的View上。所以需要先从Activity开始分析触摸事件的传递流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public void handleResumeActivity (IBinder token, boolean finalStateRequest, boolean isForward, String reason) { ... wm.addView(decor, l); ... } public void addView (View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { root = new ViewRootImpl(view.getContext(), display); root.setView(view, wparams, panelParentView); } public void setView (View view, WindowManager.LayoutParams attrs, View panelParentView) { if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0 ) { mInputChannel = new InputChannel(); } res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mWinFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel); if (mInputChannel != null ) { if (mInputQueueCallback != null ) { mInputQueue = new InputQueue(); mInputQueueCallback.onInputQueueCreated(mInputQueue); } mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); } }
addToDisplay() 1 2 3 4 5 6 7 8 9 @Override public int addToDisplay (IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { return mService.addWindow(this , window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel); }
其中mService
指的就是WindowManagerService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public int addWindow (Session session, IWindow client, int seq, LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) { ... final WindowState win = new WindowState(this , session, client, token, parentWindow, appOp[0 ], seq, attrs, viewVisibility, session.mUid, session.mCanAddInternalSystemWindow); ... final boolean openInputChannels = (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0 ); if (openInputChannels) { win.openInputChannel(outInputChannel); } }
addWindow()
主要创建了WindowState
对象,然后继续调用到openInputChannels()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void openInputChannel (InputChannel outInputChannel) { if (mInputChannel != null ) { throw new IllegalStateException("Window already has an input channel." ); } String name = getName(); 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 { mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel); } mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle); }
1 2 3 4 5 6 public void registerInputChannel (InputChannel inputChannel, InputWindowHandle inputWindowHandle) { nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false ); }
1 2 3 4 5 6 7 8 status_t NativeInputManager::registerInputChannel (JNIEnv* , const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { ATRACE_CALL(); return mInputManager->getDispatcher()->registerInputChannel( inputChannel, inputWindowHandle, monitor); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 status_t InputDispatcher::registerInputChannel (const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { { AutoMutex _l(mLock); sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); if (monitor) { mMonitoringChannels.push(inputChannel); } mLooper->addFd(fd, 0 , ALOOPER_EVENT_INPUT, handleReceiveCallback, this ); } mLooper->wake(); return OK; }
addToDisplay()
主要处理两部分内容
创建Socket pair,作为InputChannel
socket服务端
保存在WidnowState
中的mInputChannel
中
socket客户端
通过binder
传到ViewRootImpl
中的mInputChannel
通过IMS.registerInputChannel()
注册InputChannel
,监听socket服务端,收到消息后回调InputDispatcher::handleReceiveCallback()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver (InputChannel inputChannel, Looper looper) { super (inputChannel, looper); } ... @Override public void onInputEvent (InputEvent event, int displayId) { enqueueInputEvent(event, this , 0 , true ); } } public InputEventReceiver (InputChannel inputChannel, Looper looper) { mInputChannel = inputChannel; mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this ), inputChannel, mMessageQueue); mCloseGuard.open("dispose" ); } private void dispatchInputEvent (int seq, InputEvent event, int displayId) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event, displayId); }
初始化 InputEventReceiver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 static jlong nativeInit (JNIEnv* env, jclass clazz, jobject receiverWeak, jobject inputChannelObj, jobject messageQueueObj) { sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); if (inputChannel == NULL ) { jniThrowRuntimeException(env, "InputChannel is not initialized." ); return 0 ; } sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL ) { jniThrowRuntimeException(env, "MessageQueue is not initialized." ); return 0 ; } sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env, receiverWeak, inputChannel, messageQueue); status_t status = receiver->initialize(); receiver->incStrong(gInputEventReceiverClassInfo.clazz); return reinterpret_cast <jlong>(receiver.get ()); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 status_t NativeInputEventReceiver::initialize () { setFdEvents(ALOOPER_EVENT_INPUT); return OK; }void NativeInputEventReceiver::setFdEvents (int events) { if (mFdEvents != events) { mFdEvents = events; int fd = mInputConsumer.getChannel()->getFd(); if (events) { mMessageQueue->getLooper()->addFd(fd, 0 , events, this , NULL ); } else { mMessageQueue->getLooper()->removeFd(fd); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 int Looper::addFd (int fd, int ident, int events, const sp<LooperCallback>& callback, void * data) { Request request; request.fd = fd; request.ident = ident; request.events = events; request.seq = mNextRequestSeq++; request.callback = callback; request.data = data; if (mNextRequestSeq == -1 ) mNextRequestSeq = 0 ; struct epoll_event eventItem ; request.initEventItem(&eventItem); ... int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); scheduleEpollRebuildLocked(); }void Looper::scheduleEpollRebuildLocked () { if (!mEpollRebuildRequired) { mEpollRebuildRequired = true ; wake(); } }
这一部分涉及looper
在Handler
就有详细介绍,wake
之后,native request
相关消息触发后会回调到callback->handleEvent()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 int NativeInputEventReceiver::handleEvent (int receiveFd, int events, void * data) { ... if (events & ALOOPER_EVENT_INPUT) { JNIEnv* env = AndroidRuntime::getJNIEnv(); status_t status = consumeEvents(env, false , -1 , NULL ); mMessageQueue->raiseAndClearException(env, "handleReceiveCallback" ); return status == OK || status == NO_MEMORY ? 1 : 0 ; } ... }status_t NativeInputEventReceiver::consumeEvents (JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool * outConsumedBatch) { for (;;) { status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent, &displayId); if (status) { if (status == WOULD_BLOCK) { if (!skipCallbacks && !mBatchedInputEventPending && mInputConsumer.hasPendingBatch()) { if (!receiverObj.get ()) { receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal)); if (!receiverObj.get ()) { ALOGW("channel '%s' ~ Receiver object was finalized " "without being disposed." , getInputChannelName().c_str()); return DEAD_OBJECT; } } mBatchedInputEventPending = true ; if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Dispatching batched input event pending notification." , getInputChannelName().c_str()); } env->CallVoidMethod(receiverObj.get (), gInputEventReceiverClassInfo.dispatchBatchedInputEventPending); if (env->ExceptionCheck()) { ALOGE("Exception dispatching batched input events." ); mBatchedInputEventPending = false ; } } return OK; } ALOGE("channel '%s' ~ Failed to consume input event. status=%d" , getInputChannelName().c_str(), status); return status; } ... if (!skipCallbacks) { jobject inputEventObj; switch (inputEvent->getType()) { case AINPUT_EVENT_TYPE_MOTION: { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Received motion event." , getInputChannelName().c_str()); } MotionEvent* motionEvent = static_cast <MotionEvent*>(inputEvent); if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) { *outConsumedBatch = true ; } inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent); break ; } default : assert(false ); inputEventObj = NULL ; } if (inputEventObj) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Dispatching input event." , getInputChannelName().c_str()); } env->CallVoidMethod(receiverObj.get (), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj, displayId); if (env->ExceptionCheck()) { ALOGE("Exception dispatching input event." ); skipCallbacks = true ; } env->DeleteLocalRef(inputEventObj); } else { ALOGW("channel '%s' ~ Failed to obtain event object." , getInputChannelName().c_str()); skipCallbacks = true ; } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 status_t InputConsumer::consume (InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t * outSeq, InputEvent** outEvent, int32_t * displayId) { while (!*outEvent) { mMsgDeferred = false ; } else { status_t result = mChannel->receiveMessage(&mMsg); if (result) { if (consumeBatches || result != WOULD_BLOCK) { result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId); if (*outEvent) { break ; } } return result; } } }
WindowInputEventReceiver
主要执行了以下几步:
初始化了NativeInputReceiver
,调用了sendFdEvents()
发出了消息
往主线程Looper添加了一条Native Request
,且callback
为NativeInputReceiver
向Looper的mEpollFd
添加了监听,只要收到触摸事件的消息就会调用到callback->handleEvent()
NativeInputReceiver::handleEvent()
主要回调到Java层的dispatchInputEvent()
且携带InputEvent
回去(在触摸场景下,实际为MotionEvent
)。
回调到Activity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 private void dispatchInputEvent (int seq, InputEvent event, int displayId) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event, displayId); } private void dispatchBatchedInputEventPending () { onBatchedInputEventPending(); } final class WindowInputEventReceiver extends InputEventReceiver { @Override public void onInputEvent (InputEvent event, int displayId) { enqueueInputEvent(event, this , 0 , true ); } @Override public void onBatchedInputEventPending () { if (mUnbufferedInputDispatch) { super .onBatchedInputEventPending(); } else { scheduleConsumeBatchedInput(); } } } void scheduleConsumeBatchedInput () { if (!mConsumeBatchedInputScheduled) { mConsumeBatchedInputScheduled = true ; mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, mConsumedBatchedInputRunnable, null ); } } void enqueueInputEvent (InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { adjustInputEventForCompatibility(event); QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); if (processImmediately) { doProcessInputEvents(); } else { scheduleProcessInputEvents(); } } void doProcessInputEvents () { while (mPendingInputEventHead != null ) { QueuedInputEvent q = mPendingInputEventHead; mPendingInputEventHead = q.mNext; if (mPendingInputEventHead == null ) { mPendingInputEventTail = null ; } q.mNext = null ; if (q.mEvent instanceof MotionEvent) { MotionEvent me = (MotionEvent)q.mEvent; if (me.getHistorySize() > 0 ) { oldestEventTime = me.getHistoricalEventTimeNano(0 ); } } mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime); deliverInputEvent(q); } } private void deliverInputEvent (QueuedInputEvent q) { InputStage stage; if (q.shouldSendToSynthesizer()) { stage = mSyntheticInputStage; } else { stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; } if (stage != null ) { handleWindowFocusChanged(); stage.deliver(q); } else { finishInputEvent(q); } } abstract class InputStage { public final void deliver (QueuedInputEvent q) { if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0 ) { forward(q); } else if (shouldDropInputEvent(q)) { finish(q, false ); } else { apply(q, onProcess(q)); } } }
此处stage
是ViewPostImeInputStage
,向下继续调用到onProcess()
ViewPostImeInputStage
:视图处理阶段 ,主要处理按键、手指触摸等事件,分发的对象是View。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 final class ViewPostImeInputStage extends InputStage { 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); } } } private int processPointerEvent (QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; mAttachInfo.mUnbufferedDispatchRequested = false ; mAttachInfo.mHandlingPointerEvent = true ; boolean handled = mView.dispatchPointerEvent(event); return handled ? FINISH_HANDLED : FORWARD; } }
此时mView
表示的就是DecorView
,本质就是View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public final boolean dispatchPointerEvent (MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } } public boolean dispatchTouchEvent (MotionEvent ev) { final Window.Callback cb = mWindow.getCallback(); return cb != null && !mWindow.isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super .dispatchTouchEvent(ev); }
mWindow.getCallback()
就是与Window绑定的Activity
1 2 3 4 5 6 7 8 9 10 public boolean dispatchTouchEvent (MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true ; } return onTouchEvent(ev); }
所以经过一系列操作 让用户的屏幕触摸操作,最终走到了Activity.dispatchTouchEvent()
事件分发 MotionEvent
当用户点击View或ViewGroup的时候,将会产生一个事件对象,就是MotionEvent
。
MotionEvent
记录了事件的类型(action)、触摸的位置(x,y)以及触摸的时间等
。
事件的类型主要分为以下几种:
ACTION_DOWN
:监听用户手指按下的操作,一次按下标志触摸事件的开始。
ACTION_MOVE
:用户按压屏幕后,在抬起之前,如果移动的距离超过一定数值,就判定为移动事件。
ACTION_UP
:监听用户手指离开屏幕的操作,一次抬起标志触摸事件的结束。
ACTION_CANCEL
:当用户保持按下操作,并把手指移动到了控件外部区域时且父View处理事件触发。
用户手指触摸到屏幕到离开屏幕可能产生的事件序列如下:
ACTION_DOWN
-> ACTION_MOVE
-> ACTION_MOVE
-> … ACTION_MOVE
-> ACTION_UP
MotionEvent产生时机
在ViewRootImpl.setView()
时,创建了WindowInputReceiver
,当IMS写入事件(通过EventHub监听到/dev/input/
),通过一系列的操作回调到dispatchInputEvent()
,最后走到了processPointerEvent()
,此时把从Native层传递过来的InputEvent
强转成MotionEvent
,然后继续向下传递。
MotionEvent传递顺序-事件分发顺序
事件分发本质就是MotionEvent
的传递过程。
1 2 3 4 5 6 7 8 9 10 11 private int processPointerEvent (QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; mAttachInfo.mUnbufferedDispatchRequested = false ; mAttachInfo.mHandlingPointerEvent = true ; boolean handled = mView.dispatchPointerEvent(event); return handled ? FINISH_HANDLED : FORWARD; }
mView
就是DecorView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 没有实现对应方法。。。 向上寻找父类 public final boolean dispatchPointerEvent (MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } } @Override public boolean dispatchTouchEvent (MotionEvent ev) { final Window.Callback cb = mWindow.getCallback(); return cb != null && !mWindow.isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super .dispatchTouchEvent(ev); }
此时mWindow.getCallback()
指的就是Activity
Activity事件分发 1 2 3 4 5 6 7 8 9 10 11 12 13 public boolean dispatchTouchEvent (MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true ; } return onTouchEvent(ev); }
getWindow()
对应唯一实现类PhoneWindow
1 2 3 4 5 6 @Override public boolean superDispatchTouchEvent (MotionEvent event) { return mDecor.superDispatchTouchEvent(event); }
mDecor
指的就是DecorView
1 2 3 4 5 public boolean superDispatchTouchEvent (MotionEvent event) { return super .dispatchTouchEvent(event); }
总结一下:按照上述流程图,当一个点击事件进来时,Activity上的事件流程如下:
调用Activity.dispatchTouchEvent()
,然后调用onUserInteraction()
调用getWindow()即PhoneWindow.superDispatchTouchEvent()
调用mDecor即DecorView.superDispatchTouchEvent()
调用DecorView父类即ViewGroup.dispatchTouchEvent()
在这里实现了事件从Activity传递至ViewGroup
ViewGroup事件分发
上述Activity分发后,执行到ViewGroup.dispatchTouchEvent()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 @Override public boolean dispatchTouchEvent (MotionEvent ev) { ... if (actionMasked == MotionEvent.ACTION_DOWN) { cancelAndClearTouchTargets(ev); resetTouchState(); } ... final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null ) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0 ; if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); } else { intercepted = false ; } } else { intercepted = true ; } ... if (!canceled && !intercepted) { if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { final int actionIndex = ev.getActionIndex(); if (newTouchTarget == null && childrenCount != 0 ) { final float x = ev.getX(actionIndex); final float y = ev.getY(actionIndex); final ArrayList<View> preorderedList = buildTouchDispatchChildList(); final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; for (int i = childrenCount - 1 ; i >= 0 ; i--) { final int childIndex = getAndVerifyPreorderedIndex( childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView( preorderedList, children, childIndex); if (childWithAccessibilityFocus != null ) { if (childWithAccessibilityFocus != child) { continue ; } childWithAccessibilityFocus = null ; i = childrenCount - 1 ; } if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null )) { ev.setTargetAccessibilityFocus(false ); continue ; } newTouchTarget = getTouchTarget(child); if (newTouchTarget != null ) { newTouchTarget.pointerIdBits |= idBitsToAssign; break ; } resetCancelNextUpFlag(child); if (dispatchTransformedTouchEvent(ev, false , child, idBitsToAssign)) { mLastTouchDownTime = ev.getDownTime(); if (preorderedList != null ) { for (int j = 0 ; j < childrenCount; j++) { if (children[childIndex] == mChildren[j]) { mLastTouchDownIndex = j; break ; } } } else { mLastTouchDownIndex = childIndex; } mLastTouchDownX = ev.getX(); mLastTouchDownY = ev.getY(); newTouchTarget = addTouchTarget(child, idBitsToAssign); alreadyDispatchedToNewTouchTarget = true ; break ; } ev.setTargetAccessibilityFocus(false ); } if (preorderedList != null ) preorderedList.clear(); } if (newTouchTarget == null && mFirstTouchTarget != null ) { newTouchTarget = mFirstTouchTarget; while (newTouchTarget.next != null ) { newTouchTarget = newTouchTarget.next; } newTouchTarget.pointerIdBits |= idBitsToAssign; } } } if (mFirstTouchTarget == null ) { handled = dispatchTransformedTouchEvent(ev, canceled, null , TouchTarget.ALL_POINTER_IDS); } else { TouchTarget predecessor = null ; TouchTarget target = mFirstTouchTarget; while (target != null ) { final TouchTarget next = target.next; if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { handled = true ; } else { final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted; if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) { handled = true ; } if (cancelChild) { if (predecessor == null ) { mFirstTouchTarget = next; } else { predecessor.next = next; } target.recycle(); target = next; continue ; } } predecessor = target; target = next; } } ... } return handled; }
onInterceptTouchEvent() 1 2 3 4 5 6 7 8 9 public boolean onInterceptTouchEvent (MotionEvent ev) { if (ev.isFromSource(InputDevice.SOURCE_MOUSE) && ev.getAction() == MotionEvent.ACTION_DOWN && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY) && isOnScrollbarThumb(ev.getX(), ev.getY())) { return true ; } return false ; }
可以通过重写该方法,进行事件分发的拦截。
返回true,事件被拦截,执行当前View的onTouchEvent()
返回false,事件继续向下分发
buildTouchDispatchChildList() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public ArrayList<View> buildTouchDispatchChildList () { return buildOrderedChildList(); } ArrayList<View> buildOrderedChildList () { final int childrenCount = mChildrenCount; if (childrenCount <= 1 || !hasChildWithZ()) return null ; final boolean customOrder = isChildrenDrawingOrderEnabled(); for (int i = 0 ; i < childrenCount; i++) { final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); final View nextChild = mChildren[childIndex]; final float currentZ = nextChild.getZ(); int insertIndex = i; while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1 ).getZ() > currentZ) { insertIndex--; } mPreSortedChildren.add(insertIndex, nextChild); } return mPreSortedChildren; } public float getZ () { return getElevation() + getTranslationZ(); }
默认的事件分发顺序与绘制顺序一致,按照view.getZ()
从大到小排序,Z值大的先绘制且先响应事件。
当然,这个事件分发的顺序也可以修改,只需要实现两个方法:
setChildrenDrawingOrderEnabled(true)
:允许自定义顺序。isChildrenDrawingOrderEnabled()返回true
getChildDrawingOrder()
:自定义当前View的顺序
也可以通过setElevation()
、setTranslationZ()
或者setZ()
去修改Z轴的坐标值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 private boolean dispatchTransformedTouchEvent (MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) { final boolean handled; final int oldAction = event.getAction(); if (cancel || oldAction == MotionEvent.ACTION_CANCEL) { event.setAction(MotionEvent.ACTION_CANCEL); if (child == null ) { handled = super .dispatchTouchEvent(event); } else { handled = child.dispatchTouchEvent(event); } event.setAction(oldAction); return handled; } final MotionEvent transformedEvent; if (newPointerIdBits == oldPointerIdBits) { if (child == null || child.hasIdentityMatrix()) { if (child == null ) { handled = super .dispatchTouchEvent(event); } else { final float offsetX = mScrollX - child.mLeft; final float offsetY = mScrollY - child.mTop; event.offsetLocation(offsetX, offsetY); handled = child.dispatchTouchEvent(event); event.offsetLocation(-offsetX, -offsetY); } return handled; } transformedEvent = MotionEvent.obtain(event); } else { transformedEvent = event.split(newPointerIdBits); } transformedEvent.recycle(); return handled; }
dispatchTransformedTouchEvent()
分为两套处理方式:
child==null
:发生的情况:事件被拦截
或真的没有可执行触摸事件的子View
。执行View.dispatchTouchEvent()
child!=null
:向下执行子View/ViewGroup的dispatchTouchEvent()
addTouchTarget() 1 2 3 4 5 6 private TouchTarget addTouchTarget (@NonNull View child, int pointerIdBits) { final TouchTarget target = TouchTarget.obtain(child, pointerIdBits); target.next = mFirstTouchTarget; mFirstTouchTarget = target; return target; }
TouchTarget
结构如下:
1 2 3 4 5 6 7 8 9 10 private static final class TouchTarget { public View child; public int pointerIdBits; public TouchTarget next; }
TouchTarget
是一个单链表结构,记录的是事件分发链 。每一个元素表示真正对事件消费的View
。
根据上述流程图,总结一下:
点击事件从上层传递到ViewGroup,先调用ViewGroup.dispatchTouchEvent()
判断ViewGroup.onInterceptTouchEvent()
是否拦截点击事件
默认不拦截,则将事件继续向子View传递,然后调用View.dispatchTouchEvent()
被拦截返回true
,调用super.dispatchTouchEvent()
返给父布局处理,并且ViewGroup自身也处理事件,比如onTouch(),onClick(),onTouchEvent()
等事件
通常情况下ViewGroup的onInterceptTouchEvent()
返回false,不会拦截用户操作。
不过要注意的是 拦截的是 一个用户的操作序列:从用户手指按下到手指抬起为止。
拦截了Down事件,后续的事件都会交由ViewGroup.onTouchEvent()
处理
拦截了其他事件,会给之前序列头部的ACTION_DOWN
事件发送一个ACTION_CANCEL
类型事件,通知子View无法执行后续事件,回归初始状态。(例如点击ListView中的一个Item的Button,再滑动ListView,Button就会恢复初始状态。 )
View事件分发
ViewGroup事件分发完毕后,由子View继续执行事件分发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public boolean dispatchTouchEvent (MotionEvent event) { boolean result = false ; if (onFilterTouchEventForSecurity(event)) { if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { result = true ; } ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this , event)) { result = true ; } if (!result && onTouchEvent(event)) { result = true ; } } return result; }
dispatchTouchEvent()
按照如下顺序执行:
onTouchListener.ouTouch()
开始执行,返回true
表示当前事件已被消费,不需要向上执行。否则继续向下执行
onTouchEvent()
返回true
表示消费事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public boolean onTouchEvent (MotionEvent event) { final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; if ((viewFlags & ENABLED_MASK) == DISABLED) { if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0 ) { setPressed(false ); } mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; return clickable; } if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { switch (action) { case MotionEvent.ACTION_UP: if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { removeLongPressCallback(); if (!focusTaken) { if (mPerformClick == null ) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClickInternal(); } } } } } } private boolean performClickInternal () { return performClick(); } public boolean performClick () { final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null ) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this ); result = true ; } else { result = false ; } return result; }
根据上述流程图,总结一下:
点击事件从ViewGroup传递到View,调用View.dispatchTouchEvent()
判断当前View是否设置OnTouchListener
,并且设置了onTouch()
返回值,默认返回false
返回true
,代表事件被onTouch()
消费,不会继续往下传递
返回false
,事件继续向下传递,调用View.onTouchEvent()
,后续若设置点击事件,则继续调用performClick()
,最后执行onClick()
事件
拓展:
如果有一个控件是DISABLED
,注册的onTouch()
事件不会被执行。若要监听点击事件,只能实现它的onTouchEvent()
点击事件优先级: onTouch()
> onTouchEvent()
> performClick()
> onClick()
总结 根据前几节分析得出完整的事件分发顺序:
IMS -> WindowInputREceiver(ViewRootImpl) -> DecorView -> Activity -> DecorView -> viewGroup -> View
事件分发核心方法
boolean dispatchTouchEvent()
用来进行事件的分发。
返回true
:事件被当前View所消费,不会向下传递
返回false
:交由上一层的View的onTouchEvent()
处理
返回super.dispatchTouchEvent()
:继续向下分发事件
boolean onInterceptTouchEvent()
用来进行事件的拦截,在dispatchOnTouchEvent()
中调用。只有ViewGroup才可以调用
返回true
:拦截当前事件,并交由onTouchEvent()
去处理
返回false
:不拦截当前事件,继续向下传递
返回super.onInterceptTouchEvent()
:调用父类的onInterceptTouchEvent()
,大部分情况下是false
。
如果点击了子View区域,可以继续分发到child.dispatchTouchEvent()
没有子View可以响应事件,执行onTouchEvent()
boolean onTouchEvent()
用来处理点击事件,在dispatchOnTouchEvent()
中调用。
返回true
:当前View处理当前事件
返回false
:当前View无法处理事件,交由上一层View的onTouchEvent()
处理
返回super.onTouchEvent()
当前View设置了clickable/longclickable
,等价于返回true,当前View处理事件
当前View未设置clickable/longclickable
,等价于返回false,交由上一层的onTouchEvent()
处理。
上述三个核心方法,可以用如下伪代码代替
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public boolean dispatchTouchEvent () { boolean res = false ; final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0 ; if (!disallowIntercept && onInterceptTouchEvent()) { if (touchlistener && touchlistener.onTouch()) { return true ; } res = onTouchEvent(); } else if (DOWN) { for (childs) { res = child.dispatchTouchEvent(); } } else { target.child.dispatchTouchEvent(); } return res; }
点击事件传递从dispatchTouchEvent()
开始,在不修改默认返回值时,事件会按照嵌套层次由外向内传递,到达最内层View时,由最内层View.onTouchEvent()
处理
View的点击事件触发顺序为 onTouch()
> onTouchEvent()
> performClick()
> onClick()
Touch事件的后续(例如ACTION_MOVE
,ACTION_UP
)层级传递
若dispatchTouchEvent()
返回true,那么能收到ACTION_DOWN
的函数也可以收到后续事件
若onTouchEvent()
返回true,那么其他事件不再往下传递,而是直接传给自己的onTouchEvent()
并结束本次事件传递
事件分发核心在于ViewGroup.dispatchTouchEvent()
的ACTION_DOWN
过程中找到mFirstTouchTarget
是否为空。
通过遍历子View寻找view.disptachTouchEvent()
返回true
,就设置mFirstTouchTarget
为该子View。
如果mFirstTarget
不为空,ACTION_MOVE
和ACTION_UP
才会向子View传递,如果中途被ViewGroup
拦截了事件,子View就会收到ACTION_CANCEL
,并且mFirstTouchTarget
为null,后续的事件只会走到ViewGroup
。
事件分发特殊情况
ACTIOIN_CANCEL
产生场景
子View处理了Down事件,按照设定Move与Up的事件也会交给他处理。若此时,父View拦截了事件,此时子View就会收到一个Cancel事件,并且无法接收到后续的Move与Up事件。
常见场景:ListView有一个Item带有Button,此时点击按钮(触发ACTION_DOWN),再进行上下滑动,ListView就会拦截掉后续的Move事件,此时Button就会收到ACTION_CANCEL
子View收到ACTION_DOWN,但是上一个事件还没有结束(因为APP切换、ANR导致后续事件丢失),此时也会执行ACTION_CANCEL
子View拦截父View事件 子View通过使用requestDisallowInterceptTouchEvent(true)
命令指定ViewGroup不再针对事件序列进行拦截 ,将事件交由子View去处理。
设置requestDisallowInterceptTouchEvent(true)
后,父类会在每次ACTION_DOWN
的时候进行重置,避免影响其他子View的事件处理。
上述方法也是解决滑动冲突
的一种方法:
内部拦截法
:通过在子类中调用parent.requestDisallowInterceptTouchEvent()
来控制父类是否拦截事件。
还有一个是
外部拦截法
:通过重写父类的onInterceptTouchEvent()
拦截冲突的事件。
长按事件原理 在onTouchEvent()
收到ACTION_DOWN
事件时,发送一个延时消息mPendingCheckForLongPress()
,延迟400ms
后执行。内部执行performLongClick()
,再然后一步步调用到performLongClickInternal()
内部执行到mOnLongClickListener.onLongClick()
onLongClick()
返回true
就会屏蔽onClick()
执行。
事件分发完成 事件分发完毕后,执行到finishInputEvent()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 protected void onDeliverToNext (QueuedInputEvent q) { if (DEBUG_INPUT_STAGES) { Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q); } if (mNext != null ) { mNext.deliver(q); } else { finishInputEvent(q); } } private void finishInputEvent (QueuedInputEvent q) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent" , q.mEvent.getSequenceNumber()); if (q.mReceiver != null ) { boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0 ; q.mReceiver.finishInputEvent(q.mEvent, handled); } else { q.mEvent.recycleIfNeededAfterDispatch(); } recycleQueuedInputEvent(q); }
1 2 3 4 5 6 public final void finishInputEvent (InputEvent event, boolean handled) { ... nativeFinishInputEvent(mReceiverPtr, seq, handled); ... }
nativeFinishInputEvent()
通知事件结束到Native层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 static void nativeFinishInputEvent (JNIEnv* env, jclass clazz, jlong receiverPtr, jint seq, jboolean handled) { sp<NativeInputEventReceiver> receiver = reinterpret_cast <NativeInputEventReceiver*>(receiverPtr); ... status_t status = receiver->finishInputEvent(seq, handled); }status_t NativeInputEventReceiver::finishInputEvent (uint32_t seq, bool handled) { ... status_t status = mInputConsumer.sendFinishedSignal(seq, handled); if (status) { if (status == WOULD_BLOCK) { ... if (mFinishQueue.size () == 1 ) { setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT); } return OK; } } return status; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 status_t InputConsumer::sendFinishedSignal (uint32_t seq, bool handled) { ... size_t seqChainCount = mSeqChains.size (); if (seqChainCount) { ... status_t status = OK; while (!status && chainIndex > 0 ) { chainIndex--; status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled); } } return sendUnchainedFinishedSignal(seq, handled); }
1 2 3 4 5 6 7 8 status_t InputConsumer::sendUnchainedFinishedSignal (uint32_t seq, bool handled) { InputMessage msg; msg.header.type = InputMessage::TYPE_FINISHED; msg.body.finished.seq = seq; msg.body.finished.handled = handled; return mChannel->sendMessage(&msg); }
InputChannel.sendMessage()
之后,InputDispatcher
线程被唤醒,回调到handleReceiveCallback()
。执行到上面的InputDispatcheThread
相关代码。
相关示例 参考链接 InputReaderThread
Android相关源码
一次触摸,Android 到底干了啥
反思|Android 事件分发机制的设计与实现
深入理解Android卷-III