diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 3d81d37aff20f..05e17720b1752 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -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", 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 b3fff1d052632..0b87598903597 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 @@ -552,6 +552,9 @@ public class BackAnimationController implements RemoteCallable { + final BackAnimationRunner runner = mAnimationDefinition.get( + mBackNavigationInfo.getType()); + if (runner == null) { + return; + } + runner.cancelAnimation(); + if (!mBackGestureStarted) { + invokeOrCancelBack(); + } + }); + } }; mBackAnimationAdapter = new BackAnimationAdapter(runner); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java index d70b8f53a9115..82c523f337dbb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java @@ -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; + } } diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index a229fc5b00d37..2d45dc20c9635 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -75,6 +75,11 @@ class BackNavigationController { private final ArrayList mTmpOpenApps = new ArrayList<>(); private final ArrayList 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 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) { diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 12cfa26342449..a30ab11d9f6db 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -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() {