Loading services/inputflinger/dispatcher/InputDispatcher.cpp +2 −0 Original line number Original line Diff line number Diff line Loading @@ -1782,6 +1782,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } } BitSet32 pointerIds; BitSet32 pointerIds; Loading services/inputflinger/tests/InputDispatcher_test.cpp +143 −62 Original line number Original line Diff line number Diff line Loading @@ -19,10 +19,10 @@ #include <android-base/stringprintf.h> #include <android-base/stringprintf.h> #include <android-base/thread_annotations.h> #include <android-base/thread_annotations.h> #include <binder/Binder.h> #include <binder/Binder.h> #include <input/Input.h> #include <gtest/gtest.h> #include <gtest/gtest.h> #include <input/Input.h> #include <linux/input.h> #include <linux/input.h> #include <cinttypes> #include <cinttypes> #include <thread> #include <thread> #include <unordered_set> #include <unordered_set> Loading Loading @@ -68,12 +68,10 @@ class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { InputDispatcherConfiguration mConfig; InputDispatcherConfiguration mConfig; protected: protected: virtual ~FakeInputDispatcherPolicy() { virtual ~FakeInputDispatcherPolicy() {} } public: public: FakeInputDispatcherPolicy() { FakeInputDispatcherPolicy() {} } void assertFilterInputEventWasCalled(const NotifyKeyArgs& args) { void assertFilterInputEventWasCalled(const NotifyKeyArgs& args) { assertFilterInputEventWasCalled(AINPUT_EVENT_TYPE_KEY, args.eventTime, args.action, assertFilterInputEventWasCalled(AINPUT_EVENT_TYPE_KEY, args.eventTime, args.action, Loading Loading @@ -391,7 +389,6 @@ protected: } } }; }; TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { KeyEvent event; KeyEvent event; Loading Loading @@ -589,9 +586,7 @@ public: } } virtual ~FakeApplicationHandle() {} virtual ~FakeApplicationHandle() {} virtual bool updateInfo() override { virtual bool updateInfo() override { return true; } return true; } void setDispatchingTimeout(std::chrono::nanoseconds timeout) { void setDispatchingTimeout(std::chrono::nanoseconds timeout) { mInfo.dispatchingTimeout = timeout.count(); mInfo.dispatchingTimeout = timeout.count(); Loading Loading @@ -840,16 +835,17 @@ public: } } void consumeMotionPointerDown(int32_t pointerIdx, void consumeMotionPointerDown(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN int32_t expectedFlags = 0) { | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); } } void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { int32_t expectedFlags = 0) { int32_t action = AMOTION_EVENT_ACTION_POINTER_UP int32_t action = AMOTION_EVENT_ACTION_POINTER_UP | | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); } } Loading Loading @@ -902,6 +898,11 @@ public: const std::string& getName() { return mName; } const std::string& getName() { return mName; } void setOwnerInfo(int32_t ownerPid, int32_t ownerUid) { mInfo.ownerPid = ownerPid; mInfo.ownerUid = ownerUid; } private: private: const std::string mName; const std::string mName; std::unique_ptr<FakeInputReceiver> mInputReceiver; std::unique_ptr<FakeInputReceiver> mInputReceiver; Loading Loading @@ -1261,17 +1262,18 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { sp<FakeApplicationHandle> application = new FakeApplicationHandle(); sp<FakeApplicationHandle> application = new FakeApplicationHandle(); // Create a couple of windows // Create a couple of windows sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> firstWindow = "First Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> secondWindow = "Second Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window // Send down to the first window NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, NotifyMotionArgs downMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&downMotionArgs); mDispatcher->notifyMotion(&downMotionArgs); // Only the first window should get the down event // Only the first window should get the down event firstWindow->consumeMotionDown(); firstWindow->consumeMotionDown(); Loading @@ -1284,8 +1286,9 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { secondWindow->consumeMotionDown(); secondWindow->consumeMotionDown(); // Send up event to the second window // Send up event to the second window NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, NotifyMotionArgs upMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets no events and the second gets up // The first window gets no events and the second gets up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); Loading @@ -1298,26 +1301,29 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { PointF touchPoint = {10, 10}; PointF touchPoint = {10, 10}; // Create a couple of windows // Create a couple of windows sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> firstWindow = "First Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> secondWindow = "Second Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window // Send down to the first window NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, NotifyMotionArgs downMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint}); generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint}); mDispatcher->notifyMotion(&downMotionArgs); mDispatcher->notifyMotion(&downMotionArgs); // Only the first window should get the down event // Only the first window should get the down event firstWindow->consumeMotionDown(); firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); secondWindow->assertNoEvents(); // Send pointer down to the first window // Send pointer down to the first window NotifyMotionArgs pointerDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN NotifyMotionArgs pointerDownMotionArgs = | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); mDispatcher->notifyMotion(&pointerDownMotionArgs); mDispatcher->notifyMotion(&pointerDownMotionArgs); // Only the first window should get the pointer down event // Only the first window should get the pointer down event firstWindow->consumeMotionPointerDown(1); firstWindow->consumeMotionPointerDown(1); Loading @@ -1331,17 +1337,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { secondWindow->consumeMotionPointerDown(1); secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window // Send pointer up to the second window NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP NotifyMotionArgs pointerUpMotionArgs = | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); mDispatcher->notifyMotion(&pointerUpMotionArgs); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets nothing and the second gets pointer up // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window // Send up event to the second window NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, NotifyMotionArgs upMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); Loading @@ -1352,15 +1361,15 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { sp<FakeApplicationHandle> application = new FakeApplicationHandle(); sp<FakeApplicationHandle> application = new FakeApplicationHandle(); // Create a non touch modal window that supports split touch // Create a non touch modal window that supports split touch sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> firstWindow = "First Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); firstWindow->setFrame(Rect(0, 0, 600, 400)); firstWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL firstWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | InputWindowInfo::FLAG_SPLIT_TOUCH); | InputWindowInfo::FLAG_SPLIT_TOUCH); // Create a non touch modal window that supports split touch // Create a non touch modal window that supports split touch sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> secondWindow = "Second Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); secondWindow->setFrame(Rect(0, 400, 600, 800)); secondWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL secondWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | InputWindowInfo::FLAG_SPLIT_TOUCH); | InputWindowInfo::FLAG_SPLIT_TOUCH); Loading @@ -1372,17 +1381,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { PointF pointInSecond = {300, 600}; PointF pointInSecond = {300, 600}; // Send down to the first window // Send down to the first window NotifyMotionArgs firstDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, NotifyMotionArgs firstDownMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst}); generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst}); mDispatcher->notifyMotion(&firstDownMotionArgs); mDispatcher->notifyMotion(&firstDownMotionArgs); // Only the first window should get the down event // Only the first window should get the down event firstWindow->consumeMotionDown(); firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); secondWindow->assertNoEvents(); // Send down to the second window // Send down to the second window NotifyMotionArgs secondDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN NotifyMotionArgs secondDownMotionArgs = | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&secondDownMotionArgs); mDispatcher->notifyMotion(&secondDownMotionArgs); // The first window gets a move and the second a down // The first window gets a move and the second a down firstWindow->consumeMotionMove(); firstWindow->consumeMotionMove(); Loading @@ -1395,17 +1407,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { secondWindow->consumeMotionPointerDown(1); secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window // Send pointer up to the second window NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP NotifyMotionArgs pointerUpMotionArgs = | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&pointerUpMotionArgs); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets nothing and the second gets pointer up // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window // Send up event to the second window NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, NotifyMotionArgs upMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); Loading Loading @@ -1722,6 +1737,72 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); 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 { class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: protected: static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms Loading Loading @@ -1972,11 +2053,11 @@ protected: void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) { void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) { NotifyMotionArgs motionArgs; NotifyMotionArgs motionArgs; motionArgs = generateMotionArgs( motionArgs = AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); mDispatcher->notifyMotion(&motionArgs); mDispatcher->notifyMotion(&motionArgs); motionArgs = generateMotionArgs( motionArgs = AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); mDispatcher->notifyMotion(&motionArgs); mDispatcher->notifyMotion(&motionArgs); ASSERT_TRUE(mDispatcher->waitForIdle()); ASSERT_TRUE(mDispatcher->waitForIdle()); if (expectToBeFiltered) { if (expectToBeFiltered) { Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +2 −0 Original line number Original line Diff line number Diff line Loading @@ -1782,6 +1782,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } } BitSet32 pointerIds; BitSet32 pointerIds; Loading
services/inputflinger/tests/InputDispatcher_test.cpp +143 −62 Original line number Original line Diff line number Diff line Loading @@ -19,10 +19,10 @@ #include <android-base/stringprintf.h> #include <android-base/stringprintf.h> #include <android-base/thread_annotations.h> #include <android-base/thread_annotations.h> #include <binder/Binder.h> #include <binder/Binder.h> #include <input/Input.h> #include <gtest/gtest.h> #include <gtest/gtest.h> #include <input/Input.h> #include <linux/input.h> #include <linux/input.h> #include <cinttypes> #include <cinttypes> #include <thread> #include <thread> #include <unordered_set> #include <unordered_set> Loading Loading @@ -68,12 +68,10 @@ class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { InputDispatcherConfiguration mConfig; InputDispatcherConfiguration mConfig; protected: protected: virtual ~FakeInputDispatcherPolicy() { virtual ~FakeInputDispatcherPolicy() {} } public: public: FakeInputDispatcherPolicy() { FakeInputDispatcherPolicy() {} } void assertFilterInputEventWasCalled(const NotifyKeyArgs& args) { void assertFilterInputEventWasCalled(const NotifyKeyArgs& args) { assertFilterInputEventWasCalled(AINPUT_EVENT_TYPE_KEY, args.eventTime, args.action, assertFilterInputEventWasCalled(AINPUT_EVENT_TYPE_KEY, args.eventTime, args.action, Loading Loading @@ -391,7 +389,6 @@ protected: } } }; }; TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { KeyEvent event; KeyEvent event; Loading Loading @@ -589,9 +586,7 @@ public: } } virtual ~FakeApplicationHandle() {} virtual ~FakeApplicationHandle() {} virtual bool updateInfo() override { virtual bool updateInfo() override { return true; } return true; } void setDispatchingTimeout(std::chrono::nanoseconds timeout) { void setDispatchingTimeout(std::chrono::nanoseconds timeout) { mInfo.dispatchingTimeout = timeout.count(); mInfo.dispatchingTimeout = timeout.count(); Loading Loading @@ -840,16 +835,17 @@ public: } } void consumeMotionPointerDown(int32_t pointerIdx, void consumeMotionPointerDown(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN int32_t expectedFlags = 0) { | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); } } void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { int32_t expectedFlags = 0) { int32_t action = AMOTION_EVENT_ACTION_POINTER_UP int32_t action = AMOTION_EVENT_ACTION_POINTER_UP | | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags); } } Loading Loading @@ -902,6 +898,11 @@ public: const std::string& getName() { return mName; } const std::string& getName() { return mName; } void setOwnerInfo(int32_t ownerPid, int32_t ownerUid) { mInfo.ownerPid = ownerPid; mInfo.ownerUid = ownerUid; } private: private: const std::string mName; const std::string mName; std::unique_ptr<FakeInputReceiver> mInputReceiver; std::unique_ptr<FakeInputReceiver> mInputReceiver; Loading Loading @@ -1261,17 +1262,18 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { sp<FakeApplicationHandle> application = new FakeApplicationHandle(); sp<FakeApplicationHandle> application = new FakeApplicationHandle(); // Create a couple of windows // Create a couple of windows sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> firstWindow = "First Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> secondWindow = "Second Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window // Send down to the first window NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, NotifyMotionArgs downMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&downMotionArgs); mDispatcher->notifyMotion(&downMotionArgs); // Only the first window should get the down event // Only the first window should get the down event firstWindow->consumeMotionDown(); firstWindow->consumeMotionDown(); Loading @@ -1284,8 +1286,9 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { secondWindow->consumeMotionDown(); secondWindow->consumeMotionDown(); // Send up event to the second window // Send up event to the second window NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, NotifyMotionArgs upMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets no events and the second gets up // The first window gets no events and the second gets up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); Loading @@ -1298,26 +1301,29 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { PointF touchPoint = {10, 10}; PointF touchPoint = {10, 10}; // Create a couple of windows // Create a couple of windows sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> firstWindow = "First Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> secondWindow = "Second Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window // Send down to the first window NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, NotifyMotionArgs downMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint}); generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint}); mDispatcher->notifyMotion(&downMotionArgs); mDispatcher->notifyMotion(&downMotionArgs); // Only the first window should get the down event // Only the first window should get the down event firstWindow->consumeMotionDown(); firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); secondWindow->assertNoEvents(); // Send pointer down to the first window // Send pointer down to the first window NotifyMotionArgs pointerDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN NotifyMotionArgs pointerDownMotionArgs = | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); mDispatcher->notifyMotion(&pointerDownMotionArgs); mDispatcher->notifyMotion(&pointerDownMotionArgs); // Only the first window should get the pointer down event // Only the first window should get the pointer down event firstWindow->consumeMotionPointerDown(1); firstWindow->consumeMotionPointerDown(1); Loading @@ -1331,17 +1337,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { secondWindow->consumeMotionPointerDown(1); secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window // Send pointer up to the second window NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP NotifyMotionArgs pointerUpMotionArgs = | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint}); mDispatcher->notifyMotion(&pointerUpMotionArgs); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets nothing and the second gets pointer up // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window // Send up event to the second window NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, NotifyMotionArgs upMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); Loading @@ -1352,15 +1361,15 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { sp<FakeApplicationHandle> application = new FakeApplicationHandle(); sp<FakeApplicationHandle> application = new FakeApplicationHandle(); // Create a non touch modal window that supports split touch // Create a non touch modal window that supports split touch sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> firstWindow = "First Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); firstWindow->setFrame(Rect(0, 0, 600, 400)); firstWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL firstWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | InputWindowInfo::FLAG_SPLIT_TOUCH); | InputWindowInfo::FLAG_SPLIT_TOUCH); // Create a non touch modal window that supports split touch // Create a non touch modal window that supports split touch sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, sp<FakeWindowHandle> secondWindow = "Second Window", ADISPLAY_ID_DEFAULT); new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); secondWindow->setFrame(Rect(0, 400, 600, 800)); secondWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL secondWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | InputWindowInfo::FLAG_SPLIT_TOUCH); | InputWindowInfo::FLAG_SPLIT_TOUCH); Loading @@ -1372,17 +1381,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { PointF pointInSecond = {300, 600}; PointF pointInSecond = {300, 600}; // Send down to the first window // Send down to the first window NotifyMotionArgs firstDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, NotifyMotionArgs firstDownMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst}); generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst}); mDispatcher->notifyMotion(&firstDownMotionArgs); mDispatcher->notifyMotion(&firstDownMotionArgs); // Only the first window should get the down event // Only the first window should get the down event firstWindow->consumeMotionDown(); firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); secondWindow->assertNoEvents(); // Send down to the second window // Send down to the second window NotifyMotionArgs secondDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN NotifyMotionArgs secondDownMotionArgs = | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&secondDownMotionArgs); mDispatcher->notifyMotion(&secondDownMotionArgs); // The first window gets a move and the second a down // The first window gets a move and the second a down firstWindow->consumeMotionMove(); firstWindow->consumeMotionMove(); Loading @@ -1395,17 +1407,20 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { secondWindow->consumeMotionPointerDown(1); secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window // Send pointer up to the second window NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP NotifyMotionArgs pointerUpMotionArgs = | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&pointerUpMotionArgs); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets nothing and the second gets pointer up // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window // Send up event to the second window NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, NotifyMotionArgs upMotionArgs = AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); firstWindow->assertNoEvents(); Loading Loading @@ -1722,6 +1737,72 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); 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 { class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: protected: static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms Loading Loading @@ -1972,11 +2053,11 @@ protected: void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) { void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) { NotifyMotionArgs motionArgs; NotifyMotionArgs motionArgs; motionArgs = generateMotionArgs( motionArgs = AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); mDispatcher->notifyMotion(&motionArgs); mDispatcher->notifyMotion(&motionArgs); motionArgs = generateMotionArgs( motionArgs = AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); mDispatcher->notifyMotion(&motionArgs); mDispatcher->notifyMotion(&motionArgs); ASSERT_TRUE(mDispatcher->waitForIdle()); ASSERT_TRUE(mDispatcher->waitForIdle()); if (expectToBeFiltered) { if (expectToBeFiltered) { Loading