summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java107
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java29
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java13
4 files changed, 113 insertions, 40 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 064c304825da..591e3476ecd9 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
@@ -170,7 +170,9 @@ class ActivityEmbeddingAnimationAdapter {
void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
super.onAnimationEnd(t);
// Remove the screenshot leash after animation is finished.
- t.remove(mLeash);
+ if (mLeash.isValid()) {
+ t.remove(mLeash);
+ }
}
}
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 846d2c9b3396..d88cc007c7b5 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
@@ -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;
@@ -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. */
@@ -214,38 +216,65 @@ 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())) {
- // This is the window with bounds change.
- final WindowContainerToken parentToken = change.getParent();
- final Rect parentBounds;
- if (parentToken != null) {
- TransitionInfo.Change parentChange = info.getChange(parentToken);
- parentBounds = parentChange != null
- ? parentChange.getEndAbsBounds()
- : change.getEndAbsBounds();
- } else {
- parentBounds = 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();
+ TransitionInfo.Change boundsAnimationChange = change;
+ if (parentToken != null) {
+ // 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);
+ }
+
+ 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.
- final SurfaceControl screenshotLeash = createScreenshot(change, startTransaction);
- if (screenshotLeash != null) {
- // The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd
- adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter(
- animations[0], change, screenshotLeash));
- } else {
- Log.e(TAG, "Failed to take screenshot for change=" + change);
- }
- // Adapter for the ending bounds changed leash.
- adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter(
- animations[1], change));
+ // The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd
+ adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter(
+ animations[0], change, screenshotLeash));
+ } else {
+ Log.e(TAG, "Failed to take screenshot for change=" + change);
+ }
+ // Adapter for the ending bounds changed leash.
+ adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter(
+ 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.
@@ -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);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
index c4bd73ba1b4a..2a1bf0ee42ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
@@ -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
@@ -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;
}
@@ -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();
@@ -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
@@ -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;
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6538ee3c2182..4c0a0171024a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1522,8 +1522,17 @@ 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.
- newParent.initializeChangeTransition(getBounds(), getSurfaceControl());
+ 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);