Loading services/inputflinger/dispatcher/InputDispatcher.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -1032,6 +1032,21 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE } } } // If a new up event comes in, and the pending event with same key code has been asked // to try again later because of the policy. We have to reset the intercept key wake up // time for it may have been handled in the policy and could be dropped. if (keyEntry.action == AKEY_EVENT_ACTION_UP && mPendingEvent && mPendingEvent->type == EventEntry::Type::KEY) { KeyEntry& pendingKey = static_cast<KeyEntry&>(*mPendingEvent); if (pendingKey.keyCode == keyEntry.keyCode && pendingKey.interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) { pendingKey.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; pendingKey.interceptKeyWakeupTime = 0; needWake = true; } } break; } Loading services/inputflinger/tests/InputDispatcher_test.cpp +63 −2 Original line number Diff line number Diff line Loading @@ -289,6 +289,13 @@ public: ASSERT_EQ(token, *receivedToken); } /** * Set policy timeout. A value of zero means next key will not be intercepted. */ void setInterceptKeyTimeout(std::chrono::milliseconds timeout) { mInterceptKeyTimeout = timeout; } private: std::mutex mLock; std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock); Loading @@ -311,6 +318,8 @@ private: sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock); bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false; std::chrono::milliseconds mInterceptKeyTimeout = 0ms; // All three ANR-related callbacks behave the same way, so we use this generic function to wait // for a specific container to become non-empty. When the container is non-empty, return the // first entry from the container and erase it. Loading Loading @@ -429,12 +438,20 @@ private: return true; } void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {} void interceptKeyBeforeQueueing(const KeyEvent* inputEvent, uint32_t&) override { if (inputEvent->getAction() == AKEY_EVENT_ACTION_UP) { // Clear intercept state when we handled the event. mInterceptKeyTimeout = 0ms; } } void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {} nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent*, uint32_t) override { return 0; nsecs_t delay = std::chrono::nanoseconds(mInterceptKeyTimeout).count(); // Clear intercept state so we could dispatch the event in next wake. mInterceptKeyTimeout = 0ms; return delay; } bool dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent*, uint32_t, KeyEvent*) override { Loading Loading @@ -2182,6 +2199,50 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { 0 /*expectedFlags*/); } TEST_F(InputDispatcherTest, InterceptKeyByPolicy) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); setFocusedWindow(window); window->consumeFocusEvent(true); NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); const std::chrono::milliseconds interceptKeyTimeout = 50ms; const nsecs_t injectTime = keyArgs.eventTime; mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout); mDispatcher->notifyKey(&keyArgs); // The dispatching time should be always greater than or equal to intercept key timeout. window->consumeKeyDown(ADISPLAY_ID_DEFAULT); ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >= std::chrono::nanoseconds(interceptKeyTimeout).count()); } TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); setFocusedWindow(window); window->consumeFocusEvent(true); NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); mFakePolicy->setInterceptKeyTimeout(150ms); mDispatcher->notifyKey(&keyDown); mDispatcher->notifyKey(&keyUp); // Window should receive key event immediately when same key up. window->consumeKeyDown(ADISPLAY_ID_DEFAULT); window->consumeKeyUp(ADISPLAY_ID_DEFAULT); } /** * Ensure the correct coordinate spaces are used by InputDispatcher. * Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -1032,6 +1032,21 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE } } } // If a new up event comes in, and the pending event with same key code has been asked // to try again later because of the policy. We have to reset the intercept key wake up // time for it may have been handled in the policy and could be dropped. if (keyEntry.action == AKEY_EVENT_ACTION_UP && mPendingEvent && mPendingEvent->type == EventEntry::Type::KEY) { KeyEntry& pendingKey = static_cast<KeyEntry&>(*mPendingEvent); if (pendingKey.keyCode == keyEntry.keyCode && pendingKey.interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) { pendingKey.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; pendingKey.interceptKeyWakeupTime = 0; needWake = true; } } break; } Loading
services/inputflinger/tests/InputDispatcher_test.cpp +63 −2 Original line number Diff line number Diff line Loading @@ -289,6 +289,13 @@ public: ASSERT_EQ(token, *receivedToken); } /** * Set policy timeout. A value of zero means next key will not be intercepted. */ void setInterceptKeyTimeout(std::chrono::milliseconds timeout) { mInterceptKeyTimeout = timeout; } private: std::mutex mLock; std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock); Loading @@ -311,6 +318,8 @@ private: sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock); bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false; std::chrono::milliseconds mInterceptKeyTimeout = 0ms; // All three ANR-related callbacks behave the same way, so we use this generic function to wait // for a specific container to become non-empty. When the container is non-empty, return the // first entry from the container and erase it. Loading Loading @@ -429,12 +438,20 @@ private: return true; } void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {} void interceptKeyBeforeQueueing(const KeyEvent* inputEvent, uint32_t&) override { if (inputEvent->getAction() == AKEY_EVENT_ACTION_UP) { // Clear intercept state when we handled the event. mInterceptKeyTimeout = 0ms; } } void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {} nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent*, uint32_t) override { return 0; nsecs_t delay = std::chrono::nanoseconds(mInterceptKeyTimeout).count(); // Clear intercept state so we could dispatch the event in next wake. mInterceptKeyTimeout = 0ms; return delay; } bool dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent*, uint32_t, KeyEvent*) override { Loading Loading @@ -2182,6 +2199,50 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { 0 /*expectedFlags*/); } TEST_F(InputDispatcherTest, InterceptKeyByPolicy) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); setFocusedWindow(window); window->consumeFocusEvent(true); NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); const std::chrono::milliseconds interceptKeyTimeout = 50ms; const nsecs_t injectTime = keyArgs.eventTime; mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout); mDispatcher->notifyKey(&keyArgs); // The dispatching time should be always greater than or equal to intercept key timeout. window->consumeKeyDown(ADISPLAY_ID_DEFAULT); ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >= std::chrono::nanoseconds(interceptKeyTimeout).count()); } TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); setFocusedWindow(window); window->consumeFocusEvent(true); NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); mFakePolicy->setInterceptKeyTimeout(150ms); mDispatcher->notifyKey(&keyDown); mDispatcher->notifyKey(&keyUp); // Window should receive key event immediately when same key up. window->consumeKeyDown(ADISPLAY_ID_DEFAULT); window->consumeKeyUp(ADISPLAY_ID_DEFAULT); } /** * Ensure the correct coordinate spaces are used by InputDispatcher. * Loading