diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index be2f9d4104752..01eb9c5cb3d9f 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -311,7 +311,6 @@ import com.android.server.uri.UriPermissionOwner; import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot; import com.android.server.wm.ActivityStack.ActivityState; import com.android.server.wm.SurfaceAnimator.AnimationType; -import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.WindowManagerService.H; import com.android.server.wm.utils.InsetUtils; @@ -4166,14 +4165,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @Override - boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, - boolean isVoiceInteraction, - @Nullable OnAnimationFinishedCallback animationFinishedCallback) { + boolean applyAnimation(LayoutParams lp, int transit, boolean enter, + boolean isVoiceInteraction, @Nullable ArrayList sources) { if (mUseTransferredAnimation) { return false; } - return super.applyAnimation(lp, transit, enter, isVoiceInteraction, - animationFinishedCallback); + return super.applyAnimation(lp, transit, enter, isVoiceInteraction, sources); } /** diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 67fe9685fd2aa..d60d098071cc5 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -49,7 +49,7 @@ import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_W import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; -import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -75,7 +75,6 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.function.Predicate; - /** * Checks for app transition readiness, resolves animation attributes and performs visibility * change for apps that animate as part of an app transition. @@ -375,18 +374,14 @@ public class AppTransitionController { // triggers WC#onAnimationFinished only on the promoted target. So we need to take care // of triggering AR#onAnimationFinished on each ActivityRecord which is a part of the // app transition. - final ArrayList transitioningDecendants = new ArrayList<>(); + final ArrayList transitioningDescendants = new ArrayList<>(); for (int j = 0; j < apps.size(); ++j) { final ActivityRecord app = apps.valueAt(j); if (app.isDescendantOf(wc)) { - transitioningDecendants.add(app); + transitioningDescendants.add(app); } } - wc.applyAnimation(animLp, transit, visible, voiceInteraction, (type, anim) -> { - for (int j = 0; j < transitioningDecendants.size(); ++j) { - transitioningDecendants.get(j).onAnimationFinished(type, anim); - } - }); + wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants); } } @@ -540,7 +535,14 @@ public class AppTransitionController { ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", app); app.commitVisibility(true /* visible */, false /* performLayout */); - if (!app.isAnimating(PARENTS | CHILDREN)) { + + // In case a trampoline activity is used, it can happen that a new ActivityRecord is + // added and a new app transition starts before the previous app transition animation + // ends. So we cannot simply use app.isAnimating(PARENTS) to determine if the app must + // to be added to the list of tokens to be notified of app transition complete. + final WindowContainer wc = app.getAnimatingContainer(PARENTS, + ANIMATION_TYPE_APP_TRANSITION); + if (wc == null || !wc.getAnimationSources().contains(app)) { // This token isn't going to be animating. Add it to the list of tokens to // be notified of app transition complete since the notification will not be // sent be the app window animator. @@ -599,8 +601,7 @@ public class AppTransitionController { for (int i = 0; i < appsCount; i++) { WindowContainer wc = apps.valueAt(i); ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wc); - wc.applyAnimation(null, transit, true, false, - null /* animationFinishedCallback */); + wc.applyAnimation(null, transit, true, false, null /* sources */); } } diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index fdcc3f4d15109..d43a7b87ee355 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -22,7 +22,6 @@ import static com.android.server.wm.AlphaAnimationSpecProto.TO; import static com.android.server.wm.AnimationSpecProto.ALPHA; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER; -import android.annotation.Nullable; import android.graphics.Rect; import android.util.Log; import android.util.proto.ProtoOutputStream; @@ -31,7 +30,6 @@ import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.SurfaceAnimator.AnimationType; -import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import java.io.PrintWriter; @@ -160,8 +158,7 @@ class Dimmer { @VisibleForTesting interface SurfaceAnimatorStarter { void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t, - AnimationAdapter anim, boolean hidden, @AnimationType int type, - @Nullable OnAnimationFinishedCallback animationFinishedCallback); + AnimationAdapter anim, boolean hidden, @AnimationType int type); } Dimmer(WindowContainer host) { @@ -348,7 +345,7 @@ class Dimmer { mSurfaceAnimatorStarter.startAnimation(animator, t, new LocalAnimationAdapter( new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)), mHost.mWmService.mSurfaceAnimationRunner), false /* hidden */, - ANIMATION_TYPE_DIMMER, null /* animationFinishedCallback */); + ANIMATION_TYPE_DIMMER); } private long getDimDuration(WindowContainer container) { diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 6a4975950f1a9..c8d9fe0f0a659 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -280,7 +280,7 @@ class InsetsSourceProvider { } final Transaction t = mDisplayContent.getPendingTransaction(); mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */, - ANIMATION_TYPE_INSETS_CONTROL, null /* animationFinishedCallback */); + ANIMATION_TYPE_INSETS_CONTROL); // The leash was just created. We cannot dispatch it until its surface transaction is // applied. Otherwise, the client's operation to the leash might be overwritten by us. diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java index 7a38bb65f73b6..0ae9ca9b882e1 100644 --- a/services/core/java/com/android/server/wm/ShellRoot.java +++ b/services/core/java/com/android/server/wm/ShellRoot.java @@ -104,7 +104,7 @@ public class ShellRoot { 0 /* windowCornerRadius */), mDisplayContent.mWmService.mSurfaceAnimationRunner); mToken.startAnimation(mToken.getPendingTransaction(), adapter, false /* hidden */, - ANIMATION_TYPE_WINDOW_ANIMATION, null /* animationFinishedCallback */); + ANIMATION_TYPE_WINDOW_ANIMATION); } WindowInfo getWindowInfo() { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index ce2ae2a420696..56ad9643e619e 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -85,7 +85,6 @@ import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; -import static com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowContainerChildProto.TASK; @@ -3495,7 +3494,7 @@ class Task extends WindowContainer { @Override protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, int transit, boolean isVoiceInteraction, - @Nullable OnAnimationFinishedCallback finishedCallback) { + @Nullable ArrayList sources) { final RecentsAnimationController control = mWmService.getRecentsAnimationController(); if (control != null) { // We let the transition to be controlled by RecentsAnimation, and callback task's @@ -3504,10 +3503,14 @@ class Task extends WindowContainer { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "applyAnimationUnchecked, control: %s, task: %s, transit: %s", control, asTask(), AppTransition.appTransitionToString(transit)); - control.addTaskToTargets(this, finishedCallback); + control.addTaskToTargets(this, (type, anim) -> { + for (int i = 0; i < sources.size(); ++i) { + sources.get(i).onAnimationFinished(type, anim); + } + }); } } else { - super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback); + super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources); } } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 90156fd4f4756..6406f0ae51a6f 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -64,6 +64,7 @@ import android.graphics.Rect; import android.os.Debug; import android.os.IBinder; import android.os.Trace; +import android.util.ArraySet; import android.util.Pair; import android.util.Pools; import android.util.Slog; @@ -181,6 +182,14 @@ class WindowContainer extends ConfigurationContainer< final SurfaceFreezer mSurfaceFreezer; protected final WindowManagerService mWmService; + /** + * Sources which triggered a surface animation on this container. An animation target can be + * promoted to higher level, for example, from a set of {@link ActivityRecord}s to + * {@link ActivityStack}. In this case, {@link ActivityRecord}s are set on this variable while + * the animation is running, and reset after finishing it. + */ + private final ArraySet mSurfaceAnimationSources = new ArraySet<>(); + private final Point mTmpPos = new Point(); protected final Point mLastSurfacePosition = new Point(); @@ -193,8 +202,6 @@ class WindowContainer extends ConfigurationContainer< */ private boolean mCommittedReparentToAnimationLeash; - private final Configuration mTmpConfig = new Configuration(); - /** Interface for {@link #isAnimating} to check which cases for the container is animating. */ public interface AnimationFlags { /** @@ -872,29 +879,8 @@ class WindowContainer extends ConfigurationContainer< * @see AnimationFlags#PARENTS * @see AnimationFlags#CHILDREN */ - boolean isAnimating(int flags, int typesToCheck) { - int animationType = mSurfaceAnimator.getAnimationType(); - if (mSurfaceAnimator.isAnimating() && (animationType & typesToCheck) > 0) { - return true; - } - if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) { - return true; - } - if ((flags & PARENTS) != 0) { - final WindowContainer parent = getParent(); - if (parent != null && parent.isAnimating(flags & ~CHILDREN, typesToCheck)) { - return true; - } - } - if ((flags & CHILDREN) != 0) { - for (int i = 0; i < mChildren.size(); ++i) { - final WindowContainer wc = mChildren.get(i); - if (wc.isAnimating(flags & ~PARENTS, typesToCheck)) { - return true; - } - } - } - return false; + final boolean isAnimating(int flags, int typesToCheck) { + return getAnimatingContainer(flags, typesToCheck) != null; } /** @@ -904,16 +890,20 @@ class WindowContainer extends ConfigurationContainer< * checking animating status. * @param typesToExclude The combination of bitmask {@link AnimationType} to exclude when * checking if animating. + * + * @deprecated Use {@link #isAnimating(int, int)} */ - boolean isAnimatingExcluding(int flags, int typesToExclude) { + @Deprecated + final boolean isAnimatingExcluding(int flags, int typesToExclude) { return isAnimating(flags, ANIMATION_TYPE_ALL & ~typesToExclude); } /** - * @see #isAnimating(int, int) + * @deprecated Use {@link #isAnimating(int, int)} * TODO (b/152333373): Migrate calls to use isAnimating with specified animation type */ - boolean isAnimating(int flags) { + @Deprecated + final boolean isAnimating(int flags) { return isAnimating(flags, ANIMATION_TYPE_ALL); } @@ -2107,10 +2097,15 @@ class WindowContainer extends ConfigurationContainer< } void cancelAnimation() { + doAnimationFinished(mSurfaceAnimator.getAnimationType(), mSurfaceAnimator.getAnimation()); mSurfaceAnimator.cancelAnimation(); mSurfaceFreezer.unfreeze(getPendingTransaction()); } + ArraySet getAnimationSources() { + return mSurfaceAnimationSources; + } + @Override public SurfaceControl getFreezeSnapshotTarget() { return null; @@ -2156,6 +2151,7 @@ class WindowContainer extends ConfigurationContainer< * @param transit The app transition type indicates what kind of transition to be applied. * @param enter Whether the app transition is entering transition or not. * @param isVoiceInteraction Whether the container is participating in voice interaction or not. + * @param sources {@link ActivityRecord}s which causes this app transition animation. * * @return {@code true} when the container applied the app transition, {@code false} if the * app transition is disabled or skipped. @@ -2163,7 +2159,7 @@ class WindowContainer extends ConfigurationContainer< * @see #getAnimationAdapter */ boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, - boolean isVoiceInteraction, @Nullable OnAnimationFinishedCallback finishedCallback) { + boolean isVoiceInteraction, @Nullable ArrayList sources) { if (mWmService.mDisableTransitionAnimation) { ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: transition animation is disabled or skipped. " @@ -2178,7 +2174,7 @@ class WindowContainer extends ConfigurationContainer< try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation"); if (okToAnimate()) { - applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback); + applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources); } else { cancelAnimation(); } @@ -2276,14 +2272,17 @@ class WindowContainer extends ConfigurationContainer< protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, int transit, boolean isVoiceInteraction, - @Nullable OnAnimationFinishedCallback finishedCallback) { + @Nullable ArrayList sources) { final Pair adapters = getAnimationAdapter(lp, transit, enter, isVoiceInteraction); AnimationAdapter adapter = adapters.first; AnimationAdapter thumbnailAdapter = adapters.second; if (adapter != null) { + if (sources != null) { + mSurfaceAnimationSources.addAll(sources); + } startAnimation(getPendingTransaction(), adapter, !isVisible(), - ANIMATION_TYPE_APP_TRANSITION, finishedCallback); + ANIMATION_TYPE_APP_TRANSITION); if (adapter.getShowWallpaper()) { getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } @@ -2411,10 +2410,18 @@ class WindowContainer extends ConfigurationContainer< updateSurfacePosition(t); } + private void doAnimationFinished(@AnimationType int type, AnimationAdapter anim) { + for (int i = 0; i < mSurfaceAnimationSources.size(); ++i) { + mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim); + } + mSurfaceAnimationSources.clear(); + } + /** * Called when an animation has finished running. */ protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { + doAnimationFinished(type, anim); mWmService.onAnimationFinished(); } @@ -2428,16 +2435,66 @@ class WindowContainer extends ConfigurationContainer< /** * @return The {@link WindowContainer} which is running an animation. * - * It traverses from the current container to its parents recursively. If nothing is animating, - * it will return {@code null}. + * By default this only checks if this container itself is actually running an animation, but + * you can extend the check target over its relatives, or relax the condition so that this can + * return {@code WindowContainer} if an animation starts soon by giving a combination + * of {@link AnimationFlags}. + * + * Note that you can give a combination of bitmask flags to specify targets and condition for + * checking animating status. + * e.g. {@code isAnimating(TRANSITION | PARENT)} returns {@code true} if either this + * container itself or one of its parents is running an animation or waiting for an app + * transition. + * + * Note that TRANSITION propagates to parents and children as well. + * + * @param flags The combination of bitmask flags to specify targets and condition for + * checking animating status. + * @param typesToCheck The combination of bitmask {@link AnimationType} to compare when + * determining if animating. + * + * @see AnimationFlags#TRANSITION + * @see AnimationFlags#PARENTS + * @see AnimationFlags#CHILDREN */ @Nullable - WindowContainer getAnimatingContainer() { - if (isAnimating()) { + WindowContainer getAnimatingContainer(int flags, int typesToCheck) { + int animationType = mSurfaceAnimator.getAnimationType(); + if (mSurfaceAnimator.isAnimating() && (animationType & typesToCheck) > 0) { return this; } - final WindowContainer parent = getParent(); - return (parent != null) ? parent.getAnimatingContainer() : null; + if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) { + return this; + } + if ((flags & PARENTS) != 0) { + final WindowContainer parent = getParent(); + if (parent != null) { + final WindowContainer wc = parent.getAnimatingContainer( + flags & ~CHILDREN, typesToCheck); + if (wc != null) { + return wc; + } + } + } + if ((flags & CHILDREN) != 0) { + for (int i = 0; i < mChildren.size(); ++i) { + final WindowContainer wc = mChildren.get(i).getAnimatingContainer( + flags & ~PARENTS, typesToCheck); + if (wc != null) { + return wc; + } + } + } + return null; + } + + /** + * @deprecated Use {@link #getAnimatingContainer(int, int)} instead. + */ + @Nullable + @Deprecated + final WindowContainer getAnimatingContainer() { + return getAnimatingContainer(PARENTS, ANIMATION_TYPE_ALL); } /** diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java index a27a112597728..126154b103505 100644 --- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java +++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java @@ -133,15 +133,14 @@ class WindowContainerThumbnail implements Animatable { mWindowContainer.getDisplayContent().mAppTransition.canSkipFirstFrame(), mWindowContainer.getDisplayContent().getWindowCornerRadius()), mWindowContainer.mWmService.mSurfaceAnimationRunner), false /* hidden */, - ANIMATION_TYPE_RECENTS, null /* animationFinishedCallback */); + ANIMATION_TYPE_RECENTS); } /** * Start animation with existing adapter. */ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) { - mSurfaceAnimator.startAnimation(t, anim, hidden, ANIMATION_TYPE_RECENTS, - null /* animationFinishedCallback */); + mSurfaceAnimator.startAnimation(t, anim, hidden, ANIMATION_TYPE_RECENTS); } private void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index fe3ee50c34c5b..32717d0e1e651 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -5049,16 +5049,13 @@ class WindowState extends WindowContainer implements WindowManagerP mWindowFrames.updateLastInsetValues(); } + @Nullable @Override - boolean isAnimating(int flags, int typesToCheck) { - - // If we are an inset provider, all our animations are driven by the inset client, so we - // aren't really animating. - // TODO: Replace this with a proper animation type system. + WindowContainer getAnimatingContainer(int flags, int typesToCheck) { if (mControllableInsetProvider != null) { - return false; + return null; } - return super.isAnimating(flags, typesToCheck); + return super.getAnimatingContainer(flags, typesToCheck); } void startAnimation(Animation anim) { @@ -5101,8 +5098,7 @@ class WindowState extends WindowContainer implements WindowManagerP } private void startAnimation(Transaction t, AnimationAdapter adapter) { - startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION, - null /* animationFinishedCallback */); + startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION); } @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 02de408343c52..ef28a450695be 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -38,7 +38,6 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; @@ -65,12 +64,12 @@ import android.view.WindowManager; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; + /** * Tests for the {@link ActivityRecord} class. * @@ -406,12 +405,11 @@ public class AppWindowTokenTests extends WindowTestsBase { assertHasStartingWindow(activity2); // Assert that bottom activity is allowed to do animation. + ArrayList sources = new ArrayList<>(); + sources.add(activity2); doReturn(true).when(activity2).okToAnimate(); doReturn(true).when(activity2).isAnimating(); - final OnAnimationFinishedCallback onAnimationFinishedCallback = - mock(OnAnimationFinishedCallback.class); - assertTrue(activity2.applyAnimation(null, TRANSIT_ACTIVITY_OPEN, true, false, - onAnimationFinishedCallback)); + assertTrue(activity2.applyAnimation(null, TRANSIT_ACTIVITY_OPEN, true, false, sources)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java index 77ceeedae1acb..f7beb74688d62 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java @@ -29,18 +29,14 @@ import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.when; -import android.annotation.Nullable; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.SurfaceSession; import com.android.server.wm.SurfaceAnimator.AnimationType; -import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import org.junit.Before; import org.junit.Test; @@ -119,12 +115,8 @@ public class DimmerTests extends WindowTestsBase { private static class SurfaceAnimatorStarterImpl implements Dimmer.SurfaceAnimatorStarter { @Override public void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t, - AnimationAdapter anim, boolean hidden, @AnimationType int type, - @Nullable OnAnimationFinishedCallback animationFinishedCallback) { + AnimationAdapter anim, boolean hidden, @AnimationType int type) { surfaceAnimator.mStaticAnimationFinishedCallback.onAnimationFinished(type, anim); - if (animationFinishedCallback != null) { - animationFinishedCallback.onAnimationFinished(type, anim); - } } } @@ -229,7 +221,7 @@ public class DimmerTests extends WindowTestsBase { mDimmer.updateDims(mTransaction, new Rect()); verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any( SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(), - eq(ANIMATION_TYPE_DIMMER), isNull()); + eq(ANIMATION_TYPE_DIMMER)); verify(mHost.getPendingTransaction()).remove(dimLayer); } @@ -287,7 +279,7 @@ public class DimmerTests extends WindowTestsBase { mDimmer.updateDims(mTransaction, new Rect()); verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any( SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(), - eq(ANIMATION_TYPE_DIMMER), isNull()); + eq(ANIMATION_TYPE_DIMMER)); verify(mTransaction).remove(dimLayer); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java index d65b084ca8c1c..f1dbde0661256 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java @@ -153,7 +153,8 @@ public class TaskStackTests extends WindowTestsBase { // Stack removal is deferred if one of its child is animating. doReturn(true).when(stack).hasWindowsAlive(); - doReturn(true).when(task).isAnimating(eq(TRANSITION | CHILDREN), anyInt()); + doReturn(stack).when(task).getAnimatingContainer( + eq(TRANSITION | CHILDREN), anyInt()); stack.removeIfPossible(); // For the case of deferred removal the task controller will still be connected to the its diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index 00439f84702de..87485eac34121 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -66,14 +66,14 @@ import android.view.SurfaceSession; import androidx.test.filters.SmallTest; -import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; - import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; +import java.util.ArrayList; import java.util.Comparator; + /** * Test class for {@link WindowContainer}. * @@ -828,17 +828,21 @@ public class WindowContainerTests extends WindowTestsBase { public void testTaskCanApplyAnimation() { final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity = + final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); - verifyWindowContainerApplyAnimation(task, activity); + final ActivityRecord activity1 = + WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + verifyWindowContainerApplyAnimation(task, activity1, activity2); } @Test public void testStackCanApplyAnimation() { final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask(mDisplayContent, + final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, createTaskInStack(stack, 0 /* userId */)); - verifyWindowContainerApplyAnimation(stack, activity); + final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, + createTaskInStack(stack, 0 /* userId */)); + verifyWindowContainerApplyAnimation(stack, activity1, activity2); } @Test @@ -871,7 +875,8 @@ public class WindowContainerTests extends WindowTestsBase { assertEquals(displayArea, displayArea.getDisplayArea()); } - private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act) { + private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act, + ActivityRecord act2) { // Initial remote animation for app transition. final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new IRemoteAnimationRunner.Stub() { @@ -895,17 +900,23 @@ public class WindowContainerTests extends WindowTestsBase { wc.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(adapter); spyOn(wc); doReturn(true).when(wc).okToAnimate(); - final OnAnimationFinishedCallback onAnimationFinishedCallback = - mock(OnAnimationFinishedCallback.class); // Make sure animating state is as expected after applied animation. - assertTrue(wc.applyAnimation(null, TRANSIT_TASK_OPEN, true, false, - onAnimationFinishedCallback)); - assertEquals(wc.getTopMostActivity(), act); + + // Animation target is promoted from act to wc. act2 is a descendant of wc, but not a source + // of the animation. + ArrayList> sources = new ArrayList<>(); + sources.add(act); + assertTrue(wc.applyAnimation(null, TRANSIT_TASK_OPEN, true, false, sources)); + + assertEquals(act, wc.getTopMostActivity()); assertTrue(wc.isAnimating()); + assertTrue(wc.isAnimating(0, ANIMATION_TYPE_APP_TRANSITION)); + assertTrue(wc.getAnimationSources().contains(act)); + assertFalse(wc.getAnimationSources().contains(act2)); assertTrue(act.isAnimating(PARENTS)); - verify(onAnimationFinishedCallback, times(0)).onAnimationFinished( - eq(ANIMATION_TYPE_APP_TRANSITION), any()); + assertTrue(act.isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)); + assertEquals(wc, act.getAnimatingContainer(PARENTS, ANIMATION_TYPE_APP_TRANSITION)); // Make sure animation finish callback will be received and reset animating state after // animation finish. @@ -914,8 +925,6 @@ public class WindowContainerTests extends WindowTestsBase { verify(wc).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), any()); assertFalse(wc.isAnimating()); assertFalse(act.isAnimating(PARENTS)); - verify(onAnimationFinishedCallback, times(1)).onAnimationFinished( - eq(ANIMATION_TYPE_APP_TRANSITION), any()); } /* Used so we can gain access to some protected members of the {@link WindowContainer} class */