Loading services/inputflinger/dispatcher/InputDispatcher.cpp +34 −0 Original line number Diff line number Diff line Loading @@ -4747,6 +4747,40 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< return true; } // Binder call bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken) { sp<IBinder> fromToken; { // acquire lock std::scoped_lock _l(mLock); sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(destChannelToken); if (toWindowHandle == nullptr) { ALOGW("Could not find window associated with token=%p", destChannelToken.get()); return false; } const int32_t displayId = toWindowHandle->getInfo()->displayId; auto touchStateIt = mTouchStatesByDisplay.find(displayId); if (touchStateIt == mTouchStatesByDisplay.end()) { ALOGD("Could not transfer touch because the display %" PRId32 " is not being touched", displayId); return false; } TouchState& state = touchStateIt->second; if (state.windows.size() != 1) { ALOGW("Cannot transfer touch state because there are %zu windows being touched", state.windows.size()); return false; } const TouchedWindow& touchedWindow = state.windows[0]; fromToken = touchedWindow.windowHandle->getToken(); } // release lock return transferTouchFocus(fromToken, destChannelToken); } void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { if (DEBUG_FOCUS) { ALOGD("Resetting and dropping all events (%s).", reason); Loading services/inputflinger/dispatcher/InputDispatcher.h +42 −42 Original line number Diff line number Diff line Loading @@ -81,60 +81,60 @@ class Connection; */ class InputDispatcher : public android::InputDispatcherInterface { protected: virtual ~InputDispatcher(); ~InputDispatcher() override; public: explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); virtual void dump(std::string& dump) override; virtual void monitor() override; virtual bool waitForIdle() override; virtual status_t start() override; virtual status_t stop() override; virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; virtual void notifyKey(const NotifyKeyArgs* args) override; virtual void notifyMotion(const NotifyMotionArgs* args) override; virtual void notifySwitch(const NotifySwitchArgs* args) override; virtual void notifySensor(const NotifySensorArgs* args) override; virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override; virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; virtual android::os::InputEventInjectionResult injectInputEvent( void dump(std::string& dump) override; void monitor() override; bool waitForIdle() override; status_t start() override; status_t stop() override; void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; void notifyKey(const NotifyKeyArgs* args) override; void notifyMotion(const NotifyMotionArgs* args) override; void notifySwitch(const NotifySwitchArgs* args) override; void notifySensor(const NotifySensorArgs* args) override; void notifyVibratorState(const NotifyVibratorStateArgs* args) override; void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; android::os::InputEventInjectionResult injectInputEvent( const InputEvent* event, int32_t injectorPid, int32_t injectorUid, android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) override; virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override; std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override; virtual void setInputWindows( const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& void setInputWindows(const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& handlesPerDisplay) override; virtual void setFocusedApplication( void setFocusedApplication( int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) override; virtual void setFocusedDisplay(int32_t displayId) override; virtual void setInputDispatchMode(bool enabled, bool frozen) override; virtual void setInputFilterEnabled(bool enabled) override; virtual void setInTouchMode(bool inTouchMode) override; virtual void setMaximumObscuringOpacityForTouch(float opacity) override; virtual void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override; virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, void setFocusedDisplay(int32_t displayId) override; void setInputDispatchMode(bool enabled, bool frozen) override; void setInputFilterEnabled(bool enabled) override; void setInTouchMode(bool inTouchMode) override; void setMaximumObscuringOpacityForTouch(float opacity) override; void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override; bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, bool isDragDrop = false) override; bool transferTouch(const sp<IBinder>& destChannelToken) override; virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel( base::Result<std::unique_ptr<InputChannel>> createInputChannel( const std::string& name) override; virtual void setFocusedWindow(const FocusRequest&) override; virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId, void setFocusedWindow(const FocusRequest&) override; base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId, bool isGestureMonitor, const std::string& name, int32_t pid) override; virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override; virtual status_t pilferPointers(const sp<IBinder>& token) override; virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override; virtual bool flushSensor(int deviceId, InputDeviceSensorType sensorType) override; status_t removeInputChannel(const sp<IBinder>& connectionToken) override; status_t pilferPointers(const sp<IBinder>& token) override; void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override; bool flushSensor(int deviceId, InputDeviceSensorType sensorType) override; std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const; Loading services/inputflinger/dispatcher/include/InputDispatcherInterface.h +8 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,14 @@ public: */ virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, bool isDragDrop) = 0; /** * Transfer touch focus to the provided channel, no matter where the current touch is. * * Return true on success, false if there was no on-going touch. */ virtual bool transferTouch(const sp<IBinder>& destChannelToken) = 0; /** * Sets focus on the specified window. */ Loading services/inputflinger/tests/InputDispatcher_test.cpp +106 −5 Original line number Diff line number Diff line Loading @@ -1714,7 +1714,13 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { 0 /*expectedFlags*/); } TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { using TransferFunction = std::function<bool(sp<InputDispatcher> dispatcher, sp<IBinder>, sp<IBinder>)>; class TransferTouchFixture : public InputDispatcherTest, public ::testing::WithParamInterface<TransferFunction> {}; TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); // Create a couple of windows Loading @@ -1735,8 +1741,10 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Transfer touch focus to the second window mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken()); // Transfer touch to the second window TransferFunction f = GetParam(); const 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(); Loading @@ -1751,7 +1759,7 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { secondWindow->consumeMotionUp(); } TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); PointF touchPoint = {10, 10}; Loading Loading @@ -1786,7 +1794,9 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { secondWindow->assertNoEvents(); // Transfer touch focus to the second window mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken()); TransferFunction f = GetParam(); bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken()); ASSERT_TRUE(success); // The first window gets cancel and the second gets down and pointer down firstWindow->consumeMotionCancel(); secondWindow->consumeMotionDown(); Loading @@ -1813,6 +1823,21 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { secondWindow->consumeMotionUp(); } // 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. INSTANTIATE_TEST_SUITE_P(TransferFunctionTests, TransferTouchFixture, ::testing::Values( [&](sp<InputDispatcher> dispatcher, sp<IBinder> /*ignored*/, sp<IBinder> destChannelToken) { return dispatcher->transferTouch(destChannelToken); }, [&](sp<InputDispatcher> dispatcher, sp<IBinder> from, sp<IBinder> to) { return dispatcher->transferTouchFocus(from, to, false /*isDragAndDrop*/); })); TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); Loading Loading @@ -1883,6 +1908,82 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { secondWindow->consumeMotionUp(); } // Same as TransferTouchFocus_TwoPointersSplitTouch, but using 'transferTouch' api. // Unlike 'transferTouchFocus', calling 'transferTouch' when there are two windows receiving // touch is not supported, so the touch should continue on those windows and the transferred-to // window should get nothing. TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); // Create a non touch modal window that supports split touch 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); // 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); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); PointF pointInFirst = {300, 200}; PointF pointInSecond = {300, 600}; // Send down to the first window NotifyMotionArgs firstDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst}); mDispatcher->notifyMotion(&firstDownMotionArgs); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send down to the second window NotifyMotionArgs secondDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&secondDownMotionArgs); // The first window gets a move and the second a down firstWindow->consumeMotionMove(); secondWindow->consumeMotionDown(); // Transfer touch focus to the second window const bool transferred = mDispatcher->transferTouch(secondWindow->getToken()); // The 'transferTouch' call should not succeed, because there are 2 touched windows ASSERT_FALSE(transferred); firstWindow->assertNoEvents(); secondWindow->assertNoEvents(); // The rest of the dispatch should proceed as normal // Send pointer up to the second window NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets MOVE and the second gets pointer up firstWindow->consumeMotionMove(); secondWindow->consumeMotionUp(); // Send up event to the first window NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up firstWindow->consumeMotionUp(); secondWindow->assertNoEvents(); } TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +34 −0 Original line number Diff line number Diff line Loading @@ -4747,6 +4747,40 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< return true; } // Binder call bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken) { sp<IBinder> fromToken; { // acquire lock std::scoped_lock _l(mLock); sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(destChannelToken); if (toWindowHandle == nullptr) { ALOGW("Could not find window associated with token=%p", destChannelToken.get()); return false; } const int32_t displayId = toWindowHandle->getInfo()->displayId; auto touchStateIt = mTouchStatesByDisplay.find(displayId); if (touchStateIt == mTouchStatesByDisplay.end()) { ALOGD("Could not transfer touch because the display %" PRId32 " is not being touched", displayId); return false; } TouchState& state = touchStateIt->second; if (state.windows.size() != 1) { ALOGW("Cannot transfer touch state because there are %zu windows being touched", state.windows.size()); return false; } const TouchedWindow& touchedWindow = state.windows[0]; fromToken = touchedWindow.windowHandle->getToken(); } // release lock return transferTouchFocus(fromToken, destChannelToken); } void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { if (DEBUG_FOCUS) { ALOGD("Resetting and dropping all events (%s).", reason); Loading
services/inputflinger/dispatcher/InputDispatcher.h +42 −42 Original line number Diff line number Diff line Loading @@ -81,60 +81,60 @@ class Connection; */ class InputDispatcher : public android::InputDispatcherInterface { protected: virtual ~InputDispatcher(); ~InputDispatcher() override; public: explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); virtual void dump(std::string& dump) override; virtual void monitor() override; virtual bool waitForIdle() override; virtual status_t start() override; virtual status_t stop() override; virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; virtual void notifyKey(const NotifyKeyArgs* args) override; virtual void notifyMotion(const NotifyMotionArgs* args) override; virtual void notifySwitch(const NotifySwitchArgs* args) override; virtual void notifySensor(const NotifySensorArgs* args) override; virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override; virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; virtual android::os::InputEventInjectionResult injectInputEvent( void dump(std::string& dump) override; void monitor() override; bool waitForIdle() override; status_t start() override; status_t stop() override; void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; void notifyKey(const NotifyKeyArgs* args) override; void notifyMotion(const NotifyMotionArgs* args) override; void notifySwitch(const NotifySwitchArgs* args) override; void notifySensor(const NotifySensorArgs* args) override; void notifyVibratorState(const NotifyVibratorStateArgs* args) override; void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; android::os::InputEventInjectionResult injectInputEvent( const InputEvent* event, int32_t injectorPid, int32_t injectorUid, android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) override; virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override; std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override; virtual void setInputWindows( const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& void setInputWindows(const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& handlesPerDisplay) override; virtual void setFocusedApplication( void setFocusedApplication( int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) override; virtual void setFocusedDisplay(int32_t displayId) override; virtual void setInputDispatchMode(bool enabled, bool frozen) override; virtual void setInputFilterEnabled(bool enabled) override; virtual void setInTouchMode(bool inTouchMode) override; virtual void setMaximumObscuringOpacityForTouch(float opacity) override; virtual void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override; virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, void setFocusedDisplay(int32_t displayId) override; void setInputDispatchMode(bool enabled, bool frozen) override; void setInputFilterEnabled(bool enabled) override; void setInTouchMode(bool inTouchMode) override; void setMaximumObscuringOpacityForTouch(float opacity) override; void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override; bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, bool isDragDrop = false) override; bool transferTouch(const sp<IBinder>& destChannelToken) override; virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel( base::Result<std::unique_ptr<InputChannel>> createInputChannel( const std::string& name) override; virtual void setFocusedWindow(const FocusRequest&) override; virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId, void setFocusedWindow(const FocusRequest&) override; base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId, bool isGestureMonitor, const std::string& name, int32_t pid) override; virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override; virtual status_t pilferPointers(const sp<IBinder>& token) override; virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override; virtual bool flushSensor(int deviceId, InputDeviceSensorType sensorType) override; status_t removeInputChannel(const sp<IBinder>& connectionToken) override; status_t pilferPointers(const sp<IBinder>& token) override; void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override; bool flushSensor(int deviceId, InputDeviceSensorType sensorType) override; std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const; Loading
services/inputflinger/dispatcher/include/InputDispatcherInterface.h +8 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,14 @@ public: */ virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, bool isDragDrop) = 0; /** * Transfer touch focus to the provided channel, no matter where the current touch is. * * Return true on success, false if there was no on-going touch. */ virtual bool transferTouch(const sp<IBinder>& destChannelToken) = 0; /** * Sets focus on the specified window. */ Loading
services/inputflinger/tests/InputDispatcher_test.cpp +106 −5 Original line number Diff line number Diff line Loading @@ -1714,7 +1714,13 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { 0 /*expectedFlags*/); } TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { using TransferFunction = std::function<bool(sp<InputDispatcher> dispatcher, sp<IBinder>, sp<IBinder>)>; class TransferTouchFixture : public InputDispatcherTest, public ::testing::WithParamInterface<TransferFunction> {}; TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); // Create a couple of windows Loading @@ -1735,8 +1741,10 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Transfer touch focus to the second window mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken()); // Transfer touch to the second window TransferFunction f = GetParam(); const 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(); Loading @@ -1751,7 +1759,7 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { secondWindow->consumeMotionUp(); } TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); PointF touchPoint = {10, 10}; Loading Loading @@ -1786,7 +1794,9 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { secondWindow->assertNoEvents(); // Transfer touch focus to the second window mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken()); TransferFunction f = GetParam(); bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken()); ASSERT_TRUE(success); // The first window gets cancel and the second gets down and pointer down firstWindow->consumeMotionCancel(); secondWindow->consumeMotionDown(); Loading @@ -1813,6 +1823,21 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { secondWindow->consumeMotionUp(); } // 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. INSTANTIATE_TEST_SUITE_P(TransferFunctionTests, TransferTouchFixture, ::testing::Values( [&](sp<InputDispatcher> dispatcher, sp<IBinder> /*ignored*/, sp<IBinder> destChannelToken) { return dispatcher->transferTouch(destChannelToken); }, [&](sp<InputDispatcher> dispatcher, sp<IBinder> from, sp<IBinder> to) { return dispatcher->transferTouchFocus(from, to, false /*isDragAndDrop*/); })); TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); Loading Loading @@ -1883,6 +1908,82 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { secondWindow->consumeMotionUp(); } // Same as TransferTouchFocus_TwoPointersSplitTouch, but using 'transferTouch' api. // Unlike 'transferTouchFocus', calling 'transferTouch' when there are two windows receiving // touch is not supported, so the touch should continue on those windows and the transferred-to // window should get nothing. TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); // Create a non touch modal window that supports split touch 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); // 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); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); PointF pointInFirst = {300, 200}; PointF pointInSecond = {300, 600}; // Send down to the first window NotifyMotionArgs firstDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst}); mDispatcher->notifyMotion(&firstDownMotionArgs); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send down to the second window NotifyMotionArgs secondDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&secondDownMotionArgs); // The first window gets a move and the second a down firstWindow->consumeMotionMove(); secondWindow->consumeMotionDown(); // Transfer touch focus to the second window const bool transferred = mDispatcher->transferTouch(secondWindow->getToken()); // The 'transferTouch' call should not succeed, because there are 2 touched windows ASSERT_FALSE(transferred); firstWindow->assertNoEvents(); secondWindow->assertNoEvents(); // The rest of the dispatch should proceed as normal // Send pointer up to the second window NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); mDispatcher->notifyMotion(&pointerUpMotionArgs); // The first window gets MOVE and the second gets pointer up firstWindow->consumeMotionMove(); secondWindow->consumeMotionUp(); // Send up event to the first window NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(&upMotionArgs); // The first window gets nothing and the second gets up firstWindow->consumeMotionUp(); secondWindow->assertNoEvents(); } TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = Loading