Merge "Fix no back animations when the target window is animating" into udc-dev

This commit is contained in:
Arthur Hung
2023-03-03 02:37:20 +00:00
committed by Android (Google) Code Review
5 changed files with 173 additions and 64 deletions

View File

@@ -271,6 +271,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
"at": "com\/android\/server\/wm\/AppTransition.java"
},
"-1868518158": {
"message": "Pending back animation due to another animation is running",
"level": "WARN",
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
"-1868124841": {
"message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b",
"level": "VERBOSE",
@@ -1549,6 +1555,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DragState.java"
},
"-692907078": {
"message": "Handling the deferred animation after transition finished",
"level": "DEBUG",
"group": "WM_DEBUG_BACK_PREVIEW",
"at": "com\/android\/server\/wm\/BackNavigationController.java"
},
"-677449371": {
"message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b",
"level": "DEBUG",

View File

@@ -552,6 +552,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (runner.isWaitingAnimation()) {
ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Gesture released, but animation didn't ready.");
return;
} else if (runner.isAnimationCancelled()) {
invokeOrCancelBack();
return;
}
startPostCommitAnimation();
}
@@ -653,7 +656,19 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
@Override
public void onAnimationCancelled() { }
public void onAnimationCancelled() {
mShellExecutor.execute(() -> {
final BackAnimationRunner runner = mAnimationDefinition.get(
mBackNavigationInfo.getType());
if (runner == null) {
return;
}
runner.cancelAnimation();
if (!mBackGestureStarted) {
invokeOrCancelBack();
}
});
}
};
mBackAnimationAdapter = new BackAnimationAdapter(runner);
}

View File

@@ -41,6 +41,9 @@ class BackAnimationRunner {
// Whether we are waiting to receive onAnimationStart
private boolean mWaitingAnimation;
/** True when the back animation is cancelled */
private boolean mAnimationCancelled;
BackAnimationRunner(@NonNull IOnBackInvokedCallback callback,
@NonNull IRemoteAnimationRunner runner) {
mCallback = callback;
@@ -81,9 +84,19 @@ class BackAnimationRunner {
void startGesture() {
mWaitingAnimation = true;
mAnimationCancelled = false;
}
boolean isWaitingAnimation() {
return mWaitingAnimation;
}
void cancelAnimation() {
mWaitingAnimation = false;
mAnimationCancelled = true;
}
boolean isAnimationCancelled() {
return mAnimationCancelled;
}
}

View File

@@ -75,6 +75,11 @@ class BackNavigationController {
private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>();
private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>();
// This will be set if the back navigation is in progress and the current transition is still
// running. The pending animation builder will do the animation stuff includes creating leashes,
// re-parenting leashes and set launch behind, etc. Will be handled when transition finished.
private AnimationHandler.ScheduleAnimationBuilder mPendingAnimationBuilder;
/**
* true if the back predictability feature is enabled
*/
@@ -305,25 +310,26 @@ class BackNavigationController {
|| backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY)
&& adapter != null;
// Only prepare animation if no leash has been created (no animation is running).
// TODO(b/241808055): Cancel animation when preparing back animation.
if (prepareAnimation
&& (removedWindowContainer.hasCommittedReparentToAnimationLeash()
|| removedWindowContainer.mTransitionController.inTransition())) {
Slog.w(TAG, "Can't prepare back animation due to another animation is running.");
prepareAnimation = false;
}
if (prepareAnimation) {
mPendingAnimation = mAnimationHandler.scheduleAnimation(backType, adapter,
currentTask, prevTask, currentActivity, prevActivity);
prepareAnimation = mPendingAnimation != null;
mBackAnimationInProgress = prepareAnimation;
if (prepareAnimation) {
mWindowManagerService.mWindowPlacerLocked.requestTraversal();
if (mShowWallpaper) {
currentTask.getDisplayContent().mWallpaperController
.adjustWallpaperWindows();
final AnimationHandler.ScheduleAnimationBuilder builder =
mAnimationHandler.prepareAnimation(backType, adapter,
currentTask, prevTask, currentActivity, prevActivity);
mBackAnimationInProgress = builder != null;
if (mBackAnimationInProgress) {
if (removedWindowContainer.hasCommittedReparentToAnimationLeash()
|| removedWindowContainer.mTransitionController.inTransition()
|| mWindowManagerService.mSyncEngine.hasPendingSyncSets()) {
ProtoLog.w(WM_DEBUG_BACK_PREVIEW,
"Pending back animation due to another animation is running");
mPendingAnimationBuilder = builder;
// Current transition is still running, we have to defer the hiding to the
// client process to prevent the unexpected relayout when handling the back
// animation.
if (prevActivity != null) {
prevActivity.setDeferHidingClient(true);
}
} else {
scheduleAnimation(builder);
}
}
}
@@ -345,6 +351,15 @@ class BackNavigationController {
return isWaitBackTransition() || mNavigationMonitor.isMonitoring();
}
private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) {
mPendingAnimation = builder.build();
mWindowManagerService.mWindowPlacerLocked.requestTraversal();
if (mShowWallpaper) {
mWindowManagerService.getDefaultDisplayContentLocked().mWallpaperController
.adjustWallpaperWindows();
}
}
private boolean isWaitBackTransition() {
return mAnimationHandler.mComposed && mAnimationHandler.mWaitTransition;
}
@@ -526,6 +541,57 @@ class BackNavigationController {
mAnimationHandler.clearBackAnimateTarget(cleanupTransaction);
}
/**
* Handle the pending animation when the running transition finished.
* @param targets The final animation targets derived in transition.
*/
boolean handleDeferredBackAnimation(@NonNull ArrayList<Transition.ChangeInfo> targets) {
if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) {
return false;
}
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Handling the deferred animation after transition finished");
// Show the target surface and its parents to prevent it or its parents hidden when
// the transition finished.
// The target could be affected by transition when :
// Open transition -> the open target in back navigation
// Close transition -> the close target in back navigation.
boolean hasTarget = false;
final SurfaceControl.Transaction t =
mPendingAnimationBuilder.mCloseTarget.getPendingTransaction();
for (int i = 0; i < targets.size(); i++) {
final WindowContainer wc = targets.get(i).mContainer;
if (wc.asActivityRecord() == null && wc.asTask() == null) {
continue;
} else if (!mPendingAnimationBuilder.containTarget(wc)) {
continue;
}
hasTarget = true;
t.show(wc.getSurfaceControl());
}
if (!hasTarget) {
// Skip if no target participated in current finished transition.
Slog.w(TAG, "Finished transition didn't include the targets"
+ " open: " + mPendingAnimationBuilder.mOpenTarget
+ " close: " + mPendingAnimationBuilder.mCloseTarget);
try {
mPendingAnimationBuilder.mBackAnimationAdapter.getRunner().onAnimationCancelled();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
mPendingAnimationBuilder = null;
return false;
}
scheduleAnimation(mPendingAnimationBuilder);
mPendingAnimationBuilder = null;
return true;
}
/**
* Create and handling animations status for an open/close animation targets.
*/
@@ -638,6 +704,7 @@ class BackNavigationController {
if (open) {
return wc == mOpenAdaptor.mTarget || mOpenAdaptor.mTarget.hasChild(wc);
}
if (mSwitchType == TASK_SWITCH) {
return wc == mCloseAdaptor.mTarget
|| (wc.asTask() != null && wc.hasChild(mCloseAdaptor.mTarget));
@@ -841,23 +908,22 @@ class BackNavigationController {
}
}
Runnable scheduleAnimation(int backType, BackAnimationAdapter adapter,
ScheduleAnimationBuilder prepareAnimation(int backType, BackAnimationAdapter adapter,
Task currentTask, Task previousTask, ActivityRecord currentActivity,
ActivityRecord previousActivity) {
switch (backType) {
case BackNavigationInfo.TYPE_RETURN_TO_HOME:
return new ScheduleAnimationBuilder(backType, adapter)
.setIsLaunchBehind(true)
.setComposeTarget(currentTask, previousTask)
.build();
.setComposeTarget(currentTask, previousTask);
case BackNavigationInfo.TYPE_CROSS_ACTIVITY:
return new ScheduleAnimationBuilder(backType, adapter)
.setComposeTarget(currentActivity, previousActivity)
.setOpeningSnapshot(getActivitySnapshot(previousActivity)).build();
.setOpeningSnapshot(getActivitySnapshot(previousActivity));
case BackNavigationInfo.TYPE_CROSS_TASK:
return new ScheduleAnimationBuilder(backType, adapter)
.setComposeTarget(currentTask, previousTask)
.setOpeningSnapshot(getTaskSnapshot(previousTask)).build();
.setOpeningSnapshot(getTaskSnapshot(previousTask));
}
return null;
}
@@ -891,6 +957,11 @@ class BackNavigationController {
return this;
}
boolean containTarget(@NonNull WindowContainer wc) {
return wc == mOpenTarget || wc == mCloseTarget
|| wc.hasChild(mOpenTarget) || wc.hasChild(mCloseTarget);
}
Runnable build() {
if (mOpenTarget == null || mCloseTarget == null) {
return null;
@@ -967,49 +1038,43 @@ class BackNavigationController {
}
};
}
private void setLaunchBehind(ActivityRecord activity) {
if (activity == null) {
return;
}
if (!activity.isVisibleRequested()) {
activity.setVisibility(true);
}
activity.mLaunchTaskBehind = true;
// Handle fixed rotation launching app.
final DisplayContent dc = activity.mDisplayContent;
dc.rotateInDifferentOrientationIfNeeded(activity);
if (activity.hasFixedRotationTransform()) {
// Set the record so we can recognize it to continue to update display
// orientation if the previous activity becomes the top later.
dc.setFixedRotationLaunchingApp(activity,
activity.getWindowConfiguration().getRotation());
}
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity);
activity.mTaskSupervisor.mStoppingActivities.remove(activity);
activity.getDisplayContent().ensureActivitiesVisible(null /* starting */,
0 /* configChanges */, false /* preserveWindows */, true);
}
private void restoreLaunchBehind(ActivityRecord activity) {
if (activity == null) {
return;
}
activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
// Restore the launch-behind state.
activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token);
activity.mLaunchTaskBehind = false;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to false. Activity=%s",
activity);
}
}
}
private static void setLaunchBehind(@NonNull ActivityRecord activity) {
if (!activity.isVisibleRequested()) {
activity.setVisibility(true);
}
activity.mLaunchTaskBehind = true;
// Handle fixed rotation launching app.
final DisplayContent dc = activity.mDisplayContent;
dc.rotateInDifferentOrientationIfNeeded(activity);
if (activity.hasFixedRotationTransform()) {
// Set the record so we can recognize it to continue to update display
// orientation if the previous activity becomes the top later.
dc.setFixedRotationLaunchingApp(activity,
activity.getWindowConfiguration().getRotation());
}
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity);
activity.mTaskSupervisor.mStoppingActivities.remove(activity);
activity.getDisplayContent().ensureActivitiesVisible(null /* starting */,
0 /* configChanges */, false /* preserveWindows */, true);
}
private static void restoreLaunchBehind(@NonNull ActivityRecord activity) {
activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
// Restore the launch-behind state.
activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token);
activity.mLaunchTaskBehind = false;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to false. Activity=%s",
activity);
}
void checkAnimationReady(WallpaperController wallpaperController) {
if (!mBackAnimationInProgress) {
return;
@@ -1039,6 +1104,7 @@ class BackNavigationController {
mNavigationMonitor.stopMonitor();
mBackAnimationInProgress = false;
mShowWallpaper = false;
mPendingAnimationBuilder = null;
}
private static TaskSnapshot getActivitySnapshot(@NonNull ActivityRecord r) {

View File

@@ -989,6 +989,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
cleanUpInternal();
mController.updateAnimatingState(mTmpTransaction);
mTmpTransaction.apply();
// Handle back animation if it's already started.
mController.mAtm.mBackNavigationController.handleDeferredBackAnimation(mTargets);
}
void abort() {