diff options
3 files changed, 76 insertions, 20 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 215308d9e96e..00b9fcede4ca 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 @@ -30,6 +30,8 @@ import android.window.TransitionInfo; import androidx.annotation.NonNull; +import com.android.wm.shell.transition.Transitions; + /** * Wrapper to handle the ActivityEmbedding animation update in one * {@link SurfaceControl.Transaction}. @@ -50,6 +52,16 @@ class ActivityEmbeddingAnimationAdapter { /** Area in absolute coordinate that the animation surface shouldn't go beyond. */ @NonNull private final Rect mWholeAnimationBounds = new Rect(); + /** + * Area in absolute coordinate that should represent all the content to show for this window. + * This should be the end bounds for opening window, and start bounds for closing window in case + * the window is resizing during the open/close transition. + */ + @NonNull + private final Rect mContentBounds = new Rect(); + /** Offset relative to the window parent surface for {@link #mContentBounds}. */ + @NonNull + private final Point mContentRelOffset = new Point(); @NonNull final Transformation mTransformation = new Transformation(); @@ -80,6 +92,21 @@ class ActivityEmbeddingAnimationAdapter { mChange = change; mLeash = leash; mWholeAnimationBounds.set(wholeAnimationBounds); + if (Transitions.isClosingType(change.getMode())) { + // When it is closing, we want to show the content at the start position in case the + // window is resizing as well. For example, when the activities is changing from split + // to stack, the bottom TaskFragment will be resized to fullscreen when hiding. + 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); + } else { + mContentBounds.set(change.getEndAbsBounds()); + mContentRelOffset.set(change.getEndRelOffset()); + } } /** @@ -110,8 +137,7 @@ class ActivityEmbeddingAnimationAdapter { /** To be overridden by subclasses to adjust the animation surface change. */ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) { // Update the surface position and alpha. - final Point offset = mChange.getEndRelOffset(); - mTransformation.getMatrix().postTranslate(offset.x, offset.y); + mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y); t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix); t.setAlpha(mLeash, mTransformation.getAlpha()); @@ -119,8 +145,8 @@ class ActivityEmbeddingAnimationAdapter { // positionX/Y are in local coordinate, so minus the local offset to get the slide amount. final int positionX = Math.round(mMatrix[MTRANS_X]); final int positionY = Math.round(mMatrix[MTRANS_Y]); - final Rect cropRect = new Rect(mChange.getEndAbsBounds()); - cropRect.offset(positionX - offset.x, positionY - offset.y); + final Rect cropRect = new Rect(mContentBounds); + cropRect.offset(positionX - mContentRelOffset.x, positionY - mContentRelOffset.y); // Store the current offset of the surface top left from (0,0) in absolute coordinate. final int offsetX = cropRect.left; @@ -133,7 +159,7 @@ class ActivityEmbeddingAnimationAdapter { } else if (mAnimation.hasExtension()) { // Allow the surface to be shown in its original bounds in case we want to use edge // extensions. - cropRect.union(mChange.getEndAbsBounds()); + cropRect.union(mContentBounds); } // cropRect is in absolute coordinate, so we need to translate it to surface top left. 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 921861ae0913..c0a6456a2df0 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 @@ -304,6 +304,7 @@ class ActivityEmbeddingAnimationRunner { // This is because the TaskFragment surface/change won't contain the Activity's before its // reparent. Animation changeAnimation = null; + Rect parentBounds = new Rect(); for (TransitionInfo.Change change : info.getChanges()) { if (change.getMode() != TRANSIT_CHANGE || change.getStartAbsBounds().equals(change.getEndAbsBounds())) { @@ -326,10 +327,15 @@ class ActivityEmbeddingAnimationRunner { } } + // The TaskFragment may be enter/exit split, so we take the union of both as the parent + // size. + parentBounds.union(boundsAnimationChange.getStartAbsBounds()); + parentBounds.union(boundsAnimationChange.getEndAbsBounds()); + // There are two animations in the array. The first one is for the start leash // (snapshot), and the second one is for the end leash (TaskFragment). final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change, - boundsAnimationChange.getEndAbsBounds()); + parentBounds); // Keep track as we might need to add background color for the animation. // Although there may be multiple change animation, record one of them is sufficient // because the background color will be added to the root leash for the whole animation. @@ -352,6 +358,11 @@ class ActivityEmbeddingAnimationRunner { animations[1], boundsAnimationChange)); } + if (parentBounds.isEmpty()) { + throw new IllegalStateException( + "There should be at least one changing window to play the change animation"); + } + // If there is no corresponding open/close window with the change, we should show background // color to cover the empty part of the screen. boolean shouldShouldBackgroundColor = true; @@ -368,10 +379,10 @@ class ActivityEmbeddingAnimationRunner { // No-op if it will be covered by the changing parent window. animation = ActivityEmbeddingAnimationSpec.createNoopAnimation(change); } else if (Transitions.isClosingType(change.getMode())) { - animation = mAnimationSpec.createChangeBoundsCloseAnimation(change); + animation = mAnimationSpec.createChangeBoundsCloseAnimation(change, parentBounds); shouldShouldBackgroundColor = false; } else { - animation = mAnimationSpec.createChangeBoundsOpenAnimation(change); + animation = mAnimationSpec.createChangeBoundsOpenAnimation(change, parentBounds); shouldShouldBackgroundColor = false; } adapters.add(new ActivityEmbeddingAnimationAdapter(animation, change)); 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 2bb73692b457..65a7d09dafa3 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 @@ -21,7 +21,6 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation; import android.content.Context; -import android.graphics.Point; import android.graphics.Rect; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; @@ -80,15 +79,25 @@ class ActivityEmbeddingAnimationSpec { /** Animation for window that is opening in a change transition. */ @NonNull - Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo.Change change) { + Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo.Change change, + @NonNull Rect parentBounds) { + // Use end bounds for opening. final Rect bounds = change.getEndAbsBounds(); - final Point offset = change.getEndRelOffset(); - // The window will be animated in from left or right depends on its position. - final int startLeft = offset.x == 0 ? -bounds.width() : bounds.width(); + final int startLeft; + final int startTop; + if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) { + // The window will be animated in from left or right depends on its position. + startTop = 0; + startLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width(); + } else { + // The window will be animated in from top or bottom depends on its position. + startTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height(); + startLeft = 0; + } // The position should be 0-based as we will post translate in // ActivityEmbeddingAnimationAdapter#onAnimationUpdate - final Animation animation = new TranslateAnimation(startLeft, 0, 0, 0); + final Animation animation = new TranslateAnimation(startLeft, 0, startTop, 0); animation.setInterpolator(mFastOutExtraSlowInInterpolator); animation.setDuration(CHANGE_ANIMATION_DURATION); animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height()); @@ -98,15 +107,25 @@ class ActivityEmbeddingAnimationSpec { /** Animation for window that is closing in a change transition. */ @NonNull - Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo.Change change) { - final Rect bounds = change.getEndAbsBounds(); - final Point offset = change.getEndRelOffset(); - // The window will be animated out to left or right depends on its position. - final int endLeft = offset.x == 0 ? -bounds.width() : bounds.width(); + Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo.Change change, + @NonNull Rect parentBounds) { + // Use start bounds for closing. + final Rect bounds = change.getStartAbsBounds(); + final int endTop; + final int endLeft; + if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) { + // The window will be animated out to left or right depends on its position. + endTop = 0; + endLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width(); + } else { + // The window will be animated out to top or bottom depends on its position. + endTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height(); + endLeft = 0; + } // The position should be 0-based as we will post translate in // ActivityEmbeddingAnimationAdapter#onAnimationUpdate - final Animation animation = new TranslateAnimation(0, endLeft, 0, 0); + final Animation animation = new TranslateAnimation(0, endLeft, 0, endTop); animation.setInterpolator(mFastOutExtraSlowInInterpolator); animation.setDuration(CHANGE_ANIMATION_DURATION); animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height()); |