`
daojin
  • 浏览: 689969 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Android输入输出系统之TouchEvent流程

 
阅读更多

 

记不住密码怎么办?

http://a.app.qq.com/o/simple.jsp?pkgname=com.wa505.kf.epassword

 

 

一个是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;
}

void InputDispatcher::dispatchOnce() {
    nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
    nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();

    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);

        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
        }
    } // release lock

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now();
    int32_t timeoutMillis;
    if (nextWakeupTime > currentTime) {
        uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
        timeout = (timeout + 999999LL) / 1000000LL;
        timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
    } else {
        timeoutMillis = 0;
    }

    mLooper->pollOnce(timeoutMillis);
}

 

    case EventEntry::TYPE_MOTION: {
        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
            dropReason = DROP_REASON_APP_SWITCH;
        }
        done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
        break;

 

bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
    // Preprocessing.
    if (! entry->dispatchInProgress) {
        entry->dispatchInProgress = true;
        resetTargetsLocked();

        logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
    }

    // Clean up if dropping the event.
    if (*dropReason != DROP_REASON_NOT_DROPPED) {
        resetTargetsLocked();
        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
        return true;
    }

    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

    // Identify targets.
    if (! mCurrentInputTargetsValid) {
        int32_t injectionResult;
        if (isPointerEvent) {
            // Pointer event.  (eg. touchscreen)
            injectionResult = findTouchedWindowTargetsLocked(currentTime,
                    entry, nextWakeupTime);
        } else {
            // Non touch event.  (eg. trackball)
            injectionResult = findFocusedWindowTargetsLocked(currentTime,
                    entry, nextWakeupTime);
        }
        if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
            return false;
        }

        setInjectionResultLocked(entry, injectionResult);
        if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
            return true;
        }

        addMonitoringTargetsLocked();
        commitTargetsLocked();
    }

    // Dispatch the motion.
    dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
    return true;
}

 

startDispatchCycleLocked 中的方法
 status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
                motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState,
                xOffset, yOffset,
                motionEntry->xPrecision, motionEntry->yPrecision,
                motionEntry->downTime, firstMotionSample->eventTime,
                motionEntry->pointerCount, motionEntry->pointerIds,
                firstMotionSample->pointerCoords);

 

ViewRoot有个InputHandler

 

    private final InputHandler mInputHandler = new InputHandler() {
        public void handleKey(KeyEvent event, Runnable finishedCallback) {
            startInputEvent(finishedCallback);
            dispatchKey(event, true);
        }

        public void handleMotion(MotionEvent event, Runnable finishedCallback) {
            startInputEvent(finishedCallback);
            dispatchMotion(event, true);
        }
    };

 InputHandler注册给了系统

 

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

 

 dispatchMotion(event, true);方法如下
private void dispatchMotion(MotionEvent event, boolean sendDone) {
        int source = event.getSource();
        if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
            dispatchPointer(event, sendDone);
        } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
            dispatchTrackball(event, sendDone);
        } else {
            // TODO
            Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event);
            if (sendDone) {
                finishInputEvent();
            }
        }
    } 

 

调用了dispatchPointer

 ViewRoot本身就是Handler直接sendMessageAtTime

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

 

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

InputDisapatcher.cpp中调用了如下方法

 dispatchEventToCurrentInputTargetsLocked(currentTime, motionEntry,
                            true /*resumeWithAppendedMotionSample*/);

 然后

dispatchEventToCurrentInputTargetsLocked

调用了如下方法

int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
        const EventEntry* entry, nsecs_t* nextWakeupTime) {
    mCurrentInputTargets.clear();

    int32_t injectionResult;

    // If there is no currently focused window and no focused application
    // then drop the event.
    if (! mFocusedWindow) {
        if (mFocusedApplication) {
#if DEBUG_FOCUS
            LOGD("Waiting because there is no focused window but there is a "
                    "focused application that may eventually add a window: %s.",
                    getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
#endif
            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                    mFocusedApplication, NULL, nextWakeupTime);
            goto Unresponsive;
        }

        LOGI("Dropping event because there is no focused window or focused application.");
        injectionResult = INPUT_EVENT_INJECTION_FAILED;
        goto Failed;
    }

    // Check permissions.
    if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) {
        injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
        goto Failed;
    }

    // If the currently focused window is paused then keep waiting.
    if (mFocusedWindow->paused) {
#if DEBUG_FOCUS
        LOGD("Waiting because focused window is paused.");
#endif
        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                mFocusedApplication, mFocusedWindow, nextWakeupTime);
        goto Unresponsive;
    }

    // If the currently focused window is still working on previous events then keep waiting.
    if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) {
#if DEBUG_FOCUS
        LOGD("Waiting because focused window still processing previous input.");
#endif
        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                mFocusedApplication, mFocusedWindow, nextWakeupTime);
        goto Unresponsive;
    }

    // Success!  Output targets.
    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
    addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND, BitSet32(0));

    // Done.
Failed:
Unresponsive:
    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
    updateDispatchStatisticsLocked(currentTime, entry,
            injectionResult, timeSpentWaitingForApplication);
#if DEBUG_FOCUS
    LOGD("findFocusedWindow finished: injectionResult=%d, "
            "timeSpendWaitingForApplication=%0.1fms",
            injectionResult, timeSpentWaitingForApplication / 1000000.0);
#endif
    return injectionResult;
}

 

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

 

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

 

 

 /* Updates the cached window information provided to the input dispatcher. */
        public void updateInputWindowsLw() {
            // Populate the input window list with information about all of the windows that
            // could potentially receive input.
            // As an optimization, we could try to prune the list of windows but this turns
            // out to be difficult because only the native code knows for sure which window
            // currently has touch focus.
            final ArrayList<WindowState> windows = mWindows;
            final int N = windows.size();
            for (int i = N - 1; i >= 0; i--) {
                final WindowState child = windows.get(i);
                if (child.mInputChannel == null || child.mRemoved) {
                    // Skip this window because it cannot possibly receive input.
                    continue;
                }
                
                final int flags = child.mAttrs.flags;
                final int type = child.mAttrs.type;
                
                final boolean hasFocus = (child == mInputFocus);
                final boolean isVisible = child.isVisibleLw();
                final boolean hasWallpaper = (child == mWallpaperTarget)
                        && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
                
                // Add a window to our list of input windows.
                final InputWindow inputWindow = mTempInputWindows.add();
                inputWindow.inputChannel = child.mInputChannel;
                inputWindow.name = child.toString();
                inputWindow.layoutParamsFlags = flags;
                inputWindow.layoutParamsType = type;
                inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
                inputWindow.visible = isVisible;
                inputWindow.canReceiveKeys = child.canReceiveKeys();
                inputWindow.hasFocus = hasFocus;
                inputWindow.hasWallpaper = hasWallpaper;
                inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false;
                inputWindow.layer = child.mLayer;
                inputWindow.ownerPid = child.mSession.mPid;
                inputWindow.ownerUid = child.mSession.mUid;
                
                final Rect frame = child.mFrame;
                inputWindow.frameLeft = frame.left;
                inputWindow.frameTop = frame.top;
                inputWindow.frameRight = frame.right;
                inputWindow.frameBottom = frame.bottom;
                
                final Rect visibleFrame = child.mVisibleFrame;
                inputWindow.visibleFrameLeft = visibleFrame.left;
                inputWindow.visibleFrameTop = visibleFrame.top;
                inputWindow.visibleFrameRight = visibleFrame.right;
                inputWindow.visibleFrameBottom = visibleFrame.bottom;
                
                switch (child.mTouchableInsets) {
                    default:
                    case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
                        inputWindow.touchableAreaLeft = frame.left;
                        inputWindow.touchableAreaTop = frame.top;
                        inputWindow.touchableAreaRight = frame.right;
                        inputWindow.touchableAreaBottom = frame.bottom;
                        break;
                        
                    case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
                        Rect inset = child.mGivenContentInsets;
                        inputWindow.touchableAreaLeft = frame.left + inset.left;
                        inputWindow.touchableAreaTop = frame.top + inset.top;
                        inputWindow.touchableAreaRight = frame.right - inset.right;
                        inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
                        break;
                    }
                        
                    case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
                        Rect inset = child.mGivenVisibleInsets;
                        inputWindow.touchableAreaLeft = frame.left + inset.left;
                        inputWindow.touchableAreaTop = frame.top + inset.top;
                        inputWindow.touchableAreaRight = frame.right - inset.right;
                        inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
                        break;
                    }
                }
            }

            // Send windows to native code.
            mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray());
            
            // Clear the list in preparation for the next round.
            // Also avoids keeping InputChannel objects referenced unnecessarily.
            mTempInputWindows.clear();
        }

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

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

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

 

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

 

int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
        const MotionEntry* entry, nsecs_t* nextWakeupTime) {
    enum InjectionPermission {
        INJECTION_PERMISSION_UNKNOWN,
        INJECTION_PERMISSION_GRANTED,
        INJECTION_PERMISSION_DENIED
    };

    mCurrentInputTargets.clear();

    nsecs_t startTime = now();

    // For security reasons, we defer updating the touch state until we are sure that
    // event injection will be allowed.
    //
    // FIXME In the original code, screenWasOff could never be set to true.
    //       The reason is that the POLICY_FLAG_WOKE_HERE
    //       and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw
    //       EV_KEY, EV_REL and EV_ABS events.  As it happens, the touch event was
    //       actually enqueued using the policyFlags that appeared in the final EV_SYN
    //       events upon which no preprocessing took place.  So policyFlags was always 0.
    //       In the new native input dispatcher we're a bit more careful about event
    //       preprocessing so the touches we receive can actually have non-zero policyFlags.
    //       Unfortunately we obtain undesirable behavior.
    //
    //       Here's what happens:
    //
    //       When the device dims in anticipation of going to sleep, touches
    //       in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause
    //       the device to brighten and reset the user activity timer.
    //       Touches on other windows (such as the launcher window)
    //       are dropped.  Then after a moment, the device goes to sleep.  Oops.
    //
    //       Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE
    //       instead of POLICY_FLAG_WOKE_HERE...
    //
    bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE;

    int32_t action = entry->action;
    int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;

    // Update the touch state as needed based on the properties of the touch event.
    int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
    InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
        mTempTouchState.reset();
        mTempTouchState.down = true;
    } else {
        mTempTouchState.copyFrom(mTouchState);
    }

    bool isSplit = mTempTouchState.split && mTempTouchState.down;
    if (maskedAction == AMOTION_EVENT_ACTION_DOWN
            || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
        /* Case 1: New splittable pointer going down. */

        int32_t pointerIndex = getMotionEventActionPointerIndex(action);
        int32_t x = int32_t(entry->firstSample.pointerCoords[pointerIndex].x);
        int32_t y = int32_t(entry->firstSample.pointerCoords[pointerIndex].y);
        const InputWindow* newTouchedWindow = NULL;
        const InputWindow* topErrorWindow = NULL;

        // Traverse windows from front to back to find touched window and outside targets.
        size_t numWindows = mWindows.size();
        for (size_t i = 0; i < numWindows; i++) {
            const InputWindow* window = & mWindows.editItemAt(i);
            int32_t flags = window->layoutParamsFlags;

            if (flags & InputWindow::FLAG_SYSTEM_ERROR) {
                if (! topErrorWindow) {
                    topErrorWindow = window;
                }
            }

            if (window->visible) {
                if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
                    bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
                            | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
                    if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
                        if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
                            newTouchedWindow = window;
                        }
                        break; // found touched window, exit window loop
                    }
                }

                if (maskedAction == AMOTION_EVENT_ACTION_DOWN
                        && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
                    int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;
                    if (isWindowObscuredAtPointLocked(window, x, y)) {
                        outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
                    }

                    mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));
                }
            }
        }

        // If there is an error window but it is not taking focus (typically because
        // it is invisible) then wait for it.  Any other focused window may in
        // fact be in ANR state.
        if (topErrorWindow && newTouchedWindow != topErrorWindow) {
#if DEBUG_FOCUS
            LOGD("Waiting because system error window is pending.");
#endif
            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                    NULL, NULL, nextWakeupTime);
            injectionPermission = INJECTION_PERMISSION_UNKNOWN;
            goto Unresponsive;
        }

        // Figure out whether splitting will be allowed for this window.
        if (newTouchedWindow
                && (newTouchedWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH)) {
            // New window supports splitting.
            isSplit = true;
        } else if (isSplit) {
            // New window does not support splitting but we have already split events.
            // Assign the pointer to the first foreground window we find.
            // (May be NULL which is why we put this code block before the next check.)
            newTouchedWindow = mTempTouchState.getFirstForegroundWindow();
        }

        // If we did not find a touched window then fail.
        if (! newTouchedWindow) {
            if (mFocusedApplication) {
#if DEBUG_FOCUS
                LOGD("Waiting because there is no touched window but there is a "
                        "focused application that may eventually add a new window: %s.",
                        getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
#endif
                injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                        mFocusedApplication, NULL, nextWakeupTime);
                goto Unresponsive;
            }

            LOGI("Dropping event because there is no touched window or focused application.");
            injectionResult = INPUT_EVENT_INJECTION_FAILED;
            goto Failed;
        }

        // Set target flags.
        int32_t targetFlags = InputTarget::FLAG_FOREGROUND;
        if (isSplit) {
            targetFlags |= InputTarget::FLAG_SPLIT;
        }
        if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
            targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
        }

        // Update the temporary touch state.
        BitSet32 pointerIds;
        if (isSplit) {
            uint32_t pointerId = entry->pointerIds[pointerIndex];
            pointerIds.markBit(pointerId);
        }
        mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);
    } else {
        /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */

        // If the pointer is not currently down, then ignore the event.
        if (! mTempTouchState.down) {
            LOGI("Dropping event because the pointer is not down.");
            injectionResult = INPUT_EVENT_INJECTION_FAILED;
            goto Failed;
        }
    }

    // Check permission to inject into all touched foreground windows and ensure there
    // is at least one touched foreground window.
    {
        bool haveForegroundWindow = false;
        for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
            const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
            if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
                haveForegroundWindow = true;
                if (! checkInjectionPermission(touchedWindow.window, entry->injectionState)) {
                    injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
                    injectionPermission = INJECTION_PERMISSION_DENIED;
                    goto Failed;
                }
            }
        }
        if (! haveForegroundWindow) {
#if DEBUG_INPUT_DISPATCHER_POLICY
            LOGD("Dropping event because there is no touched foreground window to receive it.");
#endif
            injectionResult = INPUT_EVENT_INJECTION_FAILED;
            goto Failed;
        }

        // Permission granted to injection into all touched foreground windows.
        injectionPermission = INJECTION_PERMISSION_GRANTED;
    }

    // Ensure all touched foreground windows are ready for new input.
    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
        const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
        if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
            // If the touched window is paused then keep waiting.
            if (touchedWindow.window->paused) {
#if DEBUG_INPUT_DISPATCHER_POLICY
                LOGD("Waiting because touched window is paused.");
#endif
                injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                        NULL, touchedWindow.window, nextWakeupTime);
                goto Unresponsive;
            }

            // If the touched window is still working on previous events then keep waiting.
            if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.window)) {
#if DEBUG_FOCUS
                LOGD("Waiting because touched window still processing previous input.");
#endif
                injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                        NULL, touchedWindow.window, nextWakeupTime);
                goto Unresponsive;
            }
        }
    }

    // If this is the first pointer going down and the touched window has a wallpaper
    // then also add the touched wallpaper windows so they are locked in for the duration
    // of the touch gesture.
    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
        const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
        if (foregroundWindow->hasWallpaper) {
            for (size_t i = 0; i < mWindows.size(); i++) {
                const InputWindow* window = & mWindows[i];
                if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {
                    mTempTouchState.addOrUpdateWindow(window,
                            InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0));
                }
            }
        }
    }

    // Success!  Output targets.
    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;

    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
        const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
        addWindowTargetLocked(touchedWindow.window, touchedWindow.targetFlags,
                touchedWindow.pointerIds);
    }

    // Drop the outside touch window since we will not care about them in the next iteration.
    mTempTouchState.removeOutsideTouchWindows();

Failed:
    // Check injection permission once and for all.
    if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
        if (checkInjectionPermission(NULL, entry->injectionState)) {
            injectionPermission = INJECTION_PERMISSION_GRANTED;
        } else {
            injectionPermission = INJECTION_PERMISSION_DENIED;
        }
    }

    // Update final pieces of touch state if the injector had permission.
    if (injectionPermission == INJECTION_PERMISSION_GRANTED) {
        if (maskedAction == AMOTION_EVENT_ACTION_UP
                || maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
            // All pointers up or canceled.
            mTempTouchState.reset();
        } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
            // First pointer went down.
            if (mTouchState.down) {
#if DEBUG_FOCUS
                LOGD("Pointer down received while already down.");
#endif
            }
        } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
            // One pointer went up.
            if (isSplit) {
                int32_t pointerIndex = getMotionEventActionPointerIndex(action);
                uint32_t pointerId = entry->pointerIds[pointerIndex];

                for (size_t i = 0; i < mTempTouchState.windows.size(); ) {
                    TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i);
                    if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
                        touchedWindow.pointerIds.clearBit(pointerId);
                        if (touchedWindow.pointerIds.isEmpty()) {
                            mTempTouchState.windows.removeAt(i);
                            continue;
                        }
                    }
                    i += 1;
                }
            }
        }

        // Save changes to touch state.
        mTouchState.copyFrom(mTempTouchState);
    } else {
#if DEBUG_FOCUS
        LOGD("Not updating touch focus because injection was denied.");
#endif
    }

Unresponsive:
    // Reset temporary touch state to ensure we release unnecessary references to input channels.
    mTempTouchState.reset();

    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
    updateDispatchStatisticsLocked(currentTime, entry,
            injectionResult, timeSpentWaitingForApplication);
#if DEBUG_FOCUS
    LOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "
            "timeSpentWaitingForApplication=%0.1fms",
            injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);
#endif
    return injectionResult;
}

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

 

  if (window->visible) {  
                if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {  
                    bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE  
                            | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;  
                    if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {  
                        if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {  
                            newTouchedWindow = window;  
                        }  
                        break; // found touched window, exit window loop  
                    }  
                }  
  
                if (maskedAction == AMOTION_EVENT_ACTION_DOWN  
                        && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {  
                    int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;  
                    if (isWindowObscuredAtPointLocked(window, x, y)) {  
                        outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;  
                    }  
  
                    mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));  
                }  
            }  

 

 

 // Focus tracking for touch.
    struct TouchedWindow {
        const InputWindow* window;
        int32_t targetFlags;
        BitSet32 pointerIds;
        sp<InputChannel> channel;
    };
    struct TouchState {
        bool down;
        bool split;
        Vector<TouchedWindow> windows;

        TouchState();
        ~TouchState();
        void reset();
        void copyFrom(const TouchState& other);
        void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds);
        void removeOutsideTouchWindows();
        const InputWindow* getFirstForegroundWindow();
    };



另外如何定义按键和其他触屏焦点的:


        /* Updates the cached window information provided to the input dispatcher. */
        public void updateInputWindowsLw() {
            // Populate the input window list with information about all of the windows that
            // could potentially receive input.
            // As an optimization, we could try to prune the list of windows but this turns
            // out to be difficult because only the native code knows for sure which window
            // currently has touch focus.
            final ArrayList<WindowState> windows = mWindows;
            final int N = windows.size();
            for (int i = N - 1; i >= 0; i--) {
                final WindowState child = windows.get(i);
                if (child.mInputChannel == null || child.mRemoved) {
                    // Skip this window because it cannot possibly receive input.
                    continue;
                }
                
                final int flags = child.mAttrs.flags;
                final int type = child.mAttrs.type;
                
                final boolean hasFocus = (child == mInputFocus);
//本行代码确定,一次性的focusWindow只有一个。
                final boolean isVisible = child.isVisibleLw();
                final boolean hasWallpaper = (child == mWallpaperTarget)
                        && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);  

记不住密码怎么办?

http://a.app.qq.com/o/simple.jsp?pkgname=com.wa505.kf.epassword

 

分享到:
评论
1 楼 ritterliu 2014-04-11  
不错,按照流程把关键代码都贴出来了。谢谢分享

相关推荐

    Android TouchEvent事件传递

    在Android开发中,触摸事件(TouchEvent)是用户与设备交互的主要方式之一,它涉及到Activity、View及ViewGroup之间的事件分发。理解Android TouchEvent事件传递机制对于构建具有良好用户体验的应用至关重要。本文将...

    TouchEvent:解释Android TouchEvent的流程。http

    本文将深入解析Android TouchEvent的工作流程,帮助开发者更好地理解和利用这一关键功能。 Android系统通过MotionEvent类来封装触摸事件的信息,包括按下、移动和释放等操作。MotionEvent提供了丰富的API,如`get...

    Android源代码:android触摸事件_TouchEvent

    `TouchEvent`是Android系统处理这些交互的核心机制。本文将深入探讨Android触摸事件的工作原理、监听器的使用以及如何在应用程序中有效地处理触摸事件。 一、触摸事件的生命周期 Android触摸事件遵循一个称为...

    android touchevent 例子 Demo

    最后,为了更好地调试和理解触摸事件的流程,可以利用Log输出各个阶段的事件状态,这对于理解Android的事件处理机制非常有帮助。 总结起来,`android touchevent`涉及到的主要知识点包括:触摸事件的三个基本动作,...

    Android TouchEvent事件传递机制

    在Android系统中,TouchEvent事件处理是用户界面交互的核心部分,它涉及到UI组件的触摸响应,是应用程序接收并处理用户触摸屏幕动作的主要方式。本篇将深入解析Android的TouchEvent事件传递机制,帮助开发者更好地...

    Android代码-基于touchevent的动画对象

    OffsetAnimator OffsetAnimator lets animate objects basing on touchevents, so users can be engaged in an animation process. Usage Add the library to your project: Add it in your root build.gradle at ...

    Android Touch事件rawX,rawY与x,y的区别

    首先,`MotionEvent`是Android系统用于表示触摸事件的数据类,它包含了与触摸屏幕相关的各种信息,如动作类型(ACTION_DOWN、ACTION_UP等)、坐标位置等。当用户在屏幕上进行触控操作时,系统会生成一系列的`...

    TouchEvent的dispatchTouchEvent事件分发流程图

    TouchEvent的dispatchTouchEvent事件分发流程图

    Qt for android触摸手势事件QGestureEvent

    Qt是一个跨平台的应用程序开发框架,支持多种操作系统,包括Android。它提供了丰富的功能,使开发者能够在移动设备上创建用户界面,而QGestureEvent是Qt中处理触摸输入的关键组件。 **Qt for Android** Qt for ...

    CEGUI android 移植

    其次,CEGUI与Android的输入系统集成也是个挑战。Android使用事件驱动的输入处理机制,而CEGUI则有自己的事件模型。开发者需要编写适配器,将Android的MotionEvent、TouchEvent等转换为CEGUI可识别的事件。 然后,...

    android源码之会说话的汤姆猫.zip

    游戏事件(如触摸事件)会被监听并触发相应的反应,这可能涉及到Android的View类和TouchEvent。此外,游戏的状态管理,如暂停、恢复、结束等,也会有对应的函数来处理。 资源管理是游戏开发中的重要部分,会说话的...

    同方向和不同方向的Android滑动冲突解决方案.zip

    它的作用是提供一种系统性的方法,以有效地应对挑战、优化流程或实现目标。以下是方案的主要作用: 问题解决: 方案的核心目标是解决问题。通过系统性的规划和执行,方案能够分析问题的根本原因,提供可行的解决...

    Android开发的贪吃蛇(专门用于课程设计)

    Android提供了TouchEvent机制来处理用户的输入,你需要适配ACTION_DOWN、ACTION_MOVE和ACTION_UP等事件。 6. **游戏状态管理**:游戏有开始、暂停、结束等状态,需要合理地管理这些状态。例如,使用布尔变量跟踪...

    基于-Android日历记事功能实现.doc

    * 触摸事件:在Android系统中,需要使用TouchEvent来处理用户的触摸事件。 * 键盘操作:在Android系统中,需要使用KeyListener来处理用户的键盘事件。 4. 进展编码 * 登录:需要实现用户的登录功能,能够登录到...

    Android操作系统的飞机游戏,java源代码

    在本主题中,我们将深入探讨一个基于Android操作系统开发的飞机游戏,其核心编程语言为Java。这个项目展示了如何使用Java和Android SDK来构建一个互动性强、用户体验良好的移动游戏。让我们一起解析这个Android飞机...

    Android-简易弹钢琴

    在Android系统中,开发者通常使用Java或Kotlin语言进行编程,构建这样的应用会涉及到以下几个关键知识点: 1. **用户界面(UI)设计**:应用的界面设计是吸引用户的关键。开发者会使用Android Studio提供的布局工具...

    ANDROID框架揭秘

    本书不仅涵盖了Android框架的基础概念,还详细介绍了其内部架构、组件间通信机制、系统服务、应用生命周期管理、UI绘制流程、输入事件处理、多媒体支持、网络通信、性能优化等多个方面,是Android开发者不可多得的...

    android源码开发实战6.12.zip

    《Android源码开发实战6.12》是针对Android系统深度开发的一份宝贵资源,它涵盖了从基础到高级的各种主题,旨在帮助开发者更好地理解和利用Android的底层机制。在这个压缩包中,主要包含的是第六章第十二节的内容。...

    android随机密码键盘

    通过这个项目,开发者可以深入理解Android系统的输入机制,提升布局设计和动画编程的能力,同时也能学习到如何在实际应用中兼顾用户体验和安全性。对于Android开发初学者来说,这是一个很好的实践项目,有助于提升...

    Android(贪吃蛇源代码)

    5. **触摸事件处理**:Android通过TouchEvent系统提供对用户触摸输入的处理。在贪吃蛇游戏中,我们需要监听用户的滑动操作来改变蛇的方向。 6. **动画**:Android提供了多种动画API,如ValueAnimator和...

Global site tag (gtag.js) - Google Analytics