Merge "Implement back to launcher animation from shell and WM animation controllers." into tm-dev

This commit is contained in:
Shan Huang
2022-03-15 05:38:25 +00:00
committed by Android (Google) Code Review
6 changed files with 219 additions and 44 deletions

View File

@@ -1309,6 +1309,12 @@
"group": "WM_DEBUG_STATES", "group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java" "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": { "-706481945": {
"message": "TaskFragment parent info changed name=%s parentTaskId=%d", "message": "TaskFragment parent info changed name=%s parentTaskId=%d",
"level": "VERBOSE", "level": "VERBOSE",
@@ -2587,6 +2593,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS", "group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/WindowState.java" "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": { "600140673": {
"message": "checkBootAnimationComplete: Waiting for anim complete", "message": "checkBootAnimationComplete: Waiting for anim complete",
"level": "INFO", "level": "INFO",
@@ -2671,12 +2683,6 @@
"group": "WM_ERROR", "group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java" "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": { "665256544": {
"message": "All windows drawn!", "message": "All windows drawn!",
"level": "DEBUG", "level": "DEBUG",
@@ -2887,6 +2893,12 @@
"group": "WM_DEBUG_STATES", "group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java" "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": { "950074526": {
"message": "setLockTaskMode: Can't lock due to auth", "message": "setLockTaskMode: Can't lock due to auth",
"level": "WARN", "level": "WARN",
@@ -3103,6 +3115,12 @@
"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"
},
"1178653181": { "1178653181": {
"message": "Old wallpaper still the target.", "message": "Old wallpaper still the target.",
"level": "VERBOSE", "level": "VERBOSE",
@@ -3415,11 +3433,11 @@
"group": "WM_DEBUG_APP_TRANSITIONS", "group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java" "at": "com\/android\/server\/wm\/ActivityRecord.java"
}, },
"1554795024": { "1544805551": {
"message": "Previous Activity is %s", "message": "Skipping app transition animation. task=%s",
"level": "DEBUG", "level": "DEBUG",
"group": "WM_DEBUG_BACK_PREVIEW", "group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java" "at": "com\/android\/server\/wm\/Task.java"
}, },
"1557732761": { "1557732761": {
"message": "For Intent %s bringing to top: %s", "message": "For Intent %s bringing to top: %s",

View File

@@ -52,14 +52,17 @@ import com.android.wm.shell.common.annotations.ShellMainThread;
*/ */
public class BackAnimationController implements RemoteCallable<BackAnimationController> { 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 = private static final String BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP =
"persist.debug.back_predictability_progress_threshold"; "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 private static final int PROGRESS_THRESHOLD = SystemProperties
.getInt(BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP, -1); .getInt(BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP, -1);
private static final String TAG = "BackAnimationController"; 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. * Location of the initial touch event of the back gesture.
@@ -255,7 +258,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
backNavigationInfo.getTaskWindowConfiguration()); backNavigationInfo.getTaskWindowConfiguration());
} }
mTransaction.apply(); mTransaction.apply();
} else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) { } else if (shouldDispatchToLauncher(backType)) {
targetCallback = mBackToLauncherCallback; targetCallback = mBackToLauncherCallback;
} else if (backType == BackNavigationInfo.TYPE_CALLBACK) { } else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
targetCallback = mBackNavigationInfo.getOnBackInvokedCallback(); targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
@@ -309,7 +312,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
BackEvent backEvent = new BackEvent(0, 0, progress, swipeEdge, animationTarget); BackEvent backEvent = new BackEvent(0, 0, progress, swipeEdge, animationTarget);
IOnBackInvokedCallback targetCallback = null; IOnBackInvokedCallback targetCallback = null;
if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) { if (shouldDispatchToLauncher(backType)) {
targetCallback = mBackToLauncherCallback; targetCallback = mBackToLauncherCallback;
} else if (backType == BackNavigationInfo.TYPE_CROSS_TASK } else if (backType == BackNavigationInfo.TYPE_CROSS_TASK
|| backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) { || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
@@ -330,8 +333,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return; return;
} }
int backType = mBackNavigationInfo.getType(); int backType = mBackNavigationInfo.getType();
boolean shouldDispatchToLauncher = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME boolean shouldDispatchToLauncher = shouldDispatchToLauncher(backType);
&& mBackToLauncherCallback != null;
IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
? mBackToLauncherCallback ? mBackToLauncherCallback
: mBackNavigationInfo.getOnBackInvokedCallback(); : 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) { private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
if (callback == null) { if (callback == null) {
return; return;
@@ -468,7 +481,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return; return;
} }
RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget(); RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget();
if (animationTarget != null && mTriggerBack) { if (animationTarget != null) {
if (animationTarget.leash != null && animationTarget.leash.isValid()) { if (animationTarget.leash != null && animationTarget.leash.isValid()) {
mTransaction.remove(animationTarget.leash); mTransaction.remove(animationTarget.leash);
} }

View File

@@ -78,6 +78,7 @@ public class BackAnimationControllerTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mController = new BackAnimationController( mController = new BackAnimationController(
mShellExecutor, mTransaction, mActivityTaskManager, mContext); mShellExecutor, mTransaction, mActivityTaskManager, mContext);
mController.setEnableAnimations(true);
} }
private void createNavigationInfo(RemoteAnimationTarget topAnimationTarget, private void createNavigationInfo(RemoteAnimationTarget topAnimationTarget,

View File

@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.hardware.HardwareBuffer; import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.RemoteCallback; import android.os.RemoteCallback;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SystemProperties; import android.os.SystemProperties;
@@ -44,7 +45,11 @@ import com.android.internal.protolog.common.ProtoLog;
class BackNavigationController { class BackNavigationController {
private static final String TAG = "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 @Nullable
private TaskSnapshotController mTaskSnapshotController; private TaskSnapshotController mTaskSnapshotController;
@@ -53,11 +58,15 @@ class BackNavigationController {
* Returns true if the back predictability feature is enabled * Returns true if the back predictability feature is enabled
*/ */
static boolean isEnabled() { static boolean isEnabled() {
return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 1) > 0; return BACK_PREDICTABILITY_PROP > 0;
} }
static boolean isScreenshotEnabled() { 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; ActivityRecord prev;
WindowContainer<?> removedWindowContainer; WindowContainer<?> removedWindowContainer;
ActivityRecord activityRecord; ActivityRecord activityRecord;
ActivityRecord prevTaskTopActivity = null;
SurfaceControl animationLeashParent; SurfaceControl animationLeashParent;
WindowConfiguration taskWindowConfiguration; WindowConfiguration taskWindowConfiguration;
HardwareBuffer screenshotBuffer = null; HardwareBuffer screenshotBuffer = null;
SurfaceControl screenshotSurface;
int prevTaskId; int prevTaskId;
int prevUserId; int prevUserId;
RemoteAnimationTarget topAppTarget; RemoteAnimationTarget topAppTarget;
SurfaceControl animLeash; SurfaceControl animLeash;
IOnBackInvokedCallback callback = null; IOnBackInvokedCallback applicationCallback = null;
IOnBackInvokedCallback systemCallback = null;
synchronized (task.mWmService.mGlobalLock) { synchronized (task.mWmService.mGlobalLock) {
@@ -116,15 +128,14 @@ class BackNavigationController {
removedWindowContainer = activityRecord; removedWindowContainer = activityRecord;
taskWindowConfiguration = window.getWindowConfiguration(); taskWindowConfiguration = window.getWindowConfiguration();
} }
IOnBackInvokedCallback applicationCallback = null;
IOnBackInvokedCallback systemCallback = null;
if (window != null) { if (window != null) {
applicationCallback = window.getApplicationOnBackInvokedCallback(); applicationCallback = window.getApplicationOnBackInvokedCallback();
callback = applicationCallback; systemCallback = window.getSystemOnBackInvokedCallback();
if (callback == null) { }
systemCallback = window.getSystemOnBackInvokedCallback(); if (applicationCallback == null && systemCallback == null) {
callback = systemCallback; // 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, " ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, "
@@ -133,24 +144,24 @@ class BackNavigationController {
task, activityRecord, applicationCallback, systemCallback); task, activityRecord, applicationCallback, systemCallback);
// TODO Temp workaround for Sysui until b/221071505 is fixed // 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, return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */, null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */, null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */, null /* onBackNavigationDone */,
callback /* onBackInvokedCallback */); applicationCallback /* onBackInvokedCallback */);
} }
// For IME and Home, either a callback is registered, or we do nothing. In both cases, // 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. // we don't need to pass the leashes below.
if (activityRecord == null || task.getDisplayContent().getImeContainer().isVisible() if (activityRecord == null || task.getDisplayContent().getImeContainer().isVisible()
|| activityRecord.isActivityTypeHome()) { || activityRecord.isActivityTypeHome()) {
if (callback != null) { if (applicationCallback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK, return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */, null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */, null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */, null /* onBackNavigationDone */,
callback /* onBackInvokedCallback */); applicationCallback /* onBackInvokedCallback */);
} else { } else {
return null; return null;
} }
@@ -159,12 +170,12 @@ class BackNavigationController {
prev = task.getActivity( prev = task.getActivity(
(r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity()); (r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());
if (callback != null) { if (applicationCallback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK, return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */, null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */, null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */, null /* onBackNavigationDone */,
callback /* onBackInvokedCallback */); applicationCallback /* onBackInvokedCallback */);
} else if (prev != null) { } else if (prev != null) {
backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY; backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
} else if (task.returnsToHomeRootTask()) { } else if (task.returnsToHomeRootTask()) {
@@ -188,8 +199,8 @@ class BackNavigationController {
prevTaskId = prevTask != null ? prevTask.mTaskId : 0; prevTaskId = prevTask != null ? prevTask.mTaskId : 0;
prevUserId = prevTask != null ? prevTask.mUserId : 0; prevUserId = prevTask != null ? prevTask.mUserId : 0;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s", ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s. "
prev != null ? prev.mActivityComponent : null); + "Back type is %s", prev != null ? prev.mActivityComponent : null, backType);
//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
@@ -204,6 +215,7 @@ class BackNavigationController {
return null; return null;
} }
// Prepare a leash to animate the current top window // Prepare a leash to animate the current top window
// TODO(b/220934562): Use surface animator to better manage animation conflicts.
animLeash = removedWindowContainer.makeAnimationLeash() animLeash = removedWindowContainer.makeAnimationLeash()
.setName("BackPreview Leash for " + removedWindowContainer) .setName("BackPreview Leash for " + removedWindowContainer)
.setHidden(false) .setHidden(false)
@@ -231,12 +243,30 @@ class BackNavigationController {
activityRecord.windowType); activityRecord.windowType);
} }
SurfaceControl.Builder builder = new SurfaceControl.Builder() screenshotSurface = new SurfaceControl.Builder()
.setName("BackPreview Screenshot for " + prev) .setName("BackPreview Screenshot for " + prev)
.setParent(animationLeashParent) .setParent(animationLeashParent)
.setHidden(false) .setHidden(false)
.setBLASTLayer(); .setBLASTLayer()
SurfaceControl screenshotSurface = builder.build(); .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 // Find a screenshot of the previous activity
@@ -253,17 +283,20 @@ class BackNavigationController {
WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer; WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
try { try {
activityRecord.token.linkToDeath( activityRecord.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);
resetSurfaces(removedWindowContainer); resetSurfaces(removedWindowContainer);
return null; return null;
} }
RemoteCallback onBackNavigationDone = new RemoteCallback( int finalBackType = backType;
result -> resetSurfaces(finalRemovedWindowContainer 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, return new BackNavigationInfo(backType,
topAppTarget, topAppTarget,
screenshotSurface, screenshotSurface,
@@ -273,6 +306,39 @@ class BackNavigationController {
callback); 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, private HardwareBuffer getActivitySnapshot(@NonNull Task task,
ComponentName activityComponent) { ComponentName activityComponent) {

View File

@@ -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_FOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_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_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_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
@@ -609,6 +610,12 @@ class Task extends TaskFragment {
boolean mLastSurfaceShowing = true; 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, private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity, Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, 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 { } else {
super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources); super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
} }

View File

@@ -30,7 +30,10 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.hardware.HardwareBuffer; import android.hardware.HardwareBuffer;
import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit;
import android.window.BackEvent;
import android.window.BackNavigationInfo; import android.window.BackNavigationInfo;
import android.window.IOnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import android.window.TaskSnapshot; import android.window.TaskSnapshot;
import org.junit.Before; import org.junit.Before;
@@ -42,15 +45,19 @@ import org.junit.runner.RunWith;
public class BackNavigationControllerTests extends WindowTestsBase { public class BackNavigationControllerTests extends WindowTestsBase {
private BackNavigationController mBackNavigationController; private BackNavigationController mBackNavigationController;
private IOnBackInvokedCallback mOnBackInvokedCallback;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
mBackNavigationController = new BackNavigationController(); mBackNavigationController = new BackNavigationController();
mOnBackInvokedCallback = createBackCallback();
} }
@Test @Test
public void backTypeHomeWhenBackToLauncher() { public void backTypeHomeWhenBackToLauncher() {
Task task = createTopTaskWithActivity(); Task task = createTopTaskWithActivity();
registerSystemOnBackInvokedCallback();
BackNavigationInfo backNavigationInfo = BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction()); mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull(); assertThat(backNavigationInfo).isNotNull();
@@ -63,6 +70,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
Task taskA = createTask(mDefaultDisplay); Task taskA = createTask(mDefaultDisplay);
createActivityRecord(taskA); createActivityRecord(taskA);
Task task = createTopTaskWithActivity(); Task task = createTopTaskWithActivity();
registerSystemOnBackInvokedCallback();
BackNavigationInfo backNavigationInfo = BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction()); mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull(); assertThat(backNavigationInfo).isNotNull();
@@ -75,6 +84,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
Task task = createTopTaskWithActivity(); Task task = createTopTaskWithActivity();
mAtm.setFocusedTask(task.mTaskId, mAtm.setFocusedTask(task.mTaskId,
createAppWindow(task, FIRST_APPLICATION_WINDOW, "window").mActivityRecord); createAppWindow(task, FIRST_APPLICATION_WINDOW, "window").mActivityRecord);
registerSystemOnBackInvokedCallback();
BackNavigationInfo backNavigationInfo = BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction()); mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull(); assertThat(backNavigationInfo).isNotNull();
@@ -89,6 +100,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
public void backNavInfoFullyPopulated() { public void backNavInfoFullyPopulated() {
Task task = createTopTaskWithActivity(); Task task = createTopTaskWithActivity();
createAppWindow(task, FIRST_APPLICATION_WINDOW, "window"); createAppWindow(task, FIRST_APPLICATION_WINDOW, "window");
registerSystemOnBackInvokedCallback();
// We need a mock screenshot so // We need a mock screenshot so
TaskSnapshotController taskSnapshotController = createMockTaskSnapshotController(); TaskSnapshotController taskSnapshotController = createMockTaskSnapshotController();
@@ -104,6 +116,30 @@ public class BackNavigationControllerTests extends WindowTestsBase {
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull(); 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 @NonNull
private TaskSnapshotController createMockTaskSnapshotController() { private TaskSnapshotController createMockTaskSnapshotController() {
TaskSnapshotController taskSnapshotController = mock(TaskSnapshotController.class); TaskSnapshotController taskSnapshotController = mock(TaskSnapshotController.class);
@@ -126,4 +162,30 @@ public class BackNavigationControllerTests extends WindowTestsBase {
mAtm.setFocusedTask(task.mTaskId, record); mAtm.setFocusedTask(task.mTaskId, record);
return task; 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() { }
};
}
} }