diff options
author | 2022-12-21 09:13:01 +0000 | |
---|---|---|
committer | 2022-12-21 09:13:01 +0000 | |
commit | 34dfbf0c36c74e732b2cb2402f7a55747e56ddeb (patch) | |
tree | 108a2c38acd153988e92254de86b76b435e3d3f6 | |
parent | ca473b2e3c69741d7fb72f618606fb3fdc71d25c (diff) | |
parent | c539dbb9812e30632ca2946ef6b1150127db0182 (diff) |
Merge "Fix wallpaper window multi-touch"
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 196 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.h | 20 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 198 |
3 files changed, 310 insertions, 104 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 4aac377b42..906bb1b0d9 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2060,6 +2060,12 @@ bool InputDispatcher::shouldSplitTouch(const TouchState& touchState, if (touchedWindow.windowHandle->getInfo()->supportsSplitTouch()) { continue; } + if (touchedWindow.windowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::IS_WALLPAPER)) { + // Wallpaper window should not affect whether or not touch is split + continue; + } + // Eventually, touchedWindow will contain the deviceId of each pointer that's currently // being sent there. For now, use deviceId from touch state. if (entry.deviceId == touchState.deviceId && !touchedWindow.pointerIds.isEmpty()) { @@ -2223,6 +2229,32 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked( tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds, entry.eventTime); + + // If this is the pointer going down and the touched window has a wallpaper + // then also add the touched wallpaper windows so they are locked in for the duration + // of the touch gesture. + // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper + // engine only supports touch events. We would need to add a mechanism similar + // to View.onGenericMotionEvent to enable wallpapers to handle these events. + if (maskedAction == AMOTION_EVENT_ACTION_DOWN || + maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { + if (targetFlags.test(InputTarget::Flags::FOREGROUND) && + windowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { + sp<WindowInfoHandle> wallpaper = findWallpaperWindowBelow(windowHandle); + if (wallpaper != nullptr) { + ftl::Flags<InputTarget::Flags> wallpaperFlags = + InputTarget::Flags::WINDOW_IS_OBSCURED | + InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED | + InputTarget::Flags::DISPATCH_AS_IS; + if (isSplit) { + wallpaperFlags |= InputTarget::Flags::SPLIT; + } + tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, pointerIds, + entry.eventTime); + } + } + } } // If any existing window is pilfering pointers from newly added window, remove it @@ -2307,6 +2339,10 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked( pointerIds.markBit(entry.pointerProperties[0].id); tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds, entry.eventTime); + + // Check if the wallpaper window should deliver the corresponding event. + slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, + tempTouchState, pointerIds); } } @@ -2413,38 +2449,6 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked( } } - // If this is the first pointer going down and the touched window has a wallpaper - // then also add the touched wallpaper windows so they are locked in for the duration - // of the touch gesture. - // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper - // engine only supports touch events. We would need to add a mechanism similar - // to View.onGenericMotionEvent to enable wallpapers to handle these events. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp<WindowInfoHandle> foregroundWindowHandle = - tempTouchState.getFirstForegroundWindowHandle(); - if (foregroundWindowHandle && - foregroundWindowHandle->getInfo()->inputConfig.test( - WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { - const std::vector<sp<WindowInfoHandle>>& windowHandles = - getWindowHandlesLocked(displayId); - for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { - const WindowInfo* info = windowHandle->getInfo(); - if (info->displayId == displayId && - windowHandle->getInfo()->inputConfig.test( - WindowInfo::InputConfig::IS_WALLPAPER)) { - BitSet32 pointerIds; - pointerIds.markBit(entry.pointerProperties[0].id); - tempTouchState.addOrUpdateWindow(windowHandle, - InputTarget::Flags::WINDOW_IS_OBSCURED | - InputTarget::Flags:: - WINDOW_IS_PARTIALLY_OBSCURED | - InputTarget::Flags::DISPATCH_AS_IS, - pointerIds, entry.eventTime); - } - } - } - } - // Success! Output targets. touchedWindows = tempTouchState.windows; outInjectionResult = InputEventInjectionResult::SUCCEEDED; @@ -3726,7 +3730,8 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( - const nsecs_t downTime, const sp<Connection>& connection) { + const nsecs_t downTime, const sp<Connection>& connection, + ftl::Flags<InputTarget::Flags> targetFlags) { if (connection->status == Connection::Status::BROKEN) { return; } @@ -3752,7 +3757,7 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( target.globalScaleFactor = windowInfo->globalScaleFactor; } target.inputChannel = connection->inputChannel; - target.flags = InputTarget::Flags::DISPATCH_AS_IS; + target.flags = targetFlags; const bool wasEmpty = connection->outboundQueue.empty(); for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) { @@ -3787,6 +3792,16 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( } } +void InputDispatcher::synthesizeCancelationEventsForWindowLocked( + const sp<WindowInfoHandle>& windowHandle, const CancelationOptions& options) { + if (windowHandle != nullptr) { + sp<Connection> wallpaperConnection = getConnectionLocked(windowHandle->getToken()); + if (wallpaperConnection != nullptr) { + synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, options); + } + } +} + std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( const MotionEntry& originalMotionEntry, BitSet32 pointerIds, nsecs_t splitDownTime) { ALOG_ASSERT(pointerIds.value != 0); @@ -4847,14 +4862,7 @@ void InputDispatcher::setInputWindowsLocked( touchedWindow.windowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow(); - if (wallpaper != nullptr) { - sp<Connection> wallpaperConnection = - getConnectionLocked(wallpaper->getToken()); - if (wallpaperConnection != nullptr) { - synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, - options); - } - } + synthesizeCancelationEventsForWindowLocked(wallpaper, options); } } state.windows.erase(state.windows.begin() + i); @@ -5155,6 +5163,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< // Erase old window. ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags; BitSet32 pointerIds = touchedWindow->pointerIds; + sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle; state->removeWindowByToken(fromToken); // Add new window. @@ -5187,7 +5196,12 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, "transferring touch focus from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); - synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection); + synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection, + newTargetFlags); + + // Check if the wallpaper window should deliver the corresponding event. + transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle, + *state, pointerIds); } } // release lock @@ -6465,4 +6479,100 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon mMonitorDispatchingTimeout = timeout; } +void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, + const sp<WindowInfoHandle>& oldWindowHandle, + const sp<WindowInfoHandle>& newWindowHandle, + TouchState& state, const BitSet32& pointerIds) { + const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); + const bool newHasWallpaper = targetFlags.test(InputTarget::Flags::FOREGROUND) && + newWindowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); + const sp<WindowInfoHandle> oldWallpaper = + oldHasWallpaper ? state.getWallpaperWindow() : nullptr; + const sp<WindowInfoHandle> newWallpaper = + newHasWallpaper ? findWallpaperWindowBelow(newWindowHandle) : nullptr; + if (oldWallpaper == newWallpaper) { + return; + } + + if (oldWallpaper != nullptr) { + state.addOrUpdateWindow(oldWallpaper, InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT, + BitSet32(0)); + } + + if (newWallpaper != nullptr) { + state.addOrUpdateWindow(newWallpaper, + InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER | + InputTarget::Flags::WINDOW_IS_OBSCURED | + InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED, + pointerIds); + } +} + +void InputDispatcher::transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags, + ftl::Flags<InputTarget::Flags> newTargetFlags, + const sp<WindowInfoHandle> fromWindowHandle, + const sp<WindowInfoHandle> toWindowHandle, + TouchState& state, const BitSet32& pointerIds) { + const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) && + fromWindowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); + const bool newHasWallpaper = newTargetFlags.test(InputTarget::Flags::FOREGROUND) && + toWindowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); + + const sp<WindowInfoHandle> oldWallpaper = + oldHasWallpaper ? state.getWallpaperWindow() : nullptr; + const sp<WindowInfoHandle> newWallpaper = + newHasWallpaper ? findWallpaperWindowBelow(toWindowHandle) : nullptr; + if (oldWallpaper == newWallpaper) { + return; + } + + if (oldWallpaper != nullptr) { + CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + "transferring touch focus to another window"); + state.removeWindowByToken(oldWallpaper->getToken()); + synthesizeCancelationEventsForWindowLocked(oldWallpaper, options); + } + + if (newWallpaper != nullptr) { + nsecs_t downTimeInTarget = now(); + ftl::Flags<InputTarget::Flags> wallpaperFlags = + oldTargetFlags & (InputTarget::Flags::SPLIT | InputTarget::Flags::DISPATCH_AS_IS); + wallpaperFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED | + InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; + state.addOrUpdateWindow(newWallpaper, wallpaperFlags, pointerIds, downTimeInTarget); + sp<Connection> wallpaperConnection = getConnectionLocked(newWallpaper->getToken()); + if (wallpaperConnection != nullptr) { + sp<Connection> toConnection = getConnectionLocked(toWindowHandle->getToken()); + toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState); + synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, wallpaperConnection, + wallpaperFlags); + } + } +} + +sp<WindowInfoHandle> InputDispatcher::findWallpaperWindowBelow( + const sp<WindowInfoHandle>& windowHandle) const { + const std::vector<sp<WindowInfoHandle>>& windowHandles = + getWindowHandlesLocked(windowHandle->getInfo()->displayId); + bool foundWindow = false; + for (const sp<WindowInfoHandle>& otherHandle : windowHandles) { + if (!foundWindow && otherHandle != windowHandle) { + continue; + } + if (windowHandle == otherHandle) { + foundWindow = true; + continue; + } + + if (otherHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::IS_WALLPAPER)) { + return otherHandle; + } + } + return nullptr; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 5efb39e0f2..a32ebd3757 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -628,9 +628,14 @@ private: REQUIRES(mLock); void synthesizePointerDownEventsForConnectionLocked(const nsecs_t downTime, - const sp<Connection>& connection) + const sp<Connection>& connection, + ftl::Flags<InputTarget::Flags> targetFlags) REQUIRES(mLock); + void synthesizeCancelationEventsForWindowLocked( + const sp<android::gui::WindowInfoHandle>& windowHandle, + const CancelationOptions& options) REQUIRES(mLock); + // Splitting motion events across windows. When splitting motion event for a target, // splitDownTime refers to the time of first 'down' event on that particular target std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry, @@ -691,6 +696,19 @@ private: bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock); sp<InputReporterInterface> mReporter; + + void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, + const sp<android::gui::WindowInfoHandle>& oldWindowHandle, + const sp<android::gui::WindowInfoHandle>& newWindowHandle, + TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock); + void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags, + ftl::Flags<InputTarget::Flags> newTargetFlags, + const sp<android::gui::WindowInfoHandle> fromWindowHandle, + const sp<android::gui::WindowInfoHandle> toWindowHandle, + TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock); + + sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow( + const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock); }; } // namespace android::inputdispatcher diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index d2ff097d18..864aaea76f 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -64,6 +64,8 @@ static constexpr int32_t POINTER_2_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_3_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr int32_t POINTER_0_UP = + AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_1_UP = AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); @@ -83,6 +85,9 @@ static constexpr int32_t MONITOR_PID = 2001; static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; +static constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + struct PointF { float x; float y; @@ -1738,8 +1743,6 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance sp<FakeWindowHandle> wallpaperWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1782,8 +1785,6 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { sp<FakeWindowHandle> wallpaperWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1813,24 +1814,27 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { foregroundWindow->consumeMotionCancel(); } +class ShouldSplitTouchFixture : public InputDispatcherTest, + public ::testing::WithParamInterface<bool> {}; +INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture, + ::testing::Values(true, false)); /** * A single window that receives touch (on top), and a wallpaper window underneath it. * The top window gets a multitouch gesture. * Ensure that wallpaper gets the same gesture. */ -TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { +TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - window->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> foregroundWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); + foregroundWindow->setDupTouchToWallpaper(true); + foregroundWindow->setPreventSplitting(GetParam()); sp<FakeWindowHandle> wallpaperWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); // Touch down on top window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1839,7 +1843,7 @@ TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Both top window and its wallpaper should receive the touch down - window->consumeMotionDown(); + foregroundWindow->consumeMotionDown(); wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Second finger down on the top window @@ -1858,11 +1862,34 @@ TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionPointerDown(1 /* pointerIndex */); + foregroundWindow->consumeMotionPointerDown(1 /* pointerIndex */); wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); - window->assertNoEvents(); - wallpaperWindow->assertNoEvents(); + + const MotionEvent secondFingerUpEvent = + MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(100)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + foregroundWindow->consumeMotionPointerUp(0); + wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 100})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); + wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); } /** @@ -1889,8 +1916,6 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setFrame(Rect(0, 0, 400, 200)); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; mDispatcher->setInputWindows( {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}}); @@ -1955,62 +1980,49 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { wallpaperWindow->assertNoEvents(); } -TEST_F(InputDispatcherTest, WallpaperWindowReceivesMultiTouch) { +/** + * Two windows: a window on the left with dup touch to wallpaper and window on the right without it. + * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL + * The right window should receive ACTION_DOWN. + */ +TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); - sp<FakeWindowHandle> window = - sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - window->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> leftWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 200, 200)); + leftWindow->setDupTouchToWallpaper(true); + leftWindow->setSlippery(true); + + sp<FakeWindowHandle> rightWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + rightWindow->setFrame(Rect(200, 0, 400, 200)); sp<FakeWindowHandle> wallpaperWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - constexpr int expectedWallpaperFlags = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; - wallpaperWindow->setPreventSplitting(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}}); + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}}); + // Touch down on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {50, 50})) + {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + + // Both foreground window and its wallpaper should receive the touch down + leftWindow->consumeMotionDown(); wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); - const MotionEvent secondFingerDownEvent = - MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .displayId(ADISPLAY_ID_DEFAULT) - .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) - .build(); + // Move to right window, the left window should receive cancel. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, - InputEventInjectionSync::WAIT_FOR_RESULT)) - << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - - window->consumeMotionPointerDown(1); - wallpaperWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); - - const MotionEvent secondFingerUpEvent = - MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) - .displayId(ADISPLAY_ID_DEFAULT) - .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) - .build(); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, - InputEventInjectionSync::WAIT_FOR_RESULT)) + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {201, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionPointerUp(1); - wallpaperWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) - << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionUp(ADISPLAY_ID_DEFAULT); - wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + leftWindow->consumeMotionCancel(); + rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); + wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); } /** @@ -2858,21 +2870,26 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { sp<FakeWindowHandle> firstWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + firstWindow->setDupTouchToWallpaper(true); sp<FakeWindowHandle> secondWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); - + sp<FakeWindowHandle> wallpaper = + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaper->setIsWallpaper(true); // Add the windows to the dispatcher - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow, wallpaper}}}); // Send down to the first window 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(); secondWindow->assertNoEvents(); + wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Transfer touch to the second window TransferFunction f = GetParam(); @@ -2881,6 +2898,7 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { // The first window gets cancel and the second gets down firstWindow->consumeMotionCancel(); secondWindow->consumeMotionDown(); + wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Send up event to the second window NotifyMotionArgs upMotionArgs = @@ -2890,6 +2908,7 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { // The first window gets no events and the second gets up firstWindow->assertNoEvents(); secondWindow->consumeMotionUp(); + wallpaper->assertNoEvents(); } /** @@ -3013,6 +3032,65 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { secondWindow->consumeMotionUp(); } +TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + + // Create a couple of windows + sp<FakeWindowHandle> firstWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "First Window", + ADISPLAY_ID_DEFAULT); + firstWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> secondWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window", + ADISPLAY_ID_DEFAULT); + secondWindow->setDupTouchToWallpaper(true); + + sp<FakeWindowHandle> wallpaper1 = + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT); + wallpaper1->setIsWallpaper(true); + + sp<FakeWindowHandle> wallpaper2 = + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT); + wallpaper2->setIsWallpaper(true); + // Add the windows to the dispatcher + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {firstWindow, wallpaper1, secondWindow, wallpaper2}}}); + + // Send down to the first window + 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(); + secondWindow->assertNoEvents(); + wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaper2->assertNoEvents(); + + // Transfer touch focus to the second window + TransferFunction f = GetParam(); + bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken()); + ASSERT_TRUE(success); + + // The first window gets cancel and the second gets down + firstWindow->consumeMotionCancel(); + secondWindow->consumeMotionDown(); + wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + // Send up event to the second window + 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(); + secondWindow->consumeMotionUp(); + wallpaper1->assertNoEvents(); + wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); +} + // For the cases of single pointer touch and two pointers non-split touch, the api's // 'transferTouch' and 'transferTouchFocus' are equivalent in behaviour. They only differ // for the case where there are multiple pointers split across several windows. |