Loading libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java +4 −0 Original line number Diff line number Diff line Loading @@ -130,6 +130,10 @@ class ActivityEmbeddingAnimationAdapter { if (!cropRect.intersect(mWholeAnimationBounds)) { // Hide the surface when it is outside of the animation area. t.setAlpha(mLeash, 0); } 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 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 +85 −33 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; 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; import android.animation.Animator; Loading @@ -45,6 +46,7 @@ import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.function.Consumer; /** To run the ActivityEmbedding animations. */ class ActivityEmbeddingAnimationRunner { Loading @@ -65,11 +67,32 @@ class ActivityEmbeddingAnimationRunner { void startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { // There may be some surface change that we want to apply after the start transaction is // applied to make sure the surface is ready. final List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks = new ArrayList<>(); final Animator animator = createAnimator(info, startTransaction, finishTransaction, () -> mController.onAnimationFinished(transition)); () -> mController.onAnimationFinished(transition), postStartTransactionCallbacks); // Start the animation. if (!postStartTransactionCallbacks.isEmpty()) { // postStartTransactionCallbacks require that the start transaction is already // applied to run otherwise they may result in flickers and UI inconsistencies. startTransaction.apply(true /* sync */); // Run tasks that require startTransaction to already be applied final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); for (Consumer<SurfaceControl.Transaction> postStartTransactionCallback : postStartTransactionCallbacks) { postStartTransactionCallback.accept(t); } t.apply(); animator.start(); } else { startTransaction.apply(); animator.start(); } } /** * Sets transition animation scale settings value. Loading @@ -85,9 +108,13 @@ class ActivityEmbeddingAnimationRunner { Animator createAnimator(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Runnable animationFinishCallback) { final List<ActivityEmbeddingAnimationAdapter> adapters = createAnimationAdapters(info, startTransaction, finishTransaction); @NonNull Runnable animationFinishCallback, @NonNull List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks) { final List<ActivityEmbeddingAnimationAdapter> adapters = createAnimationAdapters(info, startTransaction); addEdgeExtensionIfNeeded(startTransaction, finishTransaction, postStartTransactionCallbacks, adapters); addBackgroundColorIfNeeded(info, startTransaction, finishTransaction, adapters); long duration = 0; for (ActivityEmbeddingAnimationAdapter adapter : adapters) { duration = Math.max(duration, adapter.getDurationHint()); Loading Loading @@ -131,8 +158,7 @@ class ActivityEmbeddingAnimationRunner { */ @NonNull private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) { boolean isChangeTransition = false; for (TransitionInfo.Change change : info.getChanges()) { if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) { Loading @@ -148,25 +174,23 @@ class ActivityEmbeddingAnimationRunner { return createChangeAnimationAdapters(info, startTransaction); } if (Transitions.isClosingType(info.getType())) { return createCloseAnimationAdapters(info, startTransaction, finishTransaction); return createCloseAnimationAdapters(info); } return createOpenAnimationAdapters(info, startTransaction, finishTransaction); return createOpenAnimationAdapters(info); } @NonNull private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction, true /* isOpening */, mAnimationSpec::loadOpenAnimation); @NonNull TransitionInfo info) { return createOpenCloseAnimationAdapters(info, true /* isOpening */, mAnimationSpec::loadOpenAnimation); } @NonNull private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction, false /* isOpening */, mAnimationSpec::loadCloseAnimation); @NonNull TransitionInfo info) { return createOpenCloseAnimationAdapters(info, false /* isOpening */, mAnimationSpec::loadCloseAnimation); } /** Loading @@ -175,8 +199,7 @@ class ActivityEmbeddingAnimationRunner { */ @NonNull private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, boolean isOpening, @NonNull TransitionInfo info, boolean isOpening, @NonNull AnimationProvider animationProvider) { // 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. Loading @@ -200,8 +223,7 @@ class ActivityEmbeddingAnimationRunner { final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>(); for (TransitionInfo.Change change : openingChanges) { final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( info, change, startTransaction, finishTransaction, animationProvider, openingWholeScreenBounds); info, change, animationProvider, openingWholeScreenBounds); if (isOpening) { adapter.overrideLayer(offsetLayer++); } Loading @@ -209,8 +231,7 @@ class ActivityEmbeddingAnimationRunner { } for (TransitionInfo.Change change : closingChanges) { final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( info, change, startTransaction, finishTransaction, animationProvider, closingWholeScreenBounds); info, change, animationProvider, closingWholeScreenBounds); if (!isOpening) { adapter.overrideLayer(offsetLayer++); } Loading @@ -219,20 +240,51 @@ class ActivityEmbeddingAnimationRunner { return adapters; } @NonNull private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter( @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, /** Adds edge extension to the surfaces that have such an animation property. */ private void addEdgeExtensionIfNeeded(@NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks, @NonNull List<ActivityEmbeddingAnimationAdapter> adapters) { for (ActivityEmbeddingAnimationAdapter adapter : adapters) { final Animation animation = adapter.mAnimation; if (!animation.hasExtension()) { continue; } final TransitionInfo.Change change = adapter.mChange; if (Transitions.isOpeningType(adapter.mChange.getMode())) { // Need to screenshot after startTransaction is applied otherwise activity // may not be visible or ready yet. postStartTransactionCallbacks.add( t -> edgeExtendWindow(change, animation, t, finishTransaction)); } else { // Can screenshot now (before startTransaction is applied) edgeExtendWindow(change, animation, startTransaction, finishTransaction); } } } /** Adds background color to the transition if any animation has such a property. */ private void addBackgroundColorIfNeeded(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) { final Animation animation = animationProvider.get(info, change, wholeAnimationBounds); // We may want to show a background color for open/close transition. final int backgroundColor = getTransitionBackgroundColorIfSet(info, change, animation, 0 /* defaultColor */); @NonNull List<ActivityEmbeddingAnimationAdapter> adapters) { for (ActivityEmbeddingAnimationAdapter adapter : adapters) { final int backgroundColor = getTransitionBackgroundColorIfSet(info, adapter.mChange, adapter.mAnimation, 0 /* defaultColor */); if (backgroundColor != 0) { // We only need to show one color. addBackgroundToTransition(info.getRootLeash(), backgroundColor, startTransaction, finishTransaction); return; } } } @NonNull private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter( @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, @NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) { final Animation animation = animationProvider.get(info, change, wholeAnimationBounds); return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(), wholeAnimationBounds); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java +6 −6 Original line number Diff line number Diff line Loading @@ -181,15 +181,15 @@ class ActivityEmbeddingAnimationSpec { @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = Transitions.isOpeningType(change.getMode()); final Animation animation; // TODO(b/207070762): Implement edgeExtension version if (shouldShowBackdrop(info, change)) { animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_clear_top_open_enter : com.android.internal.R.anim.task_fragment_clear_top_open_exit); } else { // Use the same edge extension animation as regular activity open. animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_open_enter : com.android.internal.R.anim.task_fragment_open_exit); ? com.android.internal.R.anim.activity_open_enter : com.android.internal.R.anim.activity_open_exit); } // Use the whole animation bounds instead of the change bounds, so that when multiple change // targets are opening at the same time, the animation applied to each will be the same. Loading @@ -205,15 +205,15 @@ class ActivityEmbeddingAnimationSpec { @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = Transitions.isOpeningType(change.getMode()); final Animation animation; // TODO(b/207070762): Implement edgeExtension version if (shouldShowBackdrop(info, change)) { animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_clear_top_close_enter : com.android.internal.R.anim.task_fragment_clear_top_close_exit); } else { // Use the same edge extension animation as regular activity close. animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_close_enter : com.android.internal.R.anim.task_fragment_close_exit); ? com.android.internal.R.anim.activity_close_enter : com.android.internal.R.anim.activity_close_exit); } // Use the whole animation bounds instead of the change bounds, so that when multiple change // targets are closing at the same time, the animation applied to each will be the same. Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +1 −121 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE; import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN; 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; import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation; import static com.android.wm.shell.transition.TransitionAnimationHelper.sDisableCustomTaskAnimationProperty; Loading @@ -76,10 +77,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Canvas; import android.graphics.Insets; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; Loading @@ -89,7 +87,6 @@ import android.os.IBinder; import android.os.UserHandle; import android.util.ArrayMap; import android.view.Choreographer; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowManager; Loading Loading @@ -525,123 +522,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } } private void edgeExtendWindow(TransitionInfo.Change change, Animation a, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction) { // Do not create edge extension surface for transfer starting window change. // The app surface could be empty thus nothing can draw on the hardware renderer, which will // block this thread when calling Surface#unlockCanvasAndPost. if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) { return; } final Transformation transformationAtStart = new Transformation(); a.getTransformationAt(0, transformationAtStart); final Transformation transformationAtEnd = new Transformation(); a.getTransformationAt(1, transformationAtEnd); // We want to create an extension surface that is the maximal size and the animation will // take care of cropping any part that overflows. final Insets maxExtensionInsets = Insets.min( transformationAtStart.getInsets(), transformationAtEnd.getInsets()); final int targetSurfaceHeight = Math.max(change.getStartAbsBounds().height(), change.getEndAbsBounds().height()); final int targetSurfaceWidth = Math.max(change.getStartAbsBounds().width(), change.getEndAbsBounds().width()); if (maxExtensionInsets.left < 0) { final Rect edgeBounds = new Rect(0, 0, 1, targetSurfaceHeight); final Rect extensionRect = new Rect(0, 0, -maxExtensionInsets.left, targetSurfaceHeight); final int xPos = maxExtensionInsets.left; final int yPos = 0; createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos, "Left Edge Extension", startTransaction, finishTransaction); } if (maxExtensionInsets.top < 0) { final Rect edgeBounds = new Rect(0, 0, targetSurfaceWidth, 1); final Rect extensionRect = new Rect(0, 0, targetSurfaceWidth, -maxExtensionInsets.top); final int xPos = 0; final int yPos = maxExtensionInsets.top; createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos, "Top Edge Extension", startTransaction, finishTransaction); } if (maxExtensionInsets.right < 0) { final Rect edgeBounds = new Rect(targetSurfaceWidth - 1, 0, targetSurfaceWidth, targetSurfaceHeight); final Rect extensionRect = new Rect(0, 0, -maxExtensionInsets.right, targetSurfaceHeight); final int xPos = targetSurfaceWidth; final int yPos = 0; createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos, "Right Edge Extension", startTransaction, finishTransaction); } if (maxExtensionInsets.bottom < 0) { final Rect edgeBounds = new Rect(0, targetSurfaceHeight - 1, targetSurfaceWidth, targetSurfaceHeight); final Rect extensionRect = new Rect(0, 0, targetSurfaceWidth, -maxExtensionInsets.bottom); final int xPos = maxExtensionInsets.left; final int yPos = targetSurfaceHeight; createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos, "Bottom Edge Extension", startTransaction, finishTransaction); } } private SurfaceControl createExtensionSurface(SurfaceControl surfaceToExtend, Rect edgeBounds, Rect extensionRect, int xPos, int yPos, String layerName, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction) { final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder() .setName(layerName) .setParent(surfaceToExtend) .setHidden(true) .setCallsite("DefaultTransitionHandler#startAnimation") .setOpaque(true) .setBufferSize(extensionRect.width(), extensionRect.height()) .build(); SurfaceControl.LayerCaptureArgs captureArgs = new SurfaceControl.LayerCaptureArgs.Builder(surfaceToExtend) .setSourceCrop(edgeBounds) .setFrameScale(1) .setPixelFormat(PixelFormat.RGBA_8888) .setChildrenOnly(true) .setAllowProtected(true) .build(); final SurfaceControl.ScreenshotHardwareBuffer edgeBuffer = SurfaceControl.captureLayers(captureArgs); if (edgeBuffer == null) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Failed to capture edge of window."); return null; } android.graphics.BitmapShader shader = new android.graphics.BitmapShader(edgeBuffer.asBitmap(), android.graphics.Shader.TileMode.CLAMP, android.graphics.Shader.TileMode.CLAMP); final Paint paint = new Paint(); paint.setShader(shader); final Surface surface = new Surface(edgeExtensionLayer); Canvas c = surface.lockHardwareCanvas(); c.drawRect(extensionRect, paint); surface.unlockCanvasAndPost(c); surface.release(); startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE); startTransaction.setPosition(edgeExtensionLayer, xPos, yPos); startTransaction.setVisibility(edgeExtensionLayer, true); finishTransaction.remove(edgeExtensionLayer); return edgeExtensionLayer; } @Nullable @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java +132 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java +4 −0 Original line number Diff line number Diff line Loading @@ -130,6 +130,10 @@ class ActivityEmbeddingAnimationAdapter { if (!cropRect.intersect(mWholeAnimationBounds)) { // Hide the surface when it is outside of the animation area. t.setAlpha(mLeash, 0); } 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 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 +85 −33 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; 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; import android.animation.Animator; Loading @@ -45,6 +46,7 @@ import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.function.Consumer; /** To run the ActivityEmbedding animations. */ class ActivityEmbeddingAnimationRunner { Loading @@ -65,11 +67,32 @@ class ActivityEmbeddingAnimationRunner { void startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { // There may be some surface change that we want to apply after the start transaction is // applied to make sure the surface is ready. final List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks = new ArrayList<>(); final Animator animator = createAnimator(info, startTransaction, finishTransaction, () -> mController.onAnimationFinished(transition)); () -> mController.onAnimationFinished(transition), postStartTransactionCallbacks); // Start the animation. if (!postStartTransactionCallbacks.isEmpty()) { // postStartTransactionCallbacks require that the start transaction is already // applied to run otherwise they may result in flickers and UI inconsistencies. startTransaction.apply(true /* sync */); // Run tasks that require startTransaction to already be applied final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); for (Consumer<SurfaceControl.Transaction> postStartTransactionCallback : postStartTransactionCallbacks) { postStartTransactionCallback.accept(t); } t.apply(); animator.start(); } else { startTransaction.apply(); animator.start(); } } /** * Sets transition animation scale settings value. Loading @@ -85,9 +108,13 @@ class ActivityEmbeddingAnimationRunner { Animator createAnimator(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Runnable animationFinishCallback) { final List<ActivityEmbeddingAnimationAdapter> adapters = createAnimationAdapters(info, startTransaction, finishTransaction); @NonNull Runnable animationFinishCallback, @NonNull List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks) { final List<ActivityEmbeddingAnimationAdapter> adapters = createAnimationAdapters(info, startTransaction); addEdgeExtensionIfNeeded(startTransaction, finishTransaction, postStartTransactionCallbacks, adapters); addBackgroundColorIfNeeded(info, startTransaction, finishTransaction, adapters); long duration = 0; for (ActivityEmbeddingAnimationAdapter adapter : adapters) { duration = Math.max(duration, adapter.getDurationHint()); Loading Loading @@ -131,8 +158,7 @@ class ActivityEmbeddingAnimationRunner { */ @NonNull private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) { boolean isChangeTransition = false; for (TransitionInfo.Change change : info.getChanges()) { if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) { Loading @@ -148,25 +174,23 @@ class ActivityEmbeddingAnimationRunner { return createChangeAnimationAdapters(info, startTransaction); } if (Transitions.isClosingType(info.getType())) { return createCloseAnimationAdapters(info, startTransaction, finishTransaction); return createCloseAnimationAdapters(info); } return createOpenAnimationAdapters(info, startTransaction, finishTransaction); return createOpenAnimationAdapters(info); } @NonNull private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction, true /* isOpening */, mAnimationSpec::loadOpenAnimation); @NonNull TransitionInfo info) { return createOpenCloseAnimationAdapters(info, true /* isOpening */, mAnimationSpec::loadOpenAnimation); } @NonNull private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction, false /* isOpening */, mAnimationSpec::loadCloseAnimation); @NonNull TransitionInfo info) { return createOpenCloseAnimationAdapters(info, false /* isOpening */, mAnimationSpec::loadCloseAnimation); } /** Loading @@ -175,8 +199,7 @@ class ActivityEmbeddingAnimationRunner { */ @NonNull private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, boolean isOpening, @NonNull TransitionInfo info, boolean isOpening, @NonNull AnimationProvider animationProvider) { // 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. Loading @@ -200,8 +223,7 @@ class ActivityEmbeddingAnimationRunner { final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>(); for (TransitionInfo.Change change : openingChanges) { final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( info, change, startTransaction, finishTransaction, animationProvider, openingWholeScreenBounds); info, change, animationProvider, openingWholeScreenBounds); if (isOpening) { adapter.overrideLayer(offsetLayer++); } Loading @@ -209,8 +231,7 @@ class ActivityEmbeddingAnimationRunner { } for (TransitionInfo.Change change : closingChanges) { final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( info, change, startTransaction, finishTransaction, animationProvider, closingWholeScreenBounds); info, change, animationProvider, closingWholeScreenBounds); if (!isOpening) { adapter.overrideLayer(offsetLayer++); } Loading @@ -219,20 +240,51 @@ class ActivityEmbeddingAnimationRunner { return adapters; } @NonNull private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter( @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, /** Adds edge extension to the surfaces that have such an animation property. */ private void addEdgeExtensionIfNeeded(@NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks, @NonNull List<ActivityEmbeddingAnimationAdapter> adapters) { for (ActivityEmbeddingAnimationAdapter adapter : adapters) { final Animation animation = adapter.mAnimation; if (!animation.hasExtension()) { continue; } final TransitionInfo.Change change = adapter.mChange; if (Transitions.isOpeningType(adapter.mChange.getMode())) { // Need to screenshot after startTransaction is applied otherwise activity // may not be visible or ready yet. postStartTransactionCallbacks.add( t -> edgeExtendWindow(change, animation, t, finishTransaction)); } else { // Can screenshot now (before startTransaction is applied) edgeExtendWindow(change, animation, startTransaction, finishTransaction); } } } /** Adds background color to the transition if any animation has such a property. */ private void addBackgroundColorIfNeeded(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) { final Animation animation = animationProvider.get(info, change, wholeAnimationBounds); // We may want to show a background color for open/close transition. final int backgroundColor = getTransitionBackgroundColorIfSet(info, change, animation, 0 /* defaultColor */); @NonNull List<ActivityEmbeddingAnimationAdapter> adapters) { for (ActivityEmbeddingAnimationAdapter adapter : adapters) { final int backgroundColor = getTransitionBackgroundColorIfSet(info, adapter.mChange, adapter.mAnimation, 0 /* defaultColor */); if (backgroundColor != 0) { // We only need to show one color. addBackgroundToTransition(info.getRootLeash(), backgroundColor, startTransaction, finishTransaction); return; } } } @NonNull private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter( @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, @NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) { final Animation animation = animationProvider.get(info, change, wholeAnimationBounds); return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(), wholeAnimationBounds); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java +6 −6 Original line number Diff line number Diff line Loading @@ -181,15 +181,15 @@ class ActivityEmbeddingAnimationSpec { @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = Transitions.isOpeningType(change.getMode()); final Animation animation; // TODO(b/207070762): Implement edgeExtension version if (shouldShowBackdrop(info, change)) { animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_clear_top_open_enter : com.android.internal.R.anim.task_fragment_clear_top_open_exit); } else { // Use the same edge extension animation as regular activity open. animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_open_enter : com.android.internal.R.anim.task_fragment_open_exit); ? com.android.internal.R.anim.activity_open_enter : com.android.internal.R.anim.activity_open_exit); } // Use the whole animation bounds instead of the change bounds, so that when multiple change // targets are opening at the same time, the animation applied to each will be the same. Loading @@ -205,15 +205,15 @@ class ActivityEmbeddingAnimationSpec { @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) { final boolean isEnter = Transitions.isOpeningType(change.getMode()); final Animation animation; // TODO(b/207070762): Implement edgeExtension version if (shouldShowBackdrop(info, change)) { animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_clear_top_close_enter : com.android.internal.R.anim.task_fragment_clear_top_close_exit); } else { // Use the same edge extension animation as regular activity close. animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter ? com.android.internal.R.anim.task_fragment_close_enter : com.android.internal.R.anim.task_fragment_close_exit); ? com.android.internal.R.anim.activity_close_enter : com.android.internal.R.anim.activity_close_exit); } // Use the whole animation bounds instead of the change bounds, so that when multiple change // targets are closing at the same time, the animation applied to each will be the same. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +1 −121 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE; import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN; 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; import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation; import static com.android.wm.shell.transition.TransitionAnimationHelper.sDisableCustomTaskAnimationProperty; Loading @@ -76,10 +77,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Canvas; import android.graphics.Insets; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; Loading @@ -89,7 +87,6 @@ import android.os.IBinder; import android.os.UserHandle; import android.util.ArrayMap; import android.view.Choreographer; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowManager; Loading Loading @@ -525,123 +522,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } } private void edgeExtendWindow(TransitionInfo.Change change, Animation a, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction) { // Do not create edge extension surface for transfer starting window change. // The app surface could be empty thus nothing can draw on the hardware renderer, which will // block this thread when calling Surface#unlockCanvasAndPost. if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) { return; } final Transformation transformationAtStart = new Transformation(); a.getTransformationAt(0, transformationAtStart); final Transformation transformationAtEnd = new Transformation(); a.getTransformationAt(1, transformationAtEnd); // We want to create an extension surface that is the maximal size and the animation will // take care of cropping any part that overflows. final Insets maxExtensionInsets = Insets.min( transformationAtStart.getInsets(), transformationAtEnd.getInsets()); final int targetSurfaceHeight = Math.max(change.getStartAbsBounds().height(), change.getEndAbsBounds().height()); final int targetSurfaceWidth = Math.max(change.getStartAbsBounds().width(), change.getEndAbsBounds().width()); if (maxExtensionInsets.left < 0) { final Rect edgeBounds = new Rect(0, 0, 1, targetSurfaceHeight); final Rect extensionRect = new Rect(0, 0, -maxExtensionInsets.left, targetSurfaceHeight); final int xPos = maxExtensionInsets.left; final int yPos = 0; createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos, "Left Edge Extension", startTransaction, finishTransaction); } if (maxExtensionInsets.top < 0) { final Rect edgeBounds = new Rect(0, 0, targetSurfaceWidth, 1); final Rect extensionRect = new Rect(0, 0, targetSurfaceWidth, -maxExtensionInsets.top); final int xPos = 0; final int yPos = maxExtensionInsets.top; createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos, "Top Edge Extension", startTransaction, finishTransaction); } if (maxExtensionInsets.right < 0) { final Rect edgeBounds = new Rect(targetSurfaceWidth - 1, 0, targetSurfaceWidth, targetSurfaceHeight); final Rect extensionRect = new Rect(0, 0, -maxExtensionInsets.right, targetSurfaceHeight); final int xPos = targetSurfaceWidth; final int yPos = 0; createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos, "Right Edge Extension", startTransaction, finishTransaction); } if (maxExtensionInsets.bottom < 0) { final Rect edgeBounds = new Rect(0, targetSurfaceHeight - 1, targetSurfaceWidth, targetSurfaceHeight); final Rect extensionRect = new Rect(0, 0, targetSurfaceWidth, -maxExtensionInsets.bottom); final int xPos = maxExtensionInsets.left; final int yPos = targetSurfaceHeight; createExtensionSurface(change.getLeash(), edgeBounds, extensionRect, xPos, yPos, "Bottom Edge Extension", startTransaction, finishTransaction); } } private SurfaceControl createExtensionSurface(SurfaceControl surfaceToExtend, Rect edgeBounds, Rect extensionRect, int xPos, int yPos, String layerName, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction) { final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder() .setName(layerName) .setParent(surfaceToExtend) .setHidden(true) .setCallsite("DefaultTransitionHandler#startAnimation") .setOpaque(true) .setBufferSize(extensionRect.width(), extensionRect.height()) .build(); SurfaceControl.LayerCaptureArgs captureArgs = new SurfaceControl.LayerCaptureArgs.Builder(surfaceToExtend) .setSourceCrop(edgeBounds) .setFrameScale(1) .setPixelFormat(PixelFormat.RGBA_8888) .setChildrenOnly(true) .setAllowProtected(true) .build(); final SurfaceControl.ScreenshotHardwareBuffer edgeBuffer = SurfaceControl.captureLayers(captureArgs); if (edgeBuffer == null) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Failed to capture edge of window."); return null; } android.graphics.BitmapShader shader = new android.graphics.BitmapShader(edgeBuffer.asBitmap(), android.graphics.Shader.TileMode.CLAMP, android.graphics.Shader.TileMode.CLAMP); final Paint paint = new Paint(); paint.setShader(shader); final Surface surface = new Surface(edgeExtensionLayer); Canvas c = surface.lockHardwareCanvas(); c.drawRect(extensionRect, paint); surface.unlockCanvasAndPost(c); surface.release(); startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE); startTransaction.setPosition(edgeExtensionLayer, xPos, yPos); startTransaction.setVisibility(edgeExtensionLayer, true); finishTransaction.remove(edgeExtensionLayer); return edgeExtensionLayer; } @Nullable @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java +132 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes