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

Commit 1596b7a3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "InputDispatcher: Do not drop ongoing gesture if a window is no longer a...

Merge "InputDispatcher: Do not drop ongoing gesture if a window is no longer a spy" into tm-dev am: 82637ad5

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/17186063

Change-Id: I63808babfd4c458e739ae18039783f59bca10f99
parents a1429223 82637ad5
Loading
Loading
Loading
Loading
+29 −12
Original line number Original line Diff line number Diff line
@@ -556,6 +556,17 @@ bool isPointerFromStylus(const MotionEntry& entry, int32_t pointerIndex) {
             entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_ERASER);
             entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_ERASER);
}
}


// Determines if the given window can be targeted as InputTarget::FLAG_FOREGROUND.
// Foreground events are only sent to "foreground targetable" windows, but not all gestures sent to
// such window are necessarily targeted with the flag. For example, an event with ACTION_OUTSIDE can
// be sent to such a window, but it is not a foreground event and doesn't use
// InputTarget::FLAG_FOREGROUND.
bool canReceiveForegroundTouches(const WindowInfo& info) {
    // A non-touchable window can still receive touch events (e.g. in the case of
    // STYLUS_INTERCEPTOR), so prevent such windows from receiving foreground events for touches.
    return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy();
}

} // namespace
} // namespace


// --- InputDispatcher ---
// --- InputDispatcher ---
@@ -2203,8 +2214,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            // Set target flags.
            // Set target flags.
            int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS;
            int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS;


            if (!info.isSpy()) {
            if (canReceiveForegroundTouches(*windowHandle->getInfo())) {
                // There should only be one new foreground (non-spy) window at this location.
                // There should only be one touched window that can be "foreground" for the pointer.
                targetFlags |= InputTarget::FLAG_FOREGROUND;
                targetFlags |= InputTarget::FLAG_FOREGROUND;
            }
            }


@@ -2277,8 +2288,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
                    isSplit = !isFromMouse;
                    isSplit = !isFromMouse;
                }
                }


                int32_t targetFlags =
                int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;
                        InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;
                if (canReceiveForegroundTouches(*newTouchedWindowHandle->getInfo())) {
                    targetFlags |= InputTarget::FLAG_FOREGROUND;
                }
                if (isSplit) {
                if (isSplit) {
                    targetFlags |= InputTarget::FLAG_SPLIT;
                    targetFlags |= InputTarget::FLAG_SPLIT;
                }
                }
@@ -2327,13 +2340,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
        }
        }
    }
    }


    // Ensure that we have at least one foreground or spy window. It's possible that we dropped some
    // Ensure that we have at least one foreground window or at least one window that cannot be a
    // of the touched windows we previously found if they became paused or unresponsive or were
    // foreground target. If we only have windows that are not receiving foreground touches (e.g. we
    // removed.
    // only have windows getting ACTION_OUTSIDE), then drop the event, because there is no window
    // that is actually receiving the entire gesture.
    if (std::none_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
    if (std::none_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
                     [](const TouchedWindow& touchedWindow) {
                     [](const TouchedWindow& touchedWindow) {
                         return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 ||
                         return !canReceiveForegroundTouches(
                                 touchedWindow.windowHandle->getInfo()->isSpy();
                                        *touchedWindow.windowHandle->getInfo()) ||
                                 (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0;
                     })) {
                     })) {
        ALOGI("Dropping event because there is no touched window on display %d to receive it.",
        ALOGI("Dropping event because there is no touched window on display %d to receive it.",
              displayId);
              displayId);
@@ -5072,9 +5087,11 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<
        state->removeWindowByToken(fromToken);
        state->removeWindowByToken(fromToken);


        // Add new window.
        // Add new window.
        int32_t newTargetFlags = oldTargetFlags &
        int32_t newTargetFlags =
                (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT |
                oldTargetFlags & (InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
                 InputTarget::FLAG_DISPATCH_AS_IS);
        if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) {
            newTargetFlags |= InputTarget::FLAG_FOREGROUND;
        }
        state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
        state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);


        // Store the dragging window.
        // Store the dragging window.
+34 −0
Original line number Original line Diff line number Diff line
@@ -6915,4 +6915,38 @@ TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
    window->assertNoEvents();
    window->assertNoEvents();
}
}


/**
 * Set up a scenario to test the behavior used by the stylus handwriting detection feature.
 * The scenario is as follows:
 *   - The stylus interceptor overlay is configured as a spy window.
 *   - The stylus interceptor spy receives the start of a new stylus gesture.
 *   - It pilfers pointers and then configures itself to no longer be a spy.
 *   - The stylus interceptor continues to receive the rest of the gesture.
 */
TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) {
    auto [overlay, window] = setupStylusOverlayScenario();
    overlay->setSpy(true);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});

    sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
    overlay->consumeMotionDown();
    window->consumeMotionDown();

    // The interceptor pilfers the pointers.
    EXPECT_EQ(OK, mDispatcher->pilferPointers(overlay->getToken()));
    window->consumeMotionCancel();

    // The interceptor configures itself so that it is no longer a spy.
    overlay->setSpy(false);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});

    // It continues to receive the rest of the stylus gesture.
    sendStylusEvent(AMOTION_EVENT_ACTION_MOVE);
    overlay->consumeMotionMove();
    sendStylusEvent(AMOTION_EVENT_ACTION_UP);
    overlay->consumeMotionUp();

    window->assertNoEvents();
}

} // namespace android::inputdispatcher
} // namespace android::inputdispatcher