diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java index c767376d4f295..18615f7e353a5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java @@ -19,6 +19,8 @@ package com.android.wm.shell.activityembedding; import static android.graphics.Matrix.MTRANS_X; import static android.graphics.Matrix.MTRANS_Y; +import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationRunner.shouldUseSnapshotAnimationForClosingChange; + import android.annotation.CallSuper; import android.graphics.Point; import android.graphics.Rect; @@ -97,10 +99,17 @@ class ActivityEmbeddingAnimationAdapter { final Rect startBounds = change.getStartAbsBounds(); final Rect endBounds = change.getEndAbsBounds(); mContentBounds.set(startBounds); - mContentRelOffset.set(change.getEndRelOffset()); - mContentRelOffset.offset( - startBounds.left - endBounds.left, - startBounds.top - endBounds.top); + // Put the transition to the top left for snapshot animation. + if (shouldUseSnapshotAnimationForClosingChange(mChange)) { + // TODO(b/275034335): Fix an issue that black hole when closing the right container + // in bounds change transition. + mContentRelOffset.set(0, 0); + } else { + mContentRelOffset.set(change.getEndRelOffset()); + mContentRelOffset.offset( + startBounds.left - endBounds.left, + startBounds.top - endBounds.top); + } } else { mContentBounds.set(change.getEndAbsBounds()); mContentRelOffset.set(change.getEndRelOffset()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java index 1df6ecda78c3e..ab7c7d8ae6c80 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java @@ -21,6 +21,7 @@ import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; +import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationSpec.createShowSnapshotForClosingAnimation; import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition; import static com.android.wm.shell.transition.TransitionAnimationHelper.edgeExtendWindow; import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet; @@ -42,6 +43,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationAdapter.SnapshotAdapter; import com.android.wm.shell.common.ScreenshotUtils; import com.android.wm.shell.util.TransitionUtil; @@ -185,23 +187,23 @@ class ActivityEmbeddingAnimationRunner { return createChangeAnimationAdapters(info, startTransaction); } if (TransitionUtil.isClosingType(info.getType())) { - return createCloseAnimationAdapters(info); + return createCloseAnimationAdapters(info, startTransaction); } - return createOpenAnimationAdapters(info); + return createOpenAnimationAdapters(info, startTransaction); } @NonNull private List createOpenAnimationAdapters( - @NonNull TransitionInfo info) { + @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) { return createOpenCloseAnimationAdapters(info, true /* isOpening */, - mAnimationSpec::loadOpenAnimation); + mAnimationSpec::loadOpenAnimation, startTransaction); } @NonNull private List createCloseAnimationAdapters( - @NonNull TransitionInfo info) { + @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) { return createOpenCloseAnimationAdapters(info, false /* isOpening */, - mAnimationSpec::loadCloseAnimation); + mAnimationSpec::loadCloseAnimation, startTransaction); } /** @@ -211,7 +213,8 @@ class ActivityEmbeddingAnimationRunner { @NonNull private List createOpenCloseAnimationAdapters( @NonNull TransitionInfo info, boolean isOpening, - @NonNull AnimationProvider animationProvider) { + @NonNull AnimationProvider animationProvider, + @NonNull SurfaceControl.Transaction startTransaction) { // We need to know if the change window is only a partial of the whole animation screen. // If so, we will need to adjust it to make the whole animation screen looks like one. final List openingChanges = new ArrayList<>(); @@ -224,6 +227,8 @@ class ActivityEmbeddingAnimationRunner { openingWholeScreenBounds.union(change.getEndAbsBounds()); } else { closingChanges.add(change); + // Also union with the start bounds because the closing transition may be shrunk. + closingWholeScreenBounds.union(change.getStartAbsBounds()); closingWholeScreenBounds.union(change.getEndAbsBounds()); } } @@ -241,6 +246,17 @@ class ActivityEmbeddingAnimationRunner { adapters.add(adapter); } for (TransitionInfo.Change change : closingChanges) { + if (shouldUseSnapshotAnimationForClosingChange(change)) { + SurfaceControl screenshot = getOrCreateScreenshot(change, change, startTransaction); + if (screenshot != null) { + final SnapshotAdapter snapshotAdapter = new SnapshotAdapter( + createShowSnapshotForClosingAnimation(), change, screenshot); + if (!isOpening) { + snapshotAdapter.overrideLayer(offsetLayer++); + } + adapters.add(snapshotAdapter); + } + } final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( info, change, animationProvider, closingWholeScreenBounds); if (!isOpening) { @@ -251,6 +267,22 @@ class ActivityEmbeddingAnimationRunner { return adapters; } + /** + * Returns whether we should use snapshot animation for the closing change. + * It's usually because the end bounds of the closing change are shrunk, which leaves a black + * area in the transition. + */ + static boolean shouldUseSnapshotAnimationForClosingChange( + @NonNull TransitionInfo.Change closingChange) { + // Only check closing type because we only take screenshot for closing bounds-changing + // changes. + if (!TransitionUtil.isClosingType(closingChange.getMode())) { + return false; + } + // Don't need to take screenshot if there's no bounds change. + return !closingChange.getStartAbsBounds().equals(closingChange.getEndAbsBounds()); + } + /** Sets the first frame to the {@code startTransaction} to avoid any flicker on start. */ private void prepareForFirstFrame(@NonNull SurfaceControl.Transaction startTransaction, @NonNull List adapters) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java index cb8342a10a6aa..19eff0e431692 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java @@ -77,6 +77,15 @@ class ActivityEmbeddingAnimationSpec { return new AlphaAnimation(alpha, alpha); } + /** + * Animation that intended to show snapshot for closing animation because the closing end bounds + * are changed. + */ + @NonNull + static Animation createShowSnapshotForClosingAnimation() { + return new AlphaAnimation(1f, 1f); + } + /** Animation for window that is opening in a change transition. */ @NonNull Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo.Change change,