diff options
author | Vishnu Nair <vishnun@google.com> | 2021-06-21 20:51:05 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-06-21 20:51:05 +0000 |
commit | 8296e54abbab30fa8cfa36481b24589d7a304377 (patch) | |
tree | a4d371f09fa286b2f55eed6fa9b1ed8cbbe7b0f2 | |
parent | 3c1ab22b44e9db512b4c40cb259aa2825afebba1 (diff) | |
parent | 831288d496135c75d50467facd69064e0d8fa7bc (diff) | |
download | native-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
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 |