Add edge extension for ActivityEmbedding Shell transition animation
Refactor the edge extension logic from DefaultTransitionHandler to the helper class so that we can reuse it for ActivityEmbedding. Bug: 207070762 Test: manually verify with Settings. Change-Id: I6a89b549e7b117caae75ceba6df8f41f5c4d4a15
This commit is contained in:
@@ -130,6 +130,10 @@ class ActivityEmbeddingAnimationAdapter {
|
|||||||
if (!cropRect.intersect(mWholeAnimationBounds)) {
|
if (!cropRect.intersect(mWholeAnimationBounds)) {
|
||||||
// Hide the surface when it is outside of the animation area.
|
// Hide the surface when it is outside of the animation area.
|
||||||
t.setAlpha(mLeash, 0);
|
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.
|
// cropRect is in absolute coordinate, so we need to translate it to surface top left.
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
|
|||||||
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
|
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.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.getTransitionBackgroundColorIfSet;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
@@ -45,6 +46,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.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/** To run the ActivityEmbedding animations. */
|
/** To run the ActivityEmbedding animations. */
|
||||||
class ActivityEmbeddingAnimationRunner {
|
class ActivityEmbeddingAnimationRunner {
|
||||||
@@ -65,11 +67,32 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
void startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
|
void startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
|
||||||
@NonNull SurfaceControl.Transaction startTransaction,
|
@NonNull SurfaceControl.Transaction startTransaction,
|
||||||
@NonNull SurfaceControl.Transaction finishTransaction) {
|
@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,
|
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();
|
startTransaction.apply();
|
||||||
animator.start();
|
animator.start();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets transition animation scale settings value.
|
* Sets transition animation scale settings value.
|
||||||
@@ -85,9 +108,13 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
Animator createAnimator(@NonNull TransitionInfo info,
|
Animator createAnimator(@NonNull TransitionInfo info,
|
||||||
@NonNull SurfaceControl.Transaction startTransaction,
|
@NonNull SurfaceControl.Transaction startTransaction,
|
||||||
@NonNull SurfaceControl.Transaction finishTransaction,
|
@NonNull SurfaceControl.Transaction finishTransaction,
|
||||||
@NonNull Runnable animationFinishCallback) {
|
@NonNull Runnable animationFinishCallback,
|
||||||
final List<ActivityEmbeddingAnimationAdapter> adapters =
|
@NonNull List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks) {
|
||||||
createAnimationAdapters(info, startTransaction, finishTransaction);
|
final List<ActivityEmbeddingAnimationAdapter> adapters = createAnimationAdapters(info,
|
||||||
|
startTransaction);
|
||||||
|
addEdgeExtensionIfNeeded(startTransaction, finishTransaction, postStartTransactionCallbacks,
|
||||||
|
adapters);
|
||||||
|
addBackgroundColorIfNeeded(info, startTransaction, finishTransaction, adapters);
|
||||||
long duration = 0;
|
long duration = 0;
|
||||||
for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
|
for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
|
||||||
duration = Math.max(duration, adapter.getDurationHint());
|
duration = Math.max(duration, adapter.getDurationHint());
|
||||||
@@ -131,8 +158,7 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters(
|
private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters(
|
||||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
|
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
|
||||||
@NonNull SurfaceControl.Transaction finishTransaction) {
|
|
||||||
boolean isChangeTransition = false;
|
boolean isChangeTransition = false;
|
||||||
for (TransitionInfo.Change change : info.getChanges()) {
|
for (TransitionInfo.Change change : info.getChanges()) {
|
||||||
if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) {
|
if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) {
|
||||||
@@ -148,25 +174,23 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
return createChangeAnimationAdapters(info, startTransaction);
|
return createChangeAnimationAdapters(info, startTransaction);
|
||||||
}
|
}
|
||||||
if (Transitions.isClosingType(info.getType())) {
|
if (Transitions.isClosingType(info.getType())) {
|
||||||
return createCloseAnimationAdapters(info, startTransaction, finishTransaction);
|
return createCloseAnimationAdapters(info);
|
||||||
}
|
}
|
||||||
return createOpenAnimationAdapters(info, startTransaction, finishTransaction);
|
return createOpenAnimationAdapters(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters(
|
private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters(
|
||||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
|
@NonNull TransitionInfo info) {
|
||||||
@NonNull SurfaceControl.Transaction finishTransaction) {
|
return createOpenCloseAnimationAdapters(info, true /* isOpening */,
|
||||||
return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
|
mAnimationSpec::loadOpenAnimation);
|
||||||
true /* isOpening */, mAnimationSpec::loadOpenAnimation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters(
|
private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters(
|
||||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
|
@NonNull TransitionInfo info) {
|
||||||
@NonNull SurfaceControl.Transaction finishTransaction) {
|
return createOpenCloseAnimationAdapters(info, false /* isOpening */,
|
||||||
return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
|
mAnimationSpec::loadCloseAnimation);
|
||||||
false /* isOpening */, mAnimationSpec::loadCloseAnimation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,8 +199,7 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters(
|
private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters(
|
||||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
|
@NonNull TransitionInfo info, boolean isOpening,
|
||||||
@NonNull SurfaceControl.Transaction finishTransaction, boolean isOpening,
|
|
||||||
@NonNull AnimationProvider animationProvider) {
|
@NonNull AnimationProvider animationProvider) {
|
||||||
// We need to know if the change window is only a partial of the whole animation screen.
|
// 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.
|
// If so, we will need to adjust it to make the whole animation screen looks like one.
|
||||||
@@ -200,8 +223,7 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
|
final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
|
||||||
for (TransitionInfo.Change change : openingChanges) {
|
for (TransitionInfo.Change change : openingChanges) {
|
||||||
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
|
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
|
||||||
info, change, startTransaction, finishTransaction, animationProvider,
|
info, change, animationProvider, openingWholeScreenBounds);
|
||||||
openingWholeScreenBounds);
|
|
||||||
if (isOpening) {
|
if (isOpening) {
|
||||||
adapter.overrideLayer(offsetLayer++);
|
adapter.overrideLayer(offsetLayer++);
|
||||||
}
|
}
|
||||||
@@ -209,8 +231,7 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
}
|
}
|
||||||
for (TransitionInfo.Change change : closingChanges) {
|
for (TransitionInfo.Change change : closingChanges) {
|
||||||
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
|
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
|
||||||
info, change, startTransaction, finishTransaction, animationProvider,
|
info, change, animationProvider, closingWholeScreenBounds);
|
||||||
closingWholeScreenBounds);
|
|
||||||
if (!isOpening) {
|
if (!isOpening) {
|
||||||
adapter.overrideLayer(offsetLayer++);
|
adapter.overrideLayer(offsetLayer++);
|
||||||
}
|
}
|
||||||
@@ -219,20 +240,51 @@ class ActivityEmbeddingAnimationRunner {
|
|||||||
return adapters;
|
return adapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 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 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
|
@NonNull
|
||||||
private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter(
|
private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter(
|
||||||
@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
|
@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
|
||||||
@NonNull SurfaceControl.Transaction startTransaction,
|
|
||||||
@NonNull SurfaceControl.Transaction finishTransaction,
|
|
||||||
@NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) {
|
@NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) {
|
||||||
final Animation animation = animationProvider.get(info, change, 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 */);
|
|
||||||
if (backgroundColor != 0) {
|
|
||||||
addBackgroundToTransition(info.getRootLeash(), backgroundColor, startTransaction,
|
|
||||||
finishTransaction);
|
|
||||||
}
|
|
||||||
return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
|
return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
|
||||||
wholeAnimationBounds);
|
wholeAnimationBounds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,15 +181,15 @@ class ActivityEmbeddingAnimationSpec {
|
|||||||
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
|
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
|
||||||
final boolean isEnter = Transitions.isOpeningType(change.getMode());
|
final boolean isEnter = Transitions.isOpeningType(change.getMode());
|
||||||
final Animation animation;
|
final Animation animation;
|
||||||
// TODO(b/207070762): Implement edgeExtension version
|
|
||||||
if (shouldShowBackdrop(info, change)) {
|
if (shouldShowBackdrop(info, change)) {
|
||||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
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_enter
|
||||||
: com.android.internal.R.anim.task_fragment_clear_top_open_exit);
|
: com.android.internal.R.anim.task_fragment_clear_top_open_exit);
|
||||||
} else {
|
} else {
|
||||||
|
// Use the same edge extension animation as regular activity open.
|
||||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
||||||
? com.android.internal.R.anim.task_fragment_open_enter
|
? com.android.internal.R.anim.activity_open_enter
|
||||||
: com.android.internal.R.anim.task_fragment_open_exit);
|
: com.android.internal.R.anim.activity_open_exit);
|
||||||
}
|
}
|
||||||
// Use the whole animation bounds instead of the change bounds, so that when multiple change
|
// 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.
|
// targets are opening at the same time, the animation applied to each will be the same.
|
||||||
@@ -205,15 +205,15 @@ class ActivityEmbeddingAnimationSpec {
|
|||||||
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
|
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
|
||||||
final boolean isEnter = Transitions.isOpeningType(change.getMode());
|
final boolean isEnter = Transitions.isOpeningType(change.getMode());
|
||||||
final Animation animation;
|
final Animation animation;
|
||||||
// TODO(b/207070762): Implement edgeExtension version
|
|
||||||
if (shouldShowBackdrop(info, change)) {
|
if (shouldShowBackdrop(info, change)) {
|
||||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
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_enter
|
||||||
: com.android.internal.R.anim.task_fragment_clear_top_close_exit);
|
: com.android.internal.R.anim.task_fragment_clear_top_close_exit);
|
||||||
} else {
|
} else {
|
||||||
|
// Use the same edge extension animation as regular activity close.
|
||||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
||||||
? com.android.internal.R.anim.task_fragment_close_enter
|
? com.android.internal.R.anim.activity_close_enter
|
||||||
: com.android.internal.R.anim.task_fragment_close_exit);
|
: com.android.internal.R.anim.activity_close_exit);
|
||||||
}
|
}
|
||||||
// Use the whole animation bounds instead of the change bounds, so that when multiple change
|
// 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.
|
// targets are closing at the same time, the animation applied to each will be the same.
|
||||||
|
|||||||
@@ -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_NONE;
|
||||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
|
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.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.getTransitionBackgroundColorIfSet;
|
||||||
import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
|
import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
|
||||||
import static com.android.wm.shell.transition.TransitionAnimationHelper.sDisableCustomTaskAnimationProperty;
|
import static com.android.wm.shell.transition.TransitionAnimationHelper.sDisableCustomTaskAnimationProperty;
|
||||||
@@ -76,10 +77,7 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Insets;
|
import android.graphics.Insets;
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.PixelFormat;
|
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -89,7 +87,6 @@ import android.os.IBinder;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.view.Choreographer;
|
import android.view.Choreographer;
|
||||||
import android.view.Surface;
|
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.SurfaceSession;
|
import android.view.SurfaceSession;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
@@ -97,7 +94,6 @@ import android.view.WindowManager.TransitionType;
|
|||||||
import android.view.animation.AlphaAnimation;
|
import android.view.animation.AlphaAnimation;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.Transformation;
|
import android.view.animation.Transformation;
|
||||||
import android.window.ScreenCapture;
|
|
||||||
import android.window.TransitionInfo;
|
import android.window.TransitionInfo;
|
||||||
import android.window.TransitionMetrics;
|
import android.window.TransitionMetrics;
|
||||||
import android.window.TransitionRequestInfo;
|
import android.window.TransitionRequestInfo;
|
||||||
@@ -526,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();
|
|
||||||
|
|
||||||
ScreenCapture.LayerCaptureArgs captureArgs =
|
|
||||||
new ScreenCapture.LayerCaptureArgs.Builder(surfaceToExtend)
|
|
||||||
.setSourceCrop(edgeBounds)
|
|
||||||
.setFrameScale(1)
|
|
||||||
.setPixelFormat(PixelFormat.RGBA_8888)
|
|
||||||
.setChildrenOnly(true)
|
|
||||||
.setAllowProtected(true)
|
|
||||||
.build();
|
|
||||||
final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
|
|
||||||
ScreenCapture.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
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
|
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
|
|||||||
import static android.view.WindowManager.TRANSIT_TO_BACK;
|
import static android.view.WindowManager.TRANSIT_TO_BACK;
|
||||||
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
||||||
import static android.view.WindowManager.transitTypeToString;
|
import static android.view.WindowManager.transitTypeToString;
|
||||||
|
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
|
||||||
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
|
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
|
||||||
|
|
||||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE;
|
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE;
|
||||||
@@ -34,10 +35,20 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI
|
|||||||
import android.annotation.ColorInt;
|
import android.annotation.ColorInt;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.graphics.BitmapShader;
|
||||||
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Insets;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.Shader;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
|
import android.view.Surface;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.Transformation;
|
||||||
|
import android.window.ScreenCapture;
|
||||||
import android.window.TransitionInfo;
|
import android.window.TransitionInfo;
|
||||||
|
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
@@ -217,4 +228,126 @@ public class TransitionAnimationHelper {
|
|||||||
.show(animationBackgroundSurface);
|
.show(animationBackgroundSurface);
|
||||||
finishTransaction.remove(animationBackgroundSurface);
|
finishTransaction.remove(animationBackgroundSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds edge extension surface to the given {@code change} for edge extension animation.
|
||||||
|
*/
|
||||||
|
public static void edgeExtendWindow(@NonNull TransitionInfo.Change change,
|
||||||
|
@NonNull Animation a, @NonNull SurfaceControl.Transaction startTransaction,
|
||||||
|
@NonNull 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a screenshot of {@code surfaceToExtend}'s edge and extends it for edge extension
|
||||||
|
* animation.
|
||||||
|
*/
|
||||||
|
private static SurfaceControl createExtensionSurface(@NonNull SurfaceControl surfaceToExtend,
|
||||||
|
@NonNull Rect edgeBounds, @NonNull Rect extensionRect, int xPos, int yPos,
|
||||||
|
@NonNull String layerName, @NonNull SurfaceControl.Transaction startTransaction,
|
||||||
|
@NonNull SurfaceControl.Transaction finishTransaction) {
|
||||||
|
final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
|
||||||
|
.setName(layerName)
|
||||||
|
.setParent(surfaceToExtend)
|
||||||
|
.setHidden(true)
|
||||||
|
.setCallsite("TransitionAnimationHelper#createExtensionSurface")
|
||||||
|
.setOpaque(true)
|
||||||
|
.setBufferSize(extensionRect.width(), extensionRect.height())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final ScreenCapture.LayerCaptureArgs captureArgs =
|
||||||
|
new ScreenCapture.LayerCaptureArgs.Builder(surfaceToExtend)
|
||||||
|
.setSourceCrop(edgeBounds)
|
||||||
|
.setFrameScale(1)
|
||||||
|
.setPixelFormat(PixelFormat.RGBA_8888)
|
||||||
|
.setChildrenOnly(true)
|
||||||
|
.setAllowProtected(true)
|
||||||
|
.build();
|
||||||
|
final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
|
||||||
|
ScreenCapture.captureLayers(captureArgs);
|
||||||
|
|
||||||
|
if (edgeBuffer == null) {
|
||||||
|
ProtoLog.e(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
|
||||||
|
"Failed to capture edge of window.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final BitmapShader shader = new BitmapShader(edgeBuffer.asBitmap(),
|
||||||
|
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
||||||
|
final Paint paint = new Paint();
|
||||||
|
paint.setShader(shader);
|
||||||
|
|
||||||
|
final Surface surface = new Surface(edgeExtensionLayer);
|
||||||
|
final 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ActivityEmbeddingAnimationRunner}.
|
* Tests for {@link ActivityEmbeddingAnimationRunner}.
|
||||||
*
|
*
|
||||||
@@ -62,13 +64,13 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim
|
|||||||
final TransitionInfo.Change embeddingChange = createChange();
|
final TransitionInfo.Change embeddingChange = createChange();
|
||||||
embeddingChange.setFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
|
embeddingChange.setFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
|
||||||
info.addChange(embeddingChange);
|
info.addChange(embeddingChange);
|
||||||
doReturn(mAnimator).when(mAnimRunner).createAnimator(any(), any(), any(), any());
|
doReturn(mAnimator).when(mAnimRunner).createAnimator(any(), any(), any(), any(), any());
|
||||||
|
|
||||||
mAnimRunner.startAnimation(mTransition, info, mStartTransaction, mFinishTransaction);
|
mAnimRunner.startAnimation(mTransition, info, mStartTransaction, mFinishTransaction);
|
||||||
|
|
||||||
final ArgumentCaptor<Runnable> finishCallback = ArgumentCaptor.forClass(Runnable.class);
|
final ArgumentCaptor<Runnable> finishCallback = ArgumentCaptor.forClass(Runnable.class);
|
||||||
verify(mAnimRunner).createAnimator(eq(info), eq(mStartTransaction), eq(mFinishTransaction),
|
verify(mAnimRunner).createAnimator(eq(info), eq(mStartTransaction), eq(mFinishTransaction),
|
||||||
finishCallback.capture());
|
finishCallback.capture(), any());
|
||||||
verify(mStartTransaction).apply();
|
verify(mStartTransaction).apply();
|
||||||
verify(mAnimator).start();
|
verify(mAnimator).start();
|
||||||
verifyNoMoreInteractions(mFinishTransaction);
|
verifyNoMoreInteractions(mFinishTransaction);
|
||||||
@@ -88,7 +90,8 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim
|
|||||||
info.addChange(embeddingChange);
|
info.addChange(embeddingChange);
|
||||||
final Animator animator = mAnimRunner.createAnimator(
|
final Animator animator = mAnimRunner.createAnimator(
|
||||||
info, mStartTransaction, mFinishTransaction,
|
info, mStartTransaction, mFinishTransaction,
|
||||||
() -> mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */));
|
() -> mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */),
|
||||||
|
new ArrayList());
|
||||||
|
|
||||||
// The animation should be empty when it is behind starting window.
|
// The animation should be empty when it is behind starting window.
|
||||||
assertEquals(0, animator.getDuration());
|
assertEquals(0, animator.getDuration());
|
||||||
|
|||||||
@@ -56,13 +56,12 @@ abstract class ActivityEmbeddingAnimationTestBase extends ShellTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
SurfaceControl.Transaction mFinishTransaction;
|
SurfaceControl.Transaction mFinishTransaction;
|
||||||
@Mock
|
@Mock
|
||||||
Transitions.TransitionFinishCallback mFinishCallback;
|
|
||||||
@Mock
|
|
||||||
Animator mAnimator;
|
Animator mAnimator;
|
||||||
|
|
||||||
ActivityEmbeddingController mController;
|
ActivityEmbeddingController mController;
|
||||||
ActivityEmbeddingAnimationRunner mAnimRunner;
|
ActivityEmbeddingAnimationRunner mAnimRunner;
|
||||||
ActivityEmbeddingAnimationSpec mAnimSpec;
|
ActivityEmbeddingAnimationSpec mAnimSpec;
|
||||||
|
Transitions.TransitionFinishCallback mFinishCallback;
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@Before
|
@Before
|
||||||
@@ -75,9 +74,11 @@ abstract class ActivityEmbeddingAnimationTestBase extends ShellTestCase {
|
|||||||
assertNotNull(mAnimRunner);
|
assertNotNull(mAnimRunner);
|
||||||
mAnimSpec = mAnimRunner.mAnimationSpec;
|
mAnimSpec = mAnimRunner.mAnimationSpec;
|
||||||
assertNotNull(mAnimSpec);
|
assertNotNull(mAnimSpec);
|
||||||
|
mFinishCallback = (wct, wctCB) -> {};
|
||||||
spyOn(mController);
|
spyOn(mController);
|
||||||
spyOn(mAnimRunner);
|
spyOn(mAnimRunner);
|
||||||
spyOn(mAnimSpec);
|
spyOn(mAnimSpec);
|
||||||
|
spyOn(mFinishCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a mock {@link TransitionInfo.Change}. */
|
/** Creates a mock {@link TransitionInfo.Change}. */
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
|
|||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
doReturn(mAnimator).when(mAnimRunner).createAnimator(any(), any(), any(), any());
|
doReturn(mAnimator).when(mAnimRunner).createAnimator(any(), any(), any(), any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user