diff options
3 files changed, 104 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 7f6dc8472813..fd9db0c91fec 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -73,6 +73,7 @@ import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_W import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; +import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions; import android.annotation.IntDef; import android.annotation.NonNull; @@ -223,6 +224,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { private final ArrayList<Task> mOnTopTasksAtReady = new ArrayList<>(); /** + * Tracks the top display like top tasks so we can trigger a MOVED_TO_TOP transition even when + * a display gets moved to front but there's no change in per-display focused tasks. + */ + private DisplayContent mOnTopDisplayStart = null; + private DisplayContent mOnTopDisplayAtReady = null; + + /** * Set of participating windowtokens (activity/wallpaper) which are visible at the end of * the transition animation. */ @@ -772,6 +780,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (dc == null || mTargetDisplays.contains(dc)) return; mTargetDisplays.add(dc); addOnTopTasks(dc, mOnTopTasksStart); + if (mOnTopDisplayStart == null) { + mOnTopDisplayStart = + mController.mAtm.mRootWindowContainer.getTopFocusedDisplayContent(); + } // Handle the case {transition.start(); applyTransaction(wct);} that the animating state // is set before collecting participants. if (mController.isAnimating()) { @@ -998,6 +1010,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { for (int i = 0; i < mTargetDisplays.size(); ++i) { addOnTopTasks(mTargetDisplays.get(i), mOnTopTasksAtReady); } + mOnTopDisplayAtReady = + mController.mAtm.mRootWindowContainer.getTopFocusedDisplayContent(); mController.onTransitionPopulated(this); } } @@ -2082,6 +2096,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return true; } } + if (enableDisplayFocusInShellTransitions() && mOnTopDisplayStart + != mController.mAtm.mRootWindowContainer.getTopFocusedDisplayContent()) { + return true; + } return false; } @@ -2113,6 +2131,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { includesOrderChange = true; break; } + includesOrderChange |= enableDisplayFocusInShellTransitions() + && mOnTopDisplayStart != mOnTopDisplayAtReady; if (!includesOrderChange && !reportCurrent) { // This transition doesn't include an order change, so if it isn't required to report // the current focus (eg. it's the last of a cluster of transitions), then don't @@ -2123,6 +2143,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // latest state and compare with the last reported state (or our start state if no // reported state exists). ArrayList<Task> onTopTasksEnd = new ArrayList<>(); + final DisplayContent onTopDisplayEnd = + mController.mAtm.mRootWindowContainer.getTopFocusedDisplayContent(); for (int d = 0; d < mTargetDisplays.size(); ++d) { addOnTopTasks(mTargetDisplays.get(d), onTopTasksEnd); final int displayId = mTargetDisplays.get(d).mDisplayId; @@ -2130,11 +2152,15 @@ 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 it didn't change since last report, don't report - if (reportedOnTop == null) { - if (mOnTopTasksStart.contains(task)) continue; - } else if (reportedOnTop.contains(task)) { - 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); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index fb57a1bb94c1..d63cdcd4e32a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -90,6 +90,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; +import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.fixScale; import static android.view.WindowManagerGlobal.ADD_OKAY; import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW; @@ -158,6 +159,7 @@ import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CO import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID; import static com.android.window.flags.Flags.multiCrop; import static com.android.window.flags.Flags.setScPropertiesInClient; +import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions; import android.Manifest; import android.Manifest.permission; @@ -3238,9 +3240,28 @@ public class WindowManagerService extends IWindowManager.Stub return; } + Transition transition = null; + boolean transitionNewlyCreated = false; + if (enableDisplayFocusInShellTransitions()) { + transition = mAtmService.getTransitionController().requestTransitionIfNeeded( + TRANSIT_TO_FRONT, 0 /* flags */, null /* trigger */, + displayContent); + if (transition != null) { + transitionNewlyCreated = true; + } else { + transition = + mAtmService.getTransitionController().getCollectingTransition(); + } + if (transition != null) { + transition.recordTaskOrder(displayContent); + } + } // Nothing prevented us from moving the display to the top. Let's do it! displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent, true /* includingParents */); + if (transitionNewlyCreated) { + transition.setReady(displayContent, true /* ready */); + } } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 7320c0bd4666..4e2a8fea23b1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -51,6 +51,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.window.flags.Flags.explicitRefreshRateHints; import static org.junit.Assert.assertEquals; @@ -140,8 +141,7 @@ public class TransitionTests extends WindowTestsBase { } private Transition createTestTransition(int transitType) { - final TransitionController controller = new TestTransitionController( - mock(ActivityTaskManagerService.class)); + final TransitionController controller = new TestTransitionController(mAtm); mSyncEngine = createTestBLASTSyncEngine(); controller.setSyncEngine(mSyncEngine); @@ -2358,7 +2358,7 @@ public class TransitionTests extends WindowTestsBase { } @Test - public void testMoveToTopWhileVisible() { + public void testMoveTaskToTopWhileVisible() { final Transition transition = createTestTransition(TRANSIT_OPEN); final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; final ArraySet<WindowContainer> participants = transition.mParticipants; @@ -2393,6 +2393,55 @@ public class TransitionTests extends WindowTestsBase { assertEquals(TRANSIT_CHANGE, info.getChanges().get(0).getMode()); } + @Test + @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS) + public void testMoveDisplayToTop() { + // Set up two displays, each of which has a task. + DisplayContent otherDisplay = createNewDisplay(); + final Consumer<DisplayContent> setUpTask = (DisplayContent dc) -> { + final Task task = createTask(dc); + final ActivityRecord act = createActivityRecord(task); + final TestWindowState win = createWindowState( + new WindowManager.LayoutParams(TYPE_BASE_APPLICATION), act); + act.addWindow(win); + act.setVisibleRequested(true); + }; + setUpTask.accept(mDisplayContent); + setUpTask.accept(otherDisplay); + mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /* updateImWindows */); + + final Transition transition = createTestTransition(TRANSIT_OPEN); + final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; + final ArraySet<WindowContainer> participants = transition.mParticipants; + + // Emulate WindowManagerService#moveDisplayToTopInternal(). + transition.recordTaskOrder(mDefaultDisplay); + mDefaultDisplay.getParent().positionChildAt(WindowContainer.POSITION_TOP, + mDefaultDisplay, true /* includingParents */); + mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /* updateImWindows */); + transition.setReady(mDefaultDisplay, true /* ready */); + + // Test has order changes, a shallow check of order changes. + assertTrue(transition.hasOrderChanges()); + + // We just moved a display to top, so there shouldn't be any changes. + ArrayList<Transition.ChangeInfo> targets = Transition.calculateTargets( + participants, changes); + assertTrue(targets.isEmpty()); + + // After collecting order changes, the task on the newly focused display should be + // considered to get moved to top. + transition.collectOrderChanges(true); + targets = Transition.calculateTargets(participants, changes); + assertEquals(1, targets.size()); + + // Make sure the flag is set + final TransitionInfo info = Transition.calculateTransitionInfo( + transition.mType, 0 /* flags */, targets, mMockT); + assertTrue((info.getChanges().get(0).getFlags() & TransitionInfo.FLAG_MOVED_TO_TOP) != 0); + assertEquals(TRANSIT_CHANGE, info.getChanges().get(0).getMode()); + } + private class OrderChangeTestSetup { final TransitionController mController; final TestTransitionPlayer mPlayer; |