Merge "Fix ActivityEmbedding Shell transition animation with reparent" into tm-qpr-dev
This commit is contained in:
@@ -170,7 +170,9 @@ class ActivityEmbeddingAnimationAdapter {
|
|||||||
void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
|
void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
|
||||||
super.onAnimationEnd(t);
|
super.onAnimationEnd(t);
|
||||||
// Remove the screenshot leash after animation is finished.
|
// Remove the screenshot leash after animation is finished.
|
||||||
t.remove(mLeash);
|
if (mLeash.isValid()) {
|
||||||
|
t.remove(mLeash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.animation.ValueAnimator;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
@@ -39,6 +40,7 @@ import com.android.wm.shell.transition.Transitions;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
/** To run the ActivityEmbedding animations. */
|
/** To run the ActivityEmbedding animations. */
|
||||||
@@ -214,38 +216,65 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
private List<ActivityEmbeddingAnimationAdapter> createChangeAnimationAdapters(
|
private List<ActivityEmbeddingAnimationAdapter> createChangeAnimationAdapters(
|
||||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
|
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
|
||||||
final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
|
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()) {
|
for (TransitionInfo.Change change : info.getChanges()) {
|
||||||
if (change.getMode() == TRANSIT_CHANGE
|
if (change.getMode() != TRANSIT_CHANGE
|
||||||
&& !change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
|
|| change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
|
||||||
// This is the window with bounds change.
|
continue;
|
||||||
final WindowContainerToken parentToken = change.getParent();
|
}
|
||||||
final Rect parentBounds;
|
|
||||||
if (parentToken != null) {
|
// This is the window with bounds change.
|
||||||
TransitionInfo.Change parentChange = info.getChange(parentToken);
|
handledChanges.add(change);
|
||||||
parentBounds = parentChange != null
|
final WindowContainerToken parentToken = change.getParent();
|
||||||
? parentChange.getEndAbsBounds()
|
TransitionInfo.Change boundsAnimationChange = change;
|
||||||
: change.getEndAbsBounds();
|
if (parentToken != null) {
|
||||||
} else {
|
// When the parent window is also included in the transition as an opening window,
|
||||||
parentBounds = change.getEndAbsBounds();
|
// we would like to animate the parent window instead.
|
||||||
}
|
final TransitionInfo.Change parentChange = info.getChange(parentToken);
|
||||||
final Animation[] animations =
|
if (parentChange != null && Transitions.isOpeningType(parentChange.getMode())) {
|
||||||
mAnimationSpec.createChangeBoundsChangeAnimations(change, parentBounds);
|
// We won't create a separate animation for the parent, but to animate the
|
||||||
// Adapter for the starting screenshot leash.
|
// parent for the child resizing.
|
||||||
final SurfaceControl screenshotLeash = createScreenshot(change, startTransaction);
|
handledChanges.add(parentChange);
|
||||||
if (screenshotLeash != null) {
|
boundsAnimationChange = parentChange;
|
||||||
// The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd
|
}
|
||||||
adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter(
|
}
|
||||||
animations[0], change, screenshotLeash));
|
|
||||||
} else {
|
final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change,
|
||||||
Log.e(TAG, "Failed to take screenshot for change=" + change);
|
boundsAnimationChange.getEndAbsBounds());
|
||||||
}
|
|
||||||
// Adapter for the ending bounds changed leash.
|
// Create a screenshot based on change, but attach it to the top of the
|
||||||
adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter(
|
// boundsAnimationChange.
|
||||||
animations[1], change));
|
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));
|
||||||
|
} 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are the other windows that don't have bounds change in the same transition.
|
|
||||||
final Animation animation;
|
final Animation animation;
|
||||||
if (!TransitionInfo.isIndependent(change, info)) {
|
if (!TransitionInfo.isIndependent(change, info)) {
|
||||||
// No-op if it will be covered by the changing parent window.
|
// No-op if it will be covered by the changing parent window.
|
||||||
@@ -260,13 +289,27 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
return adapters;
|
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
|
@Nullable
|
||||||
private SurfaceControl createScreenshot(@NonNull TransitionInfo.Change change,
|
private SurfaceControl getOrCreateScreenshot(@NonNull TransitionInfo.Change screenshotChange,
|
||||||
@NonNull SurfaceControl.Transaction startTransaction) {
|
@NonNull TransitionInfo.Change animationChange,
|
||||||
final Rect cropBounds = new Rect(change.getStartAbsBounds());
|
@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);
|
cropBounds.offsetTo(0, 0);
|
||||||
return ScreenshotUtils.takeScreenshot(startTransaction, change.getLeash(), cropBounds,
|
return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(),
|
||||||
Integer.MAX_VALUE);
|
animationChange.getLeash(), cropBounds, Integer.MAX_VALUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import java.util.function.Consumer;
|
|||||||
public class ScreenshotUtils {
|
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 sc the SurfaceControl to take a screenshot of
|
||||||
* @param crop the crop to use when capturing the screenshot
|
* @param crop the crop to use when capturing the screenshot
|
||||||
@@ -49,11 +49,14 @@ public class ScreenshotUtils {
|
|||||||
SurfaceControl mScreenshot = null;
|
SurfaceControl mScreenshot = null;
|
||||||
SurfaceControl.Transaction mTransaction;
|
SurfaceControl.Transaction mTransaction;
|
||||||
SurfaceControl mSurfaceControl;
|
SurfaceControl mSurfaceControl;
|
||||||
|
SurfaceControl mParentSurfaceControl;
|
||||||
int mLayer;
|
int mLayer;
|
||||||
|
|
||||||
BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, int layer) {
|
BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, SurfaceControl parentSc,
|
||||||
|
int layer) {
|
||||||
mTransaction = t;
|
mTransaction = t;
|
||||||
mSurfaceControl = sc;
|
mSurfaceControl = sc;
|
||||||
|
mParentSurfaceControl = parentSc;
|
||||||
mLayer = layer;
|
mLayer = layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +75,7 @@ public class ScreenshotUtils {
|
|||||||
|
|
||||||
mTransaction.setBuffer(mScreenshot, buffer.getHardwareBuffer());
|
mTransaction.setBuffer(mScreenshot, buffer.getHardwareBuffer());
|
||||||
mTransaction.setColorSpace(mScreenshot, buffer.getColorSpace());
|
mTransaction.setColorSpace(mScreenshot, buffer.getColorSpace());
|
||||||
mTransaction.reparent(mScreenshot, mSurfaceControl);
|
mTransaction.reparent(mScreenshot, mParentSurfaceControl);
|
||||||
mTransaction.setLayer(mScreenshot, mLayer);
|
mTransaction.setLayer(mScreenshot, mLayer);
|
||||||
mTransaction.show(mScreenshot);
|
mTransaction.show(mScreenshot);
|
||||||
mTransaction.apply();
|
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 t the transaction used to set changes on the resulting screenshot.
|
||||||
* @param sc the SurfaceControl to take a screenshot of
|
* @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,
|
public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc,
|
||||||
Rect crop, int layer) {
|
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);
|
captureLayer(sc, crop, consumer);
|
||||||
return consumer.mScreenshot;
|
return consumer.mScreenshot;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1522,8 +1522,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
this.task = newTask;
|
this.task = newTask;
|
||||||
|
|
||||||
if (shouldStartChangeTransition(newParent, oldParent)) {
|
if (shouldStartChangeTransition(newParent, oldParent)) {
|
||||||
// Animate change transition on TaskFragment level to get the correct window crop.
|
if (mTransitionController.isShellTransitionsEnabled()) {
|
||||||
newParent.initializeChangeTransition(getBounds(), getSurfaceControl());
|
// 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);
|
super.onParentChanged(newParent, oldParent);
|
||||||
|
|||||||
Reference in New Issue
Block a user