Loading libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java +31 −5 Original line number Diff line number Diff line Loading @@ -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}. Loading @@ -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(); Loading Loading @@ -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()); } } /** Loading Loading @@ -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()); Loading @@ -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; Loading @@ -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. Loading libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +14 −3 Original line number Diff line number Diff line Loading @@ -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())) { Loading @@ -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. Loading @@ -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; Loading @@ -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)); Loading libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java +31 −12 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); 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. final int startLeft = offset.x == 0 ? -bounds.width() : bounds.width(); 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()); Loading @@ -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(); 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. final int endLeft = offset.x == 0 ? -bounds.width() : bounds.width(); 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()); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java +31 −5 Original line number Diff line number Diff line Loading @@ -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}. Loading @@ -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(); Loading Loading @@ -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()); } } /** Loading Loading @@ -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()); Loading @@ -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; Loading @@ -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. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +14 −3 Original line number Diff line number Diff line Loading @@ -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())) { Loading @@ -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. Loading @@ -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; Loading @@ -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)); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java +31 −12 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); 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. final int startLeft = offset.x == 0 ? -bounds.width() : bounds.width(); 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()); Loading @@ -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(); 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. final int endLeft = offset.x == 0 ? -bounds.width() : bounds.width(); 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()); Loading