Loading libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java +3 −1 Original line number Diff line number Diff line Loading @@ -170,9 +170,11 @@ class ActivityEmbeddingAnimationAdapter { void onAnimationEnd(@NonNull SurfaceControl.Transaction t) { super.onAnimationEnd(t); // Remove the screenshot leash after animation is finished. if (mLeash.isValid()) { t.remove(mLeash); } } } /** * Should be used for the animation of the {@link TransitionInfo.Change} that has size change. Loading libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +75 −32 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Rect; import android.os.IBinder; import android.util.ArraySet; import android.util.Log; import android.view.SurfaceControl; import android.view.animation.Animation; Loading @@ -39,6 +40,7 @@ import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.function.BiFunction; /** To run the ActivityEmbedding animations. */ Loading Loading @@ -214,25 +216,47 @@ class ActivityEmbeddingAnimationRunner { private List<ActivityEmbeddingAnimationAdapter> createChangeAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) { final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>(); final Set<TransitionInfo.Change> handledChanges = new ArraySet<>(); // For the first iteration, we prepare the animation for the change type windows. This is // needed because there may be window that is reparented while resizing. In such case, we // will do the following: // 1. Capture a screenshot from the Activity surface. // 2. Attach the screenshot surface to the top of TaskFragment (Activity's parent) surface. // 3. Animate the TaskFragment using Activity Change info (start/end bounds). // This is because the TaskFragment surface/change won't contain the Activity's before its // reparent. for (TransitionInfo.Change change : info.getChanges()) { if (change.getMode() == TRANSIT_CHANGE && !change.getStartAbsBounds().equals(change.getEndAbsBounds())) { if (change.getMode() != TRANSIT_CHANGE || change.getStartAbsBounds().equals(change.getEndAbsBounds())) { continue; } // This is the window with bounds change. handledChanges.add(change); final WindowContainerToken parentToken = change.getParent(); final Rect parentBounds; TransitionInfo.Change boundsAnimationChange = change; if (parentToken != null) { TransitionInfo.Change parentChange = info.getChange(parentToken); parentBounds = parentChange != null ? parentChange.getEndAbsBounds() : change.getEndAbsBounds(); } else { parentBounds = change.getEndAbsBounds(); // When the parent window is also included in the transition as an opening window, // we would like to animate the parent window instead. final TransitionInfo.Change parentChange = info.getChange(parentToken); if (parentChange != null && Transitions.isOpeningType(parentChange.getMode())) { // We won't create a separate animation for the parent, but to animate the // parent for the child resizing. handledChanges.add(parentChange); boundsAnimationChange = parentChange; } final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change, parentBounds); // Adapter for the starting screenshot leash. final SurfaceControl screenshotLeash = createScreenshot(change, startTransaction); } final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change, boundsAnimationChange.getEndAbsBounds()); // Create a screenshot based on change, but attach it to the top of the // boundsAnimationChange. final SurfaceControl screenshotLeash = getOrCreateScreenshot(change, boundsAnimationChange, startTransaction); if (screenshotLeash != null) { // Adapter for the starting screenshot leash. // The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter( animations[0], change, screenshotLeash)); Loading @@ -241,11 +265,16 @@ class ActivityEmbeddingAnimationRunner { } // Adapter for the ending bounds changed leash. adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter( animations[1], change)); animations[1], boundsAnimationChange)); } // Handle the other windows that don't have bounds change in the same transition. for (TransitionInfo.Change change : info.getChanges()) { if (handledChanges.contains(change)) { // Skip windows that we have already handled in the previous iteration. continue; } // These are the other windows that don't have bounds change in the same transition. final Animation animation; if (!TransitionInfo.isIndependent(change, info)) { // No-op if it will be covered by the changing parent window. Loading @@ -260,13 +289,27 @@ class ActivityEmbeddingAnimationRunner { return adapters; } /** Takes a screenshot of the given {@link TransitionInfo.Change} surface. */ /** * Takes a screenshot of the given {@code screenshotChange} surface if WM Core hasn't taken one. * The screenshot leash should be attached to the {@code animationChange} surface which we will * animate later. */ @Nullable private SurfaceControl createScreenshot(@NonNull TransitionInfo.Change change, @NonNull SurfaceControl.Transaction startTransaction) { final Rect cropBounds = new Rect(change.getStartAbsBounds()); private SurfaceControl getOrCreateScreenshot(@NonNull TransitionInfo.Change screenshotChange, @NonNull TransitionInfo.Change animationChange, @NonNull SurfaceControl.Transaction t) { final SurfaceControl screenshotLeash = screenshotChange.getSnapshot(); if (screenshotLeash != null) { // If WM Core has already taken a screenshot, make sure it is reparented to the // animation leash. t.reparent(screenshotLeash, animationChange.getLeash()); return screenshotLeash; } // If WM Core hasn't taken a screenshot, take a screenshot now. final Rect cropBounds = new Rect(screenshotChange.getStartAbsBounds()); cropBounds.offsetTo(0, 0); return ScreenshotUtils.takeScreenshot(startTransaction, change.getLeash(), cropBounds, Integer.MAX_VALUE); return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(), animationChange.getLeash(), cropBounds, Integer.MAX_VALUE); } } libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java +24 −5 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ import java.util.function.Consumer; public class ScreenshotUtils { /** * Take a screenshot of the specified SurfaceControl. * Takes a screenshot of the specified SurfaceControl. * * @param sc the SurfaceControl to take a screenshot of * @param crop the crop to use when capturing the screenshot Loading @@ -49,11 +49,14 @@ public class ScreenshotUtils { SurfaceControl mScreenshot = null; SurfaceControl.Transaction mTransaction; SurfaceControl mSurfaceControl; SurfaceControl mParentSurfaceControl; int mLayer; BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, int layer) { BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, SurfaceControl parentSc, int layer) { mTransaction = t; mSurfaceControl = sc; mParentSurfaceControl = parentSc; mLayer = layer; } Loading @@ -72,7 +75,7 @@ public class ScreenshotUtils { mTransaction.setBuffer(mScreenshot, buffer.getHardwareBuffer()); mTransaction.setColorSpace(mScreenshot, buffer.getColorSpace()); mTransaction.reparent(mScreenshot, mSurfaceControl); mTransaction.reparent(mScreenshot, mParentSurfaceControl); mTransaction.setLayer(mScreenshot, mLayer); mTransaction.show(mScreenshot); mTransaction.apply(); Loading @@ -80,7 +83,7 @@ public class ScreenshotUtils { } /** * Take a screenshot of the specified SurfaceControl. * Takes a screenshot of the specified SurfaceControl. * * @param t the transaction used to set changes on the resulting screenshot. * @param sc the SurfaceControl to take a screenshot of Loading @@ -91,7 +94,23 @@ public class ScreenshotUtils { */ public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc, Rect crop, int layer) { BufferConsumer consumer = new BufferConsumer(t, sc, layer); return takeScreenshot(t, sc, sc /* parentSc */, crop, layer); } /** * Takes a screenshot of the specified SurfaceControl. * * @param t the transaction used to set changes on the resulting screenshot. * @param sc the SurfaceControl to take a screenshot of * @param parentSc the SurfaceControl to attach the screenshot to. * @param crop the crop to use when capturing the screenshot * @param layer the layer to place the screenshot * * @return A SurfaceControl where the screenshot will be attached, or null if failed. */ public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc, SurfaceControl parentSc, Rect crop, int layer) { BufferConsumer consumer = new BufferConsumer(t, sc, parentSc, layer); captureLayer(sc, crop, consumer); return consumer.mScreenshot; } Loading services/core/java/com/android/server/wm/ActivityRecord.java +11 −2 Original line number Diff line number Diff line Loading @@ -1522,9 +1522,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A this.task = newTask; if (shouldStartChangeTransition(newParent, oldParent)) { // Animate change transition on TaskFragment level to get the correct window crop. if (mTransitionController.isShellTransitionsEnabled()) { // For Shell transition, call #initializeChangeTransition directly to take the // screenshot at the Activity level. And Shell will be in charge of handling the // surface reparent and crop. initializeChangeTransition(getBounds()); } else { // For legacy app transition, we want to take a screenshot of the Activity surface, // but animate the change transition on TaskFragment level to get the correct window // crop. newParent.initializeChangeTransition(getBounds(), getSurfaceControl()); } } super.onParentChanged(newParent, oldParent); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java +3 −1 Original line number Diff line number Diff line Loading @@ -170,9 +170,11 @@ class ActivityEmbeddingAnimationAdapter { void onAnimationEnd(@NonNull SurfaceControl.Transaction t) { super.onAnimationEnd(t); // Remove the screenshot leash after animation is finished. if (mLeash.isValid()) { t.remove(mLeash); } } } /** * Should be used for the animation of the {@link TransitionInfo.Change} that has size change. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +75 −32 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Rect; import android.os.IBinder; import android.util.ArraySet; import android.util.Log; import android.view.SurfaceControl; import android.view.animation.Animation; Loading @@ -39,6 +40,7 @@ import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.function.BiFunction; /** To run the ActivityEmbedding animations. */ Loading Loading @@ -214,25 +216,47 @@ class ActivityEmbeddingAnimationRunner { private List<ActivityEmbeddingAnimationAdapter> createChangeAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) { final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>(); final Set<TransitionInfo.Change> handledChanges = new ArraySet<>(); // For the first iteration, we prepare the animation for the change type windows. This is // needed because there may be window that is reparented while resizing. In such case, we // will do the following: // 1. Capture a screenshot from the Activity surface. // 2. Attach the screenshot surface to the top of TaskFragment (Activity's parent) surface. // 3. Animate the TaskFragment using Activity Change info (start/end bounds). // This is because the TaskFragment surface/change won't contain the Activity's before its // reparent. for (TransitionInfo.Change change : info.getChanges()) { if (change.getMode() == TRANSIT_CHANGE && !change.getStartAbsBounds().equals(change.getEndAbsBounds())) { if (change.getMode() != TRANSIT_CHANGE || change.getStartAbsBounds().equals(change.getEndAbsBounds())) { continue; } // This is the window with bounds change. handledChanges.add(change); final WindowContainerToken parentToken = change.getParent(); final Rect parentBounds; TransitionInfo.Change boundsAnimationChange = change; if (parentToken != null) { TransitionInfo.Change parentChange = info.getChange(parentToken); parentBounds = parentChange != null ? parentChange.getEndAbsBounds() : change.getEndAbsBounds(); } else { parentBounds = change.getEndAbsBounds(); // When the parent window is also included in the transition as an opening window, // we would like to animate the parent window instead. final TransitionInfo.Change parentChange = info.getChange(parentToken); if (parentChange != null && Transitions.isOpeningType(parentChange.getMode())) { // We won't create a separate animation for the parent, but to animate the // parent for the child resizing. handledChanges.add(parentChange); boundsAnimationChange = parentChange; } final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change, parentBounds); // Adapter for the starting screenshot leash. final SurfaceControl screenshotLeash = createScreenshot(change, startTransaction); } final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change, boundsAnimationChange.getEndAbsBounds()); // Create a screenshot based on change, but attach it to the top of the // boundsAnimationChange. final SurfaceControl screenshotLeash = getOrCreateScreenshot(change, boundsAnimationChange, startTransaction); if (screenshotLeash != null) { // Adapter for the starting screenshot leash. // The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter( animations[0], change, screenshotLeash)); Loading @@ -241,11 +265,16 @@ class ActivityEmbeddingAnimationRunner { } // Adapter for the ending bounds changed leash. adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter( animations[1], change)); animations[1], boundsAnimationChange)); } // Handle the other windows that don't have bounds change in the same transition. for (TransitionInfo.Change change : info.getChanges()) { if (handledChanges.contains(change)) { // Skip windows that we have already handled in the previous iteration. continue; } // These are the other windows that don't have bounds change in the same transition. final Animation animation; if (!TransitionInfo.isIndependent(change, info)) { // No-op if it will be covered by the changing parent window. Loading @@ -260,13 +289,27 @@ class ActivityEmbeddingAnimationRunner { return adapters; } /** Takes a screenshot of the given {@link TransitionInfo.Change} surface. */ /** * Takes a screenshot of the given {@code screenshotChange} surface if WM Core hasn't taken one. * The screenshot leash should be attached to the {@code animationChange} surface which we will * animate later. */ @Nullable private SurfaceControl createScreenshot(@NonNull TransitionInfo.Change change, @NonNull SurfaceControl.Transaction startTransaction) { final Rect cropBounds = new Rect(change.getStartAbsBounds()); private SurfaceControl getOrCreateScreenshot(@NonNull TransitionInfo.Change screenshotChange, @NonNull TransitionInfo.Change animationChange, @NonNull SurfaceControl.Transaction t) { final SurfaceControl screenshotLeash = screenshotChange.getSnapshot(); if (screenshotLeash != null) { // If WM Core has already taken a screenshot, make sure it is reparented to the // animation leash. t.reparent(screenshotLeash, animationChange.getLeash()); return screenshotLeash; } // If WM Core hasn't taken a screenshot, take a screenshot now. final Rect cropBounds = new Rect(screenshotChange.getStartAbsBounds()); cropBounds.offsetTo(0, 0); return ScreenshotUtils.takeScreenshot(startTransaction, change.getLeash(), cropBounds, Integer.MAX_VALUE); return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(), animationChange.getLeash(), cropBounds, Integer.MAX_VALUE); } }
libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java +24 −5 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ import java.util.function.Consumer; public class ScreenshotUtils { /** * Take a screenshot of the specified SurfaceControl. * Takes a screenshot of the specified SurfaceControl. * * @param sc the SurfaceControl to take a screenshot of * @param crop the crop to use when capturing the screenshot Loading @@ -49,11 +49,14 @@ public class ScreenshotUtils { SurfaceControl mScreenshot = null; SurfaceControl.Transaction mTransaction; SurfaceControl mSurfaceControl; SurfaceControl mParentSurfaceControl; int mLayer; BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, int layer) { BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, SurfaceControl parentSc, int layer) { mTransaction = t; mSurfaceControl = sc; mParentSurfaceControl = parentSc; mLayer = layer; } Loading @@ -72,7 +75,7 @@ public class ScreenshotUtils { mTransaction.setBuffer(mScreenshot, buffer.getHardwareBuffer()); mTransaction.setColorSpace(mScreenshot, buffer.getColorSpace()); mTransaction.reparent(mScreenshot, mSurfaceControl); mTransaction.reparent(mScreenshot, mParentSurfaceControl); mTransaction.setLayer(mScreenshot, mLayer); mTransaction.show(mScreenshot); mTransaction.apply(); Loading @@ -80,7 +83,7 @@ public class ScreenshotUtils { } /** * Take a screenshot of the specified SurfaceControl. * Takes a screenshot of the specified SurfaceControl. * * @param t the transaction used to set changes on the resulting screenshot. * @param sc the SurfaceControl to take a screenshot of Loading @@ -91,7 +94,23 @@ public class ScreenshotUtils { */ public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc, Rect crop, int layer) { BufferConsumer consumer = new BufferConsumer(t, sc, layer); return takeScreenshot(t, sc, sc /* parentSc */, crop, layer); } /** * Takes a screenshot of the specified SurfaceControl. * * @param t the transaction used to set changes on the resulting screenshot. * @param sc the SurfaceControl to take a screenshot of * @param parentSc the SurfaceControl to attach the screenshot to. * @param crop the crop to use when capturing the screenshot * @param layer the layer to place the screenshot * * @return A SurfaceControl where the screenshot will be attached, or null if failed. */ public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc, SurfaceControl parentSc, Rect crop, int layer) { BufferConsumer consumer = new BufferConsumer(t, sc, parentSc, layer); captureLayer(sc, crop, consumer); return consumer.mScreenshot; } Loading
services/core/java/com/android/server/wm/ActivityRecord.java +11 −2 Original line number Diff line number Diff line Loading @@ -1522,9 +1522,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A this.task = newTask; if (shouldStartChangeTransition(newParent, oldParent)) { // Animate change transition on TaskFragment level to get the correct window crop. if (mTransitionController.isShellTransitionsEnabled()) { // For Shell transition, call #initializeChangeTransition directly to take the // screenshot at the Activity level. And Shell will be in charge of handling the // surface reparent and crop. initializeChangeTransition(getBounds()); } else { // For legacy app transition, we want to take a screenshot of the Activity surface, // but animate the change transition on TaskFragment level to get the correct window // crop. newParent.initializeChangeTransition(getBounds(), getSurfaceControl()); } } super.onParentChanged(newParent, oldParent); Loading