Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 914371c4 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I53c7d59d,Ie45d9381

* changes:
  InputDispatcher: Don't split mouse events
  InputDispatcher: Refactoring to prepare for spy windows
parents c451b5e3 713bb3e5
Loading
Loading
Loading
Loading
+129 −109
Original line number Original line Diff line number Diff line
@@ -529,6 +529,23 @@ bool isUserActivityEvent(const EventEntry& eventEntry) {
    }
    }
}
}


// Returns true if the given window can accept pointer events at the given display location.
bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y) {
    if (windowInfo.displayId != displayId || !windowInfo.visible) {
        return false;
    }
    const auto flags = windowInfo.flags;
    if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
        return false;
    }
    const bool isModalWindow = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
            !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL);
    if (!isModalWindow && !windowInfo.touchableRegionContainsPoint(x, y)) {
        return false;
    }
    return true;
}

} // namespace
} // namespace


// --- InputDispatcher ---
// --- InputDispatcher ---
@@ -1039,28 +1056,17 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI
        if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
        if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
            continue;
            continue;
        }
        }
        const WindowInfo* windowInfo = windowHandle->getInfo();
        if (windowInfo->displayId == displayId) {
            auto flags = windowInfo->flags;


            if (windowInfo->visible) {
        const WindowInfo& info = *windowHandle->getInfo();
                if (!flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
        if (windowAcceptsTouchAt(info, displayId, x, y)) {
                    bool isTouchModal = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
                            !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL);
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        // Found window.
            return windowHandle;
            return windowHandle;
        }
        }
                }


                if (addOutsideTargets && flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
        if (addOutsideTargets && info.flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
                    touchState->addOrUpdateWindow(windowHandle,
            touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
                                                  InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
                                          BitSet32(0));
                                          BitSet32(0));
        }
        }
    }
    }
        }
    }
    return nullptr;
    return nullptr;
}
}


@@ -1959,9 +1965,9 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(


    // For security reasons, we defer updating the touch state until we are sure that
    // For security reasons, we defer updating the touch state until we are sure that
    // event injection will be allowed.
    // event injection will be allowed.
    int32_t displayId = entry.displayId;
    const int32_t displayId = entry.displayId;
    int32_t action = entry.action;
    const int32_t action = entry.action;
    int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
    const int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;


    // Update the touch state as needed based on the properties of the touch event.
    // Update the touch state as needed based on the properties of the touch event.
    InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING;
    InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING;
@@ -1974,10 +1980,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
    // If no state for the specified display exists, then our initial state will be empty.
    // If no state for the specified display exists, then our initial state will be empty.
    const TouchState* oldState = nullptr;
    const TouchState* oldState = nullptr;
    TouchState tempTouchState;
    TouchState tempTouchState;
    std::unordered_map<int32_t, TouchState>::iterator oldStateIt =
    if (const auto it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) {
            mTouchStatesByDisplay.find(displayId);
        oldState = &(it->second);
    if (oldStateIt != mTouchStatesByDisplay.end()) {
        oldState = &(oldStateIt->second);
        tempTouchState.copyFrom(*oldState);
        tempTouchState.copyFrom(*oldState);
    }
    }


@@ -1985,10 +1989,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
    bool switchedDevice = tempTouchState.deviceId >= 0 && tempTouchState.displayId >= 0 &&
    bool switchedDevice = tempTouchState.deviceId >= 0 && tempTouchState.displayId >= 0 &&
            (tempTouchState.deviceId != entry.deviceId || tempTouchState.source != entry.source ||
            (tempTouchState.deviceId != entry.deviceId || tempTouchState.source != entry.source ||
             tempTouchState.displayId != displayId);
             tempTouchState.displayId != displayId);
    bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE ||

    const bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE ||
                                maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
                                maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
                                maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
                                maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
    bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
    const bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
                             maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);
                             maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);
    const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);
    const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);
    bool wrongDevice = false;
    bool wrongDevice = false;
@@ -2026,7 +2031,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(


        int32_t x;
        int32_t x;
        int32_t y;
        int32_t y;
        int32_t pointerIndex = getMotionEventActionPointerIndex(action);
        const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
        // Always dispatch mouse events to cursor position.
        // Always dispatch mouse events to cursor position.
        if (isFromMouse) {
        if (isFromMouse) {
            x = int32_t(entry.xCursorPosition);
            x = int32_t(entry.xCursorPosition);
@@ -2039,9 +2044,17 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
        newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
        newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
                                                           isDown /*addOutsideTargets*/);
                                                           isDown /*addOutsideTargets*/);


        // Handle the case where we did not find a window.
        if (newTouchedWindowHandle == nullptr) {
            ALOGD("No new touched window at (%" PRId32 ", %" PRId32 ") in display %" PRId32, x, y,
                  displayId);
            // Try to assign the pointer to the first foreground window we find, if there is one.
            newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
        }

        // Figure out whether splitting will be allowed for this window.
        // Figure out whether splitting will be allowed for this window.
        if (newTouchedWindowHandle != nullptr &&
        if (newTouchedWindowHandle != nullptr) {
            newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
            if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
                // New window supports splitting, but we should never split mouse events.
                // New window supports splitting, but we should never split mouse events.
                isSplit = !isFromMouse;
                isSplit = !isFromMouse;
            } else if (isSplit) {
            } else if (isSplit) {
@@ -2049,36 +2062,48 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
                // Ignore the new window.
                // Ignore the new window.
                newTouchedWindowHandle = nullptr;
                newTouchedWindowHandle = nullptr;
            }
            }
        } else {
            // No window is touched, so set split to true. This will allow the next pointer down to
            // be delivered to a new window which supports split touch. Pointers from a mouse device
            // should never be split.
            tempTouchState.split = isSplit = !isFromMouse;
        }


        // Handle the case where we did not find a window.
        // Update hover state.
        if (newTouchedWindowHandle == nullptr) {
        if (newTouchedWindowHandle != nullptr) {
            ALOGD("No new touched window at (%" PRId32 ", %" PRId32 ") in display %" PRId32, x, y,
            if (maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT) {
                  displayId);
                newHoverWindowHandle = nullptr;
            // Try to assign the pointer to the first foreground window we find, if there is one.
            } else if (isHoverAction) {
            newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
                newHoverWindowHandle = newTouchedWindowHandle;
            }
            }
        }

        std::vector<sp<WindowInfoHandle>> newTouchedWindows;
        if (newTouchedWindowHandle != nullptr) {
            newTouchedWindows.push_back(newTouchedWindowHandle);
        }

        for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
            const WindowInfo& info = *windowHandle->getInfo();


        if (newTouchedWindowHandle != nullptr && newTouchedWindowHandle->getInfo()->paused) {
            if (info.paused) {
                ALOGI("Not sending touch event to %s because it is paused",
                ALOGI("Not sending touch event to %s because it is paused",
                  newTouchedWindowHandle->getName().c_str());
                      windowHandle->getName().c_str());
            newTouchedWindowHandle = nullptr;
                continue;
            }
            }


            // Ensure the window has a connection and the connection is responsive
            // Ensure the window has a connection and the connection is responsive
        if (newTouchedWindowHandle != nullptr) {
            const bool isResponsive = hasResponsiveConnectionLocked(*windowHandle);
            const bool isResponsive = hasResponsiveConnectionLocked(*newTouchedWindowHandle);
            if (!isResponsive) {
            if (!isResponsive) {
                ALOGW("%s will not receive the new gesture at %" PRIu64,
                ALOGW("Not sending touch gesture to %s because it is not responsive",
                      newTouchedWindowHandle->getName().c_str(), entry.eventTime);
                      windowHandle->getName().c_str());
                newTouchedWindowHandle = nullptr;
                continue;
            }
            }
            }


            // Drop events that can't be trusted due to occlusion
            // Drop events that can't be trusted due to occlusion
        if (newTouchedWindowHandle != nullptr &&
            if (mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) {
            mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) {
                TouchOcclusionInfo occlusionInfo =
                TouchOcclusionInfo occlusionInfo =
                    computeTouchOcclusionInfoLocked(newTouchedWindowHandle, x, y);
                        computeTouchOcclusionInfoLocked(windowHandle, x, y);
                if (!isTouchTrustedLocked(occlusionInfo)) {
                if (!isTouchTrustedLocked(occlusionInfo)) {
                    if (DEBUG_TOUCH_OCCLUSION) {
                    if (DEBUG_TOUCH_OCCLUSION) {
                        ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
                        ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
@@ -2090,63 +2115,57 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
                    if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
                    if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
                        ALOGW("Dropping untrusted touch event due to %s/%d",
                        ALOGW("Dropping untrusted touch event due to %s/%d",
                              occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
                              occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
                    newTouchedWindowHandle = nullptr;
                        continue;
                    }
                    }
                }
                }
            }
            }


            // Drop touch events if requested by input feature
            // Drop touch events if requested by input feature
        if (newTouchedWindowHandle != nullptr && shouldDropInput(entry, newTouchedWindowHandle)) {
            if (shouldDropInput(entry, windowHandle)) {
            newTouchedWindowHandle = nullptr;
                continue;
            }
            }


        const std::vector<Monitor> newGestureMonitors = isDown
            // Set target flags.
                ? selectResponsiveMonitorsLocked(
            int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS;
                          getValueByKey(mGestureMonitorsByDisplay, displayId))
                : tempTouchState.gestureMonitors;


        if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) {
            // There should only be one new foreground (non-spy) window at this location.
            ALOGI("Dropping event because there is no touchable window or gesture monitor at "
            targetFlags |= InputTarget::FLAG_FOREGROUND;
                  "(%d, %d) in display %" PRId32 ".",
                  x, y, displayId);
            injectionResult = InputEventInjectionResult::FAILED;
            goto Failed;
        }


        if (newTouchedWindowHandle != nullptr) {
            // Set target flags.
            int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;
            if (isSplit) {
            if (isSplit) {
                targetFlags |= InputTarget::FLAG_SPLIT;
                targetFlags |= InputTarget::FLAG_SPLIT;
            }
            }
            if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
            if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
                targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
                targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
            } else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
            } else if (isWindowObscuredLocked(windowHandle)) {
                targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
                targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
            }
            }


            // Update hover state.
            if (maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT) {
                newHoverWindowHandle = nullptr;
            } else if (isHoverAction) {
                newHoverWindowHandle = newTouchedWindowHandle;
            }

            // Update the temporary touch state.
            // Update the temporary touch state.
            BitSet32 pointerIds;
            BitSet32 pointerIds;
            if (isSplit) {
            if (isSplit) {
                uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
                uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
                pointerIds.markBit(pointerId);
                pointerIds.markBit(pointerId);
            }
            }
            tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);

        } else if (tempTouchState.windows.empty()) {
            tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds);
            // If no window is touched, set split to true. This will allow the next pointer down to
            // be delivered to a new window which supports split touch.
            tempTouchState.split = true;
        }
        }
        if (isDown) {

            tempTouchState.addGestureMonitors(newGestureMonitors);
        const std::vector<Monitor> newGestureMonitors = isDown
                ? selectResponsiveMonitorsLocked(
                          getValueByKey(mGestureMonitorsByDisplay, displayId))
                : std::vector<Monitor>{};

        if (newTouchedWindows.empty() && newGestureMonitors.empty() &&
            tempTouchState.gestureMonitors.empty()) {
            ALOGI("Dropping event because there is no touchable window or gesture monitor at "
                  "(%d, %d) in display %" PRId32 ".",
                  x, y, displayId);
            injectionResult = InputEventInjectionResult::FAILED;
            goto Failed;
        }
        }

        tempTouchState.addGestureMonitors(newGestureMonitors);

    } else {
    } else {
        /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
        /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */


@@ -2166,8 +2185,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
        // Check whether touches should slip outside of the current foreground window.
        // Check whether touches should slip outside of the current foreground window.
        if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.pointerCount == 1 &&
        if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.pointerCount == 1 &&
            tempTouchState.isSlippery()) {
            tempTouchState.isSlippery()) {
            int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
            const int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
            int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
            const int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));


            sp<WindowInfoHandle> oldTouchedWindowHandle =
            sp<WindowInfoHandle> oldTouchedWindowHandle =
                    tempTouchState.getFirstForegroundWindowHandle();
                    tempTouchState.getFirstForegroundWindowHandle();
@@ -2193,7 +2212,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(


                // Make a slippery entrance into the new window.
                // Make a slippery entrance into the new window.
                if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
                if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
                    isSplit = true;
                    isSplit = !isFromMouse;
                }
                }


                int32_t targetFlags =
                int32_t targetFlags =
@@ -2216,9 +2235,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
        }
        }
    }
    }


    // Update dispatching for hover enter and exit.
    if (newHoverWindowHandle != mLastHoverWindowHandle) {
    if (newHoverWindowHandle != mLastHoverWindowHandle) {
        // Let the previous window know that the hover sequence is over, unless we already did it
        // Let the previous window know that the hover sequence is over, unless we already did
        // when dispatching it as is to newTouchedWindowHandle.
        // it when dispatching it as is to newTouchedWindowHandle.
        if (mLastHoverWindowHandle != nullptr &&
        if (mLastHoverWindowHandle != nullptr &&
            (maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT ||
            (maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT ||
             mLastHoverWindowHandle != newTouchedWindowHandle)) {
             mLastHoverWindowHandle != newTouchedWindowHandle)) {
+0 −1
Original line number Original line Diff line number Diff line
@@ -44,7 +44,6 @@ struct TouchState {
    void copyFrom(const TouchState& other);
    void copyFrom(const TouchState& other);
    void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
    void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
                           int32_t targetFlags, BitSet32 pointerIds);
                           int32_t targetFlags, BitSet32 pointerIds);
    void addPortalWindow(const sp<android::gui::WindowInfoHandle>& windowHandle);
    void addGestureMonitors(const std::vector<Monitor>& monitors);
    void addGestureMonitors(const std::vector<Monitor>& monitors);
    void removeWindowByToken(const sp<IBinder>& token);
    void removeWindowByToken(const sp<IBinder>& token);
    void filterNonAsIsTouchWindows();
    void filterNonAsIsTouchWindows();