diff options
Diffstat (limited to 'services/inputflinger/tests/InputDispatcher_test.cpp')
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 552 |
1 files changed, 452 insertions, 100 deletions
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 0f446532ca..eca6ebc1f5 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -29,9 +29,12 @@ #include <vector> using android::base::StringPrintf; +using android::gui::FocusRequest; +using android::gui::TouchOcclusionMode; +using android::gui::WindowInfo; +using android::gui::WindowInfoHandle; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; -using android::os::TouchOcclusionMode; using namespace android::flag_operators; namespace android::inputdispatcher { @@ -43,7 +46,8 @@ static const nsecs_t ARBITRARY_TIME = 1234; static const int32_t DEVICE_ID = 1; // An arbitrary display id. -static const int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; +static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; +static constexpr int32_t SECOND_DISPLAY_ID = 1; // An arbitrary injector pid / uid pair that has permission to inject events. static const int32_t INJECTOR_PID = 999; @@ -473,8 +477,8 @@ protected: } } - void setFocusedWindow(const sp<InputWindowHandle>& window, - const sp<InputWindowHandle>& focusedWindow = nullptr) { + void setFocusedWindow(const sp<WindowInfoHandle>& window, + const sp<WindowInfoHandle>& focusedWindow = nullptr) { FocusRequest request; request.token = window->getToken(); request.windowName = window->getName(); @@ -531,8 +535,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -545,9 +549,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, 0ms, 0)) @@ -558,9 +562,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, 0ms, 0)) @@ -572,9 +576,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, 0ms, 0)) @@ -585,9 +589,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, InputEventInjectionSync::NONE, 0ms, 0)) @@ -597,8 +601,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -608,8 +612,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -621,8 +625,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -633,8 +637,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -647,8 +651,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, @@ -899,7 +903,7 @@ protected: std::string mName; }; -class FakeWindowHandle : public InputWindowHandle { +class FakeWindowHandle : public WindowInfoHandle { public: static const int32_t WIDTH = 600; static const int32_t HEIGHT = 800; @@ -921,7 +925,7 @@ public: mInfo.token = *token; mInfo.id = sId++; mInfo.name = name; - mInfo.type = InputWindowInfo::Type::APPLICATION; + mInfo.type = WindowInfo::Type::APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.alpha = 1.0; mInfo.frameLeft = 0; @@ -941,7 +945,14 @@ public: mInfo.displayId = displayId; } - virtual bool updateInfo() { return true; } + sp<FakeWindowHandle> clone( + const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle, + const sp<InputDispatcher>& dispatcher, int32_t displayId) { + sp<FakeWindowHandle> handle = + new FakeWindowHandle(inputApplicationHandle, dispatcher, mInfo.name + "(Mirror)", + displayId, mInfo.token); + return handle; + } void setFocusable(bool focusable) { mInfo.focusable = focusable; } @@ -955,9 +966,7 @@ public: void setAlpha(float alpha) { mInfo.alpha = alpha; } - void setTouchOcclusionMode(android::os::TouchOcclusionMode mode) { - mInfo.touchOcclusionMode = mode; - } + void setTouchOcclusionMode(TouchOcclusionMode mode) { mInfo.touchOcclusionMode = mode; } void setApplicationToken(sp<IBinder> token) { mInfo.applicationInfo.token = token; } @@ -971,11 +980,11 @@ public: mInfo.addTouchableRegion(frame); } - void addFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags |= flags; } + void addFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags |= flags; } - void setFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags = flags; } + void setFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags = flags; } - void setInputFeatures(InputWindowInfo::Feature features) { mInfo.inputFeatures = features; } + void setInputFeatures(WindowInfo::Feature features) { mInfo.inputFeatures = features; } void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) { mInfo.transform.set(dsdx, dtdx, dtdy, dsdy); @@ -1109,7 +1118,7 @@ public: void assertNoEvents() { if (mInputReceiver == nullptr && - mInfo.inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL)) { + mInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { return; // Can't receive events if the window does not have input channel } ASSERT_NE(nullptr, mInputReceiver) @@ -1274,8 +1283,9 @@ public: mAction, mActionButton, mFlags, /* edgeFlags */ 0, AMETA_NONE, mButtonState, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition, - mRawYCursorPosition, mDisplayWidth, mDisplayHeight, mEventTime, mEventTime, - mPointers.size(), pointerProperties.data(), pointerCoords.data()); + mRawYCursorPosition, mDisplayOrientation, mDisplayWidth, mDisplayHeight, + mEventTime, mEventTime, mPointers.size(), pointerProperties.data(), + pointerCoords.data()); return event; } @@ -1290,8 +1300,9 @@ private: int32_t mFlags{0}; float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION}; - int32_t mDisplayWidth{AMOTION_EVENT_INVALID_DISPLAY_SIZE}; - int32_t mDisplayHeight{AMOTION_EVENT_INVALID_DISPLAY_SIZE}; + uint32_t mDisplayOrientation{ui::Transform::ROT_0}; + int32_t mDisplayWidth{INVALID_DISPLAY_SIZE}; + int32_t mDisplayHeight{INVALID_DISPLAY_SIZE}; std::vector<PointerBuilder> mPointers; }; @@ -1418,7 +1429,7 @@ TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1441,7 +1452,7 @@ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1477,11 +1488,11 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { sp<FakeWindowHandle> windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); sp<FakeWindowHandle> windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1588,7 +1599,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 1200, 800)); - window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1670,11 +1681,11 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { sp<FakeWindowHandle> windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); sp<FakeWindowHandle> windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1868,15 +1879,13 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::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); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -1942,15 +1951,13 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::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); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2007,6 +2014,134 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { secondWindow->assertNoEvents(); } +// This case will create two windows and one mirrored window on the default display and mirror +// two windows on the second display. It will test if 'transferTouchFocus' works fine if we put +// the windows info of second display before default display. +TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> firstWindowInPrimary = + new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); + firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); + firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + sp<FakeWindowHandle> secondWindowInPrimary = + new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); + secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); + secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> mirrorWindowInPrimary = + firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); + mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); + mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> firstWindowInSecondary = + firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); + firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); + firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> secondWindowInSecondary = + secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); + secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); + secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + // Update window info, let it find window handle of second display first. + mDispatcher->setInputWindows( + {{SECOND_DISPLAY_ID, {firstWindowInSecondary, secondWindowInSecondary}}, + {ADISPLAY_ID_DEFAULT, + {mirrorWindowInPrimary, firstWindowInPrimary, secondWindowInPrimary}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Window should receive motion event. + firstWindowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); + + // Transfer touch focus + ASSERT_TRUE(mDispatcher->transferTouchFocus(firstWindowInPrimary->getToken(), + secondWindowInPrimary->getToken())); + // The first window gets cancel. + firstWindowInPrimary->consumeMotionCancel(); + secondWindowInPrimary->consumeMotionDown(); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + firstWindowInPrimary->assertNoEvents(); + secondWindowInPrimary->consumeMotionMove(); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + firstWindowInPrimary->assertNoEvents(); + secondWindowInPrimary->consumeMotionUp(); +} + +// Same as TransferTouchFocus_CloneSurface, but this touch on the secondary display and use +// 'transferTouch' api. +TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> firstWindowInPrimary = + new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); + firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); + firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + sp<FakeWindowHandle> secondWindowInPrimary = + new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); + secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); + secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> mirrorWindowInPrimary = + firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); + mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); + mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> firstWindowInSecondary = + firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); + firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); + firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + sp<FakeWindowHandle> secondWindowInSecondary = + secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); + secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); + secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + + // Update window info, let it find window handle of second display first. + mDispatcher->setInputWindows( + {{SECOND_DISPLAY_ID, {firstWindowInSecondary, secondWindowInSecondary}}, + {ADISPLAY_ID_DEFAULT, + {mirrorWindowInPrimary, firstWindowInPrimary, secondWindowInPrimary}}}); + + // Touch on second display. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Window should receive motion event. + firstWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID); + + // Transfer touch focus + ASSERT_TRUE(mDispatcher->transferTouch(secondWindowInSecondary->getToken())); + + // The first window gets cancel. + firstWindowInPrimary->consumeMotionCancel(SECOND_DISPLAY_ID); + secondWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + SECOND_DISPLAY_ID, {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + firstWindowInPrimary->assertNoEvents(); + secondWindowInPrimary->consumeMotionMove(SECOND_DISPLAY_ID); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + firstWindowInPrimary->assertNoEvents(); + secondWindowInPrimary->consumeMotionUp(SECOND_DISPLAY_ID); +} + TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = @@ -2068,15 +2203,13 @@ TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Create second non touch modal window that supports split touch sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2171,6 +2304,18 @@ public: expectedDisplayId, expectedFlags); } + void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, + expectedDisplayId, expectedFlags); + } + + void consumeMotionPointerDown(int32_t pointerIdx) { + int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, ADISPLAY_ID_DEFAULT, + 0 /*expectedFlags*/); + } + MotionEvent* consumeMotion() { InputEvent* event = mInputReceiver->consume(); if (!event) { @@ -2317,6 +2462,91 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { 0 /*expectedFlags*/); } +TEST_F(InputDispatcherTest, GestureMonitor_SplitIfNoWindowTouched) { + FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + // Create a non touch modal window that supports split touch + sp<FakeWindowHandle> window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 100, 100)); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + // First finger down, no window touched. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); + + // Second finger down on window, the window should receive touch down. + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(200)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + monitor.consumeMotionPointerDown(1 /* pointerIndex */); +} + +TEST_F(InputDispatcherTest, GestureMonitor_NoSplitAfterPilfer) { + FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + // Create a non touch modal window that supports split touch + sp<FakeWindowHandle> window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 100, 100)); + window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + // First finger down, no window touched. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); + + // Gesture monitor pilfer the pointers. + mDispatcher->pilferPointers(monitor.getToken()); + + // Second finger down on window, the window should not receive touch down. + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(200)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->assertNoEvents(); + monitor.consumeMotionPointerDown(1 /* pointerIndex */); +} + /** * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to * the device default right away. In the test scenario, we check both the default value, @@ -2440,7 +2670,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); } -TEST_F(InputDispatcherTest, NonPointerMotionEvent_NotTransformed) { +TEST_F(InputDispatcherTest, NonPointerMotionEvent_JoystickAndTouchpadNotTransformed) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); @@ -2460,20 +2690,19 @@ TEST_F(InputDispatcherTest, NonPointerMotionEvent_NotTransformed) { // Second, we consume focus event if it is right or wrong according to onFocusChangedLocked. window->consumeFocusEvent(true); - constexpr const std::array nonPointerSources = {AINPUT_SOURCE_TRACKBALL, - AINPUT_SOURCE_MOUSE_RELATIVE, - AINPUT_SOURCE_JOYSTICK}; - for (const int source : nonPointerSources) { - // Notify motion with a non-pointer source. - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, source, ADISPLAY_ID_DEFAULT); + constexpr const std::array nonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD, + AMOTION_EVENT_ACTION_DOWN), + std::pair(AINPUT_SOURCE_JOYSTICK, + AMOTION_EVENT_ACTION_MOVE)}; + for (const auto& [source, action] : nonTransformedSources) { + const NotifyMotionArgs motionArgs = generateMotionArgs(action, source, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&motionArgs); MotionEvent* event = window->consumeMotion(); ASSERT_NE(event, nullptr); const MotionEvent& motionEvent = *event; - EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, motionEvent.getAction()); + EXPECT_EQ(action, motionEvent.getAction()); EXPECT_EQ(motionArgs.pointerCount, motionEvent.getPointerCount()); float expectedX = motionArgs.pointerCoords[0].getX(); @@ -2745,8 +2974,7 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { sp<FakeWindowHandle> slipperyExitWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - slipperyExitWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SLIPPERY); + slipperyExitWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::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 @@ -2921,7 +3149,6 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEvent /* Test InputDispatcher for MultiDisplay */ class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { public: - static constexpr int32_t SECOND_DISPLAY_ID = 1; virtual void SetUp() override { InputDispatcherTest::SetUp(); @@ -3084,8 +3311,6 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) class InputFilterTest : public InputDispatcherTest { protected: - static constexpr int32_t SECOND_DISPLAY_ID = 1; - void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) { NotifyMotionArgs motionArgs; @@ -3219,9 +3444,9 @@ protected: DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, - 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, - 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, eventTime, eventTime, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + 0 /*INVALID_DISPLAY_SIZE*/, 0 /*INVALID_DISPLAY_SIZE*/, eventTime, + eventTime, /*pointerCount*/ 1, pointerProperties, pointerCoords); const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER; @@ -3279,12 +3504,12 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. - mUnfocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mFocusedWindow = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -3393,14 +3618,12 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { ADISPLAY_ID_DEFAULT); // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window. // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows. - mWindow1->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + mWindow1->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); mWindow1->setFrame(Rect(0, 0, 100, 100)); mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2", ADISPLAY_ID_DEFAULT, mWindow1->getToken()); - mWindow2->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + mWindow2->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); mWindow2->setFrame(Rect(100, 100, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); @@ -3411,7 +3634,7 @@ protected: sp<FakeWindowHandle> mWindow2; // Helper function to convert the point from screen coordinates into the window's space - static PointF getPointInWindow(const InputWindowInfo* windowInfo, const PointF& point) { + static PointF getPointInWindow(const WindowInfo* windowInfo, const PointF& point) { vec2 vals = windowInfo->transform.transform(point.x, point.y); return {vals.x, vals.y}; } @@ -3599,7 +3822,7 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { mWindow->setFocusable(true); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. - mWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -4000,16 +4223,15 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped - mUnfocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH | - InputWindowInfo::Flag::SPLIT_TOUCH); + mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | + WindowInfo::Flag::WATCH_OUTSIDE_TOUCH | + WindowInfo::Flag::SPLIT_TOUCH); mFocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); mFocusedWindow->setDispatchingTimeout(30ms); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL | - InputWindowInfo::Flag::SPLIT_TOUCH); + mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -4377,7 +4599,7 @@ class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest { "Window without input channel", ADISPLAY_ID_DEFAULT, std::make_optional<sp<IBinder>>(nullptr) /*token*/); - mNoInputWindow->setInputFeatures(InputWindowInfo::Feature::NO_INPUT_CHANNEL); + mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); // It's perfectly valid for this window to not have an associated input channel @@ -4419,7 +4641,7 @@ TEST_F(InputDispatcherMultiWindowOcclusionTests, "Window with input channel and NO_INPUT_CHANNEL", ADISPLAY_ID_DEFAULT); - mNoInputWindow->setInputFeatures(InputWindowInfo::Feature::NO_INPUT_CHANNEL); + mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}}); @@ -4740,10 +4962,10 @@ protected: mTouchWindow.clear(); } - sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, - os::TouchOcclusionMode mode, float alpha = 1.0f) { + sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, TouchOcclusionMode mode, + float alpha = 1.0f) { sp<FakeWindowHandle> window = getWindow(uid, name); - window->setFlags(InputWindowInfo::Flag::NOT_TOUCHABLE); + window->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); window->setTouchOcclusionMode(mode); window->setAlpha(alpha); return window; @@ -4857,7 +5079,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) { const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); touch(); @@ -4868,7 +5090,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) { const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); touch(); @@ -5122,11 +5344,11 @@ protected: mApp = std::make_shared<FakeApplicationHandle>(); mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 100, 100)); - mWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFrame(Rect(100, 0, 200, 100)); - mSecondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL); + mSecondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); @@ -5334,4 +5556,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 |