diff options
| author | 2024-09-29 10:49:20 +0000 | |
|---|---|---|
| committer | 2024-10-01 21:17:15 +0000 | |
| commit | d4e27d9afd1e1d454fb7e4c4d2c4e981d079cd1f (patch) | |
| tree | 3f6f965559f7997f2d2b4018ddd3d47513964838 | |
| parent | 64e46a09e6023dff77e68f3764555c412708401d (diff) | |
Report display change for display focus switch
Currently, when display focus has changed, the task that caused
the focus switch is reported with the MOVED_TO_TOP flag, and
WMShell “infers” the display focus event from it. This is a bit
tricky in some cases because even when a task gets "moved to front",
sometimes the display may not come on top. For example, when a
task gets minimized, the task just behind the originally top task
comes on top, but this doesn't involve moving the display to front.
To avoid these confusions, with this change, the display itself is
reported with the MOVED_TO_TOP flag when display focus switches,
which greatly simplifies the logic and saves us considering tricky
edge cases.
Bug: 369940439
Flag: com.android.window.flags.enable_display_focus_in_shell_transitions
Test: TransitionTests
Test: atest FocusTransitionObserverTest
Change-Id: I61a5649cdc917a7d7a344329f247580cb4218190
3 files changed, 43 insertions, 46 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java index 2f5059f3161c..399e39a920fc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/FocusTransitionObserver.java @@ -17,13 +17,13 @@ package com.android.wm.shell.transition; import static android.view.Display.INVALID_DISPLAY; +import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP; import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions; import static com.android.wm.shell.transition.Transitions.TransitionObserver; import android.annotation.NonNull; -import android.app.ActivityManager.RunningTaskInfo; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; @@ -62,10 +62,9 @@ public class FocusTransitionObserver implements TransitionObserver { final List<TransitionInfo.Change> changes = info.getChanges(); for (int i = changes.size() - 1; i >= 0; i--) { final TransitionInfo.Change change = changes.get(i); - final RunningTaskInfo task = change.getTaskInfo(); - if (task != null && task.isFocused && change.hasFlags(FLAG_MOVED_TO_TOP)) { - if (mFocusedDisplayId != task.displayId) { - mFocusedDisplayId = task.displayId; + if (change.hasFlags(FLAG_IS_DISPLAY) && change.hasFlags(FLAG_MOVED_TO_TOP)) { + if (mFocusedDisplayId != change.getEndDisplayId()) { + mFocusedDisplayId = change.getEndDisplayId(); notifyFocusedDisplayChanged(); } return; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java index d37b4cf4b4b3..d63158c29688 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java @@ -18,7 +18,7 @@ package com.android.wm.shell.transition; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.TRANSIT_OPEN; -import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; @@ -97,50 +97,38 @@ public class FocusTransitionObserverTest extends ShellTestCase { } @Test - public void testTransitionWithMovedToFrontFlagChangesDisplayFocus() throws RemoteException { + public void testOnlyDisplayChangeAffectsDisplayFocus() throws RemoteException { final IBinder binder = mock(IBinder.class); final SurfaceControl.Transaction tx = mock(SurfaceControl.Transaction.class); - // Open a task on the default display, which doesn't change display focus because the - // default display already has it. + // Open a task on the secondary display, but it doesn't change display focus because it only + // has a task change. TransitionInfo info = mock(TransitionInfo.class); final List<TransitionInfo.Change> changes = new ArrayList<>(); - setupChange(changes, 123 /* taskId */, TRANSIT_OPEN, DEFAULT_DISPLAY, + setupTaskChange(changes, 123 /* taskId */, TRANSIT_OPEN, SECONDARY_DISPLAY_ID, true /* focused */); when(info.getChanges()).thenReturn(changes); mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx); verify(mListener, never()).onFocusedDisplayChanged(SECONDARY_DISPLAY_ID); clearInvocations(mListener); - // Open a new task on the secondary display and verify display focus changes to the display. + // Moving the secondary display to front must change display focus to it. changes.clear(); - setupChange(changes, 456 /* taskId */, TRANSIT_OPEN, SECONDARY_DISPLAY_ID, - true /* focused */); + setupDisplayToTopChange(changes, SECONDARY_DISPLAY_ID); when(info.getChanges()).thenReturn(changes); mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx); - verify(mListener, times(1)).onFocusedDisplayChanged(SECONDARY_DISPLAY_ID); - clearInvocations(mListener); + verify(mListener, times(1)) + .onFocusedDisplayChanged(SECONDARY_DISPLAY_ID); - // Open the first task to front and verify display focus goes back to the default display. + // Moving the secondary display to front must change display focus back to it. changes.clear(); - setupChange(changes, 123 /* taskId */, TRANSIT_TO_FRONT, DEFAULT_DISPLAY, - true /* focused */); + setupDisplayToTopChange(changes, DEFAULT_DISPLAY); when(info.getChanges()).thenReturn(changes); mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx); verify(mListener, times(1)).onFocusedDisplayChanged(DEFAULT_DISPLAY); - clearInvocations(mListener); - - // Open another task on the default display and verify no display focus switch as it's - // already on the default display. - changes.clear(); - setupChange(changes, 789 /* taskId */, TRANSIT_OPEN, DEFAULT_DISPLAY, - true /* focused */); - when(info.getChanges()).thenReturn(changes); - mFocusTransitionObserver.onTransitionReady(binder, info, tx, tx); - verify(mListener, never()).onFocusedDisplayChanged(DEFAULT_DISPLAY); } - private void setupChange(List<TransitionInfo.Change> changes, int taskId, + private void setupTaskChange(List<TransitionInfo.Change> changes, int taskId, @TransitionMode int mode, int displayId, boolean focused) { TransitionInfo.Change change = mock(TransitionInfo.Change.class); RunningTaskInfo taskInfo = mock(RunningTaskInfo.class); @@ -152,4 +140,12 @@ public class FocusTransitionObserverTest extends ShellTestCase { when(change.getMode()).thenReturn(mode); changes.add(change); } + + private void setupDisplayToTopChange(List<TransitionInfo.Change> changes, int displayId) { + TransitionInfo.Change change = mock(TransitionInfo.Change.class); + when(change.hasFlags(FLAG_MOVED_TO_TOP)).thenReturn(true); + when(change.hasFlags(FLAG_IS_DISPLAY)).thenReturn(true); + when(change.getEndDisplayId()).thenReturn(displayId); + changes.add(change); + } } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index c48590fba00d..fde502f2306c 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -2188,30 +2188,32 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { for (int i = onTopTasksEnd.size() - 1; i >= 0; --i) { final Task task = onTopTasksEnd.get(i); if (task.getDisplayId() != displayId) continue; - if (!enableDisplayFocusInShellTransitions() - || mOnTopDisplayStart == onTopDisplayEnd - || displayId != onTopDisplayEnd.mDisplayId) { - // If it didn't change since last report, don't report - if (reportedOnTop == null) { - if (mOnTopTasksStart.contains(task)) continue; - } else if (reportedOnTop.contains(task)) { - continue; - } - } - // Need to report it. - mParticipants.add(task); - int changeIdx = mChanges.indexOfKey(task); - if (changeIdx < 0) { - mChanges.put(task, new ChangeInfo(task)); - changeIdx = mChanges.indexOfKey(task); + if (reportedOnTop == null) { + if (mOnTopTasksStart.contains(task)) continue; + } else if (reportedOnTop.contains(task)) { + continue; } - mChanges.valueAt(changeIdx).mFlags |= ChangeInfo.FLAG_CHANGE_MOVED_TO_TOP; + addToTopChange(task); } // Swap in the latest on-top tasks. mController.mLatestOnTopTasksReported.put(displayId, onTopTasksEnd); onTopTasksEnd = reportedOnTop != null ? reportedOnTop : new ArrayList<>(); onTopTasksEnd.clear(); + + if (enableDisplayFocusInShellTransitions() + && mOnTopDisplayStart != onTopDisplayEnd + && displayId == onTopDisplayEnd.mDisplayId) { + addToTopChange(onTopDisplayEnd); + } + } + } + + private void addToTopChange(@NonNull WindowContainer wc) { + mParticipants.add(wc); + if (!mChanges.containsKey(wc)) { + mChanges.put(wc, new ChangeInfo(wc)); } + mChanges.get(wc).mFlags |= ChangeInfo.FLAG_CHANGE_MOVED_TO_TOP; } private void postCleanupOnFailure() { |