summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Arthur Hung <arthurhung@google.com> 2022-03-03 20:19:38 +0800
committer Arthur Hung <arthurhung@google.com> 2022-03-18 03:59:20 +0000
commit2ee6d0ba7d362ed956b5e10a6809059757bc0a41 (patch)
treeafdfd0c4dcf7916a2fe285101096c1d2a729e771
parent0af0bba332d95574f4ecc574efcf66d6cd65814a (diff)
Reset intercept key wake time when receving up event
The policy need to handle the key shortcuts via policy callbacks, and it may have a pending timeout in order to detect the combination keys. If the pending key event has already known an up event has been queued, we could reset the wake time to speed up the processing for it may be handled in policy or not. Bug: 220669913 Test: atest inputflinger_tests Change-Id: Ic002b770632e15506fd2f581fc8716b26ea3626c
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp15
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp65
2 files changed, 78 insertions, 2 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 06ad6a8f61..6bfac6cb5f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -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;
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 9633932e75..838e6aa785 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -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);
@@ -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.
@@ -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 {
@@ -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.
*