diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2021-11-09 23:53:32 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2021-11-09 23:53:32 +0000 |
commit | b27497c4bf64ff577e9a3a0f9a4ef66d6e3f8cb8 (patch) | |
tree | 2c04ed018febfb97d63d0a9c28584bae58302c38 | |
parent | 294e7b87e3221d73d294293f184d2eaba39f1e8b (diff) | |
parent | d8c6ef21387db53930d728272db24cca1cd38a38 (diff) | |
download | native-b27497c4bf64ff577e9a3a0f9a4ef66d6e3f8cb8.tar.gz |
Merge "Check if the window is partially obscured for slippery enters" into rvc-dev
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 2 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 205 |
2 files changed, 145 insertions, 62 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 98f9aaa92a..d2183c5c34 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1782,6 +1782,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; + } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { + targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } BitSet32 pointerIds; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 1a133dc01c..86c0503662 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -19,10 +19,10 @@ #include <android-base/stringprintf.h> #include <android-base/thread_annotations.h> #include <binder/Binder.h> -#include <input/Input.h> - #include <gtest/gtest.h> +#include <input/Input.h> #include <linux/input.h> + #include <cinttypes> #include <thread> #include <unordered_set> @@ -68,12 +68,10 @@ class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { InputDispatcherConfiguration mConfig; protected: - virtual ~FakeInputDispatcherPolicy() { - } + virtual ~FakeInputDispatcherPolicy() {} public: - FakeInputDispatcherPolicy() { - } + FakeInputDispatcherPolicy() {} void assertFilterInputEventWasCalled(const NotifyKeyArgs& args) { assertFilterInputEventWasCalled(AINPUT_EVENT_TYPE_KEY, args.eventTime, args.action, @@ -366,7 +364,7 @@ protected: mFakePolicy = new FakeInputDispatcherPolicy(); mDispatcher = new InputDispatcher(mFakePolicy); mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); - //Start InputDispatcher thread + // Start InputDispatcher thread ASSERT_EQ(OK, mDispatcher->start()); } @@ -391,7 +389,6 @@ protected: } }; - TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { KeyEvent event; @@ -589,9 +586,7 @@ public: } virtual ~FakeApplicationHandle() {} - virtual bool updateInfo() override { - return true; - } + virtual bool updateInfo() override { return true; } void setDispatchingTimeout(std::chrono::nanoseconds timeout) { mInfo.dispatchingTimeout = timeout.count(); @@ -822,39 +817,40 @@ public: } void consumeMotionCancel(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { + int32_t expectedFlags = 0) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, expectedDisplayId, expectedFlags); } void consumeMotionMove(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { + int32_t expectedFlags = 0) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_MOVE, expectedDisplayId, expectedFlags); } void consumeMotionDown(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { + int32_t expectedFlags = 0) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId, expectedFlags); } void consumeMotionPointerDown(int32_t pointerIdx, - int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { - int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN - | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, + int32_t expectedFlags = 0) { + int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); } void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { - int32_t action = AMOTION_EVENT_ACTION_POINTER_UP - | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + int32_t expectedFlags = 0) { + int32_t action = AMOTION_EVENT_ACTION_POINTER_UP | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); } void consumeMotionUp(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { + int32_t expectedFlags = 0) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_UP, expectedDisplayId, expectedFlags); } @@ -902,6 +898,11 @@ public: const std::string& getName() { return mName; } + void setOwnerInfo(int32_t ownerPid, int32_t ownerUid) { + mInfo.ownerPid = ownerPid; + mInfo.ownerUid = ownerUid; + } + private: const std::string mName; std::unique_ptr<FakeInputReceiver> mInputReceiver; @@ -1261,17 +1262,18 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { sp<FakeApplicationHandle> application = new FakeApplicationHandle(); // Create a couple of windows - sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, - "First Window", ADISPLAY_ID_DEFAULT); - sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, - "Second Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> firstWindow = + new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> secondWindow = + new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window - NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); + NotifyMotionArgs downMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&downMotionArgs); // Only the first window should get the down event firstWindow->consumeMotionDown(); @@ -1284,8 +1286,9 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { secondWindow->consumeMotionDown(); // Send up event to the second window - NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); + NotifyMotionArgs upMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets no events and the second gets up firstWindow->assertNoEvents(); @@ -1298,26 +1301,29 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { PointF touchPoint = {10, 10}; // Create a couple of windows - sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, - "First Window", ADISPLAY_ID_DEFAULT); - sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, - "Second Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> firstWindow = + new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> secondWindow = + new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window - NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint}); + NotifyMotionArgs downMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {touchPoint}); mDispatcher->notifyMotion(&downMotionArgs); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send pointer down to the first window - NotifyMotionArgs pointerDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN - | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); + NotifyMotionArgs pointerDownMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {touchPoint, touchPoint}); mDispatcher->notifyMotion(&pointerDownMotionArgs); // Only the first window should get the pointer down event firstWindow->consumeMotionPointerDown(1); @@ -1331,17 +1337,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window - NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP - | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); + NotifyMotionArgs pointerUpMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {touchPoint, touchPoint}); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window - NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); + NotifyMotionArgs upMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); @@ -1352,15 +1361,15 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { sp<FakeApplicationHandle> application = new FakeApplicationHandle(); // Create a non touch modal window that supports split touch - sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, - "First Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> firstWindow = + new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); firstWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | InputWindowInfo::FLAG_SPLIT_TOUCH); // Create a non touch modal window that supports split touch - sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, - "Second Window", ADISPLAY_ID_DEFAULT); + sp<FakeWindowHandle> secondWindow = + new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); secondWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | InputWindowInfo::FLAG_SPLIT_TOUCH); @@ -1372,17 +1381,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { PointF pointInSecond = {300, 600}; // Send down to the first window - NotifyMotionArgs firstDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst}); + NotifyMotionArgs firstDownMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {pointInFirst}); mDispatcher->notifyMotion(&firstDownMotionArgs); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send down to the second window - NotifyMotionArgs secondDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN - | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); + NotifyMotionArgs secondDownMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&secondDownMotionArgs); // The first window gets a move and the second a down firstWindow->consumeMotionMove(); @@ -1395,17 +1407,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window - NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP - | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); + NotifyMotionArgs pointerUpMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window - NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); + NotifyMotionArgs upMotionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); @@ -1722,6 +1737,72 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); } +/** + * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY, + * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top + * of the 'slipperyEnterWindow'. + * + * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such + * a way so that the touched location is no longer covered by the top window. + * + * Next, inject a MOVE event. Because the top window already moved earlier, this event is now + * positioned over the bottom (slipperyEnterWindow) only. And because the top window had + * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive + * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting + * with ACTION_DOWN). + * Thus, the touch has been transferred from the top window into the bottom window, because the top + * window moved itself away from the touched location and had Flag::SLIPPERY. + * + * Even though the top window moved away from the touched location, it is still obscuring the bottom + * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_ + * OBSCURED should be set for the MotionEvent that reaches the bottom window. + * + * In this test, we ensure that the event received by the bottom window has + * FLAG_WINDOW_IS_PARTIALLY_OBSCURED. + */ +TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { + constexpr int32_t SLIPPERY_PID = INJECTOR_PID + 1; + constexpr int32_t SLIPPERY_UID = INJECTOR_UID + 1; + + sp<FakeApplicationHandle> application = new FakeApplicationHandle(); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + + sp<FakeWindowHandle> slipperyExitWindow = + new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + slipperyExitWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | + InputWindowInfo::FLAG_SLIPPERY); + // Make sure this one overlaps the bottom window + slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); + // Change the owner uid/pid of the window so that it is considered to be occluding the bottom + // one. Windows with the same owner are not considered to be occluding each other. + slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID); + + sp<FakeWindowHandle> slipperyEnterWindow = + new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); + slipperyExitWindow->setFrame(Rect(0, 0, 100, 100)); + + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}}); + + // Use notifyMotion instead of injecting to avoid dealing with injection permissions + NotifyMotionArgs args = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {{50, 50}}); + mDispatcher->notifyMotion(&args); + slipperyExitWindow->consumeMotionDown(); + slipperyExitWindow->setFrame(Rect(70, 70, 100, 100)); + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}}); + + args = generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {{51, 51}}); + mDispatcher->notifyMotion(&args); + + slipperyExitWindow->consumeMotionCancel(); + + slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, + AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); +} + class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms @@ -1950,7 +2031,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // Test per-display input monitors for key event. TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) { - //Input monitor per display. + // Input monitor per display. FakeMonitorReceiver monitorInPrimary = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); FakeMonitorReceiver monitorInSecondary = @@ -1972,11 +2053,11 @@ protected: void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) { NotifyMotionArgs motionArgs; - motionArgs = generateMotionArgs( - AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); + motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); mDispatcher->notifyMotion(&motionArgs); - motionArgs = generateMotionArgs( - AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); + motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); mDispatcher->notifyMotion(&motionArgs); ASSERT_TRUE(mDispatcher->waitForIdle()); if (expectToBeFiltered) { |