Loading services/inputflinger/dispatcher/InputDispatcher.cpp +18 −18 Original line number Diff line number Diff line Loading @@ -121,11 +121,6 @@ constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2 // Log a warning when an interception call takes longer than this to process. constexpr std::chrono::milliseconds SLOW_INTERCEPTION_THRESHOLD = 50ms; // Additional key latency in case a connection is still processing some motion events. // This will help with the case when a user touched a button that opens a new window, // and gives us the chance to dispatch the key to this new window. constexpr std::chrono::nanoseconds KEY_WAITING_FOR_EVENTS_TIMEOUT = 500ms; // Number of recent events to keep for debugging purposes. constexpr size_t RECENT_QUEUE_MAX_SIZE = 10; Loading Loading @@ -1192,7 +1187,7 @@ bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) * Return true if the events preceding this incoming motion event should be dropped * Return false otherwise (the default behaviour) */ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) { bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) const { const bool isPointerDownEvent = motionEntry.action == AMOTION_EVENT_ACTION_DOWN && isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER); Loading Loading @@ -1234,16 +1229,6 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt } } // Prevent getting stuck: if we have a pending key event, and some motion events that have not // yet been processed by some connections, the dispatcher will wait for these motion // events to be processed before dispatching the key event. This is because these motion events // may cause a new window to be launched, which the user might expect to receive focus. // To prevent waiting forever for such events, just send the key to the currently focused window if (isPointerDownEvent && mKeyIsWaitingForEventsTimeout) { ALOGD("Received a new pointer down event, stop waiting for events to process and " "just send the pending key event to the focused window."); mKeyIsWaitingForEventsTimeout = now(); } return false; } Loading Loading @@ -1291,6 +1276,20 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE mNextUnblockedEvent = mInboundQueue.back(); needWake = true; } const bool isPointerDownEvent = motionEntry.action == AMOTION_EVENT_ACTION_DOWN && isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER); if (isPointerDownEvent && mKeyIsWaitingForEventsTimeout) { // Prevent waiting too long for unprocessed events: if we have a pending key event, // and some other events have not yet been processed, the dispatcher will wait for // these events to be processed before dispatching the key event. This is because // the unprocessed events may cause the focus to change (for example, by launching a // new window or tapping a different window). To prevent waiting too long, we force // the key to be sent to the currently focused window when a new tap comes in. ALOGD("Received a new pointer down event, stop waiting for events to process and " "just send the pending key event to the currently focused window."); mKeyIsWaitingForEventsTimeout = now(); } break; } case EventEntry::Type::FOCUS: { Loading Loading @@ -2137,7 +2136,8 @@ bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime, // Start the timer // Wait to send key because there are unprocessed events that may cause focus to change mKeyIsWaitingForEventsTimeout = currentTime + std::chrono::duration_cast<std::chrono::nanoseconds>(KEY_WAITING_FOR_EVENTS_TIMEOUT) std::chrono::duration_cast<std::chrono::nanoseconds>( mPolicy.getKeyWaitingForEventsTimeout()) .count(); return true; } Loading Loading @@ -4879,7 +4879,7 @@ std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const Inpu break; } default: { ALOGE("Cannot verify events of type %" PRId32, event.getType()); LOG(ERROR) << "Cannot verify events of type " << ftl::enum_string(event.getType()); return nullptr; } } Loading services/inputflinger/dispatcher/InputDispatcher.h +1 −1 Original line number Diff line number Diff line Loading @@ -470,7 +470,7 @@ private: bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry); bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock); bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) const REQUIRES(mLock); /** * Time to stop waiting for the events to be processed while trying to dispatch a key. Loading services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +19 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,18 @@ public: return std::chrono::nanoseconds(currentTime - eventTime) >= STALE_EVENT_TIMEOUT; } /** * Get the additional latency to add while waiting for other input events to process before * dispatching the pending key. * If there are unprocessed events, the pending key will not be dispatched immediately. Instead, * the dispatcher will wait for this timeout, to account for the possibility that the focus * might change due to touch or other events (such as another app getting launched by keys). * This would give the pending key the opportunity to go to a newly focused window instead. */ virtual std::chrono::nanoseconds getKeyWaitingForEventsTimeout() { return KEY_WAITING_FOR_EVENTS_TIMEOUT; } /* Notifies the policy that a pointer down event has occurred outside the current focused * window. * Loading @@ -150,6 +162,13 @@ public: /* Notifies the policy that there was an input device interaction with apps. */ virtual void notifyDeviceInteraction(DeviceId deviceId, nsecs_t timestamp, const std::set<gui::Uid>& uids) = 0; private: // Additional key latency in case a connection is still processing some motion events. // This will help with the case when a user touched a button that opens a new window, // and gives us the chance to dispatch the key to this new window. static constexpr std::chrono::nanoseconds KEY_WAITING_FOR_EVENTS_TIMEOUT = std::chrono::milliseconds(500); }; } // namespace android services/inputflinger/tests/InputDispatcher_test.cpp +38 −39 Original line number Diff line number Diff line Loading @@ -363,6 +363,8 @@ public: mInterceptKeyTimeout = timeout; } std::chrono::nanoseconds getKeyWaitingForEventsTimeout() override { return 500ms; } void setStaleEventTimeout(std::chrono::nanoseconds timeout) { mStaleEventTimeout = timeout; } void assertUserActivityNotPoked() { Loading Loading @@ -1083,8 +1085,8 @@ public: EXPECT_EQ(inTouchMode, touchModeEvent.isInTouchMode()); } void assertNoEvents() { std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); void assertNoEvents(std::chrono::milliseconds timeout) { std::unique_ptr<InputEvent> event = consume(timeout); if (event == nullptr) { return; } Loading Loading @@ -1412,14 +1414,14 @@ public: mInputReceiver->sendTimeline(inputEventId, timeline); } void assertNoEvents() { void assertNoEvents(std::chrono::milliseconds timeout = CONSUME_TIMEOUT_NO_EVENT_EXPECTED) { if (mInputReceiver == nullptr && mInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) { return; // Can't receive events if the window does not have input channel } ASSERT_NE(nullptr, mInputReceiver) << "Window without InputReceiver must specify feature NO_INPUT_CHANNEL"; mInputReceiver->assertNoEvents(); mInputReceiver->assertNoEvents(timeout); } sp<IBinder> getToken() { return mInfo.token; } Loading @@ -1437,13 +1439,6 @@ public: int getChannelFd() { return mInputReceiver->getChannelFd(); } private: FakeWindowHandle(std::string name) : mName(name){}; const std::string mName; std::shared_ptr<FakeInputReceiver> mInputReceiver; static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger friend class sp<FakeWindowHandle>; std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = true) { if (mInputReceiver == nullptr) { LOG(FATAL) << "Cannot consume event from a window with no input event receiver"; Loading @@ -1454,6 +1449,13 @@ private: } return event; } private: FakeWindowHandle(std::string name) : mName(name){}; const std::string mName; std::shared_ptr<FakeInputReceiver> mInputReceiver; static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger friend class sp<FakeWindowHandle>; }; std::atomic<int32_t> FakeWindowHandle::sId{1}; Loading Loading @@ -1512,7 +1514,7 @@ public: std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); } void assertNoEvents() { mInputReceiver.assertNoEvents(); } void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); } private: FakeInputReceiver mInputReceiver; Loading Loading @@ -8824,16 +8826,11 @@ TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { /** * If a window is processing a motion event, and then a key event comes in, the key event should * not get delivered to the focused window until the motion is processed. * * Warning!!! * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT * and the injection timeout that we specify when injecting the key. * We must have the injection timeout (100ms) be smaller than * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms). * * If that value changes, this test should also change. */ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { // The timeouts in this test are established by relying on the fact that the "key waiting for // events timeout" is equal to 500ms. ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms); mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); Loading @@ -8842,23 +8839,18 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { ASSERT_TRUE(downSequenceNum); const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent(); ASSERT_TRUE(upSequenceNum); // Don't finish the events yet, and send a key // Injection will "succeed" because we will eventually give up and send the key to the focused // window even if motions are still being processed. But because the injection timeout is short, // we will receive INJECTION_TIMED_OUT as the result. InputEventInjectionResult result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, InputEventInjectionSync::WAIT_FOR_RESULT, 100ms); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); // Don't finish the events yet, and send a key mDispatcher->notifyKey( KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD) .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) .build()); // Key will not be sent to the window, yet, because the window is still processing events // and the key remains pending, waiting for the touch events to be processed // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR. // Rely here on the fact that it uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood. static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); mWindow->assertNoEvents(); mWindow->assertNoEvents(100ms); std::this_thread::sleep_for(500ms); std::this_thread::sleep_for(400ms); // if we wait long enough though, dispatcher will give up, and still send the key // to the focused window, even though we have not yet finished the motion event mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); Loading @@ -8873,7 +8865,10 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { * focused window right away. */ TEST_F(InputDispatcherSingleWindowAnr, PendingKey_IsDroppedWhileMotionIsProcessedAndNewTouchComesIn) { PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) { // The timeouts in this test are established by relying on the fact that the "key waiting for // events timeout" is equal to 500ms. ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms); mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); Loading @@ -8888,15 +8883,19 @@ TEST_F(InputDispatcherSingleWindowAnr, .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) .build()); // At this point, key is still pending, and should not be sent to the application yet. // Make sure the `assertNoEvents` check doesn't take too long. It uses // CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood. static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); mWindow->assertNoEvents(); mWindow->assertNoEvents(100ms); // Now tap down again. It should cause the pending key to go to the focused window right away. tapOnWindow(); mWindow->consumeKeyEvent(WithKeyAction(AKEY_EVENT_ACTION_DOWN)); // it doesn't matter that we // haven't ack'd the other events yet. We can finish events in any order. // Now that we tapped, we should receive the key immediately. // Since there's still room for slowness, we use 200ms, which is much less than // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration. std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms); ASSERT_NE(nullptr, keyEvent); ASSERT_EQ(InputEventType::KEY, keyEvent->getType()); ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN)); // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any // order. mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +18 −18 Original line number Diff line number Diff line Loading @@ -121,11 +121,6 @@ constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2 // Log a warning when an interception call takes longer than this to process. constexpr std::chrono::milliseconds SLOW_INTERCEPTION_THRESHOLD = 50ms; // Additional key latency in case a connection is still processing some motion events. // This will help with the case when a user touched a button that opens a new window, // and gives us the chance to dispatch the key to this new window. constexpr std::chrono::nanoseconds KEY_WAITING_FOR_EVENTS_TIMEOUT = 500ms; // Number of recent events to keep for debugging purposes. constexpr size_t RECENT_QUEUE_MAX_SIZE = 10; Loading Loading @@ -1192,7 +1187,7 @@ bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) * Return true if the events preceding this incoming motion event should be dropped * Return false otherwise (the default behaviour) */ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) { bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) const { const bool isPointerDownEvent = motionEntry.action == AMOTION_EVENT_ACTION_DOWN && isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER); Loading Loading @@ -1234,16 +1229,6 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt } } // Prevent getting stuck: if we have a pending key event, and some motion events that have not // yet been processed by some connections, the dispatcher will wait for these motion // events to be processed before dispatching the key event. This is because these motion events // may cause a new window to be launched, which the user might expect to receive focus. // To prevent waiting forever for such events, just send the key to the currently focused window if (isPointerDownEvent && mKeyIsWaitingForEventsTimeout) { ALOGD("Received a new pointer down event, stop waiting for events to process and " "just send the pending key event to the focused window."); mKeyIsWaitingForEventsTimeout = now(); } return false; } Loading Loading @@ -1291,6 +1276,20 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE mNextUnblockedEvent = mInboundQueue.back(); needWake = true; } const bool isPointerDownEvent = motionEntry.action == AMOTION_EVENT_ACTION_DOWN && isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER); if (isPointerDownEvent && mKeyIsWaitingForEventsTimeout) { // Prevent waiting too long for unprocessed events: if we have a pending key event, // and some other events have not yet been processed, the dispatcher will wait for // these events to be processed before dispatching the key event. This is because // the unprocessed events may cause the focus to change (for example, by launching a // new window or tapping a different window). To prevent waiting too long, we force // the key to be sent to the currently focused window when a new tap comes in. ALOGD("Received a new pointer down event, stop waiting for events to process and " "just send the pending key event to the currently focused window."); mKeyIsWaitingForEventsTimeout = now(); } break; } case EventEntry::Type::FOCUS: { Loading Loading @@ -2137,7 +2136,8 @@ bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime, // Start the timer // Wait to send key because there are unprocessed events that may cause focus to change mKeyIsWaitingForEventsTimeout = currentTime + std::chrono::duration_cast<std::chrono::nanoseconds>(KEY_WAITING_FOR_EVENTS_TIMEOUT) std::chrono::duration_cast<std::chrono::nanoseconds>( mPolicy.getKeyWaitingForEventsTimeout()) .count(); return true; } Loading Loading @@ -4879,7 +4879,7 @@ std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const Inpu break; } default: { ALOGE("Cannot verify events of type %" PRId32, event.getType()); LOG(ERROR) << "Cannot verify events of type " << ftl::enum_string(event.getType()); return nullptr; } } Loading
services/inputflinger/dispatcher/InputDispatcher.h +1 −1 Original line number Diff line number Diff line Loading @@ -470,7 +470,7 @@ private: bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry); bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock); bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) const REQUIRES(mLock); /** * Time to stop waiting for the events to be processed while trying to dispatch a key. Loading
services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +19 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,18 @@ public: return std::chrono::nanoseconds(currentTime - eventTime) >= STALE_EVENT_TIMEOUT; } /** * Get the additional latency to add while waiting for other input events to process before * dispatching the pending key. * If there are unprocessed events, the pending key will not be dispatched immediately. Instead, * the dispatcher will wait for this timeout, to account for the possibility that the focus * might change due to touch or other events (such as another app getting launched by keys). * This would give the pending key the opportunity to go to a newly focused window instead. */ virtual std::chrono::nanoseconds getKeyWaitingForEventsTimeout() { return KEY_WAITING_FOR_EVENTS_TIMEOUT; } /* Notifies the policy that a pointer down event has occurred outside the current focused * window. * Loading @@ -150,6 +162,13 @@ public: /* Notifies the policy that there was an input device interaction with apps. */ virtual void notifyDeviceInteraction(DeviceId deviceId, nsecs_t timestamp, const std::set<gui::Uid>& uids) = 0; private: // Additional key latency in case a connection is still processing some motion events. // This will help with the case when a user touched a button that opens a new window, // and gives us the chance to dispatch the key to this new window. static constexpr std::chrono::nanoseconds KEY_WAITING_FOR_EVENTS_TIMEOUT = std::chrono::milliseconds(500); }; } // namespace android
services/inputflinger/tests/InputDispatcher_test.cpp +38 −39 Original line number Diff line number Diff line Loading @@ -363,6 +363,8 @@ public: mInterceptKeyTimeout = timeout; } std::chrono::nanoseconds getKeyWaitingForEventsTimeout() override { return 500ms; } void setStaleEventTimeout(std::chrono::nanoseconds timeout) { mStaleEventTimeout = timeout; } void assertUserActivityNotPoked() { Loading Loading @@ -1083,8 +1085,8 @@ public: EXPECT_EQ(inTouchMode, touchModeEvent.isInTouchMode()); } void assertNoEvents() { std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); void assertNoEvents(std::chrono::milliseconds timeout) { std::unique_ptr<InputEvent> event = consume(timeout); if (event == nullptr) { return; } Loading Loading @@ -1412,14 +1414,14 @@ public: mInputReceiver->sendTimeline(inputEventId, timeline); } void assertNoEvents() { void assertNoEvents(std::chrono::milliseconds timeout = CONSUME_TIMEOUT_NO_EVENT_EXPECTED) { if (mInputReceiver == nullptr && mInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) { return; // Can't receive events if the window does not have input channel } ASSERT_NE(nullptr, mInputReceiver) << "Window without InputReceiver must specify feature NO_INPUT_CHANNEL"; mInputReceiver->assertNoEvents(); mInputReceiver->assertNoEvents(timeout); } sp<IBinder> getToken() { return mInfo.token; } Loading @@ -1437,13 +1439,6 @@ public: int getChannelFd() { return mInputReceiver->getChannelFd(); } private: FakeWindowHandle(std::string name) : mName(name){}; const std::string mName; std::shared_ptr<FakeInputReceiver> mInputReceiver; static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger friend class sp<FakeWindowHandle>; std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = true) { if (mInputReceiver == nullptr) { LOG(FATAL) << "Cannot consume event from a window with no input event receiver"; Loading @@ -1454,6 +1449,13 @@ private: } return event; } private: FakeWindowHandle(std::string name) : mName(name){}; const std::string mName; std::shared_ptr<FakeInputReceiver> mInputReceiver; static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger friend class sp<FakeWindowHandle>; }; std::atomic<int32_t> FakeWindowHandle::sId{1}; Loading Loading @@ -1512,7 +1514,7 @@ public: std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); } void assertNoEvents() { mInputReceiver.assertNoEvents(); } void assertNoEvents() { mInputReceiver.assertNoEvents(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); } private: FakeInputReceiver mInputReceiver; Loading Loading @@ -8824,16 +8826,11 @@ TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { /** * If a window is processing a motion event, and then a key event comes in, the key event should * not get delivered to the focused window until the motion is processed. * * Warning!!! * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT * and the injection timeout that we specify when injecting the key. * We must have the injection timeout (100ms) be smaller than * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms). * * If that value changes, this test should also change. */ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { // The timeouts in this test are established by relying on the fact that the "key waiting for // events timeout" is equal to 500ms. ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms); mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); Loading @@ -8842,23 +8839,18 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { ASSERT_TRUE(downSequenceNum); const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent(); ASSERT_TRUE(upSequenceNum); // Don't finish the events yet, and send a key // Injection will "succeed" because we will eventually give up and send the key to the focused // window even if motions are still being processed. But because the injection timeout is short, // we will receive INJECTION_TIMED_OUT as the result. InputEventInjectionResult result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, InputEventInjectionSync::WAIT_FOR_RESULT, 100ms); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); // Don't finish the events yet, and send a key mDispatcher->notifyKey( KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD) .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) .build()); // Key will not be sent to the window, yet, because the window is still processing events // and the key remains pending, waiting for the touch events to be processed // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR. // Rely here on the fact that it uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood. static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); mWindow->assertNoEvents(); mWindow->assertNoEvents(100ms); std::this_thread::sleep_for(500ms); std::this_thread::sleep_for(400ms); // if we wait long enough though, dispatcher will give up, and still send the key // to the focused window, even though we have not yet finished the motion event mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); Loading @@ -8873,7 +8865,10 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { * focused window right away. */ TEST_F(InputDispatcherSingleWindowAnr, PendingKey_IsDroppedWhileMotionIsProcessedAndNewTouchComesIn) { PendingKey_IsDeliveredWhileMotionIsProcessingAndNewTouchComesIn) { // The timeouts in this test are established by relying on the fact that the "key waiting for // events timeout" is equal to 500ms. ASSERT_EQ(mFakePolicy->getKeyWaitingForEventsTimeout(), 500ms); mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); Loading @@ -8888,15 +8883,19 @@ TEST_F(InputDispatcherSingleWindowAnr, .policyFlags(DEFAULT_POLICY_FLAGS | POLICY_FLAG_DISABLE_KEY_REPEAT) .build()); // At this point, key is still pending, and should not be sent to the application yet. // Make sure the `assertNoEvents` check doesn't take too long. It uses // CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood. static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); mWindow->assertNoEvents(); mWindow->assertNoEvents(100ms); // Now tap down again. It should cause the pending key to go to the focused window right away. tapOnWindow(); mWindow->consumeKeyEvent(WithKeyAction(AKEY_EVENT_ACTION_DOWN)); // it doesn't matter that we // haven't ack'd the other events yet. We can finish events in any order. // Now that we tapped, we should receive the key immediately. // Since there's still room for slowness, we use 200ms, which is much less than // the "key waiting for events' timeout of 500ms minus the already waited 100ms duration. std::unique_ptr<InputEvent> keyEvent = mWindow->consume(200ms); ASSERT_NE(nullptr, keyEvent); ASSERT_EQ(InputEventType::KEY, keyEvent->getType()); ASSERT_THAT(static_cast<KeyEvent&>(*keyEvent), WithKeyAction(AKEY_EVENT_ACTION_DOWN)); // it doesn't matter that we haven't ack'd the other events yet. We can finish events in any // order. mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP mWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); Loading