From f2e496590797e6cc285c71fe49d479af2953b0b8 Mon Sep 17 00:00:00 2001 From: Chris Li Date: Wed, 16 Nov 2022 22:46:06 +0800 Subject: [PATCH] Fix app requested animation for ActivityEmbedding remote animation 1. Clear mNextAppTransitionBackgroundColor after the current app transition has been played or aborted. 2. Do not reset the app requested animation when the app transition is going to be animated by ActivityEmbedding remote handler, so that we can still respect app's requested background color. Bug: 241043533 Bug: 254090083 Test: atest WmTests:AppTransitionTests Test: manual verify ActivityEmbedding remote animation with app calling Activity#overridePendingTransition Change-Id: Ib650a7c97ed4ff9341bff51ce9e38c2de3cc1f2d --- .../com/android/server/wm/AppTransition.java | 49 +++++++++--- .../android/server/wm/WindowContainer.java | 7 +- .../android/server/wm/AppTransitionTests.java | 78 +++++++++++++++++++ 3 files changed, 121 insertions(+), 13 deletions(-) diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 27370bfe45dc8..adf862b78656c 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -169,7 +169,8 @@ public class AppTransition implements Dump { private final WindowManagerService mService; private final DisplayContent mDisplayContent; - private final TransitionAnimation mTransitionAnimation; + @VisibleForTesting + final TransitionAnimation mTransitionAnimation; private @TransitionFlags int mNextAppTransitionFlags = 0; private final ArrayList mNextAppTransitionRequests = new ArrayList<>(); @@ -315,10 +316,33 @@ public class AppTransition implements Dump { setAppTransitionState(APP_STATE_TIMEOUT); } + /** + * Gets the animation overridden by app via {@link #overridePendingAppTransition}. + */ + @Nullable + Animation getNextAppRequestedAnimation(boolean enter) { + final Animation a = mTransitionAnimation.loadAppTransitionAnimation( + mNextAppTransitionPackage, + enter ? mNextAppTransitionEnter : mNextAppTransitionExit); + if (mNextAppTransitionBackgroundColor != 0 && a != null) { + a.setBackdropColor(mNextAppTransitionBackgroundColor); + } + return a; + } + + /** + * Gets the animation background color overridden by app via + * {@link #overridePendingAppTransition}. + */ @ColorInt int getNextAppTransitionBackgroundColor() { return mNextAppTransitionBackgroundColor; } + @VisibleForTesting + boolean isNextAppTransitionOverrideRequested() { + return mNextAppTransitionOverrideRequested; + } + HardwareBuffer getAppTransitionThumbnailHeader(WindowContainer container) { AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get( container.hashCode()); @@ -411,9 +435,12 @@ public class AppTransition implements Dump { } void clear() { + clear(true /* clearAppOverride */); + } + + private void clear(boolean clearAppOverride) { mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; mNextAppTransitionOverrideRequested = false; - mNextAppTransitionPackage = null; mNextAppTransitionAnimationsSpecs.clear(); mRemoteAnimationController = null; mNextAppTransitionAnimationsSpecsFuture = null; @@ -421,6 +448,12 @@ public class AppTransition implements Dump { mAnimationFinishedCallback = null; mOverrideTaskTransition = false; mNextAppTransitionIsSync = false; + if (clearAppOverride) { + mNextAppTransitionPackage = null; + mNextAppTransitionEnter = 0; + mNextAppTransitionExit = 0; + mNextAppTransitionBackgroundColor = 0; + } } void freeze() { @@ -528,7 +561,7 @@ public class AppTransition implements Dump { return TransitionAnimation.loadAnimationSafely(context, resId, TAG); } - static int mapOpenCloseTransitTypes(int transit, boolean enter) { + private static int mapOpenCloseTransitTypes(int transit, boolean enter) { int animAttr = 0; switch (transit) { case TRANSIT_OLD_ACTIVITY_OPEN: @@ -788,11 +821,7 @@ public class AppTransition implements Dump { "applyAnimation: anim=%s transit=%s Callers=%s", a, appTransitionOldToString(transit), Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { - a = mTransitionAnimation.loadAppTransitionAnimation(mNextAppTransitionPackage, - enter ? mNextAppTransitionEnter : mNextAppTransitionExit); - if (mNextAppTransitionBackgroundColor != 0) { - a.setBackdropColor(mNextAppTransitionBackgroundColor); - } + a = getNextAppRequestedAnimation(enter); ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s " + "isEntrance=%b Callers=%s", @@ -1032,7 +1061,9 @@ public class AppTransition implements Dump { ProtoLog.i(WM_DEBUG_APP_TRANSITIONS, "Override pending remote transitionSet=%b adapter=%s", isTransitionSet(), remoteAnimationAdapter); if (isTransitionSet() && !mNextAppTransitionIsSync) { - clear(); + // ActivityEmbedding animation will run by the app process for which we want to respect + // the app override for whether or not to show background color. + clear(!isActivityEmbedding /* clearAppOverride */); mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE; mRemoteAnimationController = new RemoteAnimationController(mService, mDisplayContent, remoteAnimationAdapter, mHandler, isActivityEmbedding); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index fa1bc54540188..80357eb0c7faa 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2995,10 +2995,9 @@ class WindowContainer extends ConfigurationContainer< // screen empty. Show background color to cover that. showBackdrop = getDisplayContent().mChangingContainers.size() > 1; } else { - // Check whether or not to show backdrop for open/close transition. - final int animAttr = AppTransition.mapOpenCloseTransitTypes(transit, enter); - final Animation a = animAttr != 0 - ? appTransition.loadAnimationAttr(lp, animAttr, transit) : null; + // Check whether the app has requested to show backdrop for open/close + // transition. + final Animation a = appTransition.getNextAppRequestedAnimation(enter); showBackdrop = a != null && a.getShowBackdrop(); } backdropColor = appTransition.getNextAppTransitionBackgroundColor(); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 32c95fa7b6c7b..8cfe503d61d74 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -49,6 +49,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.mock; @@ -67,11 +68,14 @@ import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.WindowManager; +import android.view.animation.Animation; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentOrganizer; import androidx.test.filters.SmallTest; +import com.android.internal.policy.TransitionAnimation; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -495,6 +499,80 @@ public class AppTransitionTests extends WindowTestsBase { assertEquals(startBounds, taskFragment.mSurfaceFreezer.mFreezeBounds); } + @Test + public void testGetNextAppTransitionBackgroundColor() { + assumeFalse(WindowManagerService.sEnableShellTransitions); + + // No override by default. + assertEquals(0, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); + + // Override with a custom color. + mDc.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); + final int testColor = 123; + mDc.mAppTransition.overridePendingAppTransition("testPackage", 0 /* enterAnim */, + 0 /* exitAnim */, testColor, null /* startedCallback */, null /* endedCallback */, + false /* overrideTaskTransaction */); + + assertEquals(testColor, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); + assertTrue(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); + + // Override with ActivityEmbedding remote animation. Background color should be kept. + mDc.mAppTransition.overridePendingAppTransitionRemote(mock(RemoteAnimationAdapter.class), + false /* sync */, true /* isActivityEmbedding */); + + assertEquals(testColor, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); + assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); + + // Background color should not be cleared anymore after #clear(). + mDc.mAppTransition.clear(); + assertEquals(0, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); + assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); + } + + @Test + public void testGetNextAppRequestedAnimation() { + assumeFalse(WindowManagerService.sEnableShellTransitions); + final String packageName = "testPackage"; + final int enterAnimResId = 1; + final int exitAnimResId = 2; + final int testColor = 123; + final Animation enterAnim = mock(Animation.class); + final Animation exitAnim = mock(Animation.class); + final TransitionAnimation transitionAnimation = mDc.mAppTransition.mTransitionAnimation; + spyOn(transitionAnimation); + doReturn(enterAnim).when(transitionAnimation) + .loadAppTransitionAnimation(packageName, enterAnimResId); + doReturn(exitAnim).when(transitionAnimation) + .loadAppTransitionAnimation(packageName, exitAnimResId); + + // No override by default. + assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); + assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); + + // Override with a custom animation. + mDc.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); + mDc.mAppTransition.overridePendingAppTransition(packageName, enterAnimResId, exitAnimResId, + testColor, null /* startedCallback */, null /* endedCallback */, + false /* overrideTaskTransaction */); + + assertEquals(enterAnim, mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); + assertEquals(exitAnim, mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); + assertTrue(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); + + // Override with ActivityEmbedding remote animation. Custom animation should be kept. + mDc.mAppTransition.overridePendingAppTransitionRemote(mock(RemoteAnimationAdapter.class), + false /* sync */, true /* isActivityEmbedding */); + + assertEquals(enterAnim, mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); + assertEquals(exitAnim, mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); + assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); + + // Custom animation should not be cleared anymore after #clear(). + mDc.mAppTransition.clear(); + assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); + assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); + } + private class TestRemoteAnimationRunner implements IRemoteAnimationRunner { boolean mCancelled = false; @Override