blob: 7f3c89c58a288135c9a06fb61af8ea3550b5d72d [file] [log] [blame]
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080019import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
20import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
21import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
22
23import android.animation.Animator;
24import android.animation.ValueAnimator;
Winson Chung8bca9e42017-04-16 15:59:43 -070025import android.annotation.IntDef;
Winson Chungbaa7b722017-03-03 21:33:44 -080026import android.content.Context;
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080027import android.graphics.Rect;
Wale Ogunwale2ba71292016-05-05 09:16:47 -070028import android.os.Handler;
Robert Carrf9aa2a92016-04-26 14:22:19 -070029import android.os.IBinder;
Wale Ogunwale5658e4b2016-02-12 12:22:19 -080030import android.os.Debug;
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080031import android.util.ArrayMap;
32import android.util.Slog;
Winson Chungbaa7b722017-03-03 21:33:44 -080033import android.view.animation.AnimationUtils;
34import android.view.animation.Interpolator;
Robert Carrf9aa2a92016-04-26 14:22:19 -070035import android.view.WindowManagerInternal;
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080036
Winson Chung19953ca2017-04-11 11:19:23 -070037import com.android.internal.annotations.VisibleForTesting;
38
Winson Chung8bca9e42017-04-16 15:59:43 -070039import java.lang.annotation.Retention;
40import java.lang.annotation.RetentionPolicy;
41
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080042/**
43 * Enables animating bounds of objects.
44 *
45 * In multi-window world bounds of both stack and tasks can change. When we need these bounds to
46 * change smoothly and not require the app to relaunch (e.g. because it handles resizes and
47 * relaunching it would cause poorer experience), these class provides a way to directly animate
48 * the bounds of the resized object.
49 *
Winson Chung8bca9e42017-04-16 15:59:43 -070050 * The object that is resized needs to implement {@link BoundsAnimationTarget} interface.
Wale Ogunwale2ba71292016-05-05 09:16:47 -070051 *
52 * NOTE: All calls to methods in this class should be done on the UI thread
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080053 */
54public class BoundsAnimationController {
Wale Ogunwale5658e4b2016-02-12 12:22:19 -080055 private static final boolean DEBUG_LOCAL = false;
56 private static final boolean DEBUG = DEBUG_LOCAL || DEBUG_ANIM;
57 private static final String TAG = TAG_WITH_CLASS_NAME || DEBUG_LOCAL
58 ? "BoundsAnimationController" : TAG_WM;
Wale Ogunwalece144522016-02-05 22:51:01 -080059 private static final int DEBUG_ANIMATION_SLOW_DOWN_FACTOR = 1;
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080060
Winson Chungbaa7b722017-03-03 21:33:44 -080061 private static final int DEFAULT_TRANSITION_DURATION = 425;
62
Winson Chung8bca9e42017-04-16 15:59:43 -070063 @Retention(RetentionPolicy.SOURCE)
64 @IntDef({NO_PIP_MODE_CHANGED_CALLBACKS, SCHEDULE_PIP_MODE_CHANGED_ON_START,
65 SCHEDULE_PIP_MODE_CHANGED_ON_END})
66 public @interface SchedulePipModeChangedState {}
67 /** Do not schedule any PiP mode changed callbacks as a part of this animation. */
68 public static final int NO_PIP_MODE_CHANGED_CALLBACKS = 0;
69 /** Schedule a PiP mode changed callback when this animation starts. */
70 public static final int SCHEDULE_PIP_MODE_CHANGED_ON_START = 1;
71 /** Schedule a PiP mode changed callback when this animation ends. */
72 public static final int SCHEDULE_PIP_MODE_CHANGED_ON_END = 2;
73
Wale Ogunwalece144522016-02-05 22:51:01 -080074 // Only accessed on UI thread.
Winson Chung8bca9e42017-04-16 15:59:43 -070075 private ArrayMap<BoundsAnimationTarget, BoundsAnimator> mRunningAnimations = new ArrayMap<>();
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080076
Wale Ogunwale2ba71292016-05-05 09:16:47 -070077 private final class AppTransitionNotifier
78 extends WindowManagerInternal.AppTransitionListener implements Runnable {
Robert Carrf9aa2a92016-04-26 14:22:19 -070079
Wale Ogunwale2ba71292016-05-05 09:16:47 -070080 public void onAppTransitionCancelledLocked() {
Winson Chung87e5d552017-04-05 11:49:38 -070081 if (DEBUG) Slog.d(TAG, "onAppTransitionCancelledLocked:"
82 + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition);
Wale Ogunwale2ba71292016-05-05 09:16:47 -070083 animationFinished();
84 }
85 public void onAppTransitionFinishedLocked(IBinder token) {
Winson Chung87e5d552017-04-05 11:49:38 -070086 if (DEBUG) Slog.d(TAG, "onAppTransitionFinishedLocked:"
87 + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition);
Wale Ogunwale2ba71292016-05-05 09:16:47 -070088 animationFinished();
89 }
90 private void animationFinished() {
91 if (mFinishAnimationAfterTransition) {
92 mHandler.removeCallbacks(this);
Winson Chung87e5d552017-04-05 11:49:38 -070093 // This might end up calling into activity manager which will be bad since we have
94 // the window manager lock held at this point. Post a message to take care of the
95 // processing so we don't deadlock.
Wale Ogunwale2ba71292016-05-05 09:16:47 -070096 mHandler.post(this);
97 }
98 }
99
100 @Override
101 public void run() {
102 for (int i = 0; i < mRunningAnimations.size(); i++) {
103 final BoundsAnimator b = mRunningAnimations.valueAt(i);
104 b.onAnimationEnd(null);
105 }
106 }
107 }
108
109 private final Handler mHandler;
Robert Carrf9aa2a92016-04-26 14:22:19 -0700110 private final AppTransition mAppTransition;
Wale Ogunwale2ba71292016-05-05 09:16:47 -0700111 private final AppTransitionNotifier mAppTransitionNotifier = new AppTransitionNotifier();
Winson Chungbaa7b722017-03-03 21:33:44 -0800112 private final Interpolator mFastOutSlowInInterpolator;
Robert Carrf9aa2a92016-04-26 14:22:19 -0700113 private boolean mFinishAnimationAfterTransition = false;
114
Robert Carrecc06b32017-04-18 14:25:10 -0700115 private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
116
Winson Chungbaa7b722017-03-03 21:33:44 -0800117 BoundsAnimationController(Context context, AppTransition transition, Handler handler) {
Wale Ogunwale2ba71292016-05-05 09:16:47 -0700118 mHandler = handler;
Robert Carrf9aa2a92016-04-26 14:22:19 -0700119 mAppTransition = transition;
120 mAppTransition.registerListenerLocked(mAppTransitionNotifier);
Winson Chungbaa7b722017-03-03 21:33:44 -0800121 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
122 com.android.internal.R.interpolator.fast_out_slow_in);
Robert Carrf9aa2a92016-04-26 14:22:19 -0700123 }
124
Winson Chung19953ca2017-04-11 11:19:23 -0700125 @VisibleForTesting
126 final class BoundsAnimator extends ValueAnimator
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800127 implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
Winson Chung8bca9e42017-04-16 15:59:43 -0700128 private final BoundsAnimationTarget mTarget;
Winson Chung84a38342016-11-08 16:15:10 -0800129 private final Rect mFrom = new Rect();
130 private final Rect mTo = new Rect();
Robert Carr0d00c2e2016-02-29 17:45:02 -0800131 private final Rect mTmpRect = new Rect();
132 private final Rect mTmpTaskBounds = new Rect();
Winson Chung8bca9e42017-04-16 15:59:43 -0700133
134 // True if this this animation was canceled and will be replaced the another animation from
135 // the same {@link #BoundsAnimationTarget} target.
Winson Chung19953ca2017-04-11 11:19:23 -0700136 private boolean mSkipFinalResize;
Winson Chung5af42fc2017-03-24 17:11:33 -0700137 // True if this animation replaced a previous animation of the same
Winson Chung8bca9e42017-04-16 15:59:43 -0700138 // {@link #BoundsAnimationTarget} target.
Winson Chung5af42fc2017-03-24 17:11:33 -0700139 private final boolean mSkipAnimationStart;
Winson Chung8bca9e42017-04-16 15:59:43 -0700140 // True if this animation was canceled by the user, not as a part of a replacing animation
Winson Chung19953ca2017-04-11 11:19:23 -0700141 private boolean mSkipAnimationEnd;
Winson Chung8bca9e42017-04-16 15:59:43 -0700142 // True if the animation target should be moved to the fullscreen stack at the end of this
143 // animation
144 private boolean mMoveToFullscreen;
145
146 // Whether to schedule PiP mode changes on animation start/end
147 private @SchedulePipModeChangedState int mSchedulePipModeChangedState;
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800148
Robert Carr0d00c2e2016-02-29 17:45:02 -0800149 // Depending on whether we are animating from
150 // a smaller to a larger size
151 private final int mFrozenTaskWidth;
152 private final int mFrozenTaskHeight;
153
Winson Chung8bca9e42017-04-16 15:59:43 -0700154 BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
155 @SchedulePipModeChangedState int schedulePipModeChangedState,
156 boolean moveToFullscreen, boolean replacingExistingAnimation) {
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800157 super();
158 mTarget = target;
Winson Chung84a38342016-11-08 16:15:10 -0800159 mFrom.set(from);
160 mTo.set(to);
Winson Chung5af42fc2017-03-24 17:11:33 -0700161 mSkipAnimationStart = replacingExistingAnimation;
Winson Chung8bca9e42017-04-16 15:59:43 -0700162 mSchedulePipModeChangedState = schedulePipModeChangedState;
163 mMoveToFullscreen = moveToFullscreen;
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800164 addUpdateListener(this);
165 addListener(this);
Robert Carr0d00c2e2016-02-29 17:45:02 -0800166
167 // If we are animating from smaller to larger, we want to change the task bounds
168 // to their final size immediately so we can use scaling to make the window
169 // larger. Likewise if we are going from bigger to smaller, we want to wait until
170 // the end so we don't have to upscale from the smaller finished size.
171 if (animatingToLargerSize()) {
172 mFrozenTaskWidth = mTo.width();
173 mFrozenTaskHeight = mTo.height();
174 } else {
175 mFrozenTaskWidth = mFrom.width();
176 mFrozenTaskHeight = mFrom.height();
177 }
178 }
179
Robert Carrecc06b32017-04-18 14:25:10 -0700180 final Runnable mResumeRunnable = new Runnable() {
181 @Override
182 public void run() {
183 resume();
184 }
185 };
186
Winson Chung5af42fc2017-03-24 17:11:33 -0700187 @Override
188 public void onAnimationStart(Animator animation) {
189 if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
Winson Chung8bca9e42017-04-16 15:59:43 -0700190 + " mSkipAnimationStart=" + mSkipAnimationStart
191 + " mSchedulePipModeChangedState=" + mSchedulePipModeChangedState);
Winson Chung5af42fc2017-03-24 17:11:33 -0700192 mFinishAnimationAfterTransition = false;
193 mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth,
194 mFrom.top + mFrozenTaskHeight);
195
196 // Ensure that we have prepared the target for animation before
197 // we trigger any size changes, so it can swap surfaces
198 // in to appropriate modes, or do as it wishes otherwise.
199 if (!mSkipAnimationStart) {
Winson Chung8bca9e42017-04-16 15:59:43 -0700200 mTarget.onAnimationStart(mSchedulePipModeChangedState ==
201 SCHEDULE_PIP_MODE_CHANGED_ON_START);
Winson Chung5af42fc2017-03-24 17:11:33 -0700202 }
203
204 // Immediately update the task bounds if they have to become larger, but preserve
205 // the starting position so we don't jump at the beginning of the animation.
206 if (animatingToLargerSize()) {
207 mTarget.setPinnedStackSize(mFrom, mTmpRect);
Robert Carrecc06b32017-04-18 14:25:10 -0700208
209 // We pause the animation until the app has drawn at the new size.
210 // The target will notify us via BoundsAnimationController#resume.
211 // We do this here and pause the animation, rather than just defer starting it
212 // so we can enter the animating state and have WindowStateAnimator apply the
213 // correct logic to make this resize seamless.
214 if (mMoveToFullscreen) {
215 pause();
216 mHandler.postDelayed(mResumeRunnable, WAIT_FOR_DRAW_TIMEOUT_MS);
217 }
Winson Chung5af42fc2017-03-24 17:11:33 -0700218 }
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800219 }
220
221 @Override
Robert Carrecc06b32017-04-18 14:25:10 -0700222 public void resume() {
223 mHandler.removeCallbacks(mResumeRunnable);
224 super.resume();
225 }
226
227 @Override
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800228 public void onAnimationUpdate(ValueAnimator animation) {
229 final float value = (Float) animation.getAnimatedValue();
230 final float remains = 1 - value;
Wale Ogunwalece144522016-02-05 22:51:01 -0800231 mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value + 0.5f);
232 mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value + 0.5f);
233 mTmpRect.right = (int) (mFrom.right * remains + mTo.right * value + 0.5f);
234 mTmpRect.bottom = (int) (mFrom.bottom * remains + mTo.bottom * value + 0.5f);
Wale Ogunwale5658e4b2016-02-12 12:22:19 -0800235 if (DEBUG) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + " mBounds="
236 + mTmpRect + " from=" + mFrom + " mTo=" + mTo + " value=" + value
237 + " remains=" + remains);
Robert Carr0d00c2e2016-02-29 17:45:02 -0800238
Robert Carrc7294602016-05-13 11:32:05 -0700239 mTmpTaskBounds.set(mTmpRect.left, mTmpRect.top,
240 mTmpRect.left + mFrozenTaskWidth, mTmpRect.top + mFrozenTaskHeight);
Robert Carr0d00c2e2016-02-29 17:45:02 -0800241
Robert Carrc7294602016-05-13 11:32:05 -0700242 if (!mTarget.setPinnedStackSize(mTmpRect, mTmpTaskBounds)) {
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800243 // Whoops, the target doesn't feel like animating anymore. Let's immediately finish
244 // any further animation.
Winson Chung87e5d552017-04-05 11:49:38 -0700245 if (DEBUG) Slog.d(TAG, "animateUpdate: cancelled");
Winson Chung19953ca2017-04-11 11:19:23 -0700246
Winson Chung8bca9e42017-04-16 15:59:43 -0700247 // If we have already scheduled a PiP mode changed at the start of the animation,
248 // then we need to clean up and schedule one at the end, since we have canceled the
249 // animation to the final state.
250 if (mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
251 mSchedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
252 }
253
Winson Chung19953ca2017-04-11 11:19:23 -0700254 // Since we are cancelling immediately without a replacement animation, send the
255 // animation end to maintain callback parity, but also skip any further resizes
Winson Chung8bca9e42017-04-16 15:59:43 -0700256 cancelAndCallAnimationEnd();
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800257 }
258 }
259
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800260 @Override
261 public void onAnimationEnd(Animator animation) {
Wale Ogunwale5658e4b2016-02-12 12:22:19 -0800262 if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
Winson Chung19953ca2017-04-11 11:19:23 -0700263 + " mSkipFinalResize=" + mSkipFinalResize
Winson Chung87e5d552017-04-05 11:49:38 -0700264 + " mFinishAnimationAfterTransition=" + mFinishAnimationAfterTransition
Winson Chung8bca9e42017-04-16 15:59:43 -0700265 + " mAppTransitionIsRunning=" + mAppTransition.isRunning()
266 + " callers=" + Debug.getCallers(2));
Jaewan Kimb0033642016-04-22 18:41:37 +0900267
Robert Carrf9aa2a92016-04-26 14:22:19 -0700268 // There could be another animation running. For example in the
269 // move to fullscreen case, recents will also be closing while the
270 // previous task will be taking its place in the fullscreen stack.
271 // we have to ensure this is completed before we finish the animation
272 // and take our place in the fullscreen stack.
273 if (mAppTransition.isRunning() && !mFinishAnimationAfterTransition) {
274 mFinishAnimationAfterTransition = true;
275 return;
276 }
277
Winson Chung8bca9e42017-04-16 15:59:43 -0700278 if (!mSkipAnimationEnd) {
279 // If this animation has already scheduled the picture-in-picture mode on start, and
280 // we are not skipping the final resize due to being canceled, then move the PiP to
281 // fullscreen once the animation ends
282 if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
283 + " moveToFullscreen=" + mMoveToFullscreen);
284 mTarget.onAnimationEnd(mSchedulePipModeChangedState ==
285 SCHEDULE_PIP_MODE_CHANGED_ON_END, !mSkipFinalResize ? mTo : null,
286 mMoveToFullscreen);
Winson Chung19953ca2017-04-11 11:19:23 -0700287 }
288
Winson Chung8bca9e42017-04-16 15:59:43 -0700289 // Clean up this animation
290 removeListener(this);
291 removeUpdateListener(this);
292 mRunningAnimations.remove(mTarget);
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800293 }
294
295 @Override
296 public void onAnimationCancel(Animator animation) {
Winson Chung8bca9e42017-04-16 15:59:43 -0700297 // Always skip the final resize when the animation is canceled
298 mSkipFinalResize = true;
299 mMoveToFullscreen = false;
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800300 }
301
Winson Chung8bca9e42017-04-16 15:59:43 -0700302 private void cancelAndCallAnimationEnd() {
303 if (DEBUG) Slog.d(TAG, "cancelAndCallAnimationEnd: mTarget=" + mTarget);
304 mSkipAnimationEnd = false;
305 super.cancel();
Winson Chung19953ca2017-04-11 11:19:23 -0700306 }
307
Wale Ogunwalece144522016-02-05 22:51:01 -0800308 @Override
309 public void cancel() {
Winson Chung19953ca2017-04-11 11:19:23 -0700310 if (DEBUG) Slog.d(TAG, "cancel: mTarget=" + mTarget);
Winson Chung8bca9e42017-04-16 15:59:43 -0700311 mSkipAnimationEnd = true;
Wale Ogunwalece144522016-02-05 22:51:01 -0800312 super.cancel();
313 }
314
Winson Chung8bca9e42017-04-16 15:59:43 -0700315 /**
316 * @return true if the animation target is the same as the input bounds.
317 */
Winson Chung5af42fc2017-03-24 17:11:33 -0700318 boolean isAnimatingTo(Rect bounds) {
Wale Ogunwale5658e4b2016-02-12 12:22:19 -0800319 return mTo.equals(bounds);
320 }
321
Winson Chung8bca9e42017-04-16 15:59:43 -0700322 /**
323 * @return true if we are animating to a larger surface size
324 */
325 @VisibleForTesting
326 boolean animatingToLargerSize() {
327 // TODO: Fix this check for aspect ratio changes
328 return (mFrom.width() * mFrom.height() <= mTo.width() * mTo.height());
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800329 }
330
331 @Override
332 public void onAnimationRepeat(Animator animation) {
Winson Chung5af42fc2017-03-24 17:11:33 -0700333 // Do nothing
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800334 }
335 }
336
Winson Chung8bca9e42017-04-16 15:59:43 -0700337 public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to,
338 int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
339 boolean moveToFullscreen) {
340 animateBoundsImpl(target, from, to, animationDuration, schedulePipModeChangedState,
341 moveToFullscreen);
Winson Chung19953ca2017-04-11 11:19:23 -0700342 }
343
344 @VisibleForTesting
Winson Chung8bca9e42017-04-16 15:59:43 -0700345 BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to,
346 int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
347 boolean moveToFullscreen) {
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800348 final BoundsAnimator existing = mRunningAnimations.get(target);
Wale Ogunwalece144522016-02-05 22:51:01 -0800349 final boolean replacing = existing != null;
Wale Ogunwale5658e4b2016-02-12 12:22:19 -0800350
351 if (DEBUG) Slog.d(TAG, "animateBounds: target=" + target + " from=" + from + " to=" + to
Winson Chung8bca9e42017-04-16 15:59:43 -0700352 + " schedulePipModeChangedState=" + schedulePipModeChangedState
353 + " replacing=" + replacing);
Wale Ogunwale5658e4b2016-02-12 12:22:19 -0800354
Wale Ogunwalece144522016-02-05 22:51:01 -0800355 if (replacing) {
Wale Ogunwale5658e4b2016-02-12 12:22:19 -0800356 if (existing.isAnimatingTo(to)) {
Winson Chung19953ca2017-04-11 11:19:23 -0700357 // Just let the current animation complete if it has the same destination as the
Wale Ogunwale5658e4b2016-02-12 12:22:19 -0800358 // one we are trying to start.
359 if (DEBUG) Slog.d(TAG, "animateBounds: same destination as existing=" + existing
360 + " ignoring...");
Winson Chung8bca9e42017-04-16 15:59:43 -0700361
Winson Chung19953ca2017-04-11 11:19:23 -0700362 return existing;
Wale Ogunwale5658e4b2016-02-12 12:22:19 -0800363 }
Winson Chung8bca9e42017-04-16 15:59:43 -0700364
365 // Update the PiP callback states if we are replacing the animation
366 if (existing.mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
367 if (schedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
368 if (DEBUG) Slog.d(TAG, "animateBounds: still animating to fullscreen, keep"
369 + " existing deferred state");
370 } else {
371 if (DEBUG) Slog.d(TAG, "animateBounds: fullscreen animation canceled, callback"
372 + " on start already processed, schedule deferred update on end");
373 schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
374 }
375 } else if (existing.mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_END) {
376 if (schedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
377 if (DEBUG) Slog.d(TAG, "animateBounds: non-fullscreen animation canceled,"
378 + " callback on start will be processed");
379 } else {
380 if (DEBUG) Slog.d(TAG, "animateBounds: still animating from fullscreen, keep"
381 + " existing deferred state");
382 schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
383 }
384 }
385
386 // Since we are replacing, we skip both animation start and end callbacks
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800387 existing.cancel();
388 }
Winson Chung8bca9e42017-04-16 15:59:43 -0700389 final BoundsAnimator animator = new BoundsAnimator(target, from, to,
390 schedulePipModeChangedState, moveToFullscreen, replacing);
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800391 mRunningAnimations.put(target, animator);
392 animator.setFloatValues(0f, 1f);
Wale Ogunwalee75a9ad2016-03-18 20:43:49 -0700393 animator.setDuration((animationDuration != -1 ? animationDuration
Winson Chungbaa7b722017-03-03 21:33:44 -0800394 : DEFAULT_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
395 animator.setInterpolator(mFastOutSlowInInterpolator);
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800396 animator.start();
Winson Chung19953ca2017-04-11 11:19:23 -0700397 return animator;
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800398 }
Robert Carrecc06b32017-04-18 14:25:10 -0700399
400 private void resume() {
401 for (int i = 0; i < mRunningAnimations.size(); i++) {
402 final BoundsAnimator b = mRunningAnimations.valueAt(i);
403 b.resume();
404 }
405 }
406
407 public void onAllWindowsDrawn() {
408 mHandler.post(this::resume);
409 }
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800410}