Merge "InputFlinger: Add DROP_INPUT and DROP_INPUT_IF_OBSCURED feature flags" into sc-v2-dev
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index f090c63..4727740 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -121,9 +121,11 @@
};
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
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 65fec7d..5505726 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1828,6 +1828,11 @@
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
@@ -2074,6 +2079,11 @@
}
}
+ // 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);
@@ -2139,6 +2149,13 @@
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) {
@@ -6256,4 +6273,19 @@
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
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index db559df..04913d4 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -542,6 +542,10 @@
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.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f028349..83e74ba 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -5456,4 +5456,134 @@
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