Android输入输出系统之TouchEvent流程

时间:2023-03-09 00:51:29
Android输入输出系统之TouchEvent流程

一个是InputReader,一个是InputDispatcher。方法是dispatchTouch。

入口点是InputReader 的loopOnce方法.

InputReader里面有个线程叫做InputReaderThread,threadLoop

[code="java"]InputReaderThread::InputReaderThread(const sp& reader) :
        Thread(/*canCallJava*/ true), mReader(reader) {
}

InputReaderThread::~InputReaderThread() {
}

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}

  1. void InputDispatcher::dispatchOnce() {
  2. nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
  3. nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();
  4. nsecs_t nextWakeupTime = LONG_LONG_MAX;
  5. { // acquire lock
  6. AutoMutex _l(mLock);
  7. dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);
  8. if (runCommandsLockedInterruptible()) {
  9. nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
  10. }
  11. } // release lock
  12. // Wait for callback or timeout or wake.  (make sure we round up, not down)
  13. nsecs_t currentTime = now();
  14. int32_t timeoutMillis;
  15. if (nextWakeupTime > currentTime) {
  16. uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
  17. timeout = (timeout + 999999LL) / 1000000LL;
  18. timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
  19. } else {
  20. timeoutMillis = 0;
  21. }
  22. mLooper->pollOnce(timeoutMillis);
  23. }
  1. case EventEntry::TYPE_MOTION: {
  2. MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
  3. if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
  4. dropReason = DROP_REASON_APP_SWITCH;
  5. }
  6. done = dispatchMotionLocked(currentTime, typedEntry,
  7. &dropReason, nextWakeupTime);
  8. break;
  1. bool InputDispatcher::dispatchMotionLocked(
  2. nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
  3. // Preprocessing.
  4. if (! entry->dispatchInProgress) {
  5. entry->dispatchInProgress = true;
  6. resetTargetsLocked();
  7. logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
  8. }
  9. // Clean up if dropping the event.
  10. if (*dropReason != DROP_REASON_NOT_DROPPED) {
  11. resetTargetsLocked();
  12. setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
  13. ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
  14. return true;
  15. }
  16. bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
  17. // Identify targets.
  18. if (! mCurrentInputTargetsValid) {
  19. int32_t injectionResult;
  20. if (isPointerEvent) {
  21. // Pointer event.  (eg. touchscreen)
  22. injectionResult = findTouchedWindowTargetsLocked(currentTime,
  23. entry, nextWakeupTime);
  24. } else {
  25. // Non touch event.  (eg. trackball)
  26. injectionResult = findFocusedWindowTargetsLocked(currentTime,
  27. entry, nextWakeupTime);
  28. }
  29. if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
  30. return false;
  31. }
  32. setInjectionResultLocked(entry, injectionResult);
  33. if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
  34. return true;
  35. }
  36. addMonitoringTargetsLocked();
  37. commitTargetsLocked();
  38. }
  39. // Dispatch the motion.
  40. dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
  41. return true;
  42. }
  1. startDispatchCycleLocked 中的方法
  2. status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
  3. motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState,
  4. xOffset, yOffset,
  5. motionEntry->xPrecision, motionEntry->yPrecision,
  6. motionEntry->downTime, firstMotionSample->eventTime,
  7. motionEntry->pointerCount, motionEntry->pointerIds,
  8. firstMotionSample->pointerCoords);
  1. ViewRoot有个InputHandler
  1. private final InputHandler mInputHandler = new InputHandler() {
  2. public void handleKey(KeyEvent event, Runnable finishedCallback) {
  3. startInputEvent(finishedCallback);
  4. dispatchKey(event, true);
  5. }
  6. public void handleMotion(MotionEvent event, Runnable finishedCallback) {
  7. startInputEvent(finishedCallback);
  8. dispatchMotion(event, true);
  9. }
  10. };

InputHandler注册给了系统

  1. InputQueue.registerInputChannel(mInputChannel, mInputHandler,
  2. Looper.myQueue());
  1. dispatchMotion(event, true);方法如下
  2. rivate void dispatchMotion(MotionEvent event, boolean sendDone) {
  3. int source = event.getSource();
  4. if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
  5. dispatchPointer(event, sendDone);
  6. } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
  7. dispatchTrackball(event, sendDone);
  8. } else {
  9. // TODO
  10. Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event);
  11. if (sendDone) {
  12. finishInputEvent();
  13. }
  14. }
  15. }

调用了dispatchPointer

ViewRoot本身就是Handler直接sendMessageAtTime

然后就进入了View的焦点系统。

下面就说一下Activity的焦点是怎么回事。

  1. InputDisapatcher.cpp中调用了如下方法
  2. dispatchEventToCurrentInputTargetsLocked(currentTime, motionEntry,
  3. true /*resumeWithAppendedMotionSample*/);

然后

  1. dispatchEventToCurrentInputTargetsLocked

调用了如下方法

  1. int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
  2. const EventEntry* entry, nsecs_t* nextWakeupTime) {
  3. mCurrentInputTargets.clear();
  4. int32_t injectionResult;
  5. // If there is no currently focused window and no focused application
  6. // then drop the event.
  7. if (! mFocusedWindow) {
  8. if (mFocusedApplication) {
  9. #if DEBUG_FOCUS
  10. LOGD("Waiting because there is no focused window but there is a "
  11. "focused application that may eventually add a window: %s.",
  12. getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
  13. #endif
  14. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  15. mFocusedApplication, NULL, nextWakeupTime);
  16. goto Unresponsive;
  17. }
  18. LOGI("Dropping event because there is no focused window or focused application.");
  19. injectionResult = INPUT_EVENT_INJECTION_FAILED;
  20. goto Failed;
  21. }
  22. // Check permissions.
  23. if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) {
  24. injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
  25. goto Failed;
  26. }
  27. // If the currently focused window is paused then keep waiting.
  28. if (mFocusedWindow->paused) {
  29. #if DEBUG_FOCUS
  30. LOGD("Waiting because focused window is paused.");
  31. #endif
  32. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  33. mFocusedApplication, mFocusedWindow, nextWakeupTime);
  34. goto Unresponsive;
  35. }
  36. // If the currently focused window is still working on previous events then keep waiting.
  37. if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) {
  38. #if DEBUG_FOCUS
  39. LOGD("Waiting because focused window still processing previous input.");
  40. #endif
  41. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  42. mFocusedApplication, mFocusedWindow, nextWakeupTime);
  43. goto Unresponsive;
  44. }
  45. // Success!  Output targets.
  46. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
  47. addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND, BitSet32(0));
  48. // Done.
  49. Failed:
  50. Unresponsive:
  51. nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
  52. updateDispatchStatisticsLocked(currentTime, entry,
  53. injectionResult, timeSpentWaitingForApplication);
  54. #if DEBUG_FOCUS
  55. LOGD("findFocusedWindow finished: injectionResult=%d, "
  56. "timeSpendWaitingForApplication=%0.1fms",
  57. injectionResult, timeSpentWaitingForApplication / 1000000.0);
  58. #endif
  59. return injectionResult;
  60. }

move事件的处理和Down事件的处理很不相同。

新建立的Window在处理焦点的时候,按下事件没有起来之前,保持了原来的焦点窗口。除非ACTION_UP事件收到以后

  1. /* Updates the cached window information provided to the input dispatcher. */
  2. public void updateInputWindowsLw() {
  3. // Populate the input window list with information about all of the windows that
  4. // could potentially receive input.
  5. // As an optimization, we could try to prune the list of windows but this turns
  6. // out to be difficult because only the native code knows for sure which window
  7. // currently has touch focus.
  8. final ArrayList<WindowState> windows = mWindows;
  9. final int N = windows.size();
  10. for (int i = N - 1; i >= 0; i--) {
  11. final WindowState child = windows.get(i);
  12. if (child.mInputChannel == null || child.mRemoved) {
  13. // Skip this window because it cannot possibly receive input.
  14. continue;
  15. }
  16. final int flags = child.mAttrs.flags;
  17. final int type = child.mAttrs.type;
  18. final boolean hasFocus = (child == mInputFocus);
  19. final boolean isVisible = child.isVisibleLw();
  20. final boolean hasWallpaper = (child == mWallpaperTarget)
  21. && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
  22. // Add a window to our list of input windows.
  23. final InputWindow inputWindow = mTempInputWindows.add();
  24. inputWindow.inputChannel = child.mInputChannel;
  25. inputWindow.name = child.toString();
  26. inputWindow.layoutParamsFlags = flags;
  27. inputWindow.layoutParamsType = type;
  28. inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
  29. inputWindow.visible = isVisible;
  30. inputWindow.canReceiveKeys = child.canReceiveKeys();
  31. inputWindow.hasFocus = hasFocus;
  32. inputWindow.hasWallpaper = hasWallpaper;
  33. inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false;
  34. inputWindow.layer = child.mLayer;
  35. inputWindow.ownerPid = child.mSession.mPid;
  36. inputWindow.ownerUid = child.mSession.mUid;
  37. final Rect frame = child.mFrame;
  38. inputWindow.frameLeft = frame.left;
  39. inputWindow.frameTop = frame.top;
  40. inputWindow.frameRight = frame.right;
  41. inputWindow.frameBottom = frame.bottom;
  42. final Rect visibleFrame = child.mVisibleFrame;
  43. inputWindow.visibleFrameLeft = visibleFrame.left;
  44. inputWindow.visibleFrameTop = visibleFrame.top;
  45. inputWindow.visibleFrameRight = visibleFrame.right;
  46. inputWindow.visibleFrameBottom = visibleFrame.bottom;
  47. switch (child.mTouchableInsets) {
  48. default:
  49. case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
  50. inputWindow.touchableAreaLeft = frame.left;
  51. inputWindow.touchableAreaTop = frame.top;
  52. inputWindow.touchableAreaRight = frame.right;
  53. inputWindow.touchableAreaBottom = frame.bottom;
  54. break;
  55. case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
  56. Rect inset = child.mGivenContentInsets;
  57. inputWindow.touchableAreaLeft = frame.left + inset.left;
  58. inputWindow.touchableAreaTop = frame.top + inset.top;
  59. inputWindow.touchableAreaRight = frame.right - inset.right;
  60. inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
  61. break;
  62. }
  63. case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
  64. Rect inset = child.mGivenVisibleInsets;
  65. inputWindow.touchableAreaLeft = frame.left + inset.left;
  66. inputWindow.touchableAreaTop = frame.top + inset.top;
  67. inputWindow.touchableAreaRight = frame.right - inset.right;
  68. inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
  69. break;
  70. }
  71. }
  72. }
  73. // Send windows to native code.
  74. mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray());
  75. // Clear the list in preparation for the next round.
  76. // Also avoids keeping InputChannel objects referenced unnecessarily.
  77. mTempInputWindows.clear();
  78. }

真正的Input的控制是通过以下方式

/**
     * Z-ordered (bottom-most first) list of all Window objects.
     */
    final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();

  1. /**
  2. * Z-ordered (bottom-most first) list of all Window objects.
  3. */
  4. final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();

另外的touch的target并不是通过input focus 获得的。而是通过visible来获得

  1. int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
  2. const MotionEntry* entry, nsecs_t* nextWakeupTime) {
  3. enum InjectionPermission {
  4. INJECTION_PERMISSION_UNKNOWN,
  5. INJECTION_PERMISSION_GRANTED,
  6. INJECTION_PERMISSION_DENIED
  7. };
  8. mCurrentInputTargets.clear();
  9. nsecs_t startTime = now();
  10. // For security reasons, we defer updating the touch state until we are sure that
  11. // event injection will be allowed.
  12. //
  13. // FIXME In the original code, screenWasOff could never be set to true.
  14. //       The reason is that the POLICY_FLAG_WOKE_HERE
  15. //       and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw
  16. //       EV_KEY, EV_REL and EV_ABS events.  As it happens, the touch event was
  17. //       actually enqueued using the policyFlags that appeared in the final EV_SYN
  18. //       events upon which no preprocessing took place.  So policyFlags was always 0.
  19. //       In the new native input dispatcher we're a bit more careful about event
  20. //       preprocessing so the touches we receive can actually have non-zero policyFlags.
  21. //       Unfortunately we obtain undesirable behavior.
  22. //
  23. //       Here's what happens:
  24. //
  25. //       When the device dims in anticipation of going to sleep, touches
  26. //       in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause
  27. //       the device to brighten and reset the user activity timer.
  28. //       Touches on other windows (such as the launcher window)
  29. //       are dropped.  Then after a moment, the device goes to sleep.  Oops.
  30. //
  31. //       Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE
  32. //       instead of POLICY_FLAG_WOKE_HERE...
  33. //
  34. bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE;
  35. int32_t action = entry->action;
  36. int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
  37. // Update the touch state as needed based on the properties of the touch event.
  38. int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
  39. InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
  40. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
  41. mTempTouchState.reset();
  42. mTempTouchState.down = true;
  43. } else {
  44. mTempTouchState.copyFrom(mTouchState);
  45. }
  46. bool isSplit = mTempTouchState.split && mTempTouchState.down;
  47. if (maskedAction == AMOTION_EVENT_ACTION_DOWN
  48. || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
  49. /* Case 1: New splittable pointer going down. */
  50. int32_t pointerIndex = getMotionEventActionPointerIndex(action);
  51. int32_t x = int32_t(entry->firstSample.pointerCoords[pointerIndex].x);
  52. int32_t y = int32_t(entry->firstSample.pointerCoords[pointerIndex].y);
  53. const InputWindow* newTouchedWindow = NULL;
  54. const InputWindow* topErrorWindow = NULL;
  55. // Traverse windows from front to back to find touched window and outside targets.
  56. size_t numWindows = mWindows.size();
  57. for (size_t i = 0; i < numWindows; i++) {
  58. const InputWindow* window = & mWindows.editItemAt(i);
  59. int32_t flags = window->layoutParamsFlags;
  60. if (flags & InputWindow::FLAG_SYSTEM_ERROR) {
  61. if (! topErrorWindow) {
  62. topErrorWindow = window;
  63. }
  64. }
  65. if (window->visible) {
  66. if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
  67. bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
  68. | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
  69. if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
  70. if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
  71. newTouchedWindow = window;
  72. }
  73. break; // found touched window, exit window loop
  74. }
  75. }
  76. if (maskedAction == AMOTION_EVENT_ACTION_DOWN
  77. && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
  78. int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;
  79. if (isWindowObscuredAtPointLocked(window, x, y)) {
  80. outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
  81. }
  82. mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));
  83. }
  84. }
  85. }
  86. // If there is an error window but it is not taking focus (typically because
  87. // it is invisible) then wait for it.  Any other focused window may in
  88. // fact be in ANR state.
  89. if (topErrorWindow && newTouchedWindow != topErrorWindow) {
  90. #if DEBUG_FOCUS
  91. LOGD("Waiting because system error window is pending.");
  92. #endif
  93. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  94. NULL, NULL, nextWakeupTime);
  95. injectionPermission = INJECTION_PERMISSION_UNKNOWN;
  96. goto Unresponsive;
  97. }
  98. // Figure out whether splitting will be allowed for this window.
  99. if (newTouchedWindow
  100. && (newTouchedWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH)) {
  101. // New window supports splitting.
  102. isSplit = true;
  103. } else if (isSplit) {
  104. // New window does not support splitting but we have already split events.
  105. // Assign the pointer to the first foreground window we find.
  106. // (May be NULL which is why we put this code block before the next check.)
  107. newTouchedWindow = mTempTouchState.getFirstForegroundWindow();
  108. }
  109. // If we did not find a touched window then fail.
  110. if (! newTouchedWindow) {
  111. if (mFocusedApplication) {
  112. #if DEBUG_FOCUS
  113. LOGD("Waiting because there is no touched window but there is a "
  114. "focused application that may eventually add a new window: %s.",
  115. getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
  116. #endif
  117. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  118. mFocusedApplication, NULL, nextWakeupTime);
  119. goto Unresponsive;
  120. }
  121. LOGI("Dropping event because there is no touched window or focused application.");
  122. injectionResult = INPUT_EVENT_INJECTION_FAILED;
  123. goto Failed;
  124. }
  125. // Set target flags.
  126. int32_t targetFlags = InputTarget::FLAG_FOREGROUND;
  127. if (isSplit) {
  128. targetFlags |= InputTarget::FLAG_SPLIT;
  129. }
  130. if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
  131. targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
  132. }
  133. // Update the temporary touch state.
  134. BitSet32 pointerIds;
  135. if (isSplit) {
  136. uint32_t pointerId = entry->pointerIds[pointerIndex];
  137. pointerIds.markBit(pointerId);
  138. }
  139. mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);
  140. } else {
  141. /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
  142. // If the pointer is not currently down, then ignore the event.
  143. if (! mTempTouchState.down) {
  144. LOGI("Dropping event because the pointer is not down.");
  145. injectionResult = INPUT_EVENT_INJECTION_FAILED;
  146. goto Failed;
  147. }
  148. }
  149. // Check permission to inject into all touched foreground windows and ensure there
  150. // is at least one touched foreground window.
  151. {
  152. bool haveForegroundWindow = false;
  153. for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
  154. const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
  155. if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
  156. haveForegroundWindow = true;
  157. if (! checkInjectionPermission(touchedWindow.window, entry->injectionState)) {
  158. injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
  159. injectionPermission = INJECTION_PERMISSION_DENIED;
  160. goto Failed;
  161. }
  162. }
  163. }
  164. if (! haveForegroundWindow) {
  165. #if DEBUG_INPUT_DISPATCHER_POLICY
  166. LOGD("Dropping event because there is no touched foreground window to receive it.");
  167. #endif
  168. injectionResult = INPUT_EVENT_INJECTION_FAILED;
  169. goto Failed;
  170. }
  171. // Permission granted to injection into all touched foreground windows.
  172. injectionPermission = INJECTION_PERMISSION_GRANTED;
  173. }
  174. // Ensure all touched foreground windows are ready for new input.
  175. for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
  176. const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
  177. if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
  178. // If the touched window is paused then keep waiting.
  179. if (touchedWindow.window->paused) {
  180. #if DEBUG_INPUT_DISPATCHER_POLICY
  181. LOGD("Waiting because touched window is paused.");
  182. #endif
  183. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  184. NULL, touchedWindow.window, nextWakeupTime);
  185. goto Unresponsive;
  186. }
  187. // If the touched window is still working on previous events then keep waiting.
  188. if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.window)) {
  189. #if DEBUG_FOCUS
  190. LOGD("Waiting because touched window still processing previous input.");
  191. #endif
  192. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  193. NULL, touchedWindow.window, nextWakeupTime);
  194. goto Unresponsive;
  195. }
  196. }
  197. }
  198. // If this is the first pointer going down and the touched window has a wallpaper
  199. // then also add the touched wallpaper windows so they are locked in for the duration
  200. // of the touch gesture.
  201. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
  202. const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
  203. if (foregroundWindow->hasWallpaper) {
  204. for (size_t i = 0; i < mWindows.size(); i++) {
  205. const InputWindow* window = & mWindows[i];
  206. if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {
  207. mTempTouchState.addOrUpdateWindow(window,
  208. InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0));
  209. }
  210. }
  211. }
  212. }
  213. // Success!  Output targets.
  214. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
  215. for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
  216. const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
  217. addWindowTargetLocked(touchedWindow.window, touchedWindow.targetFlags,
  218. touchedWindow.pointerIds);
  219. }
  220. // Drop the outside touch window since we will not care about them in the next iteration.
  221. mTempTouchState.removeOutsideTouchWindows();
  222. Failed:
  223. // Check injection permission once and for all.
  224. if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
  225. if (checkInjectionPermission(NULL, entry->injectionState)) {
  226. injectionPermission = INJECTION_PERMISSION_GRANTED;
  227. } else {
  228. injectionPermission = INJECTION_PERMISSION_DENIED;
  229. }
  230. }
  231. // Update final pieces of touch state if the injector had permission.
  232. if (injectionPermission == INJECTION_PERMISSION_GRANTED) {
  233. if (maskedAction == AMOTION_EVENT_ACTION_UP
  234. || maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
  235. // All pointers up or canceled.
  236. mTempTouchState.reset();
  237. } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
  238. // First pointer went down.
  239. if (mTouchState.down) {
  240. #if DEBUG_FOCUS
  241. LOGD("Pointer down received while already down.");
  242. #endif
  243. }
  244. } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
  245. // One pointer went up.
  246. if (isSplit) {
  247. int32_t pointerIndex = getMotionEventActionPointerIndex(action);
  248. uint32_t pointerId = entry->pointerIds[pointerIndex];
  249. for (size_t i = 0; i < mTempTouchState.windows.size(); ) {
  250. TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i);
  251. if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
  252. touchedWindow.pointerIds.clearBit(pointerId);
  253. if (touchedWindow.pointerIds.isEmpty()) {
  254. mTempTouchState.windows.removeAt(i);
  255. continue;
  256. }
  257. }
  258. i += 1;
  259. }
  260. }
  261. }
  262. // Save changes to touch state.
  263. mTouchState.copyFrom(mTempTouchState);
  264. } else {
  265. #if DEBUG_FOCUS
  266. LOGD("Not updating touch focus because injection was denied.");
  267. #endif
  268. }
  269. Unresponsive:
  270. // Reset temporary touch state to ensure we release unnecessary references to input channels.
  271. mTempTouchState.reset();
  272. nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
  273. updateDispatchStatisticsLocked(currentTime, entry,
  274. injectionResult, timeSpentWaitingForApplication);
  275. #if DEBUG_FOCUS
  276. LOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "
  277. "timeSpentWaitingForApplication=%0.1fms",
  278. injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);
  279. #endif
  280. return injectionResult;
  281. }

最关键的几行代码,说明了Windows是如何找到触屏的输入焦点的:

  1. if (window->visible) {
  2. if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
  3. bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
  4. | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
  5. if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
  6. if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
  7. newTouchedWindow = window;
  8. }
  9. break; // found touched window, exit window loop
  10. }
  11. }
  12. if (maskedAction == AMOTION_EVENT_ACTION_DOWN
  13. && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
  14. int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;
  15. if (isWindowObscuredAtPointLocked(window, x, y)) {
  16. outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
  17. }
  18. mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));
  19. }
  20. }
  1. // Focus tracking for touch.
  2. struct TouchedWindow {
  3. const InputWindow* window;
  4. int32_t targetFlags;
  5. BitSet32 pointerIds;
  6. sp<InputChannel> channel;
  7. };
  8. struct TouchState {
  9. bool down;
  10. bool split;
  11. Vector<TouchedWindow> windows;
  12. TouchState();
  13. ~TouchState();
  14. void reset();
  15. void copyFrom(const TouchState& other);
  16. void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds);
  17. void removeOutsideTouchWindows();
  18. const InputWindow* getFirstForegroundWindow();
  19. };
  20. 另外如何定义按键和其他触屏焦点的:
  21. /* Updates the cached window information provided to the input dispatcher. */
  22. public void updateInputWindowsLw() {
  23. // Populate the input window list with information about all of the windows that
  24. // could potentially receive input.
  25. // As an optimization, we could try to prune the list of windows but this turns
  26. // out to be difficult because only the native code knows for sure which window
  27. // currently has touch focus.
  28. final ArrayList<WindowState> windows = mWindows;
  29. final int N = windows.size();
  30. for (int i = N - 1; i >= 0; i--) {
  31. final WindowState child = windows.get(i);
  32. if (child.mInputChannel == null || child.mRemoved) {
  33. // Skip this window because it cannot possibly receive input.
  34. continue;
  35. }
  36. final int flags = child.mAttrs.flags;
  37. final int type = child.mAttrs.type;
  38. <span style="color: #ff6600;"> final boolean hasFocus = (child == mInputFocus);</span>
  39. //本行代码确定,一次性的focusWindow只有一个。
  40. final boolean isVisible = child.isVisibleLw();
  41. final boolean hasWallpaper = (child == mWallpaperTarget)
  42. && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);