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

Commit 0e9d709e authored by Shan Huang's avatar Shan Huang
Browse files

Implement back to launcher animation from shell and WM animation

controllers.

Test: m -j.
Test: Open and swipe back on pre-T and T apps.
Test: atest BackNavigationControllerTests
Test: atest BackAnimationControllerTest
Bug: 195946584

Change-Id: I981f8deff9fad75355ee0e8bbe08b375f4da6e74
parent e8acb4a6
Loading
Loading
Loading
Loading
+27 −9
Original line number Diff line number Diff line
@@ -1309,6 +1309,12 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-711194343": {
      "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
      "level": "DEBUG",
      "group": "WM_DEBUG_BACK_PREVIEW",
      "at": "com\/android\/server\/wm\/BackNavigationController.java"
    },
    "-706481945": {
      "message": "TaskFragment parent info changed name=%s parentTaskId=%d",
      "level": "VERBOSE",
@@ -2587,6 +2593,12 @@
      "group": "WM_DEBUG_APP_TRANSITIONS",
      "at": "com\/android\/server\/wm\/WindowState.java"
    },
    "599897753": {
      "message": "Previous Activity is %s. Back type is %s",
      "level": "DEBUG",
      "group": "WM_DEBUG_BACK_PREVIEW",
      "at": "com\/android\/server\/wm\/BackNavigationController.java"
    },
    "600140673": {
      "message": "checkBootAnimationComplete: Waiting for anim complete",
      "level": "INFO",
@@ -2671,12 +2683,6 @@
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "664667685": {
      "message": "Activity %s: enableOnBackInvokedCallback=false. Returning null BackNavigationInfo.",
      "level": "DEBUG",
      "group": "WM_DEBUG_BACK_PREVIEW",
      "at": "com\/android\/server\/wm\/BackNavigationController.java"
    },
    "665256544": {
      "message": "All windows drawn!",
      "level": "DEBUG",
@@ -2887,6 +2893,12 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/TaskFragment.java"
    },
    "948208142": {
      "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
      "level": "DEBUG",
      "group": "WM_DEBUG_BACK_PREVIEW",
      "at": "com\/android\/server\/wm\/BackNavigationController.java"
    },
    "950074526": {
      "message": "setLockTaskMode: Can't lock due to auth",
      "level": "WARN",
@@ -3103,6 +3115,12 @@
      "group": "WM_DEBUG_APP_TRANSITIONS",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "1172542963": {
      "message": "onBackNavigationDone backType=%s, task=%s, prevTaskTopActivity=%s",
      "level": "DEBUG",
      "group": "WM_DEBUG_BACK_PREVIEW",
      "at": "com\/android\/server\/wm\/BackNavigationController.java"
    },
    "1178653181": {
      "message": "Old wallpaper still the target.",
      "level": "VERBOSE",
@@ -3415,11 +3433,11 @@
      "group": "WM_DEBUG_APP_TRANSITIONS",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "1554795024": {
      "message": "Previous Activity is %s",
    "1544805551": {
      "message": "Skipping app transition animation. task=%s",
      "level": "DEBUG",
      "group": "WM_DEBUG_BACK_PREVIEW",
      "at": "com\/android\/server\/wm\/BackNavigationController.java"
      "at": "com\/android\/server\/wm\/Task.java"
    },
    "1557732761": {
      "message": "For Intent %s bringing to top: %s",
+21 −8
Original line number Diff line number Diff line
@@ -52,14 +52,17 @@ import com.android.wm.shell.common.annotations.ShellMainThread;
 */
public class BackAnimationController implements RemoteCallable<BackAnimationController> {

    private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
    public static final boolean IS_ENABLED = SystemProperties
            .getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
    private static final String BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP =
            "persist.debug.back_predictability_progress_threshold";
    // By default, enable new back dispatching without any animations.
    private static final int BACK_PREDICTABILITY_PROP =
            SystemProperties.getInt("persist.debug.back_predictability", 1);
    public static final boolean IS_ENABLED = BACK_PREDICTABILITY_PROP > 0;
    private static final int PROGRESS_THRESHOLD = SystemProperties
            .getInt(BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP, -1);
    private static final String TAG = "BackAnimationController";
    @VisibleForTesting
    boolean mEnableAnimations = (BACK_PREDICTABILITY_PROP & (1 << 1)) != 0;

    /**
     * Location of the initial touch event of the back gesture.
@@ -255,7 +258,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
                        backNavigationInfo.getTaskWindowConfiguration());
            }
            mTransaction.apply();
        } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
        } else if (shouldDispatchToLauncher(backType)) {
            targetCallback = mBackToLauncherCallback;
        } else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
            targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
@@ -309,7 +312,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont

        BackEvent backEvent = new BackEvent(0, 0, progress, swipeEdge, animationTarget);
        IOnBackInvokedCallback targetCallback = null;
        if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
        if (shouldDispatchToLauncher(backType)) {
            targetCallback = mBackToLauncherCallback;
        } else if (backType == BackNavigationInfo.TYPE_CROSS_TASK
                || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
@@ -330,8 +333,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            return;
        }
        int backType = mBackNavigationInfo.getType();
        boolean shouldDispatchToLauncher = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
                && mBackToLauncherCallback != null;
        boolean shouldDispatchToLauncher = shouldDispatchToLauncher(backType);
        IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
                ? mBackToLauncherCallback
                : mBackNavigationInfo.getOnBackInvokedCallback();
@@ -356,6 +358,17 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        }
    }

    private boolean shouldDispatchToLauncher(int backType) {
        return backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
                && mBackToLauncherCallback != null
                && mEnableAnimations;
    }

    @VisibleForTesting
    void setEnableAnimations(boolean shouldEnable) {
        mEnableAnimations = shouldEnable;
    }

    private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
        if (callback == null) {
            return;
@@ -468,7 +481,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            return;
        }
        RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget();
        if (animationTarget != null && mTriggerBack) {
        if (animationTarget != null) {
            if (animationTarget.leash != null && animationTarget.leash.isValid()) {
                mTransaction.remove(animationTarget.leash);
            }
+1 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ public class BackAnimationControllerTest {
        MockitoAnnotations.initMocks(this);
        mController = new BackAnimationController(
                mShellExecutor, mTransaction, mActivityTaskManager, mContext);
        mController.setEnableAnimations(true);
    }

    private void createNavigationInfo(RemoteAnimationTarget topAnimationTarget,
+93 −27
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -44,7 +45,11 @@ import com.android.internal.protolog.common.ProtoLog;
class BackNavigationController {

    private static final String TAG = "BackNavigationController";
    private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
    // By default, enable new back dispatching without any animations.
    private static final int BACK_PREDICTABILITY_PROP =
            SystemProperties.getInt("persist.debug.back_predictability", 1);
    private static final int ANIMATIONS_MASK = 1 << 1;
    private static final int SCREENSHOT_MASK = 1 << 2;

    @Nullable
    private TaskSnapshotController mTaskSnapshotController;
@@ -53,11 +58,15 @@ class BackNavigationController {
     * Returns true if the back predictability feature is enabled
     */
    static boolean isEnabled() {
        return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
        return BACK_PREDICTABILITY_PROP > 0;
    }

    static boolean isScreenshotEnabled() {
        return false;
        return (BACK_PREDICTABILITY_PROP & SCREENSHOT_MASK) != 0;
    }

    private static boolean isAnimationEnabled() {
        return (BACK_PREDICTABILITY_PROP & ANIMATIONS_MASK) != 0;
    }

    /**
@@ -93,14 +102,17 @@ class BackNavigationController {
        ActivityRecord prev;
        WindowContainer<?> removedWindowContainer;
        ActivityRecord activityRecord;
        ActivityRecord prevTaskTopActivity = null;
        SurfaceControl animationLeashParent;
        WindowConfiguration taskWindowConfiguration;
        HardwareBuffer screenshotBuffer = null;
        SurfaceControl screenshotSurface;
        int prevTaskId;
        int prevUserId;
        RemoteAnimationTarget topAppTarget;
        SurfaceControl animLeash;
        IOnBackInvokedCallback callback = null;
        IOnBackInvokedCallback applicationCallback = null;
        IOnBackInvokedCallback systemCallback = null;

        synchronized (task.mWmService.mGlobalLock) {

@@ -116,15 +128,14 @@ class BackNavigationController {
                removedWindowContainer = activityRecord;
                taskWindowConfiguration = window.getWindowConfiguration();
            }
            IOnBackInvokedCallback applicationCallback = null;
            IOnBackInvokedCallback systemCallback = null;
            if (window != null) {
                applicationCallback = window.getApplicationOnBackInvokedCallback();
                callback = applicationCallback;
                if (callback == null) {
                systemCallback = window.getSystemOnBackInvokedCallback();
                    callback = systemCallback;
            }
            if (applicationCallback == null && systemCallback == null) {
                // Return null when either there's no window, or apps have just initialized and
                // have not finished registering callbacks.
                return null;
            }

            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, "
@@ -133,24 +144,24 @@ class BackNavigationController {
                    task, activityRecord, applicationCallback, systemCallback);

            // TODO Temp workaround for Sysui until b/221071505 is fixed
            if (activityRecord == null && callback != null) {
            if (activityRecord == null && applicationCallback != null) {
                return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
                        null /* topWindowLeash */, null /* screenshotSurface */,
                        null /* screenshotBuffer */, null /* taskWindowConfiguration */,
                        null /* onBackNavigationDone */,
                        callback /* onBackInvokedCallback */);
                        applicationCallback /* onBackInvokedCallback */);
            }

            // For IME and Home, either a callback is registered, or we do nothing. In both cases,
            // we don't need to pass the leashes below.
            if (activityRecord == null || task.getDisplayContent().getImeContainer().isVisible()
                    || activityRecord.isActivityTypeHome()) {
                if (callback != null) {
                if (applicationCallback != null) {
                    return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
                            null /* topWindowLeash */, null /* screenshotSurface */,
                            null /* screenshotBuffer */, null /* taskWindowConfiguration */,
                            null /* onBackNavigationDone */,
                            callback /* onBackInvokedCallback */);
                            applicationCallback /* onBackInvokedCallback */);
                } else {
                    return null;
                }
@@ -159,12 +170,12 @@ class BackNavigationController {
            prev = task.getActivity(
                    (r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());

            if (callback != null) {
            if (applicationCallback != null) {
                return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
                        null /* topWindowLeash */, null /* screenshotSurface */,
                        null /* screenshotBuffer */, null /* taskWindowConfiguration */,
                        null /* onBackNavigationDone */,
                        callback /* onBackInvokedCallback */);
                        applicationCallback /* onBackInvokedCallback */);
            } else if (prev != null) {
                backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
            } else if (task.returnsToHomeRootTask()) {
@@ -188,8 +199,8 @@ class BackNavigationController {
            prevTaskId = prevTask != null ? prevTask.mTaskId : 0;
            prevUserId = prevTask != null ? prevTask.mUserId : 0;

            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s",
                    prev != null ? prev.mActivityComponent : null);
            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s. "
                    + "Back type is %s", prev != null ? prev.mActivityComponent : null, backType);

            //TODO(207481538) Remove once the infrastructure to support per-activity screenshot is
            // implemented. For now we simply have the mBackScreenshots hash map that dumbly
@@ -204,6 +215,7 @@ class BackNavigationController {
                return null;
            }
            // Prepare a leash to animate the current top window
            // TODO(b/220934562): Use surface animator to better manage animation conflicts.
            animLeash = removedWindowContainer.makeAnimationLeash()
                    .setName("BackPreview Leash for " + removedWindowContainer)
                    .setHidden(false)
@@ -231,12 +243,30 @@ class BackNavigationController {
                    activityRecord.windowType);
        }

        SurfaceControl.Builder builder = new SurfaceControl.Builder()
        screenshotSurface = new SurfaceControl.Builder()
                .setName("BackPreview Screenshot for " + prev)
                .setParent(animationLeashParent)
                .setHidden(false)
                .setBLASTLayer();
        SurfaceControl screenshotSurface = builder.build();
                .setBLASTLayer()
                .build();
        if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
            task.mBackGestureStarted = true;
            // Make launcher show from behind by marking its top activity as visible and
            // launch-behind to bump its visibility for the duration of the back gesture.
            prevTaskTopActivity = prevTask.getTopNonFinishingActivity();
            if (prevTaskTopActivity != null) {
                if (!prevTaskTopActivity.mVisibleRequested) {
                    prevTaskTopActivity.setVisibility(true);
                }
                prevTaskTopActivity.mLaunchTaskBehind = true;
                ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
                        "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
                        prevTaskTopActivity);
                prevTaskTopActivity.mRootWindowContainer.ensureActivitiesVisible(
                        null /* starting */, 0 /* configChanges */,
                        false /* preserveWindows */);
            }
        }

        // Find a screenshot of the previous activity

@@ -253,17 +283,20 @@ class BackNavigationController {

        WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
        try {
            activityRecord.token.linkToDeath(
                    () -> resetSurfaces(finalRemovedWindowContainer), 0);
            activityRecord.token.linkToDeath(() -> resetSurfaces(finalRemovedWindowContainer), 0);
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to link to death", e);
            resetSurfaces(removedWindowContainer);
            return null;
        }

        RemoteCallback onBackNavigationDone = new RemoteCallback(
                result -> resetSurfaces(finalRemovedWindowContainer
                ));
        int finalBackType = backType;
        final IOnBackInvokedCallback callback =
                applicationCallback != null ? applicationCallback : systemCallback;
        ActivityRecord finalPrevTaskTopActivity = prevTaskTopActivity;
        RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
                result, finalRemovedWindowContainer, finalBackType, task,
                finalPrevTaskTopActivity));
        return new BackNavigationInfo(backType,
                topAppTarget,
                screenshotSurface,
@@ -273,6 +306,39 @@ class BackNavigationController {
                callback);
    }

    private void onBackNavigationDone(
            Bundle result, WindowContainer windowContainer, int backType,
            Task task, ActivityRecord prevTaskTopActivity) {
        SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
        boolean triggerBack = result != null
                ? result.getBoolean(BackNavigationInfo.KEY_TRIGGER_BACK)
                : false;
        ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
                + "task=%s, prevTaskTopActivity=%s", backType, task, prevTaskTopActivity);

        if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
            if (triggerBack) {
                if (surfaceControl != null && surfaceControl.isValid()) {
                    // When going back to home, hide the task surface before it is re-parented to
                    // avoid flicker.
                    SurfaceControl.Transaction t = windowContainer.getSyncTransaction();
                    t.hide(surfaceControl);
                    t.apply();
                }
            }
            if (prevTaskTopActivity != null && !triggerBack) {
                // Restore the launch-behind state.
                task.mTaskSupervisor.scheduleLaunchTaskBehindComplete(prevTaskTopActivity.token);
                prevTaskTopActivity.mLaunchTaskBehind = false;
                ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
                        "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
                        prevTaskTopActivity);
            }
        } else {
            task.mBackGestureStarted = false;
        }
        resetSurfaces(windowContainer);
    }

    private HardwareBuffer getActivitySnapshot(@NonNull Task task,
            ComponentName activityComponent) {
+15 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
@@ -609,6 +610,12 @@ class Task extends TaskFragment {

    boolean mLastSurfaceShowing = true;

    /**
     * Tracks if a back gesture is in progress.
     * Skips any system transition animations if this is set to {@code true}.
     */
    boolean mBackGestureStarted = false;

    private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
            Intent _affinityIntent, String _affinity, String _rootAffinity,
            ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -3322,6 +3329,14 @@ class Task extends TaskFragment {
                    }
                });
            }
        } else if (mBackGestureStarted) {
            // Cancel playing transitions if a back navigation animation is in progress.
            // This bit is set by {@link BackNavigationController} when a back gesture is started.
            // It is used as a one-off transition overwrite that is cleared when the back gesture
            // is committed and triggers a transition, or when the gesture is cancelled.
            mBackGestureStarted = false;
            mDisplayContent.mSkipAppTransitionAnimation = true;
            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Skipping app transition animation. task=%s", this);
        } else {
            super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
        }
Loading