InputDispatcher: Fix multi-display Pointer Capture
There is an existing requirement that a window must both have focus and
be on the focused display to be able to gain Pointer Capture.
This means that focus changes on non-focused displays should not affect
Pointer Capture, and that a window must lose capture if its display
loses focus.
Verify these requirements with a test.
Bug: 342229227
Test: atest inputflinger_tests
Change-Id: I7b1c73b7759d8f20436ee401ba657a5dc8ead7a5
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 527edb6..d22f319 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -5529,6 +5529,10 @@
}
mFocusedDisplayId = displayId;
+ // Only a window on the focused display can have Pointer Capture, so disable the active
+ // Pointer Capture session if there is one, since the focused display changed.
+ disablePointerCaptureForcedLocked();
+
// Find new focused window and validate
sp<IBinder> newFocusedWindowToken = mFocusResolver.getFocusedWindowToken(displayId);
sendFocusChangedCommandLocked(oldFocusedWindowToken, newFocusedWindowToken);
@@ -6929,17 +6933,17 @@
enqueueFocusEventLocked(changes.newFocus, /*hasFocus=*/true, changes.reason);
}
- // If a window has pointer capture, then it must have focus. We need to ensure that this
- // contract is upheld when pointer capture is being disabled due to a loss of window focus.
- // If the window loses focus before it loses pointer capture, then the window can be in a state
- // where it has pointer capture but not focus, violating the contract. Therefore we must
- // dispatch the pointer capture event before the focus event. Since focus events are added to
- // the front of the queue (above), we add the pointer capture event to the front of the queue
- // after the focus events are added. This ensures the pointer capture event ends up at the
- // front.
- disablePointerCaptureForcedLocked();
-
if (mFocusedDisplayId == changes.displayId) {
+ // If a window has pointer capture, then it must have focus and must be on the top-focused
+ // display. We need to ensure that this contract is upheld when pointer capture is being
+ // disabled due to a loss of window focus. If the window loses focus before it loses pointer
+ // capture, then the window can be in a state where it has pointer capture but not focus,
+ // violating the contract. Therefore we must dispatch the pointer capture event before the
+ // focus event. Since focus events are added to the front of the queue (above), we add the
+ // pointer capture event to the front of the queue after the focus events are added. This
+ // ensures the pointer capture event ends up at the front.
+ disablePointerCaptureForcedLocked();
+
sendFocusChangedCommandLocked(changes.oldFocus, changes.newFocus);
}
}