From 4ae444073c1195d75213ca2ba514268885a5a9ac Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Sat, 25 Mar 2023 00:48:37 +0800 Subject: [PATCH] Fix black flash when launching dual split activity The root cause is that the closing Activity is shrunck because it also matches the split pair rule with the started activity. This CL uses the snapshot to show closing transition instead, and also takes the start bounds into account because the end bounds of the closing transition may be shrunk. Test: manual - repro steps in bug with layout direction RIGHT_TO_LEFT, TOP_TO_BOTTOM and LOCALE Bug: 275034335 Change-Id: I63df42f61f03e511f2845899b2576432021ccf49 --- .../ActivityEmbeddingAnimationAdapter.java | 17 +++++-- .../ActivityEmbeddingAnimationRunner.java | 46 ++++++++++++++++--- .../ActivityEmbeddingAnimationSpec.java | 9 ++++ 3 files changed, 61 insertions(+), 11 deletions(-) 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,