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

Commit 73be4f77 authored by Vishnu Nair's avatar Vishnu Nair Committed by Automerger Merge Worker
Browse files

Merge "InputFlinger: Add DROP_INPUT and DROP_INPUT_IF_OBSCURED feature flags"...

Merge "InputFlinger: Add DROP_INPUT and DROP_INPUT_IF_OBSCURED feature flags" into sc-v2-dev am: 4541ab50

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

Change-Id: I44c11757f6ffd3835091f1583e161a001af12cd9
parents 3fe9b623 4541ab50
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -121,9 +121,11 @@ struct WindowInfo : public Parcelable {
    };

    enum class Feature {
        DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
        NO_INPUT_CHANNEL = 0x00000002,
        DISABLE_USER_ACTIVITY = 0x00000004,
        DISABLE_TOUCH_PAD_GESTURES = 1u << 0,
        NO_INPUT_CHANNEL = 1u << 1,
        DISABLE_USER_ACTIVITY = 1u << 2,
        DROP_INPUT = 1u << 3,
        DROP_INPUT_IF_OBSCURED = 1u << 4,
    };

    /* These values are filled in by the WM and passed through SurfaceFlinger
+32 −0
Original line number Diff line number Diff line
@@ -1833,6 +1833,11 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked(
        return InputEventInjectionResult::FAILED;
    }

    // Drop key events if requested by input feature
    if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) {
        return InputEventInjectionResult::FAILED;
    }

    // Compatibility behavior: raise ANR if there is a focused application, but no focused window.
    // Only start counting when we have a focused event to dispatch. The ANR is canceled if we
    // start interacting with another application via touch (app switch). This code can be removed
@@ -2079,6 +2084,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            }
        }

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

        // Also don't send the new touch event to unresponsive gesture monitors
        newGestureMonitors = selectResponsiveMonitorsLocked(newGestureMonitors);

@@ -2144,6 +2154,13 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            sp<WindowInfoHandle> oldTouchedWindowHandle =
                    tempTouchState.getFirstForegroundWindowHandle();
            newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState);

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

            if (oldTouchedWindowHandle != newTouchedWindowHandle &&
                oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) {
                if (DEBUG_FOCUS) {
@@ -6261,4 +6278,19 @@ void InputDispatcher::onWindowInfosChanged(const std::vector<gui::WindowInfo>& w
    setInputWindows(handlesPerDisplay);
}

bool InputDispatcher::shouldDropInput(
        const EventEntry& entry, const sp<android::gui::WindowInfoHandle>& windowHandle) const {
    if (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT) ||
        (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED) &&
         isWindowObscuredLocked(windowHandle))) {
        ALOGW("Dropping %s event targeting %s as requested by input feature %s on display "
              "%" PRId32 ".",
              NamedEnum::string(entry.type).c_str(), windowHandle->getName().c_str(),
              windowHandle->getInfo()->inputFeatures.string().c_str(),
              windowHandle->getInfo()->displayId);
        return true;
    }
    return false;
}

} // namespace android::inputdispatcher
+4 −0
Original line number Diff line number Diff line
@@ -542,6 +542,10 @@ private:
    std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle,
                                          const sp<android::gui::WindowInfoHandle>& windowHandle);

    bool shouldDropInput(const EventEntry& entry,
                         const sp<android::gui::WindowInfoHandle>& windowHandle) const
            REQUIRES(mLock);

    // Manage the dispatch cycle for a single connection.
    // These methods are deliberately not Interruptible because doing all of the work
    // with the mutex held makes it easier to ensure that connection invariants are maintained.
+130 −0
Original line number Diff line number Diff line
@@ -5466,4 +5466,134 @@ TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
    mSecondWindow->assertNoEvents();
}

class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};

TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> window =
            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
    window->setInputFeatures(WindowInfo::Feature::DROP_INPUT);
    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
    window->setFocusable(true);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
    setFocusedWindow(window);
    window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);

    // With the flag set, window should not get any input
    NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyKey(&keyArgs);
    window->assertNoEvents();

    NotifyMotionArgs motionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                               ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&motionArgs);
    window->assertNoEvents();

    // With the flag cleared, the window should get input
    window->setInputFeatures({});
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});

    keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyKey(&keyArgs);
    window->consumeKeyUp(ADISPLAY_ID_DEFAULT);

    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                                    ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&motionArgs);
    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
    window->assertNoEvents();
}

TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
    std::shared_ptr<FakeApplicationHandle> obscuringApplication =
            std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> obscuringWindow =
            new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
                                 ADISPLAY_ID_DEFAULT);
    obscuringWindow->setFrame(Rect(0, 0, 50, 50));
    obscuringWindow->setOwnerInfo(111, 111);
    obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> window =
            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
    window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED);
    window->setOwnerInfo(222, 222);
    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
    window->setFocusable(true);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
    setFocusedWindow(window);
    window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);

    // With the flag set, window should not get any input
    NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyKey(&keyArgs);
    window->assertNoEvents();

    NotifyMotionArgs motionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                               ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&motionArgs);
    window->assertNoEvents();

    // With the flag cleared, the window should get input
    window->setInputFeatures({});
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});

    keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyKey(&keyArgs);
    window->consumeKeyUp(ADISPLAY_ID_DEFAULT);

    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                                    ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&motionArgs);
    window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
    window->assertNoEvents();
}

TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
    std::shared_ptr<FakeApplicationHandle> obscuringApplication =
            std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> obscuringWindow =
            new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
                                 ADISPLAY_ID_DEFAULT);
    obscuringWindow->setFrame(Rect(0, 0, 50, 50));
    obscuringWindow->setOwnerInfo(111, 111);
    obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> window =
            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
    window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED);
    window->setOwnerInfo(222, 222);
    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
    window->setFocusable(true);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
    setFocusedWindow(window);
    window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);

    // With the flag set, window should not get any input
    NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyKey(&keyArgs);
    window->assertNoEvents();

    NotifyMotionArgs motionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                               ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&motionArgs);
    window->assertNoEvents();

    // When the window is no longer obscured because it went on top, it should get input
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, obscuringWindow}}});

    keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyKey(&keyArgs);
    window->consumeKeyUp(ADISPLAY_ID_DEFAULT);

    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                                    ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&motionArgs);
    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
    window->assertNoEvents();
}

} // namespace android::inputdispatcher