• 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.   
    5.     nsecs_t nextWakeupTime = LONG_LONG_MAX;  
    6.     { // acquire lock  
    7.         AutoMutex _l(mLock);  
    8.         dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);  
    9.   
    10.         if (runCommandsLockedInterruptible()) {  
    11.             nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately  
    12.         }  
    13.     } // release lock  
    14.   
    15.     // Wait for callback or timeout or wake.  (make sure we round up, not down)  
    16.     nsecs_t currentTime = now();  
    17.     int32_t timeoutMillis;  
    18.     if (nextWakeupTime > currentTime) {  
    19.         uint64_t timeout = uint64_t(nextWakeupTime - currentTime);  
    20.         timeout = (timeout + 999999LL) / 1000000LL;  
    21.         timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);  
    22.     } else {  
    23.         timeoutMillis = 0;  
    24.     }  
    25.   
    26.     mLooper->pollOnce(timeoutMillis);  
    27. }  

     

    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.   
    8.         logOutboundMotionDetailsLocked("dispatchMotion - ", entry);  
    9.     }  
    10.   
    11.     // Clean up if dropping the event.  
    12.     if (*dropReason != DROP_REASON_NOT_DROPPED) {  
    13.         resetTargetsLocked();  
    14.         setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY  
    15.                 ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);  
    16.         return true;  
    17.     }  
    18.   
    19.     bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;  
    20.   
    21.     // Identify targets.  
    22.     if (! mCurrentInputTargetsValid) {  
    23.         int32_t injectionResult;  
    24.         if (isPointerEvent) {  
    25.             // Pointer event.  (eg. touchscreen)  
    26.             injectionResult = findTouchedWindowTargetsLocked(currentTime,  
    27.                     entry, nextWakeupTime);  
    28.         } else {  
    29.             // Non touch event.  (eg. trackball)  
    30.             injectionResult = findFocusedWindowTargetsLocked(currentTime,  
    31.                     entry, nextWakeupTime);  
    32.         }  
    33.         if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {  
    34.             return false;  
    35.         }  
    36.   
    37.         setInjectionResultLocked(entry, injectionResult);  
    38.         if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {  
    39.             return true;  
    40.         }  
    41.   
    42.         addMonitoringTargetsLocked();  
    43.         commitTargetsLocked();  
    44.     }  
    45.   
    46.     // Dispatch the motion.  
    47.     dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);  
    48.     return true;  
    49. }  

     

    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.   
    7.     public void handleMotion(MotionEvent event, Runnable finishedCallback) {  
    8.         startInputEvent(finishedCallback);  
    9.         dispatchMotion(event, true);  
    10.     }  
    11. };  

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

     

    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.                  
    17.                final int flags = child.mAttrs.flags;  
    18.                final int type = child.mAttrs.type;  
    19.                  
    20.                final boolean hasFocus = (child == mInputFocus);  
    21.                final boolean isVisible = child.isVisibleLw();  
    22.                final boolean hasWallpaper = (child == mWallpaperTarget)  
    23.                        && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);  
    24.                  
    25.                // Add a window to our list of input windows.  
    26.                final InputWindow inputWindow = mTempInputWindows.add();  
    27.                inputWindow.inputChannel = child.mInputChannel;  
    28.                inputWindow.name = child.toString();  
    29.                inputWindow.layoutParamsFlags = flags;  
    30.                inputWindow.layoutParamsType = type;  
    31.                inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();  
    32.                inputWindow.visible = isVisible;  
    33.                inputWindow.canReceiveKeys = child.canReceiveKeys();  
    34.                inputWindow.hasFocus = hasFocus;  
    35.                inputWindow.hasWallpaper = hasWallpaper;  
    36.                inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false;  
    37.                inputWindow.layer = child.mLayer;  
    38.                inputWindow.ownerPid = child.mSession.mPid;  
    39.                inputWindow.ownerUid = child.mSession.mUid;  
    40.                  
    41.                final Rect frame = child.mFrame;  
    42.                inputWindow.frameLeft = frame.left;  
    43.                inputWindow.frameTop = frame.top;  
    44.                inputWindow.frameRight = frame.right;  
    45.                inputWindow.frameBottom = frame.bottom;  
    46.                  
    47.                final Rect visibleFrame = child.mVisibleFrame;  
    48.                inputWindow.visibleFrameLeft = visibleFrame.left;  
    49.                inputWindow.visibleFrameTop = visibleFrame.top;  
    50.                inputWindow.visibleFrameRight = visibleFrame.right;  
    51.                inputWindow.visibleFrameBottom = visibleFrame.bottom;  
    52.                  
    53.                switch (child.mTouchableInsets) {  
    54.                    default:  
    55.                    case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:  
    56.                        inputWindow.touchableAreaLeft = frame.left;  
    57.                        inputWindow.touchableAreaTop = frame.top;  
    58.                        inputWindow.touchableAreaRight = frame.right;  
    59.                        inputWindow.touchableAreaBottom = frame.bottom;  
    60.                        break;  
    61.                          
    62.                    case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {  
    63.                        Rect inset = child.mGivenContentInsets;  
    64.                        inputWindow.touchableAreaLeft = frame.left + inset.left;  
    65.                        inputWindow.touchableAreaTop = frame.top + inset.top;  
    66.                        inputWindow.touchableAreaRight = frame.right - inset.right;  
    67.                        inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;  
    68.                        break;  
    69.                    }  
    70.                          
    71.                    case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {  
    72.                        Rect inset = child.mGivenVisibleInsets;  
    73.                        inputWindow.touchableAreaLeft = frame.left + inset.left;  
    74.                        inputWindow.touchableAreaTop = frame.top + inset.top;  
    75.                        inputWindow.touchableAreaRight = frame.right - inset.right;  
    76.                        inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;  
    77.                        break;  
    78.                    }  
    79.                }  
    80.            }  
    81.   
    82.            // Send windows to native code.  
    83.            mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray());  
    84.              
    85.            // Clear the list in preparation for the next round.  
    86.            // Also avoids keeping InputChannel objects referenced unnecessarily.  
    87.            mTempInputWindows.clear();  
    88.        }  

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

      最关键的几行代码,说明了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.   
    13.               if (maskedAction == AMOTION_EVENT_ACTION_DOWN    
    14.                       && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {    
    15.                   int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;    
    16.                   if (isWindowObscuredAtPointLocked(window, x, y)) {    
    17.                       outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;    
    18.                   }    
    19.   
    20.                   mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));    
    21.               }    
    22.           }    

     

    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.   
    13.         TouchState();  
    14.         ~TouchState();  
    15.         void reset();  
    16.         void copyFrom(const TouchState& other);  
    17.         void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds);  
    18.         void removeOutsideTouchWindows();  
    19.         const InputWindow* getFirstForegroundWindow();  
    20.     };  
    21.   
    22.   
    23.   
    24. 另外如何定义按键和其他触屏焦点的:  
    25.   
    26.   
    27.         /* Updates the cached window information provided to the input dispatcher. */  
    28.         public void updateInputWindowsLw() {  
    29.             // Populate the input window list with information about all of the windows that  
    30.             // could potentially receive input.  
    31.             // As an optimization, we could try to prune the list of windows but this turns  
    32.             // out to be difficult because only the native code knows for sure which window  
    33.             // currently has touch focus.  
    34.             final ArrayList<WindowState> windows = mWindows;  
    35.             final int N = windows.size();  
    36.             for (int i = N - 1; i >= 0; i--) {  
    37.                 final WindowState child = windows.get(i);  
    38.                 if (child.mInputChannel == null || child.mRemoved) {  
    39.                     // Skip this window because it cannot possibly receive input.  
    40.                     continue;  
    41.                 }  
    42.                   
    43.                 final int flags = child.mAttrs.flags;  
    44.                 final int type = child.mAttrs.type;  
    45.                   
    46.                <span style="color: #ff6600;"> final boolean hasFocus = (child == mInputFocus);</span>  
    47. //本行代码确定,一次性的focusWindow只有一个。  
    48.                 final boolean isVisible = child.isVisibleLw();  
    49.                 final boolean hasWallpaper = (child == mWallpaperTarget)  
    50.                         && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);    
  • 相关阅读:
    Web安全实践
    认证授权的设计与实现
    Elasticsearch 分页查询
    【算法】三色旗
    【转】互联网项目中mysql应该选什么事务隔离级别
    Elasticsearch 聚合
    Elasticsearch 结构化搜索、keyword、Term查询
    Elasticsearch 单字符串多字段查询
    Elasticsearch 复合查询——多字符串多字段查询
    JavaScript 原型与原型链
  • 原文地址:https://www.cnblogs.com/xiaochao1234/p/4023845.html
Copyright © 2020-2023  润新知