Merge "Apply transaction when starting back nav" into tm-dev

This commit is contained in:
TreeHugger Robot
2022-04-13 05:04:39 +00:00
committed by Android (Google) Code Review
3 changed files with 111 additions and 87 deletions

View File

@@ -703,12 +703,6 @@
"group": "WM_DEBUG_STATES", "group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java" "at": "com\/android\/server\/wm\/ActivityRecord.java"
}, },
"-1427392850": {
"message": "WindowState: Setting back callback %s (priority: %d) (Client IWindow: %s). (WindowState: %s)",
"level": "DEBUG",
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/WindowState.java"
},
"-1427184084": { "-1427184084": {
"message": "addWindow: New client %s: window=%s Callers=%s", "message": "addWindow: New client %s: window=%s Callers=%s",
"level": "VERBOSE", "level": "VERBOSE",
@@ -859,6 +853,12 @@
"group": "WM_DEBUG_ANIM", "group": "WM_DEBUG_ANIM",
"at": "com\/android\/server\/wm\/WindowState.java" "at": "com\/android\/server\/wm\/WindowState.java"
}, },
"-1277068810": {
"message": "startBackNavigation currentTask=%s, topRunningActivity=%s, callbackInfo=%s, currentFocus=%s",
"level": "DEBUG",
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
"-1270731689": { "-1270731689": {
"message": "Attempted to set replacing window on app token with no content %s", "message": "Attempted to set replacing window on app token with no content %s",
"level": "WARN", "level": "WARN",
@@ -1099,12 +1099,6 @@
"group": "WM_DEBUG_STATES", "group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java" "at": "com\/android\/server\/wm\/ActivityRecord.java"
}, },
"-1010850753": {
"message": "No focused window, defaulting to top task's window",
"level": "WARN",
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
"-1009117329": { "-1009117329": {
"message": "isFetchingAppTransitionSpecs=true", "message": "isFetchingAppTransitionSpecs=true",
"level": "VERBOSE", "level": "VERBOSE",
@@ -3043,12 +3037,6 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS", "group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java" "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
}, },
"878005951": {
"message": "startBackNavigation task=%s, topRunningActivity=%s, callbackInfo=%s, currentFocus=%s",
"level": "DEBUG",
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
"892244061": { "892244061": {
"message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d", "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
"level": "INFO", "level": "INFO",
@@ -3331,12 +3319,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS", "group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/DisplayContent.java" "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"
},
"1175495463": { "1175495463": {
"message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s", "message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s",
"level": "INFO", "level": "INFO",
@@ -3409,6 +3391,12 @@
"group": "WM_DEBUG_STARTING_WINDOW", "group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java" "at": "com\/android\/server\/wm\/ActivityRecord.java"
}, },
"1264179654": {
"message": "No focused window, defaulting to top current task's window",
"level": "WARN",
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
"1270792394": { "1270792394": {
"message": "Resumed after relaunch %s", "message": "Resumed after relaunch %s",
"level": "DEBUG", "level": "DEBUG",
@@ -3859,6 +3847,12 @@
"group": "WM_ERROR", "group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java" "at": "com\/android\/server\/wm\/WindowManagerService.java"
}, },
"1778919449": {
"message": "onBackNavigationDone backType=%s, task=%s, prevActivity=%s",
"level": "DEBUG",
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
"1781673113": { "1781673113": {
"message": "onAnimationFinished(): targetRootTask=%s targetActivity=%s mRestoreTargetBehindRootTask=%s", "message": "onAnimationFinished(): targetRootTask=%s targetActivity=%s mRestoreTargetBehindRootTask=%s",
"level": "DEBUG", "level": "DEBUG",

View File

@@ -94,12 +94,22 @@ class BackNavigationController {
} }
int backType = BackNavigationInfo.TYPE_UNDEFINED; int backType = BackNavigationInfo.TYPE_UNDEFINED;
// The currently visible activity (if any).
ActivityRecord currentActivity = null;
// The currently visible task (if any).
Task currentTask = null;
// The previous task we're going back to. Can be the same as currentTask, if there are
// multiple Activities in the Stack.
Task prevTask = null; Task prevTask = null;
ActivityRecord prev;
// The previous activity we're going back to. This can be either a child of currentTask
// if there are more than one Activity in currentTask, or a child of prevTask, if
// currentActivity is the last child of currentTask.
ActivityRecord prevActivity;
WindowContainer<?> removedWindowContainer = null; WindowContainer<?> removedWindowContainer = null;
ActivityRecord activityRecord = null;
ActivityRecord prevTaskTopActivity = null;
Task task = null;
SurfaceControl animationLeashParent = null; SurfaceControl animationLeashParent = null;
HardwareBuffer screenshotBuffer = null; HardwareBuffer screenshotBuffer = null;
RemoteAnimationTarget topAppTarget = null; RemoteAnimationTarget topAppTarget = null;
@@ -143,19 +153,19 @@ class BackNavigationController {
} }
if (window == null) { if (window == null) {
// We don't have any focused window, fallback ont the top task of the focused // We don't have any focused window, fallback ont the top currentTask of the focused
// display. // display.
ProtoLog.w(WM_DEBUG_BACK_PREVIEW, ProtoLog.w(WM_DEBUG_BACK_PREVIEW,
"No focused window, defaulting to top task's window"); "No focused window, defaulting to top current task's window");
task = wmService.mAtmService.getTopDisplayFocusedRootTask(); currentTask = wmService.mAtmService.getTopDisplayFocusedRootTask();
window = task.getWindow(WindowState::isFocused); window = currentTask.getWindow(WindowState::isFocused);
} }
// Now let's find if this window has a callback from the client side. // Now let's find if this window has a callback from the client side.
OnBackInvokedCallbackInfo callbackInfo = null; OnBackInvokedCallbackInfo callbackInfo = null;
if (window != null) { if (window != null) {
activityRecord = window.mActivityRecord; currentActivity = window.mActivityRecord;
task = window.getTask(); currentTask = window.getTask();
callbackInfo = window.getOnBackInvokedCallbackInfo(); callbackInfo = window.getOnBackInvokedCallbackInfo();
if (callbackInfo == null) { if (callbackInfo == null) {
Slog.e(TAG, "No callback registered, returning null."); Slog.e(TAG, "No callback registered, returning null.");
@@ -167,9 +177,9 @@ class BackNavigationController {
infoBuilder.setOnBackInvokedCallback(callbackInfo.getCallback()); infoBuilder.setOnBackInvokedCallback(callbackInfo.getCallback());
} }
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, " ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation currentTask=%s, "
+ "topRunningActivity=%s, callbackInfo=%s, currentFocus=%s", + "topRunningActivity=%s, callbackInfo=%s, currentFocus=%s",
task, activityRecord, callbackInfo, window); currentTask, currentActivity, callbackInfo, window);
if (window == null) { if (window == null) {
Slog.e(TAG, "Window is null, returning null."); Slog.e(TAG, "Window is null, returning null.");
@@ -182,18 +192,18 @@ class BackNavigationController {
// - The IME is opened, and we just need to close it. // - The IME is opened, and we just need to close it.
// - The home activity is the focused activity. // - The home activity is the focused activity.
if (backType == BackNavigationInfo.TYPE_CALLBACK if (backType == BackNavigationInfo.TYPE_CALLBACK
|| activityRecord == null || currentActivity == null
|| task == null || currentTask == null
|| task.getDisplayContent().getImeContainer().isVisible() || currentTask.getDisplayContent().getImeContainer().isVisible()
|| activityRecord.isActivityTypeHome()) { || currentActivity.isActivityTypeHome()) {
return infoBuilder return infoBuilder
.setType(backType) .setType(backType)
.build(); .build();
} }
// We don't have an application callback, let's find the destination of the back gesture // We don't have an application callback, let's find the destination of the back gesture
Task finalTask = task; Task finalTask = currentTask;
prev = task.getActivity( prevActivity = currentTask.getActivity(
(r) -> !r.finishing && r.getTask() == finalTask && !r.isTopRunningActivity()); (r) -> !r.finishing && r.getTask() == finalTask && !r.isTopRunningActivity());
if (window.getParent().getChildCount() > 1 && window.getParent().getChildAt(0) if (window.getParent().getChildCount() > 1 && window.getParent().getChildAt(0)
!= window) { != window) {
@@ -201,24 +211,24 @@ class BackNavigationController {
// activity, we won't close the activity. // activity, we won't close the activity.
backType = BackNavigationInfo.TYPE_DIALOG_CLOSE; backType = BackNavigationInfo.TYPE_DIALOG_CLOSE;
removedWindowContainer = window; removedWindowContainer = window;
} else if (prev != null) { } else if (prevActivity != null) {
// We have another Activity in the same task to go to // We have another Activity in the same currentTask to go to
backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY; backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
removedWindowContainer = activityRecord; removedWindowContainer = currentActivity;
} else if (task.returnsToHomeRootTask()) { } else if (currentTask.returnsToHomeRootTask()) {
// Our Task should bring back to home // Our Task should bring back to home
removedWindowContainer = task; removedWindowContainer = currentTask;
backType = BackNavigationInfo.TYPE_RETURN_TO_HOME; backType = BackNavigationInfo.TYPE_RETURN_TO_HOME;
} else if (activityRecord.isRootOfTask()) { } else if (currentActivity.isRootOfTask()) {
// TODO(208789724): Create single source of truth for this, maybe in // TODO(208789724): Create single source of truth for this, maybe in
// RootWindowContainer // RootWindowContainer
// TODO: Also check Task.shouldUpRecreateTaskLocked() for prev logic // TODO: Also check Task.shouldUpRecreateTaskLocked() for prevActivity logic
prevTask = task.mRootWindowContainer.getTaskBelow(task); prevTask = currentTask.mRootWindowContainer.getTaskBelow(currentTask);
removedWindowContainer = task; removedWindowContainer = currentTask;
prevActivity = prevTask.getTopNonFinishingActivity();
if (prevTask.isActivityTypeHome()) { if (prevTask.isActivityTypeHome()) {
backType = BackNavigationInfo.TYPE_RETURN_TO_HOME; backType = BackNavigationInfo.TYPE_RETURN_TO_HOME;
} else { } else {
prev = prevTask.getTopNonFinishingActivity();
backType = BackNavigationInfo.TYPE_CROSS_TASK; backType = BackNavigationInfo.TYPE_CROSS_TASK;
} }
} }
@@ -229,7 +239,7 @@ class BackNavigationController {
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Destination is Activity:%s Task:%s " ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Destination is Activity:%s Task:%s "
+ "removedContainer:%s, backType=%s", + "removedContainer:%s, backType=%s",
prev != null ? prev.mActivityComponent : null, prevActivity != null ? prevActivity.mActivityComponent : null,
prevTask != null ? prevTask.getName() : null, prevTask != null ? prevTask.getName() : null,
removedWindowContainer, removedWindowContainer,
BackNavigationInfo.typeToString(backType)); BackNavigationInfo.typeToString(backType));
@@ -241,7 +251,8 @@ class BackNavigationController {
&& !removedWindowContainer.hasCommittedReparentToAnimationLeash(); && !removedWindowContainer.hasCommittedReparentToAnimationLeash();
if (prepareAnimation) { if (prepareAnimation) {
taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration; taskWindowConfiguration =
currentTask.getTaskInfo().configuration.windowConfiguration;
infoBuilder.setTaskWindowConfiguration(taskWindowConfiguration); infoBuilder.setTaskWindowConfiguration(taskWindowConfiguration);
// Prepare a leash to animate the current top window // Prepare a leash to animate the current top window
@@ -254,32 +265,36 @@ class BackNavigationController {
removedWindowContainer.reparentSurfaceControl(tx, animLeash); removedWindowContainer.reparentSurfaceControl(tx, animLeash);
animationLeashParent = removedWindowContainer.getAnimationLeashParent(); animationLeashParent = removedWindowContainer.getAnimationLeashParent();
topAppTarget = createRemoteAnimationTargetLocked(removedWindowContainer, topAppTarget = createRemoteAnimationTargetLocked(removedWindowContainer,
activityRecord, currentActivity,
task, animLeash); currentTask, animLeash);
infoBuilder.setDepartingAnimationTarget(topAppTarget); infoBuilder.setDepartingAnimationTarget(topAppTarget);
} }
//TODO(207481538) Remove once the infrastructure to support per-activity screenshot is //TODO(207481538) Remove once the infrastructure to support per-activity screenshot is
// implemented. For now we simply have the mBackScreenshots hash map that dumbly // implemented. For now we simply have the mBackScreenshots hash map that dumbly
// saves the screenshots. // saves the screenshots.
if (needsScreenshot(backType) && prev != null && prev.mActivityComponent != null) { if (needsScreenshot(backType) && prevActivity != null
screenshotBuffer = getActivitySnapshot(task, prev.mActivityComponent); && prevActivity.mActivityComponent != null) {
screenshotBuffer =
getActivitySnapshot(currentTask, prevActivity.mActivityComponent);
} }
if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) { // Special handling for back to home animation
task.mBackGestureStarted = true; if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()
&& prevTask != null) {
currentTask.mBackGestureStarted = true;
// Make launcher show from behind by marking its top activity as visible and // 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. // launch-behind to bump its visibility for the duration of the back gesture.
prevTaskTopActivity = prevTask.getTopNonFinishingActivity(); prevActivity = prevTask.getTopNonFinishingActivity();
if (prevTaskTopActivity != null) { if (prevActivity != null) {
if (!prevTaskTopActivity.mVisibleRequested) { if (!prevActivity.mVisibleRequested) {
prevTaskTopActivity.setVisibility(true); prevActivity.setVisibility(true);
} }
prevTaskTopActivity.mLaunchTaskBehind = true; prevActivity.mLaunchTaskBehind = true;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to true. Activity=%s", "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
prevTaskTopActivity); prevActivity);
prevTaskTopActivity.mRootWindowContainer.ensureActivitiesVisible( prevActivity.mRootWindowContainer.ensureActivitiesVisible(
null /* starting */, 0 /* configChanges */, null /* starting */, 0 /* configChanges */,
false /* preserveWindows */); false /* preserveWindows */);
} }
@@ -290,7 +305,7 @@ class BackNavigationController {
if (topAppTarget != null && needsScreenshot(backType) && prevTask != null if (topAppTarget != null && needsScreenshot(backType) && prevTask != null
&& screenshotBuffer == null) { && screenshotBuffer == null) {
SurfaceControl.Builder builder = new SurfaceControl.Builder() SurfaceControl.Builder builder = new SurfaceControl.Builder()
.setName("BackPreview Screenshot for " + prev) .setName("BackPreview Screenshot for " + prevActivity)
.setParent(animationLeashParent) .setParent(animationLeashParent)
.setHidden(false) .setHidden(false)
.setBLASTLayer(); .setBLASTLayer();
@@ -302,12 +317,12 @@ class BackNavigationController {
// The Animation leash needs to be above the screenshot surface, but the animation leash // The Animation leash needs to be above the screenshot surface, but the animation leash
// needs to be added before to be in the synchronized block. // needs to be added before to be in the synchronized block.
tx.setLayer(topAppTarget.leash, 1); tx.setLayer(topAppTarget.leash, 1);
tx.apply(); }
WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer; if (finalRemovedWindowContainer != null) {
try { try {
activityRecord.token.linkToDeath( currentActivity.token.linkToDeath(
() -> resetSurfaces(finalRemovedWindowContainer), 0); () -> resetSurfaces(finalRemovedWindowContainer), 0);
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.e(TAG, "Failed to link to death", e); Slog.e(TAG, "Failed to link to death", e);
@@ -315,11 +330,16 @@ class BackNavigationController {
return null; return null;
} }
RemoteCallback onBackNavigationDone = new RemoteCallback( int finalBackType = backType;
result -> resetSurfaces(finalRemovedWindowContainer ActivityRecord finalprevActivity = prevActivity;
)); Task finalTask = currentTask;
RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
result, finalRemovedWindowContainer, finalBackType, finalTask,
finalprevActivity));
infoBuilder.setOnBackNavigationDone(onBackNavigationDone); infoBuilder.setOnBackNavigationDone(onBackNavigationDone);
} }
tx.apply();
return infoBuilder.build(); return infoBuilder.build();
} }
@@ -348,14 +368,13 @@ class BackNavigationController {
} }
private void onBackNavigationDone( private void onBackNavigationDone(
Bundle result, WindowContainer windowContainer, int backType, Bundle result, WindowContainer<?> windowContainer, int backType,
Task task, ActivityRecord prevTaskTopActivity) { Task task, ActivityRecord prevActivity) {
SurfaceControl surfaceControl = windowContainer.getSurfaceControl(); SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
boolean triggerBack = result != null boolean triggerBack = result != null && result.getBoolean(
? result.getBoolean(BackNavigationInfo.KEY_TRIGGER_BACK) BackNavigationInfo.KEY_TRIGGER_BACK);
: false;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, " ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
+ "task=%s, prevTaskTopActivity=%s", backType, task, prevTaskTopActivity); + "task=%s, prevActivity=%s", backType, task, prevActivity);
if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) { if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
if (triggerBack) { if (triggerBack) {
@@ -367,13 +386,13 @@ class BackNavigationController {
t.apply(); t.apply();
} }
} }
if (prevTaskTopActivity != null && !triggerBack) { if (prevActivity != null && !triggerBack) {
// Restore the launch-behind state. // Restore the launch-behind state.
task.mTaskSupervisor.scheduleLaunchTaskBehindComplete(prevTaskTopActivity.token); task.mTaskSupervisor.scheduleLaunchTaskBehindComplete(prevActivity.token);
prevTaskTopActivity.mLaunchTaskBehind = false; prevActivity.mLaunchTaskBehind = false;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to false. Activity=%s", "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
prevTaskTopActivity); prevActivity);
} }
} else { } else {
task.mBackGestureStarted = false; task.mBackGestureStarted = false;

View File

@@ -29,9 +29,12 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.annotation.NonNull; import android.annotation.NonNull;
@@ -39,6 +42,7 @@ import android.annotation.Nullable;
import android.hardware.HardwareBuffer; import android.hardware.HardwareBuffer;
import android.os.RemoteException; import android.os.RemoteException;
import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.view.WindowManager; import android.view.WindowManager;
import android.window.BackEvent; import android.window.BackEvent;
import android.window.BackNavigationInfo; import android.window.BackNavigationInfo;
@@ -77,15 +81,22 @@ public class BackNavigationControllerTests extends WindowTestsBase {
@Test @Test
public void backNavInfo_HomeWhenBackToLauncher() { public void backNavInfo_HomeWhenBackToLauncher() {
IOnBackInvokedCallback callback = withSystemCallback(createTopTaskWithActivity()); Task task = createTopTaskWithActivity();
IOnBackInvokedCallback callback = withSystemCallback(task);
BackNavigationInfo backNavigationInfo = startBackNavigation(); SurfaceControl.Transaction tx = mock(SurfaceControl.Transaction.class);
BackNavigationInfo backNavigationInfo = mBackNavigationController.startBackNavigation(mWm,
tx);
assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull(); assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull();
assertThat(backNavigationInfo.getDepartingAnimationTarget()).isNotNull(); assertThat(backNavigationInfo.getDepartingAnimationTarget()).isNotNull();
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull(); assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback); assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback);
assertThat(typeToString(backNavigationInfo.getType())) assertThat(typeToString(backNavigationInfo.getType()))
.isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME)); .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
verify(tx, atLeastOnce()).apply();
verify(tx, times(1)).reparent(any(),
eq(backNavigationInfo.getDepartingAnimationTarget().leash));
} }
@Test @Test