FocusResolver: Clean up focus requests and results when a display is removed
Prevents FocusResolver from leaking focus requests and results as
displays are added and removed.
Test: atest inputflinger_tests
Fixes: 188008394
Change-Id: I635b9becf91056fd540ab9d9546dd67a09324fc6
diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp
index 17efb5b..9051ff1 100644
--- a/services/inputflinger/tests/FocusResolver_test.cpp
+++ b/services/inputflinger/tests/FocusResolver_test.cpp
@@ -256,5 +256,37 @@
// dropped.
ASSERT_FALSE(changes);
}
+TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
+ sp<IBinder> windowToken = new BBinder();
+ std::vector<sp<InputWindowHandle>> windows;
+
+ sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
+ true /* focusable */, true /* visible */);
+ windows.push_back(window);
+
+ FocusRequest request;
+ request.displayId = 42;
+ request.token = windowToken;
+ FocusResolver focusResolver;
+ std::optional<FocusResolver::FocusChanges> changes =
+ focusResolver.setFocusedWindow(request, windows);
+ ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
+ ASSERT_EQ(request.displayId, changes->displayId);
+
+ // Start with a focused window
+ window->setFocusable(true);
+ changes = focusResolver.setInputWindows(request.displayId, windows);
+ ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken);
+
+ // When a display is removed, all windows are removed from the display
+ // and our focused window loses focus
+ changes = focusResolver.setInputWindows(request.displayId, {});
+ ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr);
+ focusResolver.displayRemoved(request.displayId);
+
+ // When a display is readded, the window does not get focus since the request was cleared.
+ changes = focusResolver.setInputWindows(request.displayId, windows);
+ ASSERT_FALSE(changes);
+}
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index d51acce..77ca12c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2688,6 +2688,23 @@
window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
}
+TEST_F(InputDispatcherTest, DisplayRemoved) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ // window is granted focus.
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true);
+
+ // When a display is removed window loses focus.
+ mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT);
+ window->consumeFocusEvent(false);
+}
+
/**
* Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
* and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top