Merge "Request focus using setFocusedWindow"
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 20b83af..6ff4a3d 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -493,6 +493,14 @@
return changes;
}
+bool InputWindowCommands::empty() const {
+ bool empty = true;
+#ifndef NO_INPUT
+ empty = focusRequests.empty() && !syncInputWindows;
+#endif
+ return empty;
+}
+
void InputWindowCommands::clear() {
#ifndef NO_INPUT
focusRequests.clear();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 4c7d365..6d1f399 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1365,11 +1365,13 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow(
- const sp<IBinder>& token, const sp<IBinder>& focusedToken, nsecs_t timestampNanos) {
+ const sp<IBinder>& token, const sp<IBinder>& focusedToken, nsecs_t timestampNanos,
+ int32_t displayId) {
FocusRequest request;
request.token = token;
request.focusedToken = focusedToken;
request.timestamp = timestampNanos;
+ request.displayId = displayId;
return setFocusedWindow(request);
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 42ab458..a763d1d 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -311,6 +311,7 @@
// Merges the passed in commands and returns true if there were any changes.
bool merge(const InputWindowCommands& other);
+ bool empty() const;
void clear();
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index dc1d936..6cac287 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -508,7 +508,7 @@
#ifndef NO_INPUT
Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
Transaction& setFocusedWindow(const sp<IBinder>& token, const sp<IBinder>& focusedToken,
- nsecs_t timestampNanos);
+ nsecs_t timestampNanos, int32_t displayId);
Transaction& setFocusedWindow(const FocusRequest& request);
Transaction& syncInputWindows();
#endif
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 287a6f4..9674e24 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -47,8 +47,7 @@
using android::os::IInputFlinger;
-namespace android {
-namespace test {
+namespace android::test {
using Transaction = SurfaceComposerClient::Transaction;
@@ -176,6 +175,13 @@
t.apply(true);
}
+ void requestFocus() {
+ SurfaceComposerClient::Transaction t;
+ t.setFocusedWindow(mInputInfo.token, nullptr, systemTime(SYSTEM_TIME_MONOTONIC),
+ 0 /* displayId */);
+ t.apply(true);
+ }
+
private:
void waitForEventAvailable() {
struct pollfd fd;
@@ -281,7 +287,6 @@
TEST_F(InputSurfacesTest, can_receive_input) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(100, 100);
- surface->assertFocusChange(true);
injectTap(101, 101);
@@ -297,12 +302,9 @@
TEST_F(InputSurfacesTest, input_respects_positioning) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(100, 100);
- surface->assertFocusChange(true);
std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
surface2->showAt(200, 200);
- surface->assertFocusChange(false);
- surface2->assertFocusChange(true);
injectTap(201, 201);
surface2->expectTap(1, 1);
@@ -329,16 +331,11 @@
std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
surface->showAt(10, 10);
- surface->assertFocusChange(true);
surface2->showAt(10, 10);
- surface->assertFocusChange(false);
- surface2->assertFocusChange(true);
surface->doTransaction([](auto &t, auto &sc) {
t.setLayer(sc, LAYER_BASE + 1);
});
- surface2->assertFocusChange(false);
- surface->assertFocusChange(true);
injectTap(11, 11);
surface->expectTap(1, 1);
@@ -346,8 +343,6 @@
surface2->doTransaction([](auto &t, auto &sc) {
t.setLayer(sc, LAYER_BASE + 1);
});
- surface2->assertFocusChange(true);
- surface->assertFocusChange(false);
injectTap(11, 11);
surface2->expectTap(1, 1);
@@ -355,8 +350,6 @@
surface2->doTransaction([](auto &t, auto &sc) {
t.hide(sc);
});
- surface2->assertFocusChange(false);
- surface->assertFocusChange(true);
injectTap(11, 11);
surface->expectTap(1, 1);
@@ -369,12 +362,9 @@
std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
bgSurface->showAt(100, 100);
- bgSurface->assertFocusChange(true);
fgSurface->mInputInfo.surfaceInset = 5;
fgSurface->showAt(100, 100);
- fgSurface->assertFocusChange(true);
- bgSurface->assertFocusChange(false);
injectTap(106, 106);
fgSurface->expectTap(1, 1);
@@ -388,12 +378,9 @@
std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100);
parentSurface->showAt(100, 100);
- parentSurface->assertFocusChange(true);
childSurface->mInputInfo.surfaceInset = 10;
childSurface->showAt(100, 100);
- childSurface->assertFocusChange(true);
- parentSurface->assertFocusChange(false);
childSurface->doTransaction([&](auto &t, auto &sc) {
t.setPosition(sc, -5, -5);
@@ -412,12 +399,9 @@
std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
bgSurface->showAt(100, 100);
- bgSurface->assertFocusChange(true);
fgSurface->mInputInfo.surfaceInset = 5;
fgSurface->showAt(100, 100);
- bgSurface->assertFocusChange(false);
- fgSurface->assertFocusChange(true);
fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 4.0); });
@@ -434,7 +418,6 @@
// In case we pass the very big inset without any checking.
fgSurface->mInputInfo.surfaceInset = INT32_MAX;
fgSurface->showAt(100, 100);
- fgSurface->assertFocusChange(true);
fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
@@ -451,7 +434,6 @@
t.setTransparentRegionHint(sc, transparentRegion);
});
surface->showAt(100, 100);
- surface->assertFocusChange(true);
injectTap(101, 101);
surface->expectTap(1, 1);
}
@@ -466,10 +448,7 @@
InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
bgSurface->showAt(10, 10);
- bgSurface->assertFocusChange(true);
bufferSurface->showAt(10, 10);
- bgSurface->assertFocusChange(false);
- bufferSurface->assertFocusChange(true);
injectTap(11, 11);
bufferSurface->expectTap(1, 1);
@@ -486,10 +465,7 @@
postBuffer(bufferSurface->mSurfaceControl);
bgSurface->showAt(10, 10);
- bgSurface->assertFocusChange(true);
bufferSurface->showAt(10, 10);
- bufferSurface->assertFocusChange(true);
- bgSurface->assertFocusChange(false);
injectTap(11, 11);
bufferSurface->expectTap(1, 1);
@@ -505,10 +481,7 @@
std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
bgSurface->showAt(10, 10);
- bgSurface->assertFocusChange(true);
fgSurface->showAt(10, 10);
- bgSurface->assertFocusChange(false);
- fgSurface->assertFocusChange(true);
injectTap(11, 11);
fgSurface->expectTap(1, 1);
@@ -525,17 +498,12 @@
InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
bgSurface->showAt(10, 10);
- bgSurface->assertFocusChange(true);
containerSurface->showAt(10, 10);
- bgSurface->assertFocusChange(false);
- containerSurface->assertFocusChange(true);
injectTap(11, 11);
containerSurface->expectTap(1, 1);
containerSurface->doTransaction([](auto &t, auto &sc) { t.hide(sc); });
- containerSurface->assertFocusChange(false);
- bgSurface->assertFocusChange(true);
injectTap(11, 11);
bgSurface->expectTap(1, 1);
@@ -544,7 +512,6 @@
TEST_F(InputSurfacesTest, input_respects_outscreen) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(-1, -1);
- surface->assertFocusChange(true);
injectTap(0, 0);
surface->expectTap(1, 1);
@@ -556,11 +523,17 @@
InputSurface::makeCursorInputSurface(mComposerClient, 10, 10);
surface->showAt(10, 10);
- surface->assertFocusChange(true);
cursorSurface->showAt(10, 10);
injectTap(11, 11);
surface->expectTap(1, 1);
}
+
+TEST_F(InputSurfacesTest, can_be_focused) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(100, 100);
+ surface->requestFocus();
+
+ surface->assertFocusChange(true);
}
-}
+} // namespace android::test
diff --git a/libs/input/android/FocusRequest.aidl b/libs/input/android/FocusRequest.aidl
index a5034a4..303dd1c 100644
--- a/libs/input/android/FocusRequest.aidl
+++ b/libs/input/android/FocusRequest.aidl
@@ -36,4 +36,8 @@
* from another source such as pointer down.
*/
long timestamp;
+ /**
+ * Display id associated with this request.
+ */
+ int displayId;
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index b428c4e..7b7249a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -252,6 +252,15 @@
return removed;
}
+/**
+ * Find the entry in std::unordered_map by key and return the value as an optional.
+ */
+template <typename K, typename V>
+static std::optional<V> getOptionalValueByKey(const std::unordered_map<K, V>& map, K key) {
+ auto it = map.find(key);
+ return it != map.end() ? std::optional<V>{it->second} : std::nullopt;
+}
+
static bool haveSameToken(const sp<InputWindowHandle>& first, const sp<InputWindowHandle>& second) {
if (first == second) {
return true;
@@ -342,6 +351,19 @@
}
}
+const char* InputDispatcher::typeToString(InputDispatcher::FocusResult result) {
+ switch (result) {
+ case InputDispatcher::FocusResult::OK:
+ return "Ok";
+ case InputDispatcher::FocusResult::NO_WINDOW:
+ return "Window not found";
+ case InputDispatcher::FocusResult::NOT_FOCUSABLE:
+ return "Window not focusable";
+ case InputDispatcher::FocusResult::NOT_VISIBLE:
+ return "Window not visible";
+ }
+}
+
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -3792,26 +3814,31 @@
updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId);
- sp<IBinder> newFocusedToken = nullptr;
- bool foundHoveredWindow = false;
- for (const sp<InputWindowHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
- // Set newFocusedToken to the top most focused window instead of the last one
- if (!newFocusedToken && windowHandle->getInfo()->focusable &&
- windowHandle->getInfo()->visible) {
- newFocusedToken = windowHandle->getToken();
- }
- if (windowHandle == mLastHoverWindowHandle) {
- foundHoveredWindow = true;
- }
- }
-
- if (!foundHoveredWindow) {
+ const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
+ if (mLastHoverWindowHandle &&
+ std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) ==
+ windowHandles.end()) {
mLastHoverWindowHandle = nullptr;
}
- sp<IBinder> oldFocusedToken = getValueByKey(mFocusedWindowTokenByDisplay, displayId);
- if (oldFocusedToken != newFocusedToken) {
- onFocusChangedLocked(oldFocusedToken, newFocusedToken, displayId, "setInputWindowsLocked");
+ sp<IBinder> focusedToken = getValueByKey(mFocusedWindowTokenByDisplay, displayId);
+ if (focusedToken) {
+ FocusResult result = checkTokenFocusableLocked(focusedToken, displayId);
+ if (result != FocusResult::OK) {
+ onFocusChangedLocked(focusedToken, nullptr, displayId, typeToString(result));
+ }
+ }
+
+ std::optional<FocusRequest> focusRequest =
+ getOptionalValueByKey(mPendingFocusRequests, displayId);
+ if (focusRequest) {
+ // If the window from the pending request is now visible, provide it focus.
+ FocusResult result = handleFocusRequestLocked(*focusRequest);
+ if (result != FocusResult::NOT_VISIBLE) {
+ // Drop the request if we were able to change the focus or we cannot change
+ // it for another reason.
+ mPendingFocusRequests.erase(displayId);
+ }
}
std::unordered_map<int32_t, TouchState>::iterator stateIt =
@@ -5183,7 +5210,67 @@
* when requesting the focus change. This determines which request gets
* precedence if there is a focus change request from another source such as pointer down.
*/
-void InputDispatcher::setFocusedWindow(const FocusRequest& request) {}
+void InputDispatcher::setFocusedWindow(const FocusRequest& request) {
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+
+ const int32_t displayId = request.displayId;
+ const sp<IBinder> oldFocusedToken = getValueByKey(mFocusedWindowTokenByDisplay, displayId);
+ if (request.focusedToken && oldFocusedToken != request.focusedToken) {
+ ALOGD_IF(DEBUG_FOCUS,
+ "setFocusedWindow on display %" PRId32
+ " ignored, reason: focusedToken is not focused",
+ displayId);
+ return;
+ }
+
+ mPendingFocusRequests.erase(displayId);
+ FocusResult result = handleFocusRequestLocked(request);
+ if (result == FocusResult::NOT_VISIBLE) {
+ // The requested window is not currently visible. Wait for the window to become visible
+ // and then provide it focus. This is to handle situations where a user action triggers
+ // a new window to appear. We want to be able to queue any key events after the user
+ // action and deliver it to the newly focused window. In order for this to happen, we
+ // take focus from the currently focused window so key events can be queued.
+ ALOGD_IF(DEBUG_FOCUS,
+ "setFocusedWindow on display %" PRId32
+ " pending, reason: window is not visible",
+ displayId);
+ mPendingFocusRequests[displayId] = request;
+ onFocusChangedLocked(oldFocusedToken, nullptr, displayId,
+ "setFocusedWindow_AwaitingWindowVisibility");
+ } else if (result != FocusResult::OK) {
+ ALOGW("setFocusedWindow on display %" PRId32 " ignored, reason:%s", displayId,
+ typeToString(result));
+ }
+ } // release lock
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
+}
+
+InputDispatcher::FocusResult InputDispatcher::handleFocusRequestLocked(
+ const FocusRequest& request) {
+ const int32_t displayId = request.displayId;
+ const sp<IBinder> newFocusedToken = request.token;
+ const sp<IBinder> oldFocusedToken = getValueByKey(mFocusedWindowTokenByDisplay, displayId);
+
+ if (oldFocusedToken == request.token) {
+ ALOGD_IF(DEBUG_FOCUS,
+ "setFocusedWindow on display %" PRId32 " ignored, reason: already focused",
+ displayId);
+ return FocusResult::OK;
+ }
+
+ FocusResult result = checkTokenFocusableLocked(newFocusedToken, displayId);
+ if (result != FocusResult::OK) {
+ return result;
+ }
+
+ std::string_view reason =
+ (request.focusedToken) ? "setFocusedWindow_FocusCheck" : "setFocusedWindow";
+ onFocusChangedLocked(oldFocusedToken, newFocusedToken, displayId, reason);
+ return FocusResult::OK;
+}
void InputDispatcher::onFocusChangedLocked(const sp<IBinder>& oldFocusedToken,
const sp<IBinder>& newFocusedToken, int32_t displayId,
@@ -5207,4 +5294,48 @@
notifyFocusChangedLocked(oldFocusedToken, newFocusedToken);
}
}
+
+/**
+ * Checks if the window token can be focused on a display. The token can be focused if there is
+ * at least one window handle that is visible with the same token and all window handles with the
+ * same token are focusable.
+ *
+ * In the case of mirroring, two windows may share the same window token and their visibility
+ * might be different. Example, the mirrored window can cover the window its mirroring. However,
+ * we expect the focusability of the windows to match since its hard to reason why one window can
+ * receive focus events and the other cannot when both are backed by the same input channel.
+ */
+InputDispatcher::FocusResult InputDispatcher::checkTokenFocusableLocked(const sp<IBinder>& token,
+ int32_t displayId) const {
+ bool allWindowsAreFocusable = true;
+ bool visibleWindowFound = false;
+ bool windowFound = false;
+ for (const sp<InputWindowHandle>& window : getWindowHandlesLocked(displayId)) {
+ if (window->getToken() != token) {
+ continue;
+ }
+ windowFound = true;
+ if (window->getInfo()->visible) {
+ // Check if at least a single window is visible.
+ visibleWindowFound = true;
+ }
+ if (!window->getInfo()->focusable) {
+ // Check if all windows with the window token are focusable.
+ allWindowsAreFocusable = false;
+ break;
+ }
+ }
+
+ if (!windowFound) {
+ return FocusResult::NO_WINDOW;
+ }
+ if (!allWindowsAreFocusable) {
+ return FocusResult::NOT_FOCUSABLE;
+ }
+ if (!visibleWindowFound) {
+ return FocusResult::NOT_VISIBLE;
+ }
+
+ return FocusResult::OK;
+}
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 93d3fde..8f3d5dc 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -136,6 +136,14 @@
STALE,
};
+ enum class FocusResult {
+ OK,
+ NO_WINDOW,
+ NOT_FOCUSABLE,
+ NOT_VISIBLE,
+ };
+ static const char* typeToString(FocusResult result);
+
std::unique_ptr<InputThread> mThread;
sp<InputDispatcherPolicyInterface> mPolicy;
@@ -308,6 +316,9 @@
sp<InputWindowHandle> getFocusedWindowHandleLocked(int displayId) const REQUIRES(mLock);
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
bool hasResponsiveConnectionLocked(InputWindowHandle& windowHandle) const REQUIRES(mLock);
+ FocusResult handleFocusRequestLocked(const FocusRequest&) REQUIRES(mLock);
+ FocusResult checkTokenFocusableLocked(const sp<IBinder>& token, int32_t displayId) const
+ REQUIRES(mLock);
/*
* Validate and update InputWindowHandles for a given display.
@@ -380,6 +391,14 @@
*/
std::shared_ptr<InputApplicationHandle> mAwaitedFocusedApplication GUARDED_BY(mLock);
+ /**
+ * This map will store the pending focus requests that cannot be currently processed. This can
+ * happen if the window requested to be focused is not currently visible. Such a window might
+ * become visible later, and these requests would be processed at that time.
+ */
+ std::unordered_map<int32_t /* displayId */, FocusRequest> mPendingFocusRequests
+ GUARDED_BY(mLock);
+
// Optimization: AnrTracker is used to quickly find which connection is due for a timeout next.
// AnrTracker must be kept in-sync with all responsive connection.waitQueues.
// If a connection is not responsive, then the entries should not be added to the AnrTracker.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 3e0b5e8..6e08e1b 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -328,6 +328,18 @@
ALOGE("%s", to.c_str());
}
}
+
+ void setFocusedWindow(const sp<InputWindowHandle>& window,
+ const sp<InputWindowHandle>& focusedWindow = nullptr) {
+ FocusRequest request;
+ request.token = window->getToken();
+ if (focusedWindow) {
+ request.focusedToken = focusedWindow->getToken();
+ }
+ request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ request.displayId = window->getInfo()->displayId;
+ mDispatcher->setFocusedWindow(request);
+ }
};
@@ -725,6 +737,8 @@
void setFocusable(bool focusable) { mInfo.focusable = focusable; }
+ void setVisible(bool visible) { mInfo.visible = visible; }
+
void setDispatchingTimeout(std::chrono::nanoseconds timeout) {
mInfo.dispatchingTimeout = timeout;
}
@@ -1161,80 +1175,6 @@
windowSecond->assertNoEvents();
}
-TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) {
- std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
- ADISPLAY_ID_DEFAULT);
- sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
- ADISPLAY_ID_DEFAULT);
-
- // Set focused application.
- mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-
- // Display should have only one focused window
- windowSecond->setFocusable(true);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
-
- windowSecond->consumeFocusEvent(true);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
- << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
-
- // Focused window should receive event.
- windowTop->assertNoEvents();
- windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
-}
-
-TEST_F(InputDispatcherTest, SetInputWindow_FocusPriority) {
- std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
- ADISPLAY_ID_DEFAULT);
- sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
- ADISPLAY_ID_DEFAULT);
-
- // Set focused application.
- mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-
- // Display has two focused windows. Add them to inputWindowsHandles in z-order (top most first)
- windowTop->setFocusable(true);
- windowSecond->setFocusable(true);
-
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
- windowTop->consumeFocusEvent(true);
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
- << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
-
- // Top focused window should receive event.
- windowTop->consumeKeyDown(ADISPLAY_ID_NONE);
- windowSecond->assertNoEvents();
-}
-
-TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) {
- std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-
- sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
- ADISPLAY_ID_DEFAULT);
- sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
- ADISPLAY_ID_DEFAULT);
-
- // Set focused application.
- mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-
- windowTop->setFocusable(true);
- windowSecond->setFocusable(true);
- // Release channel for window is no longer valid.
- windowTop->releaseChannel();
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
- windowSecond->consumeFocusEvent(true);
-
- // Test inject a key down, should dispatch to a valid window.
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
- << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
-
- // Top window is invalid, so it should not receive any input event.
- windowTop->assertNoEvents();
- windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
-}
-
TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> windowLeft =
@@ -1459,6 +1399,8 @@
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
window->consumeFocusEvent(true);
NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
@@ -1660,6 +1602,7 @@
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
window->consumeFocusEvent(true);
@@ -1769,6 +1712,8 @@
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
window->consumeFocusEvent(true);
FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
@@ -1862,6 +1807,8 @@
SCOPED_TRACE("Check default value of touch mode");
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
SCOPED_TRACE("Remove the window to trigger focus loss");
@@ -1873,6 +1820,7 @@
mDispatcher->setInTouchMode(false);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
window->consumeFocusEvent(true /*hasFocus*/, false /*inTouchMode*/);
SCOPED_TRACE("Remove the window to trigger focus loss");
@@ -1884,6 +1832,7 @@
mDispatcher->setInTouchMode(true);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
window->assertNoEvents();
@@ -1898,6 +1847,8 @@
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
@@ -2020,6 +1971,151 @@
ASSERT_NE(initialHmac, mDispatcher->sign(verifiedEvent));
}
+TEST_F(InputDispatcherTest, SetFocusedWindow) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> windowTop =
+ new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond =
+ new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ // Top window is also focusable but is not granted focus.
+ windowTop->setFocusable(true);
+ windowSecond->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
+ setFocusedWindow(windowSecond);
+
+ windowSecond->consumeFocusEvent(true);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Focused window should receive event.
+ windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
+ windowTop->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ window->setFocusable(true);
+ // Release channel for window is no longer valid.
+ window->releaseChannel();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ // Test inject a key down, should timeout.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+
+ // window channel is invalid, so it should not receive any input event.
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ // Window is not focusable.
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ // Test inject a key down, should timeout.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+
+ // window is invalid, so it should not receive any input event.
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> windowTop =
+ new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond =
+ new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ windowTop->setFocusable(true);
+ windowSecond->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
+ setFocusedWindow(windowTop);
+ windowTop->consumeFocusEvent(true);
+
+ setFocusedWindow(windowSecond, windowTop);
+ windowSecond->consumeFocusEvent(true);
+ windowTop->consumeFocusEvent(false);
+
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Focused window should receive event.
+ windowSecond->consumeKeyDown(ADISPLAY_ID_NONE);
+}
+
+TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestFocusTokenNotFocused) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> windowTop =
+ new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond =
+ new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ windowTop->setFocusable(true);
+ windowSecond->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
+ setFocusedWindow(windowSecond, windowTop);
+
+ ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+
+ // Event should be dropped.
+ windowTop->assertNoEvents();
+ windowSecond->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> previousFocusedWindow =
+ new FakeWindowHandle(application, mDispatcher, "previousFocusedWindow",
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ window->setFocusable(true);
+ previousFocusedWindow->setFocusable(true);
+ window->setVisible(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, previousFocusedWindow}}});
+ setFocusedWindow(previousFocusedWindow);
+ previousFocusedWindow->consumeFocusEvent(true);
+
+ // Requesting focus on invisible window takes focus from currently focused window.
+ setFocusedWindow(window);
+ previousFocusedWindow->consumeFocusEvent(false);
+
+ // Injected key goes to pending queue.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+ injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */,
+ ADISPLAY_ID_DEFAULT, INPUT_EVENT_INJECTION_SYNC_NONE));
+
+ // Window does not get focus event or key down.
+ window->assertNoEvents();
+
+ // Window becomes visible.
+ window->setVisible(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ // Window receives focus event.
+ window->consumeFocusEvent(true);
+ // Focused window receives key down.
+ window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+}
+
class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
protected:
static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms
@@ -2044,7 +2140,7 @@
mWindow->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
-
+ setFocusedWindow(mWindow);
mWindow->consumeFocusEvent(true);
}
@@ -2134,6 +2230,7 @@
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
windowInPrimary->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowInPrimary}}});
+ setFocusedWindow(windowInPrimary);
windowInPrimary->consumeFocusEvent(true);
application2 = std::make_shared<FakeApplicationHandle>();
@@ -2146,6 +2243,7 @@
mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
windowInSecondary->setFocusable(true);
mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});
+ setFocusedWindow(windowInSecondary);
windowInSecondary->consumeFocusEvent(true);
}
@@ -2263,6 +2361,23 @@
monitorInSecondary.consumeKeyDown(ADISPLAY_ID_NONE);
}
+TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
+ sp<FakeWindowHandle> secondWindowInPrimary =
+ new FakeWindowHandle(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
+ secondWindowInPrimary->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowInPrimary, secondWindowInPrimary}}});
+ setFocusedWindow(secondWindowInPrimary);
+ windowInPrimary->consumeFocusEvent(false);
+ secondWindowInPrimary->consumeFocusEvent(true);
+
+ // Test inject a key down.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->assertNoEvents();
+ windowInSecondary->assertNoEvents();
+ secondWindowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+}
+
class InputFilterTest : public InputDispatcherTest {
protected:
static constexpr int32_t SECOND_DISPLAY_ID = 1;
@@ -2360,6 +2475,7 @@
// Expect one focus window exist in display.
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}});
+ setFocusedWindow(mFocusedWindow);
mFocusedWindow->consumeFocusEvent(true);
}
@@ -2653,6 +2769,7 @@
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
+ setFocusedWindow(mWindow);
mWindow->consumeFocusEvent(true);
}
@@ -3046,6 +3163,7 @@
// Expect one focus window exist in display.
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}});
+ setFocusedWindow(mFocusedWindow);
mFocusedWindow->consumeFocusEvent(true);
}
@@ -3242,6 +3360,7 @@
mFocusedWindow->setFocusable(false);
mUnfocusedWindow->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}});
+ setFocusedWindow(mUnfocusedWindow);
// Focus events should precede the key events
mUnfocusedWindow->consumeFocusEvent(true);
@@ -3379,4 +3498,147 @@
mBottomWindow->assertNoEvents();
}
+class InputDispatcherMirrorWindowFocusTests : public InputDispatcherTest {
+protected:
+ std::shared_ptr<FakeApplicationHandle> mApp;
+ sp<FakeWindowHandle> mWindow;
+ sp<FakeWindowHandle> mMirror;
+
+ virtual void SetUp() override {
+ InputDispatcherTest::SetUp();
+ mApp = std::make_shared<FakeApplicationHandle>();
+ mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mMirror = new FakeWindowHandle(mApp, mDispatcher, "TestWindowMirror", ADISPLAY_ID_DEFAULT,
+ mWindow->getToken());
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
+ mWindow->setFocusable(true);
+ mMirror->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}});
+ }
+};
+
+TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) {
+ // Request focus on a mirrored window
+ setFocusedWindow(mMirror);
+
+ // window gets focused
+ mWindow->consumeFocusEvent(true);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
+}
+
+// A focused & mirrored window remains focused only if the window and its mirror are both
+// focusable.
+TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) {
+ setFocusedWindow(mMirror);
+
+ // window gets focused
+ mWindow->consumeFocusEvent(true);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyUp(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
+
+ mMirror->setFocusable(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}});
+
+ // window loses focus since one of the windows associated with the token in not focusable
+ mWindow->consumeFocusEvent(false);
+
+ ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+ mWindow->assertNoEvents();
+}
+
+// A focused & mirrored window remains focused until the window and its mirror both become
+// invisible.
+TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) {
+ setFocusedWindow(mMirror);
+
+ // window gets focused
+ mWindow->consumeFocusEvent(true);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyUp(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
+
+ mMirror->setVisible(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}});
+
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyUp(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
+
+ mWindow->setVisible(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}});
+
+ // window loses focus only after all windows associated with the token become invisible.
+ mWindow->consumeFocusEvent(false);
+
+ ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+ mWindow->assertNoEvents();
+}
+
+// A focused & mirrored window remains focused until both windows are removed.
+TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) {
+ setFocusedWindow(mMirror);
+
+ // window gets focused
+ mWindow->consumeFocusEvent(true);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyUp(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
+
+ // single window is removed but the window token remains focused
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mMirror}}});
+
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyUp(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ mWindow->consumeKeyUp(ADISPLAY_ID_NONE);
+
+ // Both windows are removed
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}});
+ mWindow->consumeFocusEvent(false);
+
+ ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+ mWindow->assertNoEvents();
+}
+
+// Focus request can be pending until one window becomes visible.
+TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) {
+ // Request focus on an invisible mirror.
+ mWindow->setVisible(false);
+ mMirror->setVisible(false);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}});
+ setFocusedWindow(mMirror);
+
+ // Injected key goes to pending queue.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+ injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */,
+ ADISPLAY_ID_DEFAULT, INPUT_EVENT_INJECTION_SYNC_NONE));
+
+ mMirror->setVisible(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}});
+
+ // window gets focused
+ mWindow->consumeFocusEvent(true);
+ // window gets the pending key event
+ mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+}
} // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ff11724..5fcaae2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2913,6 +2913,9 @@
setInputWindowsFinished();
}
+ for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
+ mInputFlinger->setFocusedWindow(focusRequest);
+ }
mInputWindowCommands.clear();
}
@@ -2930,10 +2933,6 @@
mInputFlinger->setInputWindows(inputInfos,
mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
: nullptr);
- for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
- mInputFlinger->setFocusedWindow(focusRequest);
- }
- mInputWindowCommands.focusRequests.clear();
}
void SurfaceFlinger::commitInputWindowCommands() {
@@ -3477,7 +3476,11 @@
}
transactionFlags |= clientStateFlags;
- transactionFlags |= addInputWindowCommands(inputWindowCommands);
+ if (privileged) {
+ transactionFlags |= addInputWindowCommands(inputWindowCommands);
+ } else if (!inputWindowCommands.empty()) {
+ ALOGE("Only privileged callers are allowed to send input commands.");
+ }
if (uncacheBuffer.isValid()) {
ClientCache::getInstance().erase(uncacheBuffer);
@@ -3945,7 +3948,7 @@
}
uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
- const bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands);
+ bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands);
return hasChanges ? eTraversalNeeded : 0;
}