diff options
12 files changed, 324 insertions, 243 deletions
diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java index 9b91cf2e9db6..a25e0351df83 100644 --- a/core/java/android/window/BackNavigationInfo.java +++ b/core/java/android/window/BackNavigationInfo.java @@ -89,8 +89,6 @@ public final class BackNavigationInfo implements Parcelable { @Nullable private final IOnBackInvokedCallback mOnBackInvokedCallback; private final boolean mPrepareRemoteAnimation; - @Nullable - private WindowContainerToken mDepartingWindowContainerToken; /** * Create a new {@link BackNavigationInfo} instance. @@ -100,20 +98,15 @@ public final class BackNavigationInfo implements Parcelable { * back preview. * @param onBackInvokedCallback The back callback registered by the current top level window. * @param departingWindowContainerToken The {@link WindowContainerToken} of departing window. - * @param isPrepareRemoteAnimation Return whether the core is preparing a back gesture - * animation, if true, the caller of startBackNavigation should - * be expected to receive an animation start callback. */ private BackNavigationInfo(@BackTargetType int type, @Nullable RemoteCallback onBackNavigationDone, @Nullable IOnBackInvokedCallback onBackInvokedCallback, - boolean isPrepareRemoteAnimation, - @Nullable WindowContainerToken departingWindowContainerToken) { + boolean isPrepareRemoteAnimation) { mType = type; mOnBackNavigationDone = onBackNavigationDone; mOnBackInvokedCallback = onBackInvokedCallback; mPrepareRemoteAnimation = isPrepareRemoteAnimation; - mDepartingWindowContainerToken = departingWindowContainerToken; } private BackNavigationInfo(@NonNull Parcel in) { @@ -121,7 +114,6 @@ public final class BackNavigationInfo implements Parcelable { mOnBackNavigationDone = in.readTypedObject(RemoteCallback.CREATOR); mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder()); mPrepareRemoteAnimation = in.readBoolean(); - mDepartingWindowContainerToken = in.readTypedObject(WindowContainerToken.CREATOR); } @Override @@ -130,7 +122,6 @@ public final class BackNavigationInfo implements Parcelable { dest.writeTypedObject(mOnBackNavigationDone, flags); dest.writeStrongInterface(mOnBackInvokedCallback); dest.writeBoolean(mPrepareRemoteAnimation); - dest.writeTypedObject(mDepartingWindowContainerToken, flags); } /** @@ -164,18 +155,6 @@ public final class BackNavigationInfo implements Parcelable { } /** - * Returns the {@link WindowContainerToken} of the highest container in the hierarchy being - * removed. - * <p> - * For example, if an Activity is the last one of its Task, the Task's token will be given. - * Otherwise, it will be the Activity's token. - */ - @Nullable - public WindowContainerToken getDepartingWindowContainerToken() { - return mDepartingWindowContainerToken; - } - - /** * Callback to be called when the back preview is finished in order to notify the server that * it can clean up the resources created for the animation. * @@ -212,7 +191,6 @@ public final class BackNavigationInfo implements Parcelable { + "mType=" + typeToString(mType) + " (" + mType + ")" + ", mOnBackNavigationDone=" + mOnBackNavigationDone + ", mOnBackInvokedCallback=" + mOnBackInvokedCallback - + ", mWindowContainerToken=" + mDepartingWindowContainerToken + '}'; } @@ -248,8 +226,6 @@ public final class BackNavigationInfo implements Parcelable { @Nullable private IOnBackInvokedCallback mOnBackInvokedCallback = null; private boolean mPrepareRemoteAnimation; - @Nullable - private WindowContainerToken mDepartingWindowContainerToken = null; /** * @see BackNavigationInfo#getType() @@ -285,20 +261,12 @@ public final class BackNavigationInfo implements Parcelable { } /** - * @see BackNavigationInfo#getDepartingWindowContainerToken() - */ - public void setDepartingWCT(@NonNull WindowContainerToken windowContainerToken) { - mDepartingWindowContainerToken = windowContainerToken; - } - - /** * Builds and returns an instance of {@link BackNavigationInfo} */ public BackNavigationInfo build() { return new BackNavigationInfo(mType, mOnBackNavigationDone, mOnBackInvokedCallback, - mPrepareRemoteAnimation, - mDepartingWindowContainerToken); + mPrepareRemoteAnimation); } } } diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 0956a71bd92d..c2da638aca8d 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -138,8 +138,11 @@ public final class TransitionInfo implements Parcelable { /** The container is a system window, excluding wallpaper and input-method. */ public static final int FLAG_IS_SYSTEM_WINDOW = 1 << 16; + /** The window was animated by back gesture. */ + public static final int FLAG_BACK_GESTURE_ANIMATED = 1 << 17; + /** The first unused bit. This can be used by remotes to attach custom flags to this change. */ - public static final int FLAG_FIRST_CUSTOM = 1 << 17; + public static final int FLAG_FIRST_CUSTOM = 1 << 18; /** The change belongs to a window that won't contain activities. */ public static final int FLAGS_IS_NON_APP_WINDOW = @@ -165,6 +168,7 @@ public final class TransitionInfo implements Parcelable { FLAG_IS_BEHIND_STARTING_WINDOW, FLAG_IS_OCCLUDED, FLAG_IS_SYSTEM_WINDOW, + FLAG_BACK_GESTURE_ANIMATED, FLAG_FIRST_CUSTOM }) public @interface ChangeFlags {} @@ -380,6 +384,9 @@ public final class TransitionInfo implements Parcelable { if ((flags & FLAG_IS_SYSTEM_WINDOW) != 0) { sb.append(sb.length() == 0 ? "" : "|").append("FLAG_IS_SYSTEM_WINDOW"); } + if ((flags & FLAG_BACK_GESTURE_ANIMATED) != 0) { + sb.append(sb.length() == 0 ? "" : "|").append("FLAG_BACK_GESTURE_ANIMATED"); + } if ((flags & FLAG_FIRST_CUSTOM) != 0) { sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM"); } diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index c1b4dcc1d3ff..4cc06e33ab62 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -2179,12 +2179,6 @@ "group": "WM_DEBUG_ANIM", "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "-23020844": { - "message": "Back: Reset surfaces", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, "-21399771": { "message": "activity %s already destroying, skipping request with reason:%s", "level": "VERBOSE", @@ -3823,12 +3817,6 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "1544805551": { - "message": "Skipping app transition animation. task=%s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/Task.java" - }, "1557732761": { "message": "For Intent %s bringing to top: %s", "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 64220c82fd9a..b6327e5d91f5 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 @@ -62,7 +62,6 @@ import com.android.wm.shell.common.annotations.ShellBackgroundThread; import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; -import com.android.wm.shell.transition.Transitions; import java.util.concurrent.atomic.AtomicBoolean; @@ -82,8 +81,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont SETTING_VALUE_OFF) == SETTING_VALUE_ON; /** Predictive back animation developer option */ private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false); - // TODO (b/241808055) Find a appropriate time to remove during refactor - private static final boolean ENABLE_SHELL_TRANSITIONS = Transitions.ENABLE_SHELL_TRANSITIONS; /** * Max duration to wait for a transition to finish before accepting another gesture start * request. @@ -121,8 +118,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private final TouchTracker mTouchTracker = new TouchTracker(); private final SparseArray<BackAnimationRunner> mAnimationDefinition = new SparseArray<>(); - private final Transitions mTransitions; - private BackTransitionHandler mBackTransitionHandler; @VisibleForTesting final IWindowFocusObserver mFocusObserver = new IWindowFocusObserver.Stub() { @@ -148,11 +143,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont @NonNull ShellController shellController, @NonNull @ShellMainThread ShellExecutor shellExecutor, @NonNull @ShellBackgroundThread Handler backgroundHandler, - Context context, - Transitions transitions) { + Context context) { this(shellInit, shellController, shellExecutor, backgroundHandler, - ActivityTaskManager.getService(), context, context.getContentResolver(), - transitions); + ActivityTaskManager.getService(), context, context.getContentResolver()); } @VisibleForTesting @@ -162,8 +155,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont @NonNull @ShellMainThread ShellExecutor shellExecutor, @NonNull @ShellBackgroundThread Handler bgHandler, @NonNull IActivityTaskManager activityTaskManager, - Context context, ContentResolver contentResolver, - Transitions transitions) { + Context context, ContentResolver contentResolver) { mShellController = shellController; mShellExecutor = shellExecutor; mActivityTaskManager = activityTaskManager; @@ -171,7 +163,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mContentResolver = contentResolver; mBgHandler = bgHandler; shellInit.addInitCallback(this::onInit, this); - mTransitions = transitions; } @VisibleForTesting @@ -182,10 +173,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private void onInit() { setupAnimationDeveloperSettingsObserver(mContentResolver, mBgHandler); createAdapter(); - if (ENABLE_SHELL_TRANSITIONS) { - mBackTransitionHandler = new BackTransitionHandler(this); - mTransitions.addHandler(mBackTransitionHandler); - } mShellController.addExternalInterface(KEY_EXTRA_SHELL_BACK_ANIMATION, this::createExternalInterface, this); @@ -335,17 +322,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } } - // In legacy transition, it would use `Task.mBackGestureStarted` in core to handle the - // following transition when back callback is invoked. - // If the back callback is not invoked, we should reset the token and finish the whole back - // navigation without waiting the transition. - if (!ENABLE_SHELL_TRANSITIONS) { - finishBackNavigation(); - } else if (!mTriggerBack) { - // reset the token to prevent it consume next transition. - mBackTransitionHandler.setDepartingWindowContainerToken(null); - finishBackNavigation(); - } + finishBackNavigation(); } /** @@ -614,10 +591,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont return; } mTransitionInProgress = true; - if (ENABLE_SHELL_TRANSITIONS) { - mBackTransitionHandler.setDepartingWindowContainerToken( - mBackNavigationInfo.getDepartingWindowContainerToken()); - } mShellExecutor.executeDelayed(mResetTransitionRunnable, MAX_TRANSITION_DURATION); } @@ -626,19 +599,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mTransitionInProgress = false; } - /** - * This should be called from {@link BackTransitionHandler#startAnimation} when the following - * transition is triggered by the real back callback in {@link #onBackAnimationFinished}. - * Will consume the default transition and finish current back navigation. - */ - void finishTransition(Transitions.TransitionFinishCallback finishCallback) { - ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishTransition()"); - mShellExecutor.execute(() -> { - finishBackNavigation(); - finishCallback.onTransitionFinished(null, null); - }); - } - private void createAdapter() { IBackAnimationRunner runner = new IBackAnimationRunner.Stub() { @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackTransitionHandler.java deleted file mode 100644 index 6d72d9c1f637..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackTransitionHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.back; - -import android.os.IBinder; -import android.view.SurfaceControl; -import android.window.TransitionInfo; -import android.window.TransitionRequestInfo; -import android.window.WindowContainerToken; -import android.window.WindowContainerTransaction; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.wm.shell.transition.Transitions; - -class BackTransitionHandler implements Transitions.TransitionHandler { - private BackAnimationController mBackAnimationController; - private WindowContainerToken mDepartingWindowContainerToken; - - BackTransitionHandler(@NonNull BackAnimationController backAnimationController) { - mBackAnimationController = backAnimationController; - } - - @Override - public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - if (mDepartingWindowContainerToken != null) { - final TransitionInfo.Change change = info.getChange(mDepartingWindowContainerToken); - if (change == null) { - return false; - } - - startTransaction.hide(change.getLeash()); - startTransaction.apply(); - mDepartingWindowContainerToken = null; - mBackAnimationController.finishTransition(finishCallback); - return true; - } - - return false; - } - - @Nullable - @Override - public WindowContainerTransaction handleRequest(@NonNull IBinder transition, - @NonNull TransitionRequestInfo request) { - return null; - } - - @Override - public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - } - - void setDepartingWindowContainerToken( - @Nullable WindowContainerToken departingWindowContainerToken) { - mDepartingWindowContainerToken = departingWindowContainerToken; - } -} - 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 1977dcb81e97..962be9da2111 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 @@ -260,13 +260,12 @@ public abstract class WMShellBaseModule { ShellInit shellInit, ShellController shellController, @ShellMainThread ShellExecutor shellExecutor, - @ShellBackgroundThread Handler backgroundHandler, - Transitions transitions + @ShellBackgroundThread Handler backgroundHandler ) { if (BackAnimationController.IS_ENABLED) { return Optional.of( new BackAnimationController(shellInit, shellController, shellExecutor, - backgroundHandler, context, transitions)); + backgroundHandler, context)); } return Optional.empty(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 928e71f8d3a6..63d4a6f5acd9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -41,6 +41,7 @@ import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_RELAUNCH; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL; import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL; import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS; @@ -395,6 +396,11 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } } + // The back gesture has animated this change before transition happen, so here we don't + // play the animation again. + if (change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)) { + continue; + } // Don't animate anything that isn't independent. if (!TransitionInfo.isIndependent(change, info)) continue; 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 7896247c5f5a..7eccbf42e67d 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 @@ -64,7 +64,6 @@ import com.android.wm.shell.TestShellExecutor; 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.Rule; @@ -103,9 +102,6 @@ public class BackAnimationControllerTest extends ShellTestCase { private IRemoteAnimationRunner mBackAnimationRunner; @Mock - private Transitions mTransitions; - - @Mock private ShellController mShellController; private BackAnimationController mController; @@ -127,7 +123,7 @@ public class BackAnimationControllerTest extends ShellTestCase { mController = new BackAnimationController(mShellInit, mShellController, mShellExecutor, new Handler(mTestableLooper.getLooper()), mActivityTaskManager, mContext, - mContentResolver, mTransitions); + mContentResolver); mController.setEnableUAnimation(true); mShellInit.init(); mEventTime = 0; @@ -225,7 +221,7 @@ public class BackAnimationControllerTest extends ShellTestCase { mController = new BackAnimationController(shellInit, mShellController, mShellExecutor, new Handler(mTestableLooper.getLooper()), mActivityTaskManager, mContext, - mContentResolver, mTransitions); + mContentResolver); shellInit.init(); mController.setBackToLauncherCallback(mIOnBackInvokedCallback, mBackAnimationRunner); diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 901153300169..bd22b32742a1 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -215,9 +215,20 @@ public class AppTransitionController { mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded( mDisplayContent.mOpeningApps); + ArraySet<ActivityRecord> tmpOpenApps = mDisplayContent.mOpeningApps; + ArraySet<ActivityRecord> tmpCloseApps = mDisplayContent.mClosingApps; + if (mDisplayContent.mAtmService.mBackNavigationController.isWaitBackTransition()) { + tmpOpenApps = new ArraySet<>(mDisplayContent.mOpeningApps); + tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps); + if (mDisplayContent.mAtmService.mBackNavigationController + .removeIfContainsBackAnimationTargets(tmpOpenApps, tmpCloseApps)) { + mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(null); + } + } + @TransitionOldType final int transit = getTransitCompatType( - mDisplayContent.mAppTransition, mDisplayContent.mOpeningApps, - mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers, + mDisplayContent.mAppTransition, tmpOpenApps, + tmpCloseApps, mDisplayContent.mChangingContainers, mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(), mDisplayContent.mSkipAppTransitionAnimation); mDisplayContent.mSkipAppTransitionAnimation = false; @@ -225,22 +236,21 @@ public class AppTransitionController { ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "handleAppTransitionReady: displayId=%d appTransition={%s}" + " openingApps=[%s] closingApps=[%s] transit=%s", - mDisplayContent.mDisplayId, appTransition.toString(), mDisplayContent.mOpeningApps, - mDisplayContent.mClosingApps, AppTransition.appTransitionOldToString(transit)); + mDisplayContent.mDisplayId, appTransition.toString(), tmpOpenApps, + tmpCloseApps, AppTransition.appTransitionOldToString(transit)); // Find the layout params of the top-most application window in the tokens, which is // what will control the animation theme. If all closing windows are obscured, then there is // no need to do an animation. This is the case, for example, when this transition is being // done behind a dream window. - final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps, - mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers); + final ArraySet<Integer> activityTypes = collectActivityTypes(tmpOpenApps, + tmpCloseApps, mDisplayContent.mChangingContainers); final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - mDisplayContent.mChangingContainers); + tmpOpenApps, tmpCloseApps, mDisplayContent.mChangingContainers); final ActivityRecord topOpeningApp = - getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */); + getTopApp(tmpOpenApps, false /* ignoreHidden */); final ActivityRecord topClosingApp = - getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */); + getTopApp(tmpCloseApps, false /* ignoreHidden */); final ActivityRecord topChangingApp = getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */); final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity); @@ -258,8 +268,7 @@ public class AppTransitionController { final int layoutRedo; mService.mSurfaceAnimationRunner.deferStartingAnimations(); try { - applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit, - animLp, voiceInteraction); + applyAnimations(tmpOpenApps, tmpCloseApps, transit, animLp, voiceInteraction); handleClosingApps(); handleOpeningApps(); handleChangingApps(transit); diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 6ff2bb30cc0c..9398bbec4a63 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -19,6 +19,8 @@ package com.android.server.wm; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; +import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_TO_BACK; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW; @@ -32,6 +34,7 @@ import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.SystemProperties; +import android.util.ArraySet; import android.util.Slog; import android.view.IWindowFocusObserver; import android.view.RemoteAnimationTarget; @@ -41,7 +44,6 @@ import android.window.BackNavigationInfo; import android.window.IBackAnimationFinishedCallback; import android.window.OnBackInvokedCallbackInfo; import android.window.TaskSnapshot; -import android.window.WindowContainerToken; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; @@ -60,9 +62,9 @@ class BackNavigationController { private boolean mShowWallpaper; private Runnable mPendingAnimation; - // TODO (b/241808055) Find a appropriate time to remove during refactor - // Execute back animation with legacy transition system. Temporary flag for easier debugging. - static final boolean ENABLE_SHELL_TRANSITIONS = WindowManagerService.sEnableShellTransitions; + private final AnimationTargets mAnimationTargets = new AnimationTargets(); + private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>(); + private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>(); /** * true if the back predictability feature is enabled @@ -284,7 +286,6 @@ class BackNavigationController { } if (prepareAnimation) { - infoBuilder.setDepartingWCT(toWindowContainerToken(currentTask)); prepareAnimationIfNeeded(currentTask, prevTask, prevActivity, removedWindowContainer, backType, adapter); } @@ -303,11 +304,233 @@ class BackNavigationController { return infoBuilder.build(); } - private static WindowContainerToken toWindowContainerToken(WindowContainer<?> windowContainer) { - if (windowContainer == null || windowContainer.mRemoteToken == null) { - return null; + boolean isWaitBackTransition() { + return mAnimationTargets.mComposed && mAnimationTargets.mWaitTransition; + } + + // For legacy transition. + /** + * Once we find the transition targets match back animation targets, remove the target from + * list, so that transition won't count them in since the close animation was finished. + * + * @return {@code true} if the participants of this transition was animated by back gesture + * animations, and shouldn't join next transition. + */ + boolean removeIfContainsBackAnimationTargets(ArraySet<ActivityRecord> openApps, + ArraySet<ActivityRecord> closeApps) { + if (!isWaitBackTransition()) { + return false; + } + mTmpCloseApps.addAll(closeApps); + boolean result = false; + // Note: TmpOpenApps is empty. Unlike shell transition, the open apps will be removed from + // mOpeningApps if there is no visibility change. + if (mAnimationTargets.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps)) { + // remove close target from close list, open target from open list; + // but the open target can be in close list. + for (int i = openApps.size() - 1; i >= 0; --i) { + final ActivityRecord ar = openApps.valueAt(i); + if (mAnimationTargets.isTarget(ar, true /* open */)) { + openApps.removeAt(i); + } + } + for (int i = closeApps.size() - 1; i >= 0; --i) { + final ActivityRecord ar = closeApps.valueAt(i); + if (mAnimationTargets.isTarget(ar, false /* open */)) { + closeApps.removeAt(i); + } + } + result = true; + } + mTmpCloseApps.clear(); + return result; + } + + // For shell transition + /** + * Check whether the transition targets was animated by back gesture animation. + * Because the opening target could request to do other stuff at onResume, so it could become + * close target for a transition. So the condition here is + * The closing target should only exist in close list, but the opening target can be either in + * open or close list. + * @return {@code true} if the participants of this transition was animated by back gesture + * animations, and shouldn't join next transition. + */ + boolean containsBackAnimationTargets(Transition transition) { + if (!mAnimationTargets.mComposed + || (transition.mType != TRANSIT_CLOSE && transition.mType != TRANSIT_TO_BACK)) { + return false; + } + final ArraySet<WindowContainer> targets = transition.mParticipants; + for (int i = targets.size() - 1; i >= 0; --i) { + final WindowContainer wc = targets.valueAt(i); + if (wc.asActivityRecord() == null && wc.asTask() == null) { + continue; + } + // WC can be visible due to setLaunchBehind + if (wc.isVisibleRequested()) { + mTmpOpenApps.add(wc); + } else { + mTmpCloseApps.add(wc); + } + } + final boolean result = mAnimationTargets.containsBackAnimationTargets( + mTmpOpenApps, mTmpCloseApps); + mTmpOpenApps.clear(); + mTmpCloseApps.clear(); + return result; + } + + boolean isMonitorTransitionTarget(WindowContainer wc) { + if (!mAnimationTargets.mComposed || !mAnimationTargets.mWaitTransition) { + return false; + } + return mAnimationTargets.isTarget(wc, wc.isVisibleRequested() /* open */); + } + + /** + * Cleanup animation, this can either happen when transition ready or finish. + * @param cleanupTransaction The transaction which the caller want to apply the internal + * cleanup together. + */ + void clearBackAnimations(SurfaceControl.Transaction cleanupTransaction) { + mAnimationTargets.clearBackAnimateTarget(cleanupTransaction); + } + + /** + * TODO: Animation composer + * prepareAnimationIfNeeded will become too complicated in order to support + * ActivityRecord/WindowState, using a factory class to create the RemoteAnimationTargets for + * different scenario. + */ + private static class AnimationTargets { + ActivityRecord mCloseTarget; // Must be activity + WindowContainer mOpenTarget; // Can be activity or task if activity was removed + private boolean mComposed; + private boolean mWaitTransition; + private int mSwitchType = UNKNOWN; + private SurfaceControl.Transaction mFinishedTransaction; + + private static final int UNKNOWN = 0; + private static final int TASK_SWITCH = 1; + private static final int ACTIVITY_SWITCH = 2; + + void reset(@NonNull WindowContainer close, @NonNull WindowContainer open) { + clearBackAnimateTarget(null); + if (close.asActivityRecord() != null && open.asActivityRecord() != null + && (close.asActivityRecord().getTask() == open.asActivityRecord().getTask())) { + mSwitchType = ACTIVITY_SWITCH; + mCloseTarget = close.asActivityRecord(); + } else if (close.asTask() != null && open.asTask() != null + && close.asTask() != open.asTask()) { + mSwitchType = TASK_SWITCH; + mCloseTarget = close.asTask().getTopNonFinishingActivity(); + } else { + mSwitchType = UNKNOWN; + return; + } + + mOpenTarget = open; + mComposed = false; + mWaitTransition = false; + } + + void composeNewAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) { + reset(close, open); + if (mSwitchType == UNKNOWN || mComposed || mCloseTarget == mOpenTarget + || mCloseTarget == null || mOpenTarget == null) { + return; + } + mComposed = true; + mWaitTransition = false; + } + + boolean containTarget(ArrayList<WindowContainer> wcs, boolean open) { + for (int i = wcs.size() - 1; i >= 0; --i) { + if (isTarget(wcs.get(i), open)) { + return true; + } + } + return wcs.isEmpty(); + } + + boolean isTarget(WindowContainer wc, boolean open) { + if (open) { + return wc == mOpenTarget || mOpenTarget.hasChild(wc); + } + if (mSwitchType == TASK_SWITCH) { + return wc == mCloseTarget + || (wc.asTask() != null && wc.hasChild(mCloseTarget)); + } else if (mSwitchType == ACTIVITY_SWITCH) { + return wc == mCloseTarget; + } + return false; + } + + boolean setFinishTransaction(SurfaceControl.Transaction finishTransaction) { + if (!mComposed) { + return false; + } + mFinishedTransaction = finishTransaction; + return true; + } + + void finishPresentAnimations(SurfaceControl.Transaction t) { + if (!mComposed) { + return; + } + final SurfaceControl.Transaction pt = t != null ? t + : mOpenTarget.getPendingTransaction(); + if (mFinishedTransaction != null) { + pt.merge(mFinishedTransaction); + mFinishedTransaction = null; + } + } + + void clearBackAnimateTarget(SurfaceControl.Transaction cleanupTransaction) { + finishPresentAnimations(cleanupTransaction); + mCloseTarget = null; + mOpenTarget = null; + mComposed = false; + mWaitTransition = false; + mSwitchType = UNKNOWN; + if (mFinishedTransaction != null) { + Slog.w(TAG, "Clear back animation, found un-processed finished transaction"); + if (cleanupTransaction != null) { + cleanupTransaction.merge(mFinishedTransaction); + } else { + mFinishedTransaction.apply(); + } + mFinishedTransaction = null; + } + } + + // The close target must in close list + // The open target can either in close or open list + boolean containsBackAnimationTargets(ArrayList<WindowContainer> openApps, + ArrayList<WindowContainer> closeApps) { + return containTarget(closeApps, false /* open */) + && (containTarget(openApps, true /* open */) + || containTarget(openApps, false /* open */)); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(128); + sb.append("AnimationTargets{"); + sb.append(" mOpenTarget= "); + sb.append(mOpenTarget); + sb.append(" mCloseTarget= "); + sb.append(mCloseTarget); + sb.append(" mSwitchType= "); + sb.append(mSwitchType); + sb.append(" mComposed= "); + sb.append(mComposed); + sb.append(" mWaitTransition= "); + sb.append(mWaitTransition); + sb.append('}'); + return sb.toString(); } - return windowContainer.mRemoteToken.toWindowContainerToken(); } private void prepareAnimationIfNeeded(Task currentTask, @@ -373,10 +596,6 @@ class BackNavigationController { leashes.add(screenshotSurface); } } else if (prevTask != null) { - if (!ENABLE_SHELL_TRANSITIONS) { - // Special handling for preventing next transition. - currentTask.mBackGestureStarted = true; - } prevActivity = prevTask.getTopNonFinishingActivity(); if (prevActivity != null) { // Make previous task show from behind by marking its top activity as visible @@ -417,35 +636,36 @@ class BackNavigationController { for (SurfaceControl sc: leashes) { finishedTransaction.remove(sc); } - synchronized (mWindowManagerService.mGlobalLock) { - if (ENABLE_SHELL_TRANSITIONS) { - if (!triggerBack) { - if (!needsScreenshot(backType)) { - restoreLaunchBehind(finalPrevActivity); - } + if (triggerBack) { + final SurfaceControl surfaceControl = + removedWindowContainer.getSurfaceControl(); + if (surfaceControl != null && surfaceControl.isValid()) { + // The animation is finish and start waiting for transition, + // hide the task surface before it re-parented to avoid flicker. + finishedTransaction.hide(surfaceControl); } + } else if (!needsScreenshot(backType)) { + restoreLaunchBehind(finalPrevActivity); + } + if (!mAnimationTargets.setFinishTransaction(finishedTransaction)) { + finishedTransaction.apply(); + } + if (!triggerBack) { + mAnimationTargets.clearBackAnimateTarget(null); } else { - if (triggerBack) { - final SurfaceControl surfaceControl = - removedWindowContainer.getSurfaceControl(); - if (surfaceControl != null && surfaceControl.isValid()) { - // When going back to home, hide the task surface before it - // re-parented to avoid flicker. - finishedTransaction.hide(surfaceControl); - } - } else { - currentTask.mBackGestureStarted = false; - if (!needsScreenshot(backType)) { - restoreLaunchBehind(finalPrevActivity); - } - } + mAnimationTargets.mWaitTransition = true; } } - finishedTransaction.apply(); + // TODO Add timeout monitor if transition didn't happen } }; - + if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) { + mAnimationTargets.composeNewAnimations(removedWindowContainer, prevActivity); + } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME + || backType == BackNavigationInfo.TYPE_CROSS_TASK) { + mAnimationTargets.composeNewAnimations(removedWindowContainer, prevTask); + } scheduleAnimationLocked(backType, targets, adapter, callback); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index d75ab6476ecb..cdb332123fe2 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -67,7 +67,6 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; 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_RECENTS_ANIMATIONS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; @@ -607,12 +606,6 @@ class Task extends TaskFragment { 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, Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, @@ -3333,14 +3326,6 @@ 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 { super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources); } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index a64bd694605c..ef6859092689 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -928,10 +928,16 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED; } + // Check whether the participants were animated from back navigation. + final boolean markBackAnimated = mController.mAtm.mBackNavigationController + .containsBackAnimationTargets(this); // Resolve the animating targets from the participants mTargets = calculateTargets(mParticipants, mChanges); final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges, transaction); + if (markBackAnimated) { + mController.mAtm.mBackNavigationController.clearBackAnimations(mStartTransaction); + } if (mOverrideOptions != null) { info.setAnimationOptions(mOverrideOptions); if (mOverrideOptions.getType() == ANIM_OPEN_CROSS_PROFILE_APPS) { @@ -1935,9 +1941,20 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe final Task task = wc.asTask(); if (task != null) { final ActivityRecord topActivity = task.getTopNonFinishingActivity(); - if (topActivity != null && topActivity.mStartingData != null - && topActivity.mStartingData.hasImeSurface()) { - flags |= FLAG_WILL_IME_SHOWN; + if (topActivity != null) { + if (topActivity.mStartingData != null + && topActivity.mStartingData.hasImeSurface()) { + flags |= FLAG_WILL_IME_SHOWN; + } + if (topActivity.mAtmService.mBackNavigationController + .isMonitorTransitionTarget(topActivity)) { + flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; + } + } else { + if (task.mAtmService.mBackNavigationController + .isMonitorTransitionTarget(task)) { + flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; + } } if (task.voiceSession != null) { flags |= FLAG_IS_VOICE_INTERACTION; @@ -1951,6 +1968,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe flags |= FLAG_IS_VOICE_INTERACTION; } flags |= record.mTransitionChangeFlags; + if (record.mAtmService.mBackNavigationController + .isMonitorTransitionTarget(record)) { + flags |= TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; + } } final TaskFragment taskFragment = wc.asTaskFragment(); if (taskFragment != null && task == null) { |