Merge "Implement back to launcher animation from shell and WM animation controllers." into tm-dev
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index df2b2a3..e898f57 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -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",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index e50ad38..08cb252 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -52,14 +52,17 @@
  */
 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 @@
                         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 @@
 
         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 @@
             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 @@
         }
     }
 
+    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 @@
             return;
         }
         RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget();
-        if (animationTarget != null && mTriggerBack) {
+        if (animationTarget != null) {
             if (animationTarget.leash != null && animationTarget.leash.isValid()) {
                 mTransaction.remove(animationTarget.leash);
             }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 9054685..3e7ee25 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -78,6 +78,7 @@
         MockitoAnnotations.initMocks(this);
         mController = new BackAnimationController(
                 mShellExecutor, mTransaction, mActivityTaskManager, mContext);
+        mController.setEnableAnimations(true);
     }
 
     private void createNavigationInfo(RemoteAnimationTarget topAnimationTarget,
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 487aff6..dbc0141 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -25,6 +25,7 @@
 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 @@
 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 @@
      * 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 @@
         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 @@
                 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;
-                }
+                systemCallback = window.getSystemOnBackInvokedCallback();
+            }
+            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 @@
                     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 @@
             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 @@
             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 @@
                 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 @@
                     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 @@
 
         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 @@
                 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) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index cd7ebe3..dd4dd5f 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -72,6 +72,7 @@
 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 @@
 
     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 @@
                     }
                 });
             }
+        } 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);
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index c21a5b6..92550a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -30,7 +30,10 @@
 import android.annotation.NonNull;
 import android.hardware.HardwareBuffer;
 import android.platform.test.annotations.Presubmit;
+import android.window.BackEvent;
 import android.window.BackNavigationInfo;
+import android.window.IOnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
 import android.window.TaskSnapshot;
 
 import org.junit.Before;
@@ -42,15 +45,19 @@
 public class BackNavigationControllerTests extends WindowTestsBase {
 
     private BackNavigationController mBackNavigationController;
+    private IOnBackInvokedCallback mOnBackInvokedCallback;
 
     @Before
     public void setUp() throws Exception {
         mBackNavigationController = new BackNavigationController();
+        mOnBackInvokedCallback = createBackCallback();
     }
 
     @Test
     public void backTypeHomeWhenBackToLauncher() {
         Task task = createTopTaskWithActivity();
+        registerSystemOnBackInvokedCallback();
+
         BackNavigationInfo backNavigationInfo =
                 mBackNavigationController.startBackNavigation(task, new StubTransaction());
         assertThat(backNavigationInfo).isNotNull();
@@ -63,6 +70,8 @@
         Task taskA = createTask(mDefaultDisplay);
         createActivityRecord(taskA);
         Task task = createTopTaskWithActivity();
+        registerSystemOnBackInvokedCallback();
+
         BackNavigationInfo backNavigationInfo =
                 mBackNavigationController.startBackNavigation(task, new StubTransaction());
         assertThat(backNavigationInfo).isNotNull();
@@ -75,6 +84,8 @@
         Task task = createTopTaskWithActivity();
         mAtm.setFocusedTask(task.mTaskId,
                 createAppWindow(task, FIRST_APPLICATION_WINDOW, "window").mActivityRecord);
+        registerSystemOnBackInvokedCallback();
+
         BackNavigationInfo backNavigationInfo =
                 mBackNavigationController.startBackNavigation(task, new StubTransaction());
         assertThat(backNavigationInfo).isNotNull();
@@ -89,6 +100,7 @@
     public void backNavInfoFullyPopulated() {
         Task task = createTopTaskWithActivity();
         createAppWindow(task, FIRST_APPLICATION_WINDOW, "window");
+        registerSystemOnBackInvokedCallback();
 
         // We need a mock screenshot so
         TaskSnapshotController taskSnapshotController = createMockTaskSnapshotController();
@@ -104,6 +116,30 @@
         assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
     }
 
+    @Test
+    public void preparesForBackToHome() {
+        Task task = createTopTaskWithActivity();
+        ActivityRecord activity = task.getTopActivity(false, false);
+        registerSystemOnBackInvokedCallback();
+
+        BackNavigationInfo backNavigationInfo =
+                mBackNavigationController.startBackNavigation(task, new StubTransaction());
+        assertThat(typeToString(backNavigationInfo.getType()))
+                .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
+    }
+
+    @Test
+    public void backTypeCallback() {
+        Task task = createTopTaskWithActivity();
+        ActivityRecord activity = task.getTopActivity(false, false);
+        registerApplicationOnBackInvokedCallback();
+
+        BackNavigationInfo backNavigationInfo =
+                mBackNavigationController.startBackNavigation(task, new StubTransaction());
+        assertThat(typeToString(backNavigationInfo.getType()))
+                .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK));
+    }
+
     @NonNull
     private TaskSnapshotController createMockTaskSnapshotController() {
         TaskSnapshotController taskSnapshotController = mock(TaskSnapshotController.class);
@@ -126,4 +162,30 @@
         mAtm.setFocusedTask(task.mTaskId, record);
         return task;
     }
+
+    private void registerSystemOnBackInvokedCallback() {
+        mWm.getFocusedWindowLocked().setOnBackInvokedCallback(
+                mOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_SYSTEM);
+    }
+
+    private void registerApplicationOnBackInvokedCallback() {
+        mWm.getFocusedWindowLocked().setOnBackInvokedCallback(
+                mOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+    }
+
+    private IOnBackInvokedCallback createBackCallback() {
+        return new IOnBackInvokedCallback.Stub() {
+            @Override
+            public void onBackStarted() { }
+
+            @Override
+            public void onBackProgressed(BackEvent backEvent) { }
+
+            @Override
+            public void onBackCancelled() { }
+
+            @Override
+            public void onBackInvoked() { }
+        };
+    }
 }