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

Commit 294c7e84 authored by Evan Rosky's avatar Evan Rosky Committed by Android (Google) Code Review
Browse files

Merge "Stabilize overview/quick-switch transitions" into udc-dev

parents 02b3713d 89e82322
Loading
Loading
Loading
Loading
+124 −59
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
import android.view.IRecentsAnimationController;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -106,12 +105,24 @@ public class RemoteTransitionCompat {
        private RecentsAnimationListener mListener = null;
        private RecentsAnimationControllerCompat mWrapped = null;
        private IRemoteTransitionFinishedCallback mFinishCB = null;

        /**
         * List of tasks that we are switching away from via this transition. Upon finish, these
         * pausing tasks will become invisible.
         * These need to be ordered since the order must be restored if there is no task-switch.
         */
        private ArrayList<TaskState> mPausingTasks = null;

        /**
         * List of tasks that we are switching to. Upon finish, these will remain visible and
         * on top.
         */
        private ArrayList<TaskState> mOpeningTasks = null;

        private WindowContainerToken mPipTask = null;
        private WindowContainerToken mRecentsTask = null;
        private int mRecentsTaskId = 0;
        private TransitionInfo mInfo = null;
        private ArrayList<SurfaceControl> mOpeningLeashes = null;
        private boolean mOpeningSeparateHome = false;
        private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
        private PictureInPictureSurfaceTransaction mPipTransaction = null;
@@ -120,6 +131,15 @@ public class RemoteTransitionCompat {
        private RemoteAnimationTarget[] mAppearedTargets;
        private boolean mWillFinishToHome = false;

        /** The animation is idle, waiting for the user to choose a task to switch to. */
        private static final int STATE_NORMAL = 0;

        /** The user chose a new task to switch to and the animation is animating to it. */
        private static final int STATE_NEW_TASK = 1;

        /** The latest state that the recents animation is operating in. */
        private int mState = STATE_NORMAL;

        void start(RecentsAnimationControllerCompat wrapped, RecentsAnimationListener listener,
                IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
                IRemoteTransitionFinishedCallback finishedCallback) {
@@ -132,12 +152,14 @@ public class RemoteTransitionCompat {
            mInfo = info;
            mFinishCB = finishedCallback;
            mPausingTasks = new ArrayList<>();
            mOpeningTasks = new ArrayList<>();
            mPipTask = null;
            mRecentsTask = null;
            mRecentsTaskId = -1;
            mLeashMap = new ArrayMap<>();
            mTransition = transition;
            mKeyguardLocked = (info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0;
            mState = STATE_NORMAL;

            final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
            final ArrayList<RemoteAnimationTarget> wallpapers = new ArrayList<>();
@@ -178,6 +200,9 @@ public class RemoteTransitionCompat {
                    } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
                        mRecentsTask = taskInfo.token;
                        mRecentsTaskId = taskInfo.taskId;
                    } else if (change.getMode() == TRANSIT_OPEN
                            || change.getMode() == TRANSIT_TO_FRONT) {
                        mOpeningTasks.add(new TaskState(change, target.leash));
                    }
                }
            }
@@ -189,34 +214,41 @@ public class RemoteTransitionCompat {

        @SuppressLint("NewApi")
        boolean merge(TransitionInfo info, SurfaceControl.Transaction t) {
            SparseArray<TransitionInfo.Change> openingTasks = null;
            ArrayList<TransitionInfo.Change> openingTasks = null;
            ArrayList<TransitionInfo.Change> closingTasks = null;
            mAppearedTargets = null;
            boolean foundHomeOpening = false;
            mOpeningSeparateHome = false;
            TransitionInfo.Change recentsOpening = null;
            boolean foundRecentsClosing = false;
            boolean hasChangingApp = false;
            for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter =
                    new RemoteAnimationTargetCompat.LeafTaskFilter();
            for (int i = 0; i < info.getChanges().size(); ++i) {
                final TransitionInfo.Change change = info.getChanges().get(i);
                if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
                final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
                    if (taskInfo != null) {
                final boolean isLeafTask = leafTaskFilter.test(change);
                if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
                    if (mRecentsTask.equals(change.getContainer())) {
                        recentsOpening = change;
                    } else if (isLeafTask) {
                        if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
                            // This is usually a 3p launcher
                            foundHomeOpening = true;
                            mOpeningSeparateHome = true;
                        }
                        if (openingTasks == null) {
                            openingTasks = new SparseArray<>();
                        }
                        if (taskInfo.hasParentTask()) {
                            // Collects opening leaf tasks only since Launcher monitors leaf task
                            // ids to perform recents animation.
                            openingTasks.remove(taskInfo.parentTaskId);
                            openingTasks = new ArrayList<>();
                        }
                        openingTasks.put(taskInfo.taskId, change);
                        openingTasks.add(change);
                    }
                } else if (change.getMode() == TRANSIT_CLOSE
                        || change.getMode() == TRANSIT_TO_BACK) {
                    if (mRecentsTask.equals(change.getContainer())) {
                        foundRecentsClosing = true;
                    } else if (isLeafTask) {
                        if (closingTasks == null) {
                            closingTasks = new ArrayList<>();
                        }
                        closingTasks.add(change);
                    }
                } else if (change.getMode() == TRANSIT_CHANGE) {
                    hasChangingApp = true;
@@ -234,45 +266,72 @@ public class RemoteTransitionCompat {
                }
                return false;
            }
            if (openingTasks == null) return false;
            int pauseMatches = 0;
            if (!foundHomeOpening) {
                for (int i = 0; i < openingTasks.size(); ++i) {
                    if (TaskState.indexOf(mPausingTasks, openingTasks.valueAt(i)) >= 0) {
                        ++pauseMatches;
                    }
                }
            }
            if (pauseMatches > 0) {
                if (pauseMatches != mPausingTasks.size()) {
                    // We are not really "returning" properly... something went wrong.
                    throw new IllegalStateException("\"Concelling\" a recents transitions by "
                            + "unpausing " + pauseMatches + " apps after pausing "
                            + mPausingTasks.size() + " apps.");
                }
                // In this case, we are "returning" to an already running app, so just consume
                // the merge and do nothing.
                info.releaseAllSurfaces();
                t.close();
                return true;
            }
            if (recentsOpening != null) {
                // the recents task re-appeared. This happens if the user gestures before the
                // task-switch (NEW_TASK) animation finishes.
                if (mState == STATE_NORMAL) {
                    Log.e(TAG, "Returning to recents while recents is already idle.");
                }
                if (closingTasks == null || closingTasks.size() == 0) {
                    Log.e(TAG, "Returning to recents without closing any opening tasks.");
                }
                // Setup may hide it initially since it doesn't know that overview was still active.
                t.show(recentsOpening.getLeash());
                t.setAlpha(recentsOpening.getLeash(), 1.f);
                mState = STATE_NORMAL;
            }
            boolean didMergeThings = false;
            if (closingTasks != null) {
                // Cancelling a task-switch. Move the tasks back to mPausing from mOpening
                for (int i = 0; i < closingTasks.size(); ++i) {
                    final TransitionInfo.Change change = closingTasks.get(i);
                    int openingIdx = TaskState.indexOf(mOpeningTasks, change);
                    if (openingIdx < 0) {
                        Log.e(TAG, "Back to existing recents animation from an unrecognized "
                                + "task: " + change.getTaskInfo().taskId);
                        continue;
                    }
                    mPausingTasks.add(mOpeningTasks.remove(openingIdx));
                    didMergeThings = true;
                }
            }
            if (openingTasks != null && openingTasks.size() > 0) {
                // Switching to some new tasks, add to mOpening and remove from mPausing. Also,
                // enter NEW_TASK state since this will start the switch-to animation.
                final int layer = mInfo.getChanges().size() * 3;
            mOpeningLeashes = new ArrayList<>();
            mOpeningSeparateHome = foundHomeOpening;
                final RemoteAnimationTarget[] targets =
                        new RemoteAnimationTarget[openingTasks.size()];
                for (int i = 0; i < openingTasks.size(); ++i) {
                final TransitionInfo.Change change = openingTasks.valueAt(i);
                mOpeningLeashes.add(change.getLeash());
                    final TransitionInfo.Change change = openingTasks.get(i);
                    int pausingIdx = TaskState.indexOf(mPausingTasks, change);
                    if (pausingIdx >= 0) {
                        // Something is showing/opening a previously-pausing app.
                        targets[i] = newTarget(change, layer, mPausingTasks.get(pausingIdx).mLeash);
                        mOpeningTasks.add(mPausingTasks.remove(pausingIdx));
                        // Setup hides opening tasks initially, so make it visible again (since we
                        // are already showing it).
                        t.show(change.getLeash());
                        t.setAlpha(change.getLeash(), 1.f);
                    } else {
                        // We are receiving new opening tasks, so convert to onTasksAppeared.
                        targets[i] = newTarget(change, layer, info, t, mLeashMap);
                        t.reparent(targets[i].leash, mInfo.getRootLeash());
                        t.setLayer(targets[i].leash, layer);
                        mOpeningTasks.add(new TaskState(change, targets[i].leash));
                    }
                }
                didMergeThings = true;
                mState = STATE_NEW_TASK;
                mAppearedTargets = targets;
            }
            if (!didMergeThings) {
                // Didn't recognize anything in incoming transition so don't merge it.
                Log.w(TAG, "Don't know how to merge this transition.");
                return false;
            }
            t.apply();
            // not using the incoming anim-only surfaces
            info.releaseAnimSurfaces();
            mAppearedTargets = targets;
            return true;
        }

@@ -300,6 +359,8 @@ public class RemoteTransitionCompat {
            if (enabled) {
                // transient launches don't receive focus automatically. Since we are taking over
                // the gesture now, take focus explicitly.
                // This also moves recents back to top if the user gestured before a switch
                // animation finished.
                try {
                    ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId);
                } catch (RemoteException e) {
@@ -336,8 +397,8 @@ public class RemoteTransitionCompat {
                if (toHome) wct.reorder(mRecentsTask, true /* toTop */);
                else wct.restoreTransientOrder(mRecentsTask);
            }
            if (!toHome && !mWillFinishToHome && mPausingTasks != null && mOpeningLeashes == null) {
                // The gesture went back to opening the app rather than continuing with
            if (!toHome && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL) {
                // The gesture is returning to the pausing-task(s) rather than continuing with
                // recents, so end the transition by moving the app back to the top (and also
                // re-showing it's task).
                for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
@@ -349,25 +410,28 @@ public class RemoteTransitionCompat {
                    wct.restoreTransientOrder(mRecentsTask);
                }
            } else if (toHome && mOpeningSeparateHome && mPausingTasks != null) {
                // Special situaition where 3p launcher was changed during recents (this happens
                // Special situation where 3p launcher was changed during recents (this happens
                // during tapltests...). Here we get both "return to home" AND "home opening".
                // This is basically going home, but we have to restore recents order and also
                // treat the home "pausing" task properly.
                for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
                    final TaskState state = mPausingTasks.get(i);
                // This is basically going home, but we have to restore the recents and home order.
                for (int i = 0; i < mOpeningTasks.size(); ++i) {
                    final TaskState state = mOpeningTasks.get(i);
                    if (state.mTaskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
                        // Treat as opening (see above)
                        // Make sure it is on top.
                        wct.reorder(state.mToken, true /* onTop */);
                    }
                    t.show(state.mTaskSurface);
                    } else {
                        // Treat as hiding (see below)
                        t.hide(state.mTaskSurface);
                }
                for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
                    t.hide(mPausingTasks.get(i).mTaskSurface);
                }
                if (!mKeyguardLocked && mRecentsTask != null) {
                    wct.restoreTransientOrder(mRecentsTask);
                }
            } else {
                // The general case: committing to recents, going home, or switching tasks.
                for (int i = 0; i < mOpeningTasks.size(); ++i) {
                    t.show(mOpeningTasks.get(i).mTaskSurface);
                }
                for (int i = 0; i < mPausingTasks.size(); ++i) {
                    if (!sendUserLeaveHint) {
                        // This means recents is not *actually* finishing, so of course we gotta
@@ -391,7 +455,7 @@ public class RemoteTransitionCompat {
            try {
                mFinishCB.onTransitionFinished(wct.isEmpty() ? null : wct, t);
            } catch (RemoteException e) {
                Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e);
                Log.e(TAG, "Failed to call animation finish callback", e);
                t.apply();
            }
            // Only release the non-local created surface references. The animator is responsible
@@ -402,12 +466,13 @@ public class RemoteTransitionCompat {
            mListener = null;
            mFinishCB = null;
            mPausingTasks = null;
            mOpeningTasks = null;
            mAppearedTargets = null;
            mInfo = null;
            mOpeningLeashes = null;
            mOpeningSeparateHome = false;
            mLeashMap = null;
            mTransition = null;
            mState = STATE_NORMAL;
        }

        @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+19 −1
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;

import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
@@ -2034,7 +2035,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
            return;
        }

        if (r.moveFocusableActivityToTop("setFocusedTask")) {
        final Transition transition = (getTransitionController().isCollecting()
                || !getTransitionController().isShellTransitionsEnabled()) ? null
                : getTransitionController().createTransition(TRANSIT_TO_FRONT);
        if (transition != null) {
            // Set ready before doing anything. If order does change, then that will set it unready
            // so that we wait for the new lifecycles to complete.
            transition.setReady(task, true /* ready */);
        }
        final boolean movedToTop = r.moveFocusableActivityToTop("setFocusedTask");
        if (movedToTop) {
            if (transition != null) {
                getTransitionController().requestStartTransition(
                        transition, null /* startTask */, null /* remote */, null /* display */);
            }
            mRootWindowContainer.resumeFocusedTasksTopActivities();
        } else if (touchedActivity != null && touchedActivity.isFocusable()) {
            final TaskFragment parent = touchedActivity.getTaskFragment();
@@ -2046,6 +2060,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
                        true /* updateInputWindows */);
            }
        }
        if (transition != null && !movedToTop) {
            // No order changes and focus-changes, alone, aren't captured in transitions.
            transition.abort();
        }
    }

    @Override