summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVishnu Nair <vishnun@google.com>2021-06-21 20:51:05 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-06-21 20:51:05 +0000
commit8296e54abbab30fa8cfa36481b24589d7a304377 (patch)
treea4d371f09fa286b2f55eed6fa9b1ed8cbbe7b0f2
parent3c1ab22b44e9db512b4c40cb259aa2825afebba1 (diff)
parent831288d496135c75d50467facd69064e0d8fa7bc (diff)
downloadnative-8296e54abbab30fa8cfa36481b24589d7a304377.tar.gz
Merge "FocusResolver: Clean up focus requests and results when a display is removed" into sc-dev am: 831288d496
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/15032232 Change-Id: I677cdb280211830cccd803bae075d628708a0476
-rw-r--r--services/inputflinger/dispatcher/FocusResolver.cpp5
-rw-r--r--services/inputflinger/dispatcher/FocusResolver.h3
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp53
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h5
-rw-r--r--services/inputflinger/dispatcher/include/InputDispatcherInterface.h5
-rw-r--r--services/inputflinger/tests/FocusResolver_test.cpp32
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp17
7 files changed, 103 insertions, 17 deletions
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index 2db8c13a67..fb194355ba 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -216,4 +216,9 @@ std::string FocusResolver::dump() const {
return dump;
}
+void FocusResolver::displayRemoved(int32_t displayId) {
+ mFocusRequestByDisplay.erase(displayId);
+ mLastFocusResultByDisplay.erase(displayId);
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h
index dc5eeebb4e..afe16b3b45 100644
--- a/services/inputflinger/dispatcher/FocusResolver.h
+++ b/services/inputflinger/dispatcher/FocusResolver.h
@@ -62,6 +62,9 @@ public:
std::optional<FocusResolver::FocusChanges> setFocusedWindow(
const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows);
+ // Display has been removed from the system, clean up old references.
+ void displayRemoved(int32_t displayId);
+
// exposed for debugging
bool hasFocusedWindowTokens() const { return !mFocusedWindowTokenByDisplay.empty(); }
std::string dumpFocusedWindows() const;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d2b8739f96..c0010abf8a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4613,28 +4613,32 @@ void InputDispatcher::setFocusedApplication(
}
{ // acquire lock
std::scoped_lock _l(mLock);
+ setFocusedApplicationLocked(displayId, inputApplicationHandle);
+ } // release lock
- std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle =
- getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
+}
- if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) {
- return; // This application is already focused. No need to wake up or change anything.
- }
+void InputDispatcher::setFocusedApplicationLocked(
+ int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
+ std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle =
+ getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
- // Set the new application handle.
- if (inputApplicationHandle != nullptr) {
- mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
- } else {
- mFocusedApplicationHandlesByDisplay.erase(displayId);
- }
+ if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) {
+ return; // This application is already focused. No need to wake up or change anything.
+ }
- // No matter what the old focused application was, stop waiting on it because it is
- // no longer focused.
- resetNoFocusedWindowTimeoutLocked();
- } // release lock
+ // Set the new application handle.
+ if (inputApplicationHandle != nullptr) {
+ mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
+ } else {
+ mFocusedApplicationHandlesByDisplay.erase(displayId);
+ }
- // Wake up poll loop since it may need to make new input dispatching choices.
- mLooper->wake();
+ // No matter what the old focused application was, stop waiting on it because it is
+ // no longer focused.
+ resetNoFocusedWindowTimeoutLocked();
}
/**
@@ -6208,4 +6212,19 @@ void InputDispatcher::doSetPointerCaptureLockedInterruptible(
mLock.lock();
}
+void InputDispatcher::displayRemoved(int32_t displayId) {
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+ // Set an empty list to remove all handles from the specific display.
+ setInputWindowsLocked(/* window handles */ {}, displayId);
+ setFocusedApplicationLocked(displayId, nullptr);
+ // Call focus resolver to clean up stale requests. This must be called after input windows
+ // have been removed for the removed display.
+ mFocusResolver.displayRemoved(displayId);
+ } // release lock
+
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index bb3f3e6dfc..9edf41c9c0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -139,6 +139,8 @@ public:
std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
+ void displayRemoved(int32_t displayId) override;
+
private:
enum class DropReason {
NOT_DROPPED,
@@ -343,6 +345,9 @@ private:
std::unordered_map<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock);
std::unique_ptr<DragState> mDragState GUARDED_BY(mLock);
+ void setFocusedApplicationLocked(
+ int32_t displayId,
+ const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) REQUIRES(mLock);
// Focused applications.
std::unordered_map<int32_t, std::shared_ptr<InputApplicationHandle>>
mFocusedApplicationHandlesByDisplay GUARDED_BY(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 7f85e5393b..43428a0130 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -209,6 +209,11 @@ public:
* Returns true on success.
*/
virtual bool flushSensor(int deviceId, InputDeviceSensorType sensorType) = 0;
+
+ /**
+ * Called when a display has been removed from the system.
+ */
+ virtual void displayRemoved(int32_t displayId) = 0;
};
} // namespace android
diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp
index 17efb5b99f..9051ff12c2 100644
--- a/services/inputflinger/tests/FocusResolver_test.cpp
+++ b/services/inputflinger/tests/FocusResolver_test.cpp
@@ -256,5 +256,37 @@ TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
// 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 d51acce4b2..77ca12c5dc 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2688,6 +2688,23 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
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