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;
}

Java代码  

  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. }

Java代码  

  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;

Java代码  

  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. }

Java代码  

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

Java代码  

  1. ViewRoot有个InputHandler

Java代码  

  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注册给了系统

Java代码  

  1. InputQueue.registerInputChannel(mInputChannel, mInputHandler,
  2. Looper.myQueue());

Java代码  

  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的焦点是怎么回事。

Java代码  

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

然后

Java代码  

  1. dispatchEventToCurrentInputTargetsLocked

调用了如下方法

Java代码  

  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事件收到以后

Java代码  

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

Java代码  

  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来获得

Java代码  

  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是如何找到触屏的输入焦点的:

Cpp代码  

  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. }

Java代码  

  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);
时间: 2024-10-27 11:14:09

Android输入输出系统之TouchEvent流程的相关文章

5. 蛤蟆的计算机组成原理笔记五输入输出系统

5. 蛤蟆的计算机组成原理笔记五输入输出系统 本篇名言:"质朴却比巧妙的言辞更能打动我的心. --莎士比亚" 欢迎转载,转载请标明出:http://blog.csdn.net/notbaron/article/details/48037245 1.  输入输出系统 1.1             I/O 软件 (1) I/O 指令 CPU 指令的一部分 (2) 通道指令 通道自身的指令 1.2             I/O设备与主机信息传送的控制方式 1. 程序查询方式 2. 程序中

Android Touch系统简介(二):实例详解onInterceptTouchEvent与onTouchEvent的调用过程

上一篇文章主要讲述了Android的TouchEvent的分发过程,其中有两个重要的函数:onInterceptTouchEvent和onTouchEvent,这两个函数可被重装以完成特定的逻辑.onInterceptTouchEvent的定义为于ViewGroup中,默认返回值为false,表示不拦截TouchEvent.onTouchEvent的定义位于View中,当ViewGroup要调用onTouchEvent时,会利用super.onTouchEvent.ViewGroup调用onTo

TaintDroid下载预编译(五):TaintDroid(Android)系统编译虚拟机和真机測试

光说不练非好汉,如今就让我们开启自己编译的系统測试!事实上懂得这些过程.就知道了Android手机系统定制的整个流程.现有的智能机都是使用Google的android开源的系统然后加入一些自己的东西.就成为公司的系统! TaintDroid(Android)虚拟机上測试 我们前面讲了怎样编译,编译的成功的标识就是生成system.img文件,例如以下图: sdk替换 拷贝system.img镜像文件,替换掉sdk中的镜像.例如以下图: 对于创建AVD非常easy,这里几张图就能够看懂. wate

Linux系统开机启动流程介绍

一.linux系统进程启动流程图: 二.简单概括描述linux系统从开机到登陆界面的启动过程 1.开机BIOS自检 2.MBR引导 3.grub引导菜单 4.加载内核 5.启动init进程 6.读取inittab文件执行rc.sysinit.rc等脚本 7.启动mingetty进入系统登录界面 三.详细剖析linux系统启动过程 1.POST开机自检 电脑主机打开电源的时候随后会听到滴的一声响系统启动开始了开机自检POST-power on self Test自检开始这个过程中主要是检测计算机硬

《深入理解Android 卷III》第五章 深入理解Android输入系统

<深入理解Android 卷III>即将公布.作者是张大伟.此书填补了深入理解Android Framework卷中的一个主要空白.即Android Framework中和UI相关的部分.在一个特别讲究颜值的时代,本书分析了Android 4.2中WindowManagerService.ViewRoot.Input系统.StatusBar.Wallpaper等重要"颜值绘制/处理"模块 第5章 深入理解Android输入系统(节选) 本章主要内容: ·  研究输入事件从设

Android 音频系统:从 AudioTrack 到 AudioFlinger

1. Android 音频框架概述 Audio 是整个 Android 平台非常重要的一个组成部分,负责音频数据的采集和输出.音频流的控制.音频设备的管理.音量调节等,主要包括如下部分: Audio Application Framework:音频应用框架 AudioTrack:负责回放数据的输出,属 Android 应用框架 API 类 AudioRecord:负责录音数据的采集,属 Android 应用框架 API 类 AudioSystem: 负责音频事务的综合管理,属 Android 应

Android应用开发编译框架流程与IDE及Gradle概要

1 背景 建议阅读本文之前先阅读<Android Studio入门到精通>和<Groovy脚本基础全攻略>及<Gradle脚本基础全攻略>三篇博客作为背景知识,这样才能更好.更系统的串起来.本文的核心就是下图: 关于Gradle的Android插件本文不会过多的说明,只给一个抛砖引玉的提示,详细使用参见文档API及Gradle配置,其实个性化的构建配置一般都是Gradle与Groovy的编写,与Android插件没太多关系,所以重点还在Groovy与Gradle构建.

Android View系统解析(下)

转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/38426471(来自singwhatiwanna的csdn博客) Android View系统解析系列: Android View系统解析(上) 介绍View的基础知识.View的滑动.弹性滑动.滑动冲突解决方式.事件分发等 Android View系统解析(下) 介绍View的Framework层原理.View的measure / layout / draw三大流程和一些高

深入理解 Android 之 View 的绘制流程

概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定实现细节则可以日后再对相应源码进行研读.在进行实际的分析之前,我们先来看下面这张图: 我们来对上图做出简单解释:DecorView是一个应用窗口的根容器,它本质上是一个FrameLayout.DecorView有唯一一个子View,它是一个垂直LinearLayout,包含两个子元素,一个是Titl