diff options
11 files changed, 600 insertions, 117 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 14978ede88cc..85d4ec00c7bc 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -478,6 +478,12 @@ public interface WindowManager extends ViewManager { */ int TRANSIT_SLEEP = 12; /** + * An Activity was going to be visible from back navigation. + * @hide + */ + int TRANSIT_PREPARE_BACK_NAVIGATION = 13; + + /** * The first slot for custom transition types. Callers (like Shell) can make use of custom * transition types for dealing with special cases. These types are effectively ignored by * Core and will just be passed along as part of TransitionInfo objects. An example is @@ -505,6 +511,7 @@ public interface WindowManager extends ViewManager { TRANSIT_PIP, TRANSIT_WAKE, TRANSIT_SLEEP, + TRANSIT_PREPARE_BACK_NAVIGATION, TRANSIT_FIRST_CUSTOM }) @Retention(RetentionPolicy.SOURCE) @@ -1918,6 +1925,7 @@ public interface WindowManager extends ViewManager { case TRANSIT_PIP: return "PIP"; case TRANSIT_WAKE: return "WAKE"; case TRANSIT_SLEEP: return "SLEEP"; + case TRANSIT_PREPARE_BACK_NAVIGATION: return "PREDICTIVE_BACK"; case TRANSIT_FIRST_CUSTOM: return "FIRST_CUSTOM"; default: if (type > TRANSIT_FIRST_CUSTOM) { diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index e5a9b6ac55c8..14d752ec6201 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -219,3 +219,13 @@ flag { purpose: PURPOSE_BUGFIX } } +flag { + name: "migrate_predictive_back_transition" + namespace: "windowing_frontend" + description: "Create transition when visibility change from predictive back" + bug: "347168362" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} 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 a9fdea34515e..f14f4198c3f2 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 @@ -16,7 +16,12 @@ package com.android.wm.shell.back; +import static android.view.RemoteAnimationTarget.MODE_CLOSING; +import static android.view.RemoteAnimationTarget.MODE_OPENING; +import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; + import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_HOME; +import static com.android.window.flags.Flags.migratePredictiveBackTransition; import static com.android.window.flags.Flags.predictiveBackSystemAnims; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION; @@ -30,11 +35,13 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Configuration; import android.database.ContentObserver; +import android.graphics.Point; import android.graphics.Rect; import android.hardware.input.InputManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.SystemClock; @@ -48,6 +55,7 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; import android.view.WindowManager; import android.window.BackAnimationAdapter; import android.window.BackEvent; @@ -57,6 +65,9 @@ import android.window.BackTouchTracker; import android.window.IBackAnimationFinishedCallback; import android.window.IBackAnimationRunner; import android.window.IOnBackInvokedCallback; +import android.window.TransitionInfo; +import android.window.TransitionRequestInfo; +import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; @@ -66,12 +77,14 @@ import com.android.wm.shell.R; import com.android.wm.shell.common.ExternalInterfaceBinder; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.shared.TransitionUtil; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; import com.android.wm.shell.shared.annotations.ShellMainThread; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; import java.util.concurrent.atomic.AtomicBoolean; @@ -101,6 +114,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont /** Tracks if an uninterruptible animation is in progress */ private boolean mPostCommitAnimationInProgress = false; + private boolean mRealCallbackInvoked = false; /** Tracks if we should start the back gesture on the next motion move event */ private boolean mShouldStartOnNextMoveEvent = false; @@ -123,6 +137,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private final ShellExecutor mShellExecutor; private final Handler mBgHandler; private final WindowManager mWindowManager; + private final Transitions mTransitions; + private final BackTransitionHandler mBackTransitionHandler; @VisibleForTesting final Rect mTouchableArea = new Rect(); @@ -190,7 +206,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont Context context, @NonNull BackAnimationBackground backAnimationBackground, ShellBackAnimationRegistry shellBackAnimationRegistry, - ShellCommandHandler shellCommandHandler) { + ShellCommandHandler shellCommandHandler, + Transitions transitions) { this( shellInit, shellController, @@ -201,7 +218,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont context.getContentResolver(), backAnimationBackground, shellBackAnimationRegistry, - shellCommandHandler); + shellCommandHandler, + transitions); } @VisibleForTesting @@ -215,7 +233,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont ContentResolver contentResolver, @NonNull BackAnimationBackground backAnimationBackground, ShellBackAnimationRegistry shellBackAnimationRegistry, - ShellCommandHandler shellCommandHandler) { + ShellCommandHandler shellCommandHandler, + Transitions transitions) { mShellController = shellController; mShellExecutor = shellExecutor; mActivityTaskManager = activityTaskManager; @@ -230,6 +249,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mLatencyTracker = LatencyTracker.getInstance(mContext); mShellCommandHandler = shellCommandHandler; mWindowManager = context.getSystemService(WindowManager.class); + mTransitions = transitions; + mBackTransitionHandler = new BackTransitionHandler(); + mTransitions.addHandler(mBackTransitionHandler); updateTouchableArea(); } @@ -730,7 +752,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mBackAnimationFinishedCallback = null; } - if (mBackNavigationInfo != null) { + if (mBackNavigationInfo != null && !mRealCallbackInvoked) { final IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback(); if (touchTracker.getTriggerBack()) { dispatchOnBackInvoked(callback); @@ -738,6 +760,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont tryDispatchOnBackCancelled(callback); } } + mRealCallbackInvoked = false; finishBackNavigation(touchTracker.getTriggerBack()); } @@ -815,14 +838,38 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont // The next callback should be {@link #onBackAnimationFinished}. if (mCurrentTracker.getTriggerBack()) { - // notify gesture finished - mBackNavigationInfo.onBackGestureFinished(true); + if (migratePredictiveBackTransition()) { + // notify core gesture is commit + if (shouldTriggerCloseTransition()) { + mBackTransitionHandler.mCloseTransitionRequested = true; + final IOnBackInvokedCallback callback = + mBackNavigationInfo.getOnBackInvokedCallback(); + // invoked client side onBackInvoked + dispatchOnBackInvoked(callback); + mRealCallbackInvoked = true; + } + } else { + // notify gesture finished + mBackNavigationInfo.onBackGestureFinished(true); + } + + // start post animation dispatchOnBackInvoked(mActiveCallback); } else { tryDispatchOnBackCancelled(mActiveCallback); } } + // Close window won't create any transition + private boolean shouldTriggerCloseTransition() { + if (mBackNavigationInfo == null) { + return false; + } + int type = mBackNavigationInfo.getType(); + return type == BackNavigationInfo.TYPE_RETURN_TO_HOME + || type == BackNavigationInfo.TYPE_CROSS_TASK + || type == BackNavigationInfo.TYPE_CROSS_ACTIVITY; + } /** * Called when the post commit animation is completed or timeout. * This will trigger the real {@link IOnBackInvokedCallback} behavior. @@ -857,6 +904,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont "mCurrentBackGestureInfo was null when back animation finished"); } resetTouchTracker(); + mBackTransitionHandler.onAnimationFinished(); } /** @@ -1016,11 +1064,13 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont endLatencyTracking(); if (!validateAnimationTargets(apps)) { Log.e(TAG, "Invalid animation targets!"); + mBackTransitionHandler.consumeQueuedTransitionIfNeeded(); return; } mBackAnimationFinishedCallback = finishedCallback; mApps = apps; startSystemAnimation(); + mBackTransitionHandler.consumeQueuedTransitionIfNeeded(); // Dispatch the first progress after animation start for // smoothing the initial animation, instead of waiting for next @@ -1041,6 +1091,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont public void onAnimationCancelled() { mShellExecutor.execute( () -> { + mBackTransitionHandler.consumeQueuedTransitionIfNeeded(); if (!mShellBackAnimationRegistry.cancel( mBackNavigationInfo != null ? mBackNavigationInfo.getType() @@ -1073,4 +1124,249 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mQueuedTracker.dump(pw, prefix + " "); } + class BackTransitionHandler implements Transitions.TransitionHandler { + + Runnable mOnAnimationFinishCallback; + boolean mCloseTransitionRequested; + boolean mOpeningRunning; + SurfaceControl.Transaction mFinishOpenTransaction; + Transitions.TransitionFinishCallback mFinishOpenTransitionCallback; + QueuedTransition mQueuedTransition = null; + void onAnimationFinished() { + if (!mCloseTransitionRequested) { + applyFinishOpenTransition(); + } + if (mOnAnimationFinishCallback != null) { + mOnAnimationFinishCallback.run(); + mOnAnimationFinishCallback = null; + } + } + + void consumeQueuedTransitionIfNeeded() { + if (mQueuedTransition != null) { + mQueuedTransition.consume(); + mQueuedTransition = null; + } + } + + private void applyFinishOpenTransition() { + if (mFinishOpenTransaction != null) { + mFinishOpenTransaction.apply(); + mFinishOpenTransaction = null; + } + if (mFinishOpenTransitionCallback != null) { + mFinishOpenTransitionCallback.onTransitionFinished(null); + mFinishOpenTransitionCallback = null; + } + mOpeningRunning = false; + } + + private void applyAndFinish(@NonNull SurfaceControl.Transaction st, + @NonNull SurfaceControl.Transaction ft, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + applyFinishOpenTransition(); + st.apply(); + ft.apply(); + finishCallback.onTransitionFinished(null); + mCloseTransitionRequested = false; + } + @Override + public boolean startAnimation(@NonNull IBinder transition, + @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction st, + @NonNull SurfaceControl.Transaction ft, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + // Both mShellExecutor and Transitions#mMainExecutor are ShellMainThread, so we don't + // need to post to ShellExecutor when called. + if (info.getType() != WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION + && !isGestureBackTransition(info)) { + return false; + } + if (mApps == null || mApps.length == 0) { + if (mBackNavigationInfo != null && mShellBackAnimationRegistry + .isWaitingAnimation(mBackNavigationInfo.getType())) { + // Waiting for animation? Queue update to wait for animation start. + consumeQueuedTransitionIfNeeded(); + mQueuedTransition = new QueuedTransition(info, st, ft, finishCallback); + } else { + // animation was done, consume directly + applyAndFinish(st, ft, finishCallback); + } + return true; + } + + if (handlePrepareTransition(info, st, ft, finishCallback)) { + return true; + } + return handleCloseTransition(info, st, ft, finishCallback); + } + + @Override + public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + if (!isGestureBackTransition(info)) { + if (mOpeningRunning) { + applyFinishOpenTransition(); + } + if (mQueuedTransition != null) { + consumeQueuedTransitionIfNeeded(); + } + return; + } + // Handle the commit transition if this handler is running the open transition. + finishCallback.onTransitionFinished(null); + if (mCloseTransitionRequested) { + if (mApps == null || mApps.length == 0) { + if (mQueuedTransition == null) { + // animation was done + applyFinishOpenTransition(); + mCloseTransitionRequested = false; + } // else, let queued transition to play + } else { + // we are animating, wait until animation finish + mOnAnimationFinishCallback = () -> { + applyFinishOpenTransition(); + mCloseTransitionRequested = false; + }; + } + } + } + + /** + * Check whether this transition is prepare for predictive back animation, which could + * happen when core make an activity become visible. + */ + private boolean handlePrepareTransition( + @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction st, + @NonNull SurfaceControl.Transaction ft, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + if (info.getType() != WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION) { + return false; + } + + SurfaceControl openingLeash = null; + for (int i = mApps.length - 1; i >= 0; --i) { + if (mApps[i].mode == MODE_OPENING) { + openingLeash = mApps[i].leash; + } + } + if (openingLeash != null) { + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change c = info.getChanges().get(i); + if (TransitionUtil.isOpeningMode(c.getMode())) { + final Point offset = c.getEndRelOffset(); + st.setPosition(c.getLeash(), offset.x, offset.y); + st.reparent(c.getLeash(), openingLeash); + } + } + } + st.apply(); + mFinishOpenTransaction = ft; + mFinishOpenTransitionCallback = finishCallback; + mOpeningRunning = true; + return true; + } + + private boolean isGestureBackTransition(@NonNull TransitionInfo info) { + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change c = info.getChanges().get(i); + if (c.hasFlags(FLAG_BACK_GESTURE_ANIMATED) + && (TransitionUtil.isOpeningMode(c.getMode()) + || TransitionUtil.isClosingMode(c.getMode()))) { + return true; + } + } + return false; + } + /** + * Check whether this transition is triggered from back gesture commitment. + * Reparent the transition targets to animation leashes, so the animation won't be broken. + */ + private boolean handleCloseTransition(@NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction st, + @NonNull SurfaceControl.Transaction ft, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + SurfaceControl openingLeash = null; + SurfaceControl closingLeash = null; + for (int i = mApps.length - 1; i >= 0; --i) { + if (mApps[i].mode == MODE_OPENING) { + openingLeash = mApps[i].leash; + } + if (mApps[i].mode == MODE_CLOSING) { + closingLeash = mApps[i].leash; + } + } + if (openingLeash != null && closingLeash != null) { + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change c = info.getChanges().get(i); + if (TransitionUtil.isOpeningMode(c.getMode())) { + final Point offset = c.getEndRelOffset(); + st.setPosition(c.getLeash(), offset.x, offset.y); + st.reparent(c.getLeash(), openingLeash); + } else if (TransitionUtil.isClosingMode(c.getMode())) { + st.reparent(c.getLeash(), closingLeash); + } + } + } + st.apply(); + // mApps must exists + mOnAnimationFinishCallback = () -> { + ft.apply(); + finishCallback.onTransitionFinished(null); + mCloseTransitionRequested = false; + }; + return true; + } + + @Nullable + @Override + public WindowContainerTransaction handleRequest( + @NonNull IBinder transition, + @NonNull TransitionRequestInfo request) { + if (request.getType() == WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION) { + return new WindowContainerTransaction(); + } + if (TransitionUtil.isClosingType(request.getType()) && mCloseTransitionRequested) { + return new WindowContainerTransaction(); + } + return null; + } + + class QueuedTransition { + final TransitionInfo mInfo; + final SurfaceControl.Transaction mSt; + final SurfaceControl.Transaction mFt; + final Transitions.TransitionFinishCallback mFinishCallback; + QueuedTransition(@NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction st, + @NonNull SurfaceControl.Transaction ft, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + mInfo = info; + mSt = st; + mFt = ft; + mFinishCallback = finishCallback; + } + + void consume() { + // not animating, consume transition directly + if (mApps == null || mApps.length == 0) { + applyAndFinish(mSt, mFt, mFinishCallback); + return; + } + // we are animating + if (handlePrepareTransition(mInfo, mSt, mFt, mFinishCallback)) { + // handle merge transition if any + if (mCloseTransitionRequested) { + mOnAnimationFinishCallback = () -> { + applyFinishOpenTransition(); + mCloseTransitionRequested = false; + }; + } + } + handleCloseTransition(mInfo, mSt, mFt, mFinishCallback); + } + } + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 2dc6382d494d..717a4146dd31 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -375,7 +375,8 @@ public abstract class WMShellBaseModule { @ShellBackgroundThread Handler backgroundHandler, BackAnimationBackground backAnimationBackground, Optional<ShellBackAnimationRegistry> shellBackAnimationRegistry, - ShellCommandHandler shellCommandHandler) { + ShellCommandHandler shellCommandHandler, + Transitions transitions) { if (BackAnimationController.IS_ENABLED) { return shellBackAnimationRegistry.map( (animations) -> @@ -387,7 +388,8 @@ public abstract class WMShellBaseModule { context, backAnimationBackground, animations, - shellCommandHandler)); + shellCommandHandler, + transitions)); } return Optional.empty(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 874cca523ad1..066896b6f431 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -41,6 +41,7 @@ import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPI import static com.android.window.flags.Flags.enforceShellThreadModel; import static com.android.window.flags.Flags.ensureWallpaperInTransitions; import static com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary; +import static com.android.window.flags.Flags.migratePredictiveBackTransition; import static com.android.wm.shell.shared.TransitionUtil.isClosingType; import static com.android.wm.shell.shared.TransitionUtil.isOpeningType; import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; @@ -822,7 +823,8 @@ public class Transitions implements RemoteCallable<Transitions>, } // The change has already animated by back gesture, don't need to play transition // animation on it. - if (change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)) { + if (!migratePredictiveBackTransition() + && change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)) { info.getChanges().remove(i); } } 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 57e469d5cbd2..56fad952dc31 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 @@ -68,6 +68,7 @@ import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.sysui.ShellSharedConstants; +import com.android.wm.shell.transition.Transitions; import org.junit.Before; import org.junit.Test; @@ -114,6 +115,8 @@ public class BackAnimationControllerTest extends ShellTestCase { @Mock private ShellCommandHandler mShellCommandHandler; @Mock + private Transitions mTransitions; + @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private BackAnimationController mController; @@ -156,7 +159,8 @@ public class BackAnimationControllerTest extends ShellTestCase { mContentResolver, mAnimationBackground, mShellBackAnimationRegistry, - mShellCommandHandler); + mShellCommandHandler, + mTransitions); mShellInit.init(); mShellExecutor.flushAll(); mTouchableRegion = new Rect(0, 0, 100, 100); @@ -316,7 +320,8 @@ public class BackAnimationControllerTest extends ShellTestCase { mContentResolver, mAnimationBackground, mShellBackAnimationRegistry, - mShellCommandHandler); + mShellCommandHandler, + mTransitions); shellInit.init(); registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 7d70ea13f12c..5b96d2fd4171 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -10803,6 +10803,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return true; } } + if (mAtmService.mBackNavigationController.isStartingSurfaceShown(this)) { + return true; + } if (!super.isSyncFinished(group)) return false; if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController .isVisibilityUnknown(this)) { diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 78636a7870cf..5a0cbf3e5f83 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -250,7 +250,7 @@ public class AppTransitionController { ArraySet<ActivityRecord> tmpOpenApps = mDisplayContent.mOpeningApps; ArraySet<ActivityRecord> tmpCloseApps = mDisplayContent.mClosingApps; - if (mDisplayContent.mAtmService.mBackNavigationController.isMonitoringTransition()) { + if (mDisplayContent.mAtmService.mBackNavigationController.isMonitoringFinishTransition()) { tmpOpenApps = new ArraySet<>(mDisplayContent.mOpeningApps); tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps); if (mDisplayContent.mAtmService.mBackNavigationController diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 0f8d68b713a7..924f765ae79d 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_NONE; +import static android.view.WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION; import static android.view.WindowManager.TRANSIT_TO_BACK; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW; @@ -47,6 +48,7 @@ import android.os.RemoteException; import android.os.SystemProperties; import android.text.TextUtils; import android.util.ArraySet; +import android.util.Pair; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.RemoteAnimationTarget; @@ -83,11 +85,6 @@ class BackNavigationController { private AnimationHandler mAnimationHandler; - /** - * The transition who match the back navigation targets, - * release animation after this transition finish. - */ - private Transition mWaitTransitionFinish; private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>(); @@ -143,7 +140,7 @@ class BackNavigationController { BackNavigationInfo.Builder infoBuilder = new BackNavigationInfo.Builder(); synchronized (wmService.mGlobalLock) { - if (isMonitoringTransition()) { + if (isMonitoringFinishTransition()) { Slog.w(TAG, "Previous animation hasn't finish, status: " + mAnimationHandler); // Don't start any animation for it. return null; @@ -308,6 +305,7 @@ class BackNavigationController { backType = BackNavigationInfo.TYPE_CALLBACK; } else if (prevTask.isActivityTypeHome()) { removedWindowContainer = currentTask; + prevTask = prevTask.getRootTask(); backType = BackNavigationInfo.TYPE_RETURN_TO_HOME; final ActivityRecord ar = prevTask.getTopNonFinishingActivity(); mShowWallpaper = ar != null && ar.hasWallpaper(); @@ -562,10 +560,15 @@ class BackNavigationController { return !prevActivities.isEmpty(); } - boolean isMonitoringTransition() { + boolean isMonitoringFinishTransition() { return mAnimationHandler.mComposed || mNavigationMonitor.isMonitorForRemote(); } + boolean isMonitoringPrepareTransition(Transition transition) { + return mAnimationHandler.mComposed + && mAnimationHandler.mOpenAnimAdaptor.mPreparedOpenTransition == transition; + } + private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) { mPendingAnimation = builder.build(); mWindowManagerService.mWindowPlacerLocked.requestTraversal(); @@ -576,7 +579,9 @@ class BackNavigationController { } private boolean isWaitBackTransition() { - return mAnimationHandler.mComposed && mAnimationHandler.mWaitTransition; + // Ignore mWaitTransition while flag is enabled. + return mAnimationHandler.mComposed && (Flags.migratePredictiveBackTransition() + || mAnimationHandler.mWaitTransition); } boolean isKeyguardOccluded(WindowState focusWindow) { @@ -626,7 +631,7 @@ class BackNavigationController { */ boolean removeIfContainsBackAnimationTargets(ArraySet<ActivityRecord> openApps, ArraySet<ActivityRecord> closeApps) { - if (!isMonitoringTransition()) { + if (!isMonitoringFinishTransition()) { return false; } mTmpCloseApps.addAll(closeApps); @@ -652,7 +657,6 @@ class BackNavigationController { final ActivityRecord ar = openApps.valueAt(i); if (mAnimationHandler.isTarget(ar, true /* open */)) { openApps.removeAt(i); - mAnimationHandler.markStartingSurfaceMatch(null /* reparentTransaction */); } } for (int i = closeApps.size() - 1; i >= 0; --i) { @@ -670,6 +674,12 @@ class BackNavigationController { mAnimationHandler.markWindowHasDrawn(openActivity); } + boolean isStartingSurfaceShown(ActivityRecord openActivity) { + if (!Flags.migratePredictiveBackTransition()) { + return false; + } + return mAnimationHandler.isStartingSurfaceDrawn(openActivity); + } @VisibleForTesting class NavigationMonitor { // The window which triggering the back navigation. @@ -767,8 +777,14 @@ class BackNavigationController { * open or close list. */ void onTransactionReady(Transition transition, ArrayList<Transition.ChangeInfo> targets, - SurfaceControl.Transaction startTransaction) { - if (!isMonitoringTransition() || targets.isEmpty()) { + SurfaceControl.Transaction startTransaction, + SurfaceControl.Transaction finishTransaction) { + if (isMonitoringPrepareTransition(transition)) { + // Flag target matches and prepare to remove windowless surface. + mAnimationHandler.markStartingSurfaceMatch(startTransaction); + return; + } + if (!isMonitoringFinishTransition() || targets.isEmpty()) { return; } if (mAnimationHandler.hasTargetDetached()) { @@ -801,42 +817,40 @@ class BackNavigationController { if (!matchAnimationTargets) { mNavigationMonitor.onTransitionReadyWhileNavigate(mTmpOpenApps, mTmpCloseApps); } else { - if (mWaitTransitionFinish != null) { + if (mAnimationHandler.mPrepareCloseTransition != null) { Slog.e(TAG, "Gesture animation is applied on another transition?"); } - mWaitTransitionFinish = transition; - // Flag target matches to defer remove the splash screen. - for (int i = mTmpOpenApps.size() - 1; i >= 0; --i) { - final WindowContainer wc = mTmpOpenApps.get(i); - if (mAnimationHandler.isTarget(wc, true /* open */)) { - mAnimationHandler.markStartingSurfaceMatch(startTransaction); - break; - } + mAnimationHandler.mPrepareCloseTransition = transition; + if (!Flags.migratePredictiveBackTransition()) { + // Because the target will reparent to transition root, so it cannot be controlled + // by animation leash. Hide the close target when transition starts. + startTransaction.hide(mAnimationHandler.mCloseAdaptor.mTarget.getSurfaceControl()); } + // Flag target matches and prepare to remove windowless surface. + mAnimationHandler.markStartingSurfaceMatch(startTransaction); // release animation leash if (mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction != null) { - startTransaction.merge(mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction); + finishTransaction.merge(mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction); mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction = null; } - // Because the target will reparent to transition root, so it cannot be controlled by - // animation leash. Hide the close target when transition starts. - startTransaction.hide(mAnimationHandler.mCloseAdaptor.mTarget.getSurfaceControl()); } mTmpOpenApps.clear(); mTmpCloseApps.clear(); } boolean isMonitorTransitionTarget(WindowContainer wc) { - if (!isWaitBackTransition() || mWaitTransitionFinish == null) { - return false; + if ((isWaitBackTransition() && mAnimationHandler.mPrepareCloseTransition != null) + || (mAnimationHandler.mOpenAnimAdaptor != null + && mAnimationHandler.mOpenAnimAdaptor.mPreparedOpenTransition != null)) { + return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */); } - return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */); + return false; } boolean shouldPauseTouch(WindowContainer wc) { // Once the close transition is ready, it means the onBackInvoked callback has invoked, and // app is ready to trigger next transition, no matter what it will be. - return mAnimationHandler.mComposed && mWaitTransitionFinish == null + return mAnimationHandler.mComposed && mAnimationHandler.mPrepareCloseTransition == null && mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */); } @@ -847,7 +861,6 @@ class BackNavigationController { void clearBackAnimations(boolean cancel) { mAnimationHandler.clearBackAnimateTarget(cancel); mNavigationMonitor.stopMonitorTransition(); - mWaitTransitionFinish = null; } /** @@ -858,7 +871,13 @@ class BackNavigationController { */ void onTransitionFinish(ArrayList<Transition.ChangeInfo> targets, @NonNull Transition finishedTransition) { - if (finishedTransition == mWaitTransitionFinish) { + if (isMonitoringPrepareTransition(finishedTransition)) { + if (mAnimationHandler.mPrepareCloseTransition == null) { + clearBackAnimations(true /* cancel */); + } + return; + } + if (finishedTransition == mAnimationHandler.mPrepareCloseTransition) { clearBackAnimations(false /* cancel */); } if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) { @@ -938,6 +957,7 @@ class BackNavigationController { // the opening target like starting window do. private boolean mStartingSurfaceTargetMatch; private ActivityRecord[] mOpenActivities; + Transition mPrepareCloseTransition; AnimationHandler(WindowManagerService wms) { mWindowManagerService = wms; @@ -982,6 +1002,12 @@ class BackNavigationController { @NonNull ActivityRecord[] openingActivities) { if (isActivitySwitch(close, open)) { mSwitchType = ACTIVITY_SWITCH; + if (Flags.migratePredictiveBackTransition()) { + final Pair<WindowContainer, WindowContainer[]> replaced = + promoteToTFIfNeeded(close, open); + close = replaced.first; + open = replaced.second; + } } else if (isTaskSwitch(close, open)) { mSwitchType = TASK_SWITCH; } else if (isDialogClose(close)) { @@ -1019,6 +1045,34 @@ class BackNavigationController { mOpenActivities = openingActivities; } + private Pair<WindowContainer, WindowContainer[]> promoteToTFIfNeeded( + WindowContainer close, WindowContainer[] open) { + WindowContainer replaceClose = close; + TaskFragment closeTF = close.asActivityRecord().getTaskFragment(); + if (closeTF != null && !closeTF.isEmbedded()) { + closeTF = null; + } + final WindowContainer[] replaceOpen = new WindowContainer[open.length]; + if (open.length >= 2) { // Promote to TaskFragment + for (int i = open.length - 1; i >= 0; --i) { + replaceOpen[i] = open[i].asActivityRecord().getTaskFragment(); + replaceClose = closeTF != null ? closeTF : close; + } + } else { + TaskFragment openTF = open[0].asActivityRecord().getTaskFragment(); + if (openTF != null && !openTF.isEmbedded()) { + openTF = null; + } + if (closeTF != openTF) { + replaceOpen[0] = openTF != null ? openTF : open[0]; + replaceClose = closeTF != null ? closeTF : close; + } else { + replaceOpen[0] = open[0]; + } + } + return new Pair<>(replaceClose, replaceOpen); + } + private boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer[] open, @NonNull ActivityRecord[] openingActivities) { if (mComposed || mWaitTransition) { @@ -1080,7 +1134,8 @@ class BackNavigationController { } void markWindowHasDrawn(ActivityRecord activity) { - if (!mComposed || mWaitTransition) { + if (!mComposed || mWaitTransition || mOpenAnimAdaptor.mPreparedOpenTransition == null + || mOpenAnimAdaptor.mRequestedStartingSurfaceId == INVALID_TASK_ID) { return; } boolean allWindowDrawn = true; @@ -1096,6 +1151,17 @@ class BackNavigationController { } } + boolean isStartingSurfaceDrawn(ActivityRecord activity) { + // Check whether we create windowless surface to prepare open transition + if (!mComposed || mOpenAnimAdaptor.mPreparedOpenTransition == null) { + return false; + } + if (isTarget(activity, true /* open */)) { + return mOpenAnimAdaptor.mStartingSurface != null; + } + return false; + } + private static boolean isAnimateTarget(@NonNull WindowContainer window, @NonNull WindowContainer animationTarget, int switchType) { if (switchType == TASK_SWITCH) { @@ -1109,7 +1175,9 @@ class BackNavigationController { && window.hasChild(animationTarget)); } else if (switchType == ACTIVITY_SWITCH) { return window == animationTarget - || (window.asTaskFragment() != null && window.hasChild(animationTarget)); + || (window.asTaskFragment() != null && window.hasChild(animationTarget)) + || (animationTarget.asTaskFragment() != null + && animationTarget.hasChild(window)); } return false; } @@ -1122,8 +1190,14 @@ class BackNavigationController { resetActivity.mDisplayContent .continueUpdateOrientationForDiffOrienLaunchingApp(); } + final Transition finishTransition = + resetActivity.mTransitionController.mFinishingTransition; + final boolean inFinishTransition = finishTransition != null + && (mPrepareCloseTransition == finishTransition + || (mOpenAnimAdaptor != null + && mOpenAnimAdaptor.mPreparedOpenTransition == finishTransition)); if (resetActivity.mLaunchTaskBehind) { - restoreLaunchBehind(resetActivity, cancel); + restoreLaunchBehind(resetActivity, cancel, inFinishTransition); } } } @@ -1137,12 +1211,25 @@ class BackNavigationController { } } - void markStartingSurfaceMatch(SurfaceControl.Transaction reparentTransaction) { + void markStartingSurfaceMatch(SurfaceControl.Transaction startTransaction) { if (mStartingSurfaceTargetMatch) { return; } mStartingSurfaceTargetMatch = true; - mOpenAnimAdaptor.reparentWindowlessSurfaceToTarget(reparentTransaction); + + if (mOpenAnimAdaptor.mRequestedStartingSurfaceId == INVALID_TASK_ID) { + return; + } + final SurfaceControl startingSurface = mOpenAnimAdaptor.mStartingSurface; + if (startingSurface != null && startingSurface.isValid()) { + startTransaction.addTransactionCommittedListener(Runnable::run, () -> { + synchronized (mWindowManagerService.mGlobalLock) { + if (mOpenAnimAdaptor != null) { + mOpenAnimAdaptor.cleanUpWindowlessSurface(true); + } + } + }); + } } void clearBackAnimateTarget(boolean cancel) { @@ -1150,6 +1237,7 @@ class BackNavigationController { mComposed = false; finishPresentAnimations(cancel); } + mPrepareCloseTransition = null; mWaitTransition = false; mStartingSurfaceTargetMatch = false; mSwitchType = UNKNOWN; @@ -1239,6 +1327,9 @@ class BackNavigationController { // requested one during animating. private int mRequestedStartingSurfaceId = INVALID_TASK_ID; private SurfaceControl mStartingSurface; + + private Transition mPreparedOpenTransition; + BackWindowAnimationAdaptorWrapper(boolean isOpen, int switchType, @NonNull WindowContainer... targets) { mAdaptors = new BackWindowAnimationAdaptor[targets.length]; @@ -1267,6 +1358,8 @@ class BackNavigationController { mCloseTransaction.apply(); mCloseTransaction = null; } + + mPreparedOpenTransition = null; } private RemoteAnimationTarget createWrapTarget() { @@ -1279,8 +1372,7 @@ class BackNavigationController { unionBounds.union(mAdaptors[i].mAnimationTarget.localBounds); } final WindowContainer wc = mAdaptors[0].mTarget; - final Task task = wc.asActivityRecord() != null - ? wc.asActivityRecord().getTask() : wc.asTask(); + final Task task = mAdaptors[0].getTopTask(); final RemoteAnimationTarget represent = mAdaptors[0].mAnimationTarget; final SurfaceControl leashSurface = new SurfaceControl.Builder() .setName("cross-animation-leash") @@ -1293,7 +1385,7 @@ class BackNavigationController { mCloseTransaction = new SurfaceControl.Transaction(); mCloseTransaction.reparent(leashSurface, null); final SurfaceControl.Transaction pt = wc.getPendingTransaction(); - pt.setLayer(leashSurface, wc.getParent().getLastLayer()); + pt.setLayer(leashSurface, wc.getLastLayer()); for (int i = mAdaptors.length - 1; i >= 0; --i) { BackWindowAnimationAdaptor adaptor = mAdaptors[i]; pt.reparent(adaptor.mAnimationTarget.leash, leashSurface); @@ -1323,15 +1415,20 @@ class BackNavigationController { } final WindowContainer mainOpen = mAdaptors[0].mTarget; final int switchType = mAdaptors[0].mSwitchType; - final Task openTask = switchType == TASK_SWITCH - ? mainOpen.asTask() : switchType == ACTIVITY_SWITCH - ? mainOpen.asActivityRecord().getTask() : null; + final Task openTask = mAdaptors[0].getTopTask(); if (openTask == null) { return; } - final ActivityRecord mainActivity = switchType == ACTIVITY_SWITCH - ? mainOpen.asActivityRecord() - : openTask.getTopNonFinishingActivity(); + ActivityRecord mainActivity = null; + if (switchType == ACTIVITY_SWITCH) { + mainActivity = mainOpen.asActivityRecord(); + if (mainActivity == null && mainOpen.asTaskFragment() != null) { + mainActivity = mainOpen.asTaskFragment().getTopNonFinishingActivity(); + } + } + if (mainActivity == null) { + mainActivity = openTask.getTopNonFinishingActivity(); + } if (mainActivity == null) { return; } @@ -1363,6 +1460,8 @@ class BackNavigationController { synchronized (openTask.mWmService.mGlobalLock) { if (mRequestedStartingSurfaceId != INVALID_TASK_ID) { mStartingSurface = sc; + openTask.mWmService.mWindowPlacerLocked + .requestTraversal(); } else { sc.release(); } @@ -1371,28 +1470,6 @@ class BackNavigationController { }); } - // When back gesture has triggered and transition target matches navigation target, - // reparent the starting surface to the opening target as it's starting window. - void reparentWindowlessSurfaceToTarget(SurfaceControl.Transaction reparentTransaction) { - if (mRequestedStartingSurfaceId == INVALID_TASK_ID) { - return; - } - // If open target matches, reparent to open activity or task - if (mStartingSurface != null && mStartingSurface.isValid()) { - SurfaceControl.Transaction transaction = reparentTransaction != null - ? reparentTransaction : mAdaptors[0].mTarget.getPendingTransaction(); - if (mAdaptors.length != 1) { - // More than one opening window, reparent starting surface to leaf task. - final WindowContainer wc = mAdaptors[0].mTarget; - final Task task = wc.asActivityRecord() != null - ? wc.asActivityRecord().getTask() : wc.asTask(); - transaction.reparent(mStartingSurface, task != null - ? task.getSurfaceControl() - : mAdaptors[0].mTarget.getSurfaceControl()); - } - } - } - /** * Ask shell to clear the starting surface. * @param openTransitionMatch if true, shell will play the remove starting window @@ -1430,6 +1507,22 @@ class BackNavigationController { mSwitchType = switchType; } + Task getTopTask() { + final Task asTask = mTarget.asTask(); + if (asTask != null) { + return asTask; + } + final ActivityRecord ar = mTarget.asActivityRecord(); + if (ar != null) { + return ar.getTask(); + } + final TaskFragment tf = mTarget.asTaskFragment(); + if (tf != null) { + return tf.getTask(); + } + return null; + } + @Override public boolean getShowWallpaper() { return false; @@ -1619,9 +1712,8 @@ class BackNavigationController { needsLaunchBehind = snapshot == null; } if (needsLaunchBehind) { - for (int i = visibleOpenActivities.length - 1; i >= 0; --i) { - setLaunchBehind(visibleOpenActivities[i]); - } + openAnimationAdaptor.mPreparedOpenTransition = + setLaunchBehind(visibleOpenActivities); } // Force update mLastSurfaceShowing for opening activity and its task. if (mWindowManagerService.mRoot.mTransitionController.isShellTransitionsEnabled()) { @@ -1677,13 +1769,22 @@ class BackNavigationController { // animation was canceled return; } - if (!triggerBack) { - clearBackAnimateTarget(true /* cancel */); + if (Flags.migratePredictiveBackTransition()) { + if (mOpenAnimAdaptor == null + || mOpenAnimAdaptor.mPreparedOpenTransition == null) { + // no open nor close transition, this is window animation + if (!triggerBack) { + clearBackAnimateTarget(true /* cancel */); + } + } } else { - mWaitTransition = true; + if (!triggerBack) { + clearBackAnimateTarget(true /* cancel */); + } else { + mWaitTransition = true; + } } } - // TODO Add timeout monitor if transition didn't happen } }; } @@ -1740,28 +1841,75 @@ class BackNavigationController { return openActivities; } - private static void setLaunchBehind(@NonNull ActivityRecord activity) { - if (!activity.isVisibleRequested()) { - // The transition could commit the visibility and in the finishing state, that could - // skip commitVisibility call in setVisibility cause the activity won't visible here. - // Call it again to make sure the activity could be visible while handling the pending - // animation. - // Do not performLayout during prepare animation, because it could cause focus window - // change. Let that happen after the BackNavigationInfo has returned to shell. - activity.commitVisibility(true, false /* performLayout */); + private static Transition setLaunchBehind(@NonNull ActivityRecord[] activities) { + final boolean migrateBackTransition = Flags.migratePredictiveBackTransition(); + final ArrayList<ActivityRecord> affects = new ArrayList<>(); + for (int i = activities.length - 1; i >= 0; --i) { + final ActivityRecord activity = activities[i]; + if (activity.mLaunchTaskBehind || activity.isVisibleRequested()) { + continue; + } + affects.add(activity); + } + if (affects.isEmpty()) { + return null; + } + + final TransitionController tc = activities[0].mTransitionController; + final Transition prepareOpen = migrateBackTransition && !tc.isCollecting() + ? tc.createTransition(TRANSIT_PREPARE_BACK_NAVIGATION) : null; + + for (int i = affects.size() - 1; i >= 0; --i) { + final ActivityRecord activity = affects.get(i); + if (!migrateBackTransition && !activity.isVisibleRequested()) { + // The transition could commit the visibility and in the finishing state, that could + // skip commitVisibility call in setVisibility cause the activity won't visible + // here. + // Call it again to make sure the activity could be visible while handling the + // pending animation. + // Do not performLayout during prepare animation, because it could cause focus + // window change. Let that happen after the BackNavigationInfo has returned to + // shell. + activity.commitVisibility(true, false /* performLayout */); + } activity.mTransitionController.mSnapshotController .mActivitySnapshotController.addOnBackPressedActivity(activity); + activity.mLaunchTaskBehind = true; + + ProtoLog.d(WM_DEBUG_BACK_PREVIEW, + "Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity); + activity.mTaskSupervisor.mStoppingActivities.remove(activity); + + if (!migrateBackTransition) { + activity.getDisplayContent().ensureActivitiesVisible(null /* starting */, + true /* notifyClients */); + } else if (activity.shouldBeVisible()) { + activity.ensureActivityConfiguration(true /* ignoreVisibility */); + activity.makeVisibleIfNeeded(null /* starting */, true /* notifyToClient */); + } + } + boolean needTransition = false; + final DisplayContent dc = affects.get(0).getDisplayContent(); + for (int i = affects.size() - 1; i >= 0; --i) { + final ActivityRecord activity = affects.get(i); + needTransition |= tc.isCollecting(activity); + } + if (prepareOpen != null) { + if (needTransition) { + tc.requestStartTransition(prepareOpen, + null /*startTask */, null /* remoteTransition */, + null /* displayChange */); + tc.setReady(dc); + return prepareOpen; + } else { + prepareOpen.abort(); + } } - activity.mLaunchTaskBehind = true; - - ProtoLog.d(WM_DEBUG_BACK_PREVIEW, - "Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity); - activity.mTaskSupervisor.mStoppingActivities.remove(activity); - activity.getDisplayContent().ensureActivitiesVisible(null /* starting */, - true /* notifyClients */); + return null; } - private static void restoreLaunchBehind(@NonNull ActivityRecord activity, boolean cancel) { + private static void restoreLaunchBehind(@NonNull ActivityRecord activity, boolean cancel, + boolean finishTransition) { if (!activity.isAttached()) { // The activity was detached from hierarchy. return; @@ -1771,9 +1919,15 @@ class BackNavigationController { "Setting Activity.mLauncherTaskBehind to false. Activity=%s", activity); if (cancel) { - // Restore the launch-behind state - // TODO b/347168362 Change status directly during collecting for a transition. - activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token); + final boolean migrateBackTransition = Flags.migratePredictiveBackTransition(); + if (migrateBackTransition && finishTransition) { + activity.commitVisibility(false /* visible */, false /* performLayout */, + true /* fromTransition */); + } else { + // Restore the launch-behind state + // TODO b/347168362 Change status directly during collecting for a transition. + activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token); + } // Ignore all change activity.mTransitionController.mSnapshotController .mActivitySnapshotController.clearOnBackPressedActivities(); @@ -1835,12 +1989,7 @@ class BackNavigationController { && ah.mSwitchType != AnimationHandler.ACTIVITY_SWITCH)) { return; } - for (int i = mAnimationHandler.mOpenActivities.length - 1; i >= 0; --i) { - final ActivityRecord preDrawActivity = mAnimationHandler.mOpenActivities[i]; - if (!preDrawActivity.mLaunchTaskBehind) { - setLaunchBehind(preDrawActivity); - } - } + setLaunchBehind(mAnimationHandler.mOpenActivities); } } } @@ -1853,10 +2002,15 @@ class BackNavigationController { snapshot = task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( task.mTaskId, task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */); - } else if (w.asActivityRecord() != null) { - final ActivityRecord ar = w.asActivityRecord(); - snapshot = ar.mWmService.mSnapshotController.mActivitySnapshotController - .getSnapshot(visibleOpenActivities); + } else { + ActivityRecord ar = w.asActivityRecord(); + if (ar == null && w.asTaskFragment() != null) { + ar = w.asTaskFragment().getTopNonFinishingActivity(); + } + if (ar != null) { + snapshot = ar.mWmService.mSnapshotController.mActivitySnapshotController + .getSnapshot(visibleOpenActivities); + } } return isSnapshotCompatible(snapshot, visibleOpenActivities) ? snapshot : null; diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index af3ed28d2c2a..db95a1e14157 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1763,7 +1763,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // Check whether the participants were animated from back navigation. mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets, - transaction); + transaction, mFinishTransaction); final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction); info.setDebugId(mSyncId); mController.assignTrack(this, info); 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 a159ce354a7b..44837d7ba32e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -58,6 +58,7 @@ import android.os.Looper; import android.os.RemoteCallback; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsDisabled; import android.util.ArraySet; import android.view.WindowManager; import android.window.BackAnimationAdapter; @@ -72,6 +73,7 @@ import android.window.TaskSnapshot; import android.window.WindowOnBackInvokedDispatcher; import com.android.server.LocalServices; +import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Test; @@ -612,6 +614,7 @@ public class BackNavigationControllerTests extends WindowTestsBase { } @Test + @RequiresFlagsDisabled(Flags.FLAG_MIGRATE_PREDICTIVE_BACK_TRANSITION) public void testTransitionHappensCancelNavigation() { // Create a floating task and a fullscreen task, then navigating on fullscreen task. // The navigation should not been cancelled when transition happens on floating task, and |