Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5675ae13 authored by Kazuki Takise's avatar Kazuki Takise Committed by Android (Google) Code Review
Browse files

Merge changes I3f74a169,I351aea69 into main

* changes:
  Add multi-display support to focus switching in shell transitions
  Create a flag for display focus switch in shell transitions
parents a7922e81 3be9c5a2
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -251,3 +251,10 @@ flag {
    description: "Persists the desktop windowing session across reboots."
    description: "Persists the desktop windowing session across reboots."
    bug: "350456942"
    bug: "350456942"
}
}

flag {
    name: "enable_display_focus_in_shell_transitions"
    namespace: "lse_desktop_experience"
    description: "Creates a shell transition when display focus switches."
    bug: "356109871"
}
+31 −5
Original line number Original line Diff line number Diff line
@@ -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.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION;
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.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
@@ -222,6 +223,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
     */
     */
    private final ArrayList<Task> mOnTopTasksAtReady = new ArrayList<>();
    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
     * Set of participating windowtokens (activity/wallpaper) which are visible at the end of
     * the transition animation.
     * the transition animation.
@@ -772,6 +780,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        if (dc == null || mTargetDisplays.contains(dc)) return;
        if (dc == null || mTargetDisplays.contains(dc)) return;
        mTargetDisplays.add(dc);
        mTargetDisplays.add(dc);
        addOnTopTasks(dc, mOnTopTasksStart);
        addOnTopTasks(dc, mOnTopTasksStart);
        if (mOnTopDisplayStart == null) {
            mOnTopDisplayStart =
                    mController.mAtm.mRootWindowContainer.getTopFocusedDisplayContent();
        }
        // Handle the case {transition.start(); applyTransaction(wct);} that the animating state
        // Handle the case {transition.start(); applyTransaction(wct);} that the animating state
        // is set before collecting participants.
        // is set before collecting participants.
        if (mController.isAnimating()) {
        if (mController.isAnimating()) {
@@ -995,6 +1007,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
            for (int i = 0; i < mTargetDisplays.size(); ++i) {
            for (int i = 0; i < mTargetDisplays.size(); ++i) {
                addOnTopTasks(mTargetDisplays.get(i), mOnTopTasksAtReady);
                addOnTopTasks(mTargetDisplays.get(i), mOnTopTasksAtReady);
            }
            }
            mOnTopDisplayAtReady =
                    mController.mAtm.mRootWindowContainer.getTopFocusedDisplayContent();
            mController.onTransitionPopulated(this);
            mController.onTransitionPopulated(this);
        }
        }
    }
    }
@@ -2079,6 +2093,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
                return true;
                return true;
            }
            }
        }
        }
        if (enableDisplayFocusInShellTransitions() && mOnTopDisplayStart
                != mController.mAtm.mRootWindowContainer.getTopFocusedDisplayContent()) {
            return true;
        }
        return false;
        return false;
    }
    }


@@ -2110,6 +2128,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
            includesOrderChange = true;
            includesOrderChange = true;
            break;
            break;
        }
        }
        includesOrderChange |= enableDisplayFocusInShellTransitions()
                && mOnTopDisplayStart != mOnTopDisplayAtReady;
        if (!includesOrderChange && !reportCurrent) {
        if (!includesOrderChange && !reportCurrent) {
            // This transition doesn't include an order change, so if it isn't required to report
            // 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
            // the current focus (eg. it's the last of a cluster of transitions), then don't
@@ -2120,6 +2140,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        // latest state and compare with the last reported state (or our start state if no
        // latest state and compare with the last reported state (or our start state if no
        // reported state exists).
        // reported state exists).
        ArrayList<Task> onTopTasksEnd = new ArrayList<>();
        ArrayList<Task> onTopTasksEnd = new ArrayList<>();
        final DisplayContent onTopDisplayEnd =
                mController.mAtm.mRootWindowContainer.getTopFocusedDisplayContent();
        for (int d = 0; d < mTargetDisplays.size(); ++d) {
        for (int d = 0; d < mTargetDisplays.size(); ++d) {
            addOnTopTasks(mTargetDisplays.get(d), onTopTasksEnd);
            addOnTopTasks(mTargetDisplays.get(d), onTopTasksEnd);
            final int displayId = mTargetDisplays.get(d).mDisplayId;
            final int displayId = mTargetDisplays.get(d).mDisplayId;
@@ -2127,12 +2149,16 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
            for (int i = onTopTasksEnd.size() - 1; i >= 0; --i) {
            for (int i = onTopTasksEnd.size() - 1; i >= 0; --i) {
                final Task task = onTopTasksEnd.get(i);
                final Task task = onTopTasksEnd.get(i);
                if (task.getDisplayId() != displayId) continue;
                if (task.getDisplayId() != displayId) continue;
                if (!enableDisplayFocusInShellTransitions()
                        || mOnTopDisplayStart == onTopDisplayEnd
                        || displayId != onTopDisplayEnd.mDisplayId) {
                    // If it didn't change since last report, don't report
                    // If it didn't change since last report, don't report
                    if (reportedOnTop == null) {
                    if (reportedOnTop == null) {
                        if (mOnTopTasksStart.contains(task)) continue;
                        if (mOnTopTasksStart.contains(task)) continue;
                    } else if (reportedOnTop.contains(task)) {
                    } else if (reportedOnTop.contains(task)) {
                        continue;
                        continue;
                    }
                    }
                }
                // Need to report it.
                // Need to report it.
                mParticipants.add(task);
                mParticipants.add(task);
                int changeIdx = mChanges.indexOfKey(task);
                int changeIdx = mChanges.indexOfKey(task);
+21 −0
Original line number Original line Diff line number Diff line
@@ -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.REMOVE_CONTENT_MODE_UNDEFINED;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
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.WindowManager.fixScale;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
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.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID;
import static com.android.window.flags.Flags.multiCrop;
import static com.android.window.flags.Flags.multiCrop;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions;


import android.Manifest;
import android.Manifest;
import android.Manifest.permission;
import android.Manifest.permission;
@@ -3238,9 +3240,28 @@ public class WindowManagerService extends IWindowManager.Stub
                    return;
                    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!
                // Nothing prevented us from moving the display to the top. Let's do it!
                displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP,
                displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP,
                        displayContent, true /* includingParents */);
                        displayContent, true /* includingParents */);
                if (transitionNewlyCreated) {
                    transition.setReady(displayContent, true /* ready */);
                }
            }
            }
        }
        }
    }
    }
+52 −3
Original line number Original line Diff line number Diff line
@@ -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.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
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.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.window.flags.Flags.explicitRefreshRateHints;
import static com.android.window.flags.Flags.explicitRefreshRateHints;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
@@ -140,8 +141,7 @@ public class TransitionTests extends WindowTestsBase {
    }
    }


    private Transition createTestTransition(int transitType) {
    private Transition createTestTransition(int transitType) {
        final TransitionController controller = new TestTransitionController(
        final TransitionController controller = new TestTransitionController(mAtm);
                mock(ActivityTaskManagerService.class));


        mSyncEngine = createTestBLASTSyncEngine();
        mSyncEngine = createTestBLASTSyncEngine();
        controller.setSyncEngine(mSyncEngine);
        controller.setSyncEngine(mSyncEngine);
@@ -2357,7 +2357,7 @@ public class TransitionTests extends WindowTestsBase {
    }
    }


    @Test
    @Test
    public void testMoveToTopWhileVisible() {
    public void testMoveTaskToTopWhileVisible() {
        final Transition transition = createTestTransition(TRANSIT_OPEN);
        final Transition transition = createTestTransition(TRANSIT_OPEN);
        final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
        final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
        final ArraySet<WindowContainer> participants = transition.mParticipants;
        final ArraySet<WindowContainer> participants = transition.mParticipants;
@@ -2392,6 +2392,55 @@ public class TransitionTests extends WindowTestsBase {
        assertEquals(TRANSIT_CHANGE, info.getChanges().get(0).getMode());
        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 {
    private class OrderChangeTestSetup {
        final TransitionController mController;
        final TransitionController mController;
        final TestTransitionPlayer mPlayer;
        final TestTransitionPlayer mPlayer;