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