Loading libs/gui/include/gui/WindowInfo.h +5 −3 Original line number Diff line number Diff line Loading @@ -132,9 +132,11 @@ struct WindowInfo : public Parcelable { }; enum class Feature : uint32_t { 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 Loading services/inputflinger/dispatcher/InputDispatcher.cpp +32 −0 Original line number Diff line number Diff line Loading @@ -1868,6 +1868,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 Loading Loading @@ -2113,6 +2118,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); Loading Loading @@ -2178,6 +2188,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) { Loading Loading @@ -6192,4 +6209,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 ".", ftl::enum_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 services/inputflinger/dispatcher/InputDispatcher.h +4 −0 Original line number Diff line number Diff line Loading @@ -554,6 +554,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. Loading services/inputflinger/tests/InputDispatcher_test.cpp +130 −0 Original line number Diff line number Diff line Loading @@ -5734,4 +5734,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 Loading
libs/gui/include/gui/WindowInfo.h +5 −3 Original line number Diff line number Diff line Loading @@ -132,9 +132,11 @@ struct WindowInfo : public Parcelable { }; enum class Feature : uint32_t { 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 Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +32 −0 Original line number Diff line number Diff line Loading @@ -1868,6 +1868,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 Loading Loading @@ -2113,6 +2118,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); Loading Loading @@ -2178,6 +2188,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) { Loading Loading @@ -6192,4 +6209,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 ".", ftl::enum_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
services/inputflinger/dispatcher/InputDispatcher.h +4 −0 Original line number Diff line number Diff line Loading @@ -554,6 +554,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. Loading
services/inputflinger/tests/InputDispatcher_test.cpp +130 −0 Original line number Diff line number Diff line Loading @@ -5734,4 +5734,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