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

Commit 3e2980ed authored by Winson Chung's avatar Winson Chung
Browse files

Generalize the recents animation to work with non-home activity.

- When quickstep is enabled with 3p launchers, we need to still swipe up
  to the recents component activity (as defined in the framework resource),
  which is started in the recents stack. This CL resolves the target by
  looking at the target intent (only resolving to HOME or RECENTS) to
  determine which stack to use for the transition.

Bug: 77157702
Test: atest FrameworksServicesTests:com.android.server.am.ActivityStackTests
Test: Manual, ensure we can still swipe up to home and also to fallback
      activity when launcher is not the default home

Change-Id: If98f63cfd561861b1772249079ed07e8354142e0
parent c4a5f78b
Loading
Loading
Loading
Loading
+26 −33
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.server.am;

import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -44,7 +43,6 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.IntArray;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -702,57 +700,52 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
    }

    /**
     * @return the stack currently above the home stack.  Can be null if there is no home stack, or
     *         the home stack is already on top.
     * @return the stack currently above the {@param stack}.  Can be null if the {@param stack} is
     *         already top-most.
     */
    ActivityStack getStackAboveHome() {
        if (mHomeStack == null) {
            // Skip if there is no home stack
            return null;
        }

        final int stackIndex = mStacks.indexOf(mHomeStack) + 1;
    ActivityStack getStackAbove(ActivityStack stack) {
        final int stackIndex = mStacks.indexOf(stack) + 1;
        return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
    }

    /**
     * Adjusts the home stack behind the last visible stack in the display if necessary. Generally
     * used in conjunction with {@link #moveHomeStackBehindStack}.
     * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
     * Generally used in conjunction with {@link #moveStackBehindStack}.
     */
    void moveHomeStackBehindBottomMostVisibleStack() {
        if (mHomeStack == null || mHomeStack.shouldBeVisible(null)) {
            // Skip if there is no home stack, or if it is already visible
    void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
        if (stack.shouldBeVisible(null)) {
            // Skip if the stack is already visible
            return;
        }

        // Move the home stack to the bottom to not affect the following visibility checks
        positionChildAtBottom(mHomeStack);
        // Move the stack to the bottom to not affect the following visibility checks
        positionChildAtBottom(stack);

        // Find the next position where the homes stack should be placed
        // Find the next position where the stack should be placed
        final int numStacks = mStacks.size();
        for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
            final ActivityStack stack = mStacks.get(stackNdx);
            if (stack == mHomeStack) {
            final ActivityStack s = mStacks.get(stackNdx);
            if (s == stack) {
                continue;
            }
            final int winMode = stack.getWindowingMode();
            final int winMode = s.getWindowingMode();
            final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
                    winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
            if (stack.shouldBeVisible(null) && isValidWindowingMode) {
                // Move the home stack to behind this stack
                positionChildAt(mHomeStack, Math.max(0, stackNdx - 1));
            if (s.shouldBeVisible(null) && isValidWindowingMode) {
                // Move the provided stack to behind this stack
                positionChildAt(stack, Math.max(0, stackNdx - 1));
                break;
            }
        }
    }

    /**
     * Moves the home stack behind the given {@param stack} if possible. If {@param stack} is not
     * currently in the display, then then the home stack is moved to the back. Generally used in
     * conjunction with {@link #moveHomeStackBehindBottomMostVisibleStack}.
     * Moves the {@param stack} behind the given {@param behindStack} if possible. If
     * {@param behindStack} is not currently in the display, then then the stack is moved to the
     * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
     */
    void moveHomeStackBehindStack(ActivityStack behindStack) {
        if (behindStack == null || behindStack == mHomeStack) {
    void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
        if (behindStack == null || behindStack == stack) {
            return;
        }

@@ -760,11 +753,11 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
        // list, so we need to adjust the insertion index to account for the removed index
        // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
        //       position internally
        final int homeStackIndex = mStacks.indexOf(mHomeStack);
        final int stackIndex = mStacks.indexOf(stack);
        final int behindStackIndex = mStacks.indexOf(behindStack);
        final int insertIndex = homeStackIndex <= behindStackIndex
        final int insertIndex = stackIndex <= behindStackIndex
                ? behindStackIndex - 1 : behindStackIndex;
        positionChildAt(mHomeStack, Math.max(0, insertIndex));
        positionChildAt(stack, Math.max(0, insertIndex));
    }

    boolean isSleeping() {
+5 −4
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import static android.app.ActivityManagerInternal.ASSIST_KEY_STRUCTURE;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -205,8 +206,8 @@ import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_HOME_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -5246,8 +5247,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        try {
            synchronized (this) {
                mWindowManager.cancelRecentsAnimation(restoreHomeStackPosition
                        ? REORDER_MOVE_HOME_TO_ORIGINAL_POSITION
                        : REORDER_KEEP_HOME_IN_PLACE);
                        ? REORDER_MOVE_TO_ORIGINAL_POSITION
                        : REORDER_KEEP_IN_PLACE);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
+71 −55
Original line number Diff line number Diff line
@@ -18,19 +18,20 @@ package com.android.server.am;

import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.WindowManager.TRANSIT_NONE;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_HOME_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_TOP;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;

import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Handler;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Slog;
@@ -51,16 +52,20 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
    private final ActivityStartController mActivityStartController;
    private final WindowManagerService mWindowManager;
    private final UserController mUserController;
    private final ActivityDisplay mDefaultDisplay;
    private final int mCallingPid;

    // The stack to restore the home stack behind when the animation is finished
    private ActivityStack mRestoreHomeBehindStack;
    private int mTargetActivityType;

    // The stack to restore the target stack behind when the animation is finished
    private ActivityStack mRestoreTargetBehindStack;

    RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor,
            ActivityStartController activityStartController, WindowManagerService wm,
            UserController userController, int callingPid) {
        mService = am;
        mStackSupervisor = stackSupervisor;
        mDefaultDisplay = stackSupervisor.getDefaultDisplay();
        mActivityStartController = activityStartController;
        mWindowManager = wm;
        mUserController = userController;
@@ -76,23 +81,31 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
            return;
        }

        // If the existing home activity is already on top, then cancel
        ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
        final boolean hasExistingHomeActivity = homeActivity != null;
        if (hasExistingHomeActivity) {
            final ActivityDisplay display = homeActivity.getDisplay();
            mRestoreHomeBehindStack = display.getStackAboveHome();
            if (mRestoreHomeBehindStack == null) {
        // If the activity is associated with the recents stack, then try and get that first
        mTargetActivityType = intent.getComponent() != null
                && recentsComponent.equals(intent.getComponent())
                        ? ACTIVITY_TYPE_RECENTS
                        : ACTIVITY_TYPE_HOME;
        final ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
                mTargetActivityType);
        ActivityRecord targetActivity = targetStack != null
                ? targetStack.getTopActivity()
                : null;
        final boolean hasExistingActivity = targetActivity != null;
        if (hasExistingActivity) {
            final ActivityDisplay display = targetActivity.getDisplay();
            mRestoreTargetBehindStack = display.getStackAbove(targetStack);
            if (mRestoreTargetBehindStack == null) {
                notifyAnimationCancelBeforeStart(recentsAnimationRunner);
                return;
            }
        }

        // Send launch hint if we are actually launching home. If it's already visible (shouldn't
        // happen in general) we don't need to send it.
        if (homeActivity == null || !homeActivity.visible) {
        // Send launch hint if we are actually launching the target. If it's already visible
        // (shouldn't happen in general) we don't need to send it.
        if (targetActivity == null || !targetActivity.visible) {
            mStackSupervisor.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */,
                    homeActivity);
                    targetActivity);
        }

        mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
@@ -102,48 +115,49 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
        mWindowManager.deferSurfaceLayout();
        try {
            final ActivityDisplay display;
            if (hasExistingHomeActivity) {
                // Move the home activity into place for the animation if it is not already top most
                display = homeActivity.getDisplay();
                display.moveHomeStackBehindBottomMostVisibleStack();
            if (hasExistingActivity) {
                // Move the recents activity into place for the animation if it is not top most
                display = targetActivity.getDisplay();
                display.moveStackBehindBottomMostVisibleStack(targetStack);
            } else {
                // No home activity
                final ActivityOptions opts = ActivityOptions.makeBasic();
                opts.setLaunchActivityType(ACTIVITY_TYPE_HOME);
                opts.setAvoidMoveToFront();
                // No recents activity
                ActivityOptions options = ActivityOptions.makeBasic();
                options.setLaunchActivityType(mTargetActivityType);
                options.setAvoidMoveToFront();
                intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION);

                mActivityStartController
                        .obtainStarter(intent, "startRecentsActivity_noHomeActivity")
                        .obtainStarter(intent, "startRecentsActivity_noTargetActivity")
                        .setCallingUid(recentsUid)
                        .setCallingPackage(recentsComponent.getPackageName())
                        .setActivityOptions(SafeActivityOptions.fromBundle(opts.toBundle()))
                        .setActivityOptions(SafeActivityOptions.fromBundle(options.toBundle()))
                        .setMayWait(mUserController.getCurrentUserId())
                        .execute();
                mWindowManager.prepareAppTransition(TRANSIT_NONE, false);

                homeActivity = mStackSupervisor.getHomeActivity();
                display = homeActivity.getDisplay();
                targetActivity = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
                        mTargetActivityType).getTopActivity();
                display = targetActivity.getDisplay();

                // TODO: Maybe wait for app to draw in this particular case?
            }

            // Mark the home activity as launch-behind to bump its visibility for the
            // Mark the target activity as launch-behind to bump its visibility for the
            // duration of the gesture that is driven by the recents component
            homeActivity.mLaunchTaskBehind = true;
            targetActivity.mLaunchTaskBehind = true;

            // Fetch all the surface controls and pass them to the client to get the animation
            // started
            mWindowManager.cancelRecentsAnimation(REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
            mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this,
                    display.mDisplayId, mStackSupervisor.mRecentTasks.getRecentTaskIds());
            mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
            mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner,
                    this, display.mDisplayId, mStackSupervisor.mRecentTasks.getRecentTaskIds());

            // If we updated the launch-behind state, update the visibility of the activities after
            // we fetch the visible tasks to be controlled by the animation
            mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);

            mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT,
                    homeActivity);
                    targetActivity);
        } finally {
            mWindowManager.continueSurfaceLayout();
            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
@@ -155,9 +169,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
        synchronized (mService) {
            if (mWindowManager.getRecentsAnimationController() == null) return;

            // Just to be sure end the launch hint in case home was never launched. However, if
            // we're keeping home and making it visible, we can leave it on.
            if (reorderMode != REORDER_KEEP_HOME_IN_PLACE) {
            // Just to be sure end the launch hint in case the target activity was never launched.
            // However, if we're keeping the activity and making it visible, we can leave it on.
            if (reorderMode != REORDER_KEEP_IN_PLACE) {
                mStackSupervisor.sendPowerHintForLaunchEndIfNeeded();
            }

@@ -170,26 +184,27 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
                try {
                    mWindowManager.cleanupRecentsAnimation(reorderMode);

                    final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
                    if (homeActivity == null) {
                    final ActivityStack targetStack = mDefaultDisplay.getStack(
                            WINDOWING_MODE_UNDEFINED, mTargetActivityType);
                    final ActivityRecord targetActivity = targetStack.getTopActivity();
                    if (targetActivity == null) {
                        return;
                    }

                    // Restore the launched-behind state
                    homeActivity.mLaunchTaskBehind = false;

                    if (reorderMode == REORDER_MOVE_HOME_TO_TOP) {
                        // Bring the home stack to the front
                        final ActivityStack homeStack = homeActivity.getStack();
                        mStackSupervisor.mNoAnimActivities.add(homeActivity);
                        homeStack.moveToFront("RecentsAnimation.onAnimationFinished()");
                    } else if (reorderMode == REORDER_MOVE_HOME_TO_ORIGINAL_POSITION){
                        // Restore the home stack to its previous position
                        final ActivityDisplay display = homeActivity.getDisplay();
                        display.moveHomeStackBehindStack(mRestoreHomeBehindStack);
                    targetActivity.mLaunchTaskBehind = false;

                    if (reorderMode == REORDER_MOVE_TO_TOP) {
                        // Bring the target stack to the front
                        mStackSupervisor.mNoAnimActivities.add(targetActivity);
                        targetStack.moveToFront("RecentsAnimation.onAnimationFinished()");
                    } else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){
                        // Restore the target stack to its previous position
                        final ActivityDisplay display = targetActivity.getDisplay();
                        display.moveStackBehindStack(targetStack, mRestoreTargetBehindStack);
                    } else {
                        // Keep home stack in place, nothing changes, so ignore the transition logic
                        // below
                        // Keep target stack in place, nothing changes, so ignore the transition
                        // logic below
                        return;
                    }

@@ -202,8 +217,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
                    mWindowManager.executeAppTransition();

                    // After reordering the stacks, reset the minimized state. At this point, either
                    // home is now top-most and we will stay minimized (if in split-screen), or we
                    // will have returned to the app, and the minimized state should be reset
                    // the target activity is now top-most and we will stay minimized (if in
                    // split-screen), or we will have returned to the app, and the minimized state
                    // should be reset
                    mWindowManager.checkSplitScreenMinimizedChanged(true /* animate */);
                } finally {
                    mWindowManager.continueSurfaceLayout();
+43 −40

File changed.

Preview size limit exceeded, changes collapsed.

+2 −2
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;

import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_HOME_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
@@ -620,7 +620,7 @@ class WallpaperController {
            // If there was a recents animation in progress, cancel that animation
            if (mService.getRecentsAnimationController() != null) {
                mService.getRecentsAnimationController().cancelAnimation(
                        REORDER_MOVE_HOME_TO_ORIGINAL_POSITION);
                        REORDER_MOVE_TO_ORIGINAL_POSITION);
            }
            return true;
        }
Loading