Merge "Implement the new PiP animation (fade-in)." into qt-dev
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user