diff options
8 files changed, 121 insertions, 20 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b156d1bd8886..b5a57a4adc86 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -555,7 +555,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private RemoteAnimationDefinition mRemoteAnimationDefinition; - private AnimatingActivityRegistry mAnimatingActivityRegistry; + AnimatingActivityRegistry mAnimatingActivityRegistry; private Task mLastParent; @@ -3089,7 +3089,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Removing app %s delayed=%b animation=%s animating=%b", this, delayed, - getAnimation(), isAnimating(TRANSITION)); + getAnimation(), isAnimating(PARENTS | TRANSITION)); ProtoLog.v(WM_DEBUG_ADD_REMOVE, "removeAppToken: %s" + " delayed=%b Callers=%s", this, delayed, Debug.getCallers(4)); @@ -3101,7 +3101,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If this window was animating, then we need to ensure that the app transition notifies // that animations have completed in DisplayContent.handleAnimatingStoppedAndTransition(), // so add to that list now - if (isAnimating(TRANSITION)) { + if (isAnimating(PARENTS | TRANSITION)) { getDisplayContent().mNoAnimationNotifyOnTransitionFinished.add(token); } @@ -3437,7 +3437,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * color mode set to avoid jank in the middle of the transition. */ boolean canShowWindows() { - return allDrawn && !(isAnimating() && hasNonDefaultColorWindow()); + return allDrawn && !(isAnimating(PARENTS) && hasNonDefaultColorWindow()); } /** @@ -5345,13 +5345,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (!allDrawn && w.mightAffectAllDrawn()) { if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) { Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() - + ", isAnimationSet=" + isAnimating(TRANSITION)); + + ", isAnimationSet=" + isAnimating(PARENTS | TRANSITION)); if (!w.isDrawnLw()) { Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController + " pv=" + w.isVisibleByPolicy() + " mDrawState=" + winAnimator.drawStateToString() + " ph=" + w.isParentWindowHidden() + " th=" + mVisibleRequested - + " a=" + isAnimating(TRANSITION)); + + " a=" + isAnimating(PARENTS | TRANSITION)); } } @@ -5952,7 +5952,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override void prepareSurfaces() { - final boolean show = isVisible() || isAnimating(); + final boolean show = isVisible() || isAnimating(PARENTS); if (mSurfaceControl != null) { if (show && !mLastSurfaceShowing) { @@ -5980,7 +5980,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void attachThumbnailAnimation() { - if (!isAnimating()) { + if (!isAnimating(PARENTS)) { return; } final GraphicBuffer thumbnailHeader = @@ -6000,7 +6000,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation. */ void attachCrossProfileAppsThumbnailAnimation() { - if (!isAnimating()) { + if (!isAnimating(PARENTS)) { return; } clearThumbnail(); @@ -7512,7 +7512,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A super.dumpDebug(proto, WINDOW_TOKEN, logLevel); proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing); proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart()); - proto.write(IS_ANIMATING, isAnimating()); + proto.write(IS_ANIMATING, isAnimating(PARENTS)); if (mThumbnail != null){ mThumbnail.dumpDebug(proto, THUMBNAIL); } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index ef34327597bc..b47c28455027 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -4889,6 +4889,18 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn } } + @Override + protected void onAnimationFinished() { + super.onAnimationFinished(); + // TODO(b/142617871): we may need to add animation type parameter on onAnimationFinished to + // identify if the callback is for launch animation finish and then calling + // activity#onAnimationFinished. + final ActivityRecord activity = getTopMostActivity(); + if (activity != null) { + activity.onAnimationFinished(); + } + } + /** * Sets the current picture-in-picture aspect ratio. */ diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 67fe1491c48b..36f1de395ef6 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3360,7 +3360,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // to look at all windows below the current target that are in this app, finding the // highest visible one in layering. WindowState highestTarget = null; - if (activity.isAnimating(TRANSITION)) { + if (activity.isAnimating(PARENTS | TRANSITION)) { highestTarget = activity.getHighestAnimLayerWindow(curTarget); } diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 0b9be1acbf93..6f7eeabfc4cd 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -378,9 +378,10 @@ class RemoteAnimationController implements DeathRecipient { int getMode() { final DisplayContent dc = mWindowContainer.getDisplayContent(); - if (dc.mOpeningApps.contains(mWindowContainer)) { + final ActivityRecord topActivity = mWindowContainer.getTopMostActivity(); + if (dc.mOpeningApps.contains(topActivity)) { return RemoteAnimationTarget.MODE_OPENING; - } else if (dc.mChangingApps.contains(mWindowContainer)) { + } else if (dc.mChangingApps.contains(topActivity)) { return RemoteAnimationTarget.MODE_CHANGING; } else { return RemoteAnimationTarget.MODE_CLOSING; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 914b95c1c04c..b4633184c969 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -94,6 +94,7 @@ import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; import static java.lang.Integer.MAX_VALUE; @@ -2555,6 +2556,16 @@ class Task extends WindowContainer<WindowContainer> { return getAppAnimationLayer(ANIMATION_LAYER_HOME); } + @Override + Rect getAnimationBounds(int appStackClipMode) { + // TODO(b/131661052): we should remove appStackClipMode with hierarchical animations. + if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) { + // Using the stack bounds here effectively applies the clipping before animation. + return getStack().getBounds(); + } + return super.getAnimationBounds(appStackClipMode); + } + boolean shouldAnimate() { // Don't animate while the task runs recents animation but only if we are in the mode // where we cancel with deferred screenshot, which means that the controller has @@ -2568,6 +2579,18 @@ class Task extends WindowContainer<WindowContainer> { } @Override + protected void onAnimationFinished() { + super.onAnimationFinished(); + // TODO(b/142617871): we may need to add animation type parameter on onAnimationFinished to + // identify if the callback is for launch animation finish and then calling + // activity#onAnimationFinished. + final ActivityRecord activity = getTopMostActivity(); + if (activity != null) { + activity.onAnimationFinished(); + } + } + + @Override SurfaceControl.Builder makeSurface() { return super.makeSurface().setMetadata(METADATA_TASK_ID, mTaskId); } @@ -2594,7 +2617,7 @@ class Task extends WindowContainer<WindowContainer> { @Override RemoteAnimationTarget createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record) { - final ActivityRecord activity = getTopVisibleActivity(); + final ActivityRecord activity = getTopMostActivity(); return activity != null ? activity.createRemoteAnimationTarget(record) : null; } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 5daf56767fed..039cf5f8f352 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -777,7 +777,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * otherwise. */ boolean isWaitingForTransitionStart() { - return false; + return getActivity(app -> app.isWaitingForTransitionStart()) != null; } /** @@ -785,7 +785,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * {@code ActivityRecord#isAnimating(TRANSITION)}, {@code false} otherwise. */ boolean isAppTransitioning() { - return getActivity(app -> app.isAnimating(TRANSITION)) != null; + return getActivity(app -> app.isAnimating(PARENTS | TRANSITION)) != null; } /** @@ -1895,7 +1895,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (adapter != null) { startAnimation(getPendingTransaction(), adapter, !isVisible()); if (adapter.getShowWallpaper()) { - mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; + getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } if (thumbnailAdapter != null) { mThumbnail.startAnimation( @@ -2040,7 +2040,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } boolean okToDisplay() { - return mDisplayContent != null && mDisplayContent.okToDisplay(); + final DisplayContent dc = getDisplayContent(); + return dc != null && dc.okToDisplay(); } boolean okToAnimate() { @@ -2048,7 +2049,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } boolean okToAnimate(boolean ignoreFrozen) { - return mDisplayContent != null && mDisplayContent.okToAnimate(ignoreFrozen); + final DisplayContent dc = getDisplayContent(); + return dc != null && dc.okToAnimate(ignoreFrozen); } @Override diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 1a11766ac9a8..486616df6f11 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1398,7 +1398,7 @@ class WindowStateAnimator { mWin.getDisplayContent().adjustForImeIfNeeded(); } - return mWin.isAnimating(TRANSITION | PARENTS); + return mWin.isAnimating(PARENTS); } void dumpDebug(ProtoOutputStream proto, long fieldId) { 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 248b06b26b6d..d3cd3cbb42ca 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -21,6 +21,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.WindowManager.TRANSIT_TASK_OPEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat; @@ -49,7 +50,12 @@ import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.os.IBinder; +import android.os.RemoteException; import android.platform.test.annotations.Presubmit; +import android.view.IRemoteAnimationFinishedCallback; +import android.view.IRemoteAnimationRunner; +import android.view.RemoteAnimationAdapter; +import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceSession; @@ -782,6 +788,63 @@ public class WindowContainerTests extends WindowTestsBase { assertEquals(newDc, activity.mDisplayContent); } + @Test + public void testTaskCanApplyAnimation() { + final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final Task task = createTaskInStack(stack, 0 /* userId */); + final ActivityRecord activity = + WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + verifyWindowContainerApplyAnimation(task, activity); + } + + @Test + public void testStackCanApplyAnimation() { + final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); + final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask(mDisplayContent, + createTaskInStack(stack, 0 /* userId */)); + verifyWindowContainerApplyAnimation(stack, activity); + } + + private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act) { + // Initial remote animation for app transition. + final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( + new IRemoteAnimationRunner.Stub() { + @Override + public void onAnimationStart(RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, + IRemoteAnimationFinishedCallback finishedCallback) { + try { + finishedCallback.onAnimationFinished(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + public void onAnimationCancelled() { + } + }, 0, 0, false); + adapter.setCallingPidUid(123, 456); + wc.getDisplayContent().prepareAppTransition(TRANSIT_TASK_OPEN, false); + wc.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(adapter); + spyOn(wc); + doReturn(true).when(wc).okToAnimate(); + + // Make sure animating state is as expected after applied animation. + assertTrue(wc.applyAnimation(null, TRANSIT_TASK_OPEN, true, false)); + assertEquals(wc.getTopMostActivity(), act); + assertTrue(wc.isAnimating()); + assertTrue(act.isAnimating(PARENTS)); + + // Make sure animation finish callback will be received and reset animating state after + // animation finish. + wc.getDisplayContent().mAppTransition.goodToGo(TRANSIT_TASK_OPEN, act, + mDisplayContent.mOpeningApps); + verify(wc).onAnimationFinished(); + assertFalse(wc.isAnimating()); + assertFalse(act.isAnimating(PARENTS)); + } + /* Used so we can gain access to some protected members of the {@link WindowContainer} class */ private static class TestWindowContainer extends WindowContainer<TestWindowContainer> { private final int mLayer; |