Merge "Implement the new PiP animation (fade-in)." into qt-dev

This commit is contained in:
Tracy Zhou
2019-04-09 21:06:28 +00:00
committed by Android (Google) Code Review
10 changed files with 254 additions and 77 deletions

View File

@@ -41,9 +41,11 @@ interface IRecentsAnimationController {
* with remote animation targets should be relinquished. If {@param moveHomeToTop} is true, then
* the home activity should be moved to the top. Otherwise, the home activity is hidden and the
* user is returned to the app.
* @param sendUserLeaveHint If set to true, {@link Activity#onUserLeaving} will be sent to the
* top resumed app, false otherwise.
*/
@UnsupportedAppUsage
void finish(boolean moveHomeToTop);
void finish(boolean moveHomeToTop, boolean sendUserLeaveHint);
/**
* Called by the handler to indicate that the recents animation input consumer should be

View File

@@ -77,9 +77,15 @@ public class RecentsAnimationControllerCompat {
}
}
public void finish(boolean toHome) {
/**
* Finish the current recents animation.
* @param toHome Going to home or back to the previous app.
* @param sendUserLeaveHint determines whether userLeaveHint will be set true to the previous
* app.
*/
public void finish(boolean toHome, boolean sendUserLeaveHint) {
try {
mAnimationController.finish(toHome);
mAnimationController.finish(toHome, sendUserLeaveHint);
} catch (RemoteException e) {
Log.e(TAG, "Failed to finish recents animation", e);
}

View File

@@ -73,6 +73,13 @@ public class BoundsAnimationController {
/** Schedule a PiP mode changed callback when this animation ends. */
public static final int SCHEDULE_PIP_MODE_CHANGED_ON_END = 2;
public static final int BOUNDS = 0;
public static final int FADE_IN = 1;
@IntDef({BOUNDS, FADE_IN}) public @interface AnimationType {}
private static final int FADE_IN_DURATION = 500;
// Only accessed on UI thread.
private ArrayMap<BoundsAnimationTarget, BoundsAnimator> mRunningAnimations = new ArrayMap<>();
@@ -115,6 +122,7 @@ public class BoundsAnimationController {
private boolean mFinishAnimationAfterTransition = false;
private final AnimationHandler mAnimationHandler;
private Choreographer mChoreographer;
private @AnimationType int mAnimationType;
private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
@@ -140,6 +148,7 @@ public class BoundsAnimationController {
implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
private final BoundsAnimationTarget mTarget;
private final @AnimationType int mAnimationType;
private final Rect mFrom = new Rect();
private final Rect mTo = new Rect();
private final Rect mTmpRect = new Rect();
@@ -166,8 +175,8 @@ public class BoundsAnimationController {
// Depending on whether we are animating from
// a smaller to a larger size
private final int mFrozenTaskWidth;
private final int mFrozenTaskHeight;
private int mFrozenTaskWidth;
private int mFrozenTaskHeight;
// Timeout callback to ensure we continue the animation if waiting for resuming or app
// windows drawn fails
@@ -176,12 +185,13 @@ public class BoundsAnimationController {
resume();
};
BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
@SchedulePipModeChangedState int schedulePipModeChangedState,
BoundsAnimator(BoundsAnimationTarget target, @AnimationType int animationType, Rect from,
Rect to, @SchedulePipModeChangedState int schedulePipModeChangedState,
@SchedulePipModeChangedState int prevShedulePipModeChangedState,
boolean moveFromFullscreen, boolean moveToFullscreen, Rect frozenTask) {
super();
mTarget = target;
mAnimationType = animationType;
mFrom.set(from);
mTo.set(to);
mSchedulePipModeChangedState = schedulePipModeChangedState;
@@ -195,12 +205,14 @@ public class BoundsAnimationController {
// to their final size immediately so we can use scaling to make the window
// larger. Likewise if we are going from bigger to smaller, we want to wait until
// the end so we don't have to upscale from the smaller finished size.
if (animatingToLargerSize()) {
mFrozenTaskWidth = mTo.width();
mFrozenTaskHeight = mTo.height();
} else {
mFrozenTaskWidth = frozenTask.isEmpty() ? mFrom.width() : frozenTask.width();
mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height();
if (mAnimationType == BOUNDS) {
if (animatingToLargerSize()) {
mFrozenTaskWidth = mTo.width();
mFrozenTaskHeight = mTo.height();
} else {
mFrozenTaskWidth = frozenTask.isEmpty() ? mFrom.width() : frozenTask.width();
mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height();
}
}
}
@@ -222,8 +234,9 @@ public class BoundsAnimationController {
// otherwise.
boolean continueAnimation;
if (mPrevSchedulePipModeChangedState == NO_PIP_MODE_CHANGED_CALLBACKS) {
continueAnimation = mTarget.onAnimationStart(mSchedulePipModeChangedState ==
SCHEDULE_PIP_MODE_CHANGED_ON_START, false /* forceUpdate */);
continueAnimation = mTarget.onAnimationStart(
mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START,
false /* forceUpdate */, mAnimationType);
// When starting an animation from fullscreen, pause here and wait for the
// windows-drawn signal before we start the rest of the transition down into PiP.
@@ -238,7 +251,8 @@ public class BoundsAnimationController {
// However, we still need to report to them that they are leaving PiP, so this will
// force an update via a mode changed callback.
continueAnimation = mTarget.onAnimationStart(
true /* schedulePipModeChangedCallback */, true /* forceUpdate */);
true /* schedulePipModeChangedCallback */, true /* forceUpdate */,
mAnimationType);
} else {
// The animation is already running, but we should check that the TaskStack is still
// valid before continuing with the animation
@@ -285,6 +299,13 @@ public class BoundsAnimationController {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final float value = (Float) animation.getAnimatedValue();
if (mAnimationType == FADE_IN) {
if (!mTarget.setPinnedStackAlpha(value)) {
cancelAndCallAnimationEnd();
}
return;
}
final float remains = 1 - value;
mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value + 0.5f);
mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value + 0.5f);
@@ -408,16 +429,29 @@ public class BoundsAnimationController {
public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to,
int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
boolean moveFromFullscreen, boolean moveToFullscreen) {
boolean moveFromFullscreen, boolean moveToFullscreen,
@AnimationType int animationType) {
animateBoundsImpl(target, from, to, animationDuration, schedulePipModeChangedState,
moveFromFullscreen, moveToFullscreen);
moveFromFullscreen, moveToFullscreen, animationType);
}
@VisibleForTesting
BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to,
int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
boolean moveFromFullscreen, boolean moveToFullscreen) {
boolean moveFromFullscreen, boolean moveToFullscreen,
@AnimationType int animationType) {
final BoundsAnimator existing = mRunningAnimations.get(target);
// animateBoundsImpl gets called twice for each animation. The second time we get the final
// to rect that respects the shelf, which is when we want to resize. Our signal for fade in
// comes in from how to enter into pip, but we also need to use the to and from rect to
// decide which animation we want to run finally.
boolean shouldResize = false;
if (isRunningFadeInAnimation(target)) {
shouldResize = true;
if (from.contains(to)) {
animationType = FADE_IN;
}
}
final boolean replacing = existing != null;
@SchedulePipModeChangedState int prevSchedulePipModeChangedState =
NO_PIP_MODE_CHANGED_CALLBACKS;
@@ -477,18 +511,34 @@ public class BoundsAnimationController {
// Since we are replacing, we skip both animation start and end callbacks
existing.cancel();
}
final BoundsAnimator animator = new BoundsAnimator(target, from, to,
if (shouldResize) {
target.setPinnedStackSize(to, null);
}
final BoundsAnimator animator = new BoundsAnimator(target, animationType, from, to,
schedulePipModeChangedState, prevSchedulePipModeChangedState,
moveFromFullscreen, moveToFullscreen, frozenTask);
mRunningAnimations.put(target, animator);
animator.setFloatValues(0f, 1f);
animator.setDuration((animationDuration != -1 ? animationDuration
: DEFAULT_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
animator.setDuration(animationType == FADE_IN ? FADE_IN_DURATION
: (animationDuration != -1 ? animationDuration : DEFAULT_TRANSITION_DURATION)
* DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
animator.setInterpolator(mFastOutSlowInInterpolator);
animator.start();
return animator;
}
public void setAnimationType(@AnimationType int animationType) {
mAnimationType = animationType;
}
/** return the current animation type. */
public @AnimationType int getAnimationType() {
@AnimationType int animationType = mAnimationType;
// Default to BOUNDS.
mAnimationType = BOUNDS;
return animationType;
}
public Handler getHandler() {
return mHandler;
}
@@ -498,6 +548,11 @@ public class BoundsAnimationController {
mHandler.post(this::resume);
}
private boolean isRunningFadeInAnimation(final BoundsAnimationTarget target) {
final BoundsAnimator existing = mRunningAnimations.get(target);
return existing != null && existing.mAnimationType == FADE_IN && existing.isStarted();
}
private void resume() {
for (int i = 0; i < mRunningAnimations.size(); i++) {
final BoundsAnimator b = mRunningAnimations.valueAt(i);

View File

@@ -32,7 +32,8 @@ interface BoundsAnimationTarget {
* callbacks
* @return whether to continue the animation
*/
boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate);
boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate,
@BoundsAnimationController.AnimationType int animationType);
/**
* @return Whether the animation should be paused waiting for the windows to draw before
@@ -53,6 +54,9 @@ interface BoundsAnimationTarget {
*/
boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds);
/** Sets the alpha of the animation target */
boolean setPinnedStackAlpha(float alpha);
/**
* Callback for the target to inform it that the animation has ended, so it can do some
* necessary cleanup.

View File

@@ -26,6 +26,8 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.WindowManager.TRANSIT_NONE;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.BoundsAnimationController.BOUNDS;
import static com.android.server.wm.BoundsAnimationController.FADE_IN;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
@@ -201,7 +203,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
}
}
private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode,
boolean sendUserLeaveHint) {
synchronized (mService.mGlobalLock) {
if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller="
+ mWindowManager.getRecentsAnimationController()
@@ -246,7 +249,18 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
if (reorderMode == REORDER_MOVE_TO_TOP) {
// Bring the target stack to the front
mStackSupervisor.mNoAnimActivities.add(targetActivity);
targetStack.moveToFront("RecentsAnimation.onAnimationFinished()");
if (sendUserLeaveHint) {
// Setting this allows the previous app to PiP.
mStackSupervisor.mUserLeaving = true;
targetStack.moveTaskToFrontLocked(targetActivity.getTaskRecord(),
true /* noAnimation */, null /* activityOptions */,
targetActivity.appTimeTracker,
"RecentsAnimation.onAnimationFinished()");
} else {
targetStack.moveToFront("RecentsAnimation.onAnimationFinished()");
}
if (DEBUG) {
final ActivityStack topStack = getTopNonAlwaysOnTopStack();
if (topStack != targetStack) {
@@ -300,11 +314,11 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
@Override
public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode,
boolean runSychronously) {
boolean runSychronously, boolean sendUserLeaveHint) {
if (runSychronously) {
finishAnimation(reorderMode);
finishAnimation(reorderMode, sendUserLeaveHint);
} else {
mService.mH.post(() -> finishAnimation(reorderMode));
mService.mH.post(() -> finishAnimation(reorderMode, sendUserLeaveHint));
}
}
@@ -317,6 +331,10 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
}
final RecentsAnimationController controller =
mWindowManager.getRecentsAnimationController();
final DisplayContent dc =
mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
dc.mBoundsAnimationController.setAnimationType(
controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS);
// Cancel running recents animation and screenshot previous task when the next
// transition starts in below cases:

View File

@@ -27,6 +27,7 @@ import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
import static com.android.server.wm.BoundsAnimationController.FADE_IN;
import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
@@ -142,7 +143,9 @@ public class RecentsAnimationController implements DeathRecipient {
};
public interface RecentsAnimationCallbacks {
void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously);
/** Callback when recents animation is finished. */
void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously,
boolean sendUserLeaveHint);
}
private final IRecentsAnimationController mController =
@@ -179,7 +182,7 @@ public class RecentsAnimationController implements DeathRecipient {
}
@Override
public void finish(boolean moveHomeToTop) {
public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) {
if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):"
+ " mCanceled=" + mCanceled);
final long token = Binder.clearCallingIdentity();
@@ -195,7 +198,9 @@ public class RecentsAnimationController implements DeathRecipient {
mCallbacks.onAnimationFinished(moveHomeToTop
? REORDER_MOVE_TO_TOP
: REORDER_MOVE_TO_ORIGINAL_POSITION,
true /* runSynchronously */);
true /* runSynchronously */, sendUserLeaveHint);
final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
dc.mBoundsAnimationController.setAnimationType(FADE_IN);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -497,7 +502,8 @@ public class RecentsAnimationController implements DeathRecipient {
Slog.e(TAG, "Failed to cancel recents animation", e);
}
// Clean up and return to the previous app
mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
false /* sendUserLeaveHint */);
}
}
@@ -542,7 +548,8 @@ public class RecentsAnimationController implements DeathRecipient {
if (DEBUG_RECENTS_ANIMATIONS) {
Slog.d(TAG, "mRecentScreenshotAnimator finish");
}
mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
false /* sendUserLeaveHint */);
}, mService);
mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
}

View File

@@ -34,6 +34,7 @@ import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
import static com.android.server.wm.BoundsAnimationController.FADE_IN;
import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
@@ -148,6 +149,7 @@ public class TaskStack extends WindowContainer<Task> implements
private boolean mCancelCurrentBoundsAnimation = false;
private Rect mBoundsAnimationTarget = new Rect();
private Rect mBoundsAnimationSourceHintBounds = new Rect();
private @BoundsAnimationController.AnimationType int mAnimationType;
Rect mPreAnimationBounds = new Rect();
@@ -1572,7 +1574,8 @@ public class TaskStack extends WindowContainer<Task> implements
}
@Override // AnimatesBounds
public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) {
public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate,
@BoundsAnimationController.AnimationType int animationType) {
// Hold the lock since this is called from the BoundsAnimator running on the UiThread
synchronized (mWmService.mGlobalLock) {
if (!isAttached()) {
@@ -1583,6 +1586,7 @@ public class TaskStack extends WindowContainer<Task> implements
mBoundsAnimatingRequested = false;
mBoundsAnimating = true;
mCancelCurrentBoundsAnimation = false;
mAnimationType = animationType;
// If we are changing UI mode, as in the PiP to fullscreen
// transition, then we need to wait for the window to draw.
@@ -1599,7 +1603,8 @@ public class TaskStack extends WindowContainer<Task> implements
// I don't believe you...
}
if (schedulePipModeChangedCallback && mActivityStack != null) {
if ((schedulePipModeChangedCallback || animationType == FADE_IN)
&& mActivityStack != null) {
// We need to schedule the PiP mode change before the animation up. It is possible
// in this case for the animation down to not have been completed, so always
// force-schedule and update to the client to ensure that it is notified that it
@@ -1614,6 +1619,21 @@ public class TaskStack extends WindowContainer<Task> implements
@Override // AnimatesBounds
public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
boolean moveToFullscreen) {
if (mAnimationType == BoundsAnimationController.FADE_IN) {
setPinnedStackAlpha(1f);
try {
mWmService.mActivityTaskManager.notifyPinnedStackAnimationEnded();
} catch (RemoteException e) {
// I don't believe you...
}
return;
}
onBoundAnimationEnd(schedulePipModeChangedCallback, finalStackSize, moveToFullscreen);
}
private void onBoundAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
boolean moveToFullscreen) {
if (inPinnedWindowingMode()) {
// Update to the final bounds if requested. This is done here instead of in the bounds
// animator to allow us to coordinate this after we notify the PiP mode changed
@@ -1725,10 +1745,23 @@ public class TaskStack extends WindowContainer<Task> implements
final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
schedulePipModeChangedState;
final DisplayContent displayContent = getDisplayContent();
@BoundsAnimationController.AnimationType int intendedAnimationType =
displayContent.mBoundsAnimationController.getAnimationType();
if (intendedAnimationType == FADE_IN) {
if (fromFullscreen) {
setPinnedStackAlpha(0f);
}
if (toBounds.width() == fromBounds.width()
&& toBounds.height() == fromBounds.height()) {
intendedAnimationType = BoundsAnimationController.BOUNDS;
}
}
final @BoundsAnimationController.AnimationType int animationType = intendedAnimationType;
displayContent.mBoundsAnimationController.getHandler().post(() -> {
displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
finalToBounds, animationDuration, finalSchedulePipModeChangedState,
fromFullscreen, toFullscreen);
fromFullscreen, toFullscreen, animationType);
});
}
@@ -1905,6 +1938,20 @@ public class TaskStack extends WindowContainer<Task> implements
}
}
@Override
public boolean setPinnedStackAlpha(float alpha) {
// Hold the lock since this is called from the BoundsAnimator running on the UiThread
synchronized (mWmService.mGlobalLock) {
if (mCancelCurrentBoundsAnimation) {
return false;
}
getPendingTransaction().setAlpha(getSurfaceControl(), alpha);
scheduleAnimation();
}
return true;
}
public DisplayInfo getDisplayInfo() {
return mDisplayContent.getDisplayInfo();
}

View File

@@ -18,6 +18,8 @@ package com.android.server.wm;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.server.wm.BoundsAnimationController.BOUNDS;
import static com.android.server.wm.BoundsAnimationController.FADE_IN;
import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
@@ -131,6 +133,8 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
boolean mCancelRequested;
Rect mStackBounds;
Rect mTaskBounds;
float mAlpha;
@BoundsAnimationController.AnimationType int mAnimationType;
void initialize(Rect from) {
mAwaitingAnimationStart = true;
@@ -148,11 +152,12 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@Override
public boolean onAnimationStart(boolean schedulePipModeChangedCallback,
boolean forceUpdate) {
boolean forceUpdate, @BoundsAnimationController.AnimationType int animationType) {
mAwaitingAnimationStart = false;
mAnimationStarted = true;
mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback;
mForcePipModeChangedCallback = forceUpdate;
mAnimationType = animationType;
return true;
}
@@ -185,6 +190,12 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
mMovedToFullscreen = moveToFullscreen;
mTaskBounds = null;
}
@Override
public boolean setPinnedStackAlpha(float alpha) {
mAlpha = alpha;
return true;
}
}
/**
@@ -201,6 +212,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
private Rect mTo;
private Rect mLargerBounds;
private Rect mExpectedFinalBounds;
private @BoundsAnimationController.AnimationType int mAnimationType;
BoundsAnimationDriver(BoundsAnimationController controller,
TestBoundsAnimationTarget target, MockValueAnimator mockValueAnimator) {
@@ -209,7 +221,8 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
mMockAnimator = mockValueAnimator;
}
BoundsAnimationDriver start(Rect from, Rect to) {
BoundsAnimationDriver start(Rect from, Rect to,
@BoundsAnimationController.AnimationType int animationType) {
if (mAnimator != null) {
throw new IllegalArgumentException("Call restart() to restart an animation");
}
@@ -223,7 +236,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
assertTrue(mTarget.mAwaitingAnimationStart);
assertFalse(mTarget.mAnimationStarted);
startImpl(from, to);
startImpl(from, to, animationType);
// Ensure that the animator is paused for the all windows drawn signal when animating
// to/from fullscreen
@@ -253,7 +266,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
mTarget.mAnimationStarted = false;
// Start animation
startImpl(mTarget.mStackBounds, to);
startImpl(mTarget.mStackBounds, to, BOUNDS);
if (toSameBounds) {
// Same animator if same final bounds
@@ -273,13 +286,15 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
return this;
}
private BoundsAnimationDriver startImpl(Rect from, Rect to) {
private BoundsAnimationDriver startImpl(Rect from, Rect to,
@BoundsAnimationController.AnimationType int animationType) {
boolean fromFullscreen = from.equals(BOUNDS_FULL);
boolean toFullscreen = to.equals(BOUNDS_FULL);
mFrom = new Rect(from);
mTo = new Rect(to);
mExpectedFinalBounds = new Rect(to);
mLargerBounds = getLargerBounds(mFrom, mTo);
mAnimationType = animationType;
// Start animation
final @SchedulePipModeChangedState int schedulePipModeChangedState = toFullscreen
@@ -288,17 +303,19 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
? SCHEDULE_PIP_MODE_CHANGED_ON_END
: NO_PIP_MODE_CHANGED_CALLBACKS;
mAnimator = mController.animateBoundsImpl(mTarget, from, to, DURATION,
schedulePipModeChangedState, fromFullscreen, toFullscreen);
schedulePipModeChangedState, fromFullscreen, toFullscreen, animationType);
// Original stack bounds, frozen task bounds
assertEquals(mFrom, mTarget.mStackBounds);
assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
if (animationType == BOUNDS) {
// Original stack bounds, frozen task bounds
assertEquals(mFrom, mTarget.mStackBounds);
assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
// Animating to larger size
if (mFrom.equals(mLargerBounds)) {
assertFalse(mAnimator.animatingToLargerSize());
} else if (mTo.equals(mLargerBounds)) {
assertTrue(mAnimator.animatingToLargerSize());
// Animating to larger size
if (mFrom.equals(mLargerBounds)) {
assertFalse(mAnimator.animatingToLargerSize());
} else if (mTo.equals(mLargerBounds)) {
assertTrue(mAnimator.animatingToLargerSize());
}
}
return this;
@@ -315,16 +332,20 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
BoundsAnimationDriver update(float t) {
mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(t));
// Temporary stack bounds, frozen task bounds
if (t == 0f) {
assertEquals(mFrom, mTarget.mStackBounds);
} else if (t == 1f) {
assertEquals(mTo, mTarget.mStackBounds);
if (mAnimationType == BOUNDS) {
// Temporary stack bounds, frozen task bounds
if (t == 0f) {
assertEquals(mFrom, mTarget.mStackBounds);
} else if (t == 1f) {
assertEquals(mTo, mTarget.mStackBounds);
} else {
assertNotEquals(mFrom, mTarget.mStackBounds);
assertNotEquals(mTo, mTarget.mStackBounds);
}
assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
} else {
assertNotEquals(mFrom, mTarget.mStackBounds);
assertNotEquals(mTo, mTarget.mStackBounds);
assertEquals((float) mMockAnimator.getAnimatedValue(), mTarget.mAlpha, 0.01f);
}
assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
return this;
}
@@ -353,10 +374,14 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
BoundsAnimationDriver end() {
mAnimator.end();
// Final stack bounds
assertEquals(mTo, mTarget.mStackBounds);
assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds);
assertNull(mTarget.mTaskBounds);
if (mAnimationType == BOUNDS) {
// Final stack bounds
assertEquals(mTo, mTarget.mStackBounds);
assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds);
assertNull(mTarget.mTaskBounds);
} else {
assertEquals(mTarget.mAlpha, 1f, 0.01f);
}
return this;
}
@@ -413,7 +438,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFullscreenToFloatingTransition() {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0f)
.update(0.5f)
@@ -425,7 +450,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFloatingToFullscreenTransition() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0f)
.update(0.5f)
@@ -437,7 +462,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFloatingToSmallerFloatingTransition() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING, BOUNDS)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0f)
.update(0.5f)
@@ -449,7 +474,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFloatingToLargerFloatingTransition() {
mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING, BOUNDS)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0f)
.update(0.5f)
@@ -463,7 +488,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFullscreenToFloatingCancelFromTarget() {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
.cancel()
@@ -473,7 +498,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFullscreenToFloatingCancelFromAnimationToSameBounds() {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
.restart(BOUNDS_FLOATING, false /* expectStartedAndPipModeChangedCallback */)
@@ -484,7 +509,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
.restart(BOUNDS_SMALLER_FLOATING,
@@ -498,7 +523,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() {
// When animating from fullscreen and the animation is interruped, we expect the animation
// start callback to be made, with a forced pip mode change callback
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
.restart(BOUNDS_FULL, true /* expectStartedAndPipModeChangedCallback */)
@@ -511,7 +536,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFloatingToFullscreenCancelFromTarget() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
.cancel()
@@ -521,7 +546,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFloatingToFullscreenCancelFromAnimationToSameBounds() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
.restart(BOUNDS_FULL, false /* expectStartedAndPipModeChangedCallback */)
@@ -532,7 +557,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
.restart(BOUNDS_SMALLER_FLOATING,
@@ -546,7 +571,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFloatingToSmallerFloatingCancelFromTarget() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING, BOUNDS)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
.cancel()
@@ -556,13 +581,25 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFloatingToLargerFloatingCancelFromTarget() {
mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING, BOUNDS)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
.cancel()
.expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
}
@UiThreadTest
@Test
public void testFadeIn() {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, FADE_IN)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0f)
.update(0.5f)
.update(1f)
.end()
.expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
}
/** MISC **/
@UiThreadTest
@@ -570,7 +607,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
public void testBoundsAreCopied() {
Rect from = new Rect(0, 0, 100, 100);
Rect to = new Rect(25, 25, 75, 75);
mDriver.start(from, to)
mDriver.start(from, to, BOUNDS)
.update(0.25f)
.end();
assertEquals(new Rect(0, 0, 100, 100), from);

View File

@@ -163,7 +163,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Assume IRecentsAnimationController#cleanupScreenshot called to finish screenshot
// animation.
mController.mRecentScreenshotAnimator.cancelAnimation();
verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true);
verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
}
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {

View File

@@ -71,6 +71,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
@Test
public void testCancelAnimationOnVisibleStackOrderChange() {
ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class);
ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mService)