184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski/* 284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * Copyright (C) 2016 The Android Open Source Project 384fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * 484fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * Licensed under the Apache License, Version 2.0 (the "License"); 584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * you may not use this file except in compliance with the License. 684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * You may obtain a copy of the License at 784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * 884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * http://www.apache.org/licenses/LICENSE-2.0 984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * 1084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * Unless required by applicable law or agreed to in writing, software 1184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * distributed under the License is distributed on an "AS IS" BASIS, 1284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1384fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * See the License for the specific language governing permissions and 1484fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * limitations under the License. 1584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski */ 1684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 1784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskipackage com.android.server.wm; 1884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 1984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION; 2084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 2184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 2284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 2384fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 2484fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport android.animation.Animator; 2584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport android.animation.ValueAnimator; 2684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport android.graphics.Rect; 272ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwaleimport android.os.Handler; 28f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carrimport android.os.IBinder; 295658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwaleimport android.os.Debug; 3084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport android.util.ArrayMap; 3184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport android.util.Slog; 3284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskiimport android.view.animation.LinearInterpolator; 33f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carrimport android.view.WindowManagerInternal; 3484fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 3584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski/** 3684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * Enables animating bounds of objects. 3784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * 3884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * In multi-window world bounds of both stack and tasks can change. When we need these bounds to 3984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * change smoothly and not require the app to relaunch (e.g. because it handles resizes and 4084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * relaunching it would cause poorer experience), these class provides a way to directly animate 4184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * the bounds of the resized object. 4284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * 4384fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * The object that is resized needs to implement {@link AnimateBoundsUser} interface. 442ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale * 452ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale * NOTE: All calls to methods in this class should be done on the UI thread 4684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski */ 4784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynskipublic class BoundsAnimationController { 485658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale private static final boolean DEBUG_LOCAL = false; 495658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale private static final boolean DEBUG = DEBUG_LOCAL || DEBUG_ANIM; 505658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale private static final String TAG = TAG_WITH_CLASS_NAME || DEBUG_LOCAL 515658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale ? "BoundsAnimationController" : TAG_WM; 52ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale private static final int DEBUG_ANIMATION_SLOW_DOWN_FACTOR = 1; 5384fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 54ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale // Only accessed on UI thread. 5584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>(); 5684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 572ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale private final class AppTransitionNotifier 582ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale extends WindowManagerInternal.AppTransitionListener implements Runnable { 592ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale 602ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale public void onAppTransitionCancelledLocked() { 612ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale animationFinished(); 622ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale } 632ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale public void onAppTransitionFinishedLocked(IBinder token) { 642ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale animationFinished(); 652ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale } 662ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale private void animationFinished() { 672ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale if (mFinishAnimationAfterTransition) { 682ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale mHandler.removeCallbacks(this); 692ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale // This might end up calling into activity manager which will be bad since we have the 702ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale // window manager lock held at this point. Post a message to take care of the processing 712ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale // so we don't deadlock. 722ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale mHandler.post(this); 732ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale } 742ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale } 752ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale 762ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale @Override 772ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale public void run() { 782ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale for (int i = 0; i < mRunningAnimations.size(); i++) { 792ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale final BoundsAnimator b = mRunningAnimations.valueAt(i); 802ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale b.onAnimationEnd(null); 812ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale } 822ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale } 832ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale } 84f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr 852ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale private final Handler mHandler; 86f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr private final AppTransition mAppTransition; 872ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale private final AppTransitionNotifier mAppTransitionNotifier = new AppTransitionNotifier(); 88f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr private boolean mFinishAnimationAfterTransition = false; 89f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr 902ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale BoundsAnimationController(AppTransition transition, Handler handler) { 912ba712905fe70d70024912fc27f99dfe0dc4bf94Wale Ogunwale mHandler = handler; 92f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr mAppTransition = transition; 93f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr mAppTransition.registerListenerLocked(mAppTransitionNotifier); 94f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr } 95f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr 9684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski private final class BoundsAnimator extends ValueAnimator 9784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { 9884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski private final AnimateBoundsUser mTarget; 9984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski private final Rect mFrom; 10084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski private final Rect mTo; 1010d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr private final Rect mTmpRect = new Rect(); 1020d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr private final Rect mTmpTaskBounds = new Rect(); 103c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski private final boolean mMoveToFullScreen; 104ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale // True if this this animation was cancelled and will be replaced the another animation from 105ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale // the same {@link #AnimateBoundsUser} target. 106ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale private boolean mWillReplace; 107ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale // True to true if this animation replaced a previous animation of the same 108ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale // {@link #AnimateBoundsUser} target. 109ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale private final boolean mReplacement; 110ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale 1110d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr // Depending on whether we are animating from 1120d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr // a smaller to a larger size 1130d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr private final int mFrozenTaskWidth; 1140d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr private final int mFrozenTaskHeight; 1150d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr 116ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to, 117ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale boolean moveToFullScreen, boolean replacement) { 11884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski super(); 11984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski mTarget = target; 12084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski mFrom = from; 12184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski mTo = to; 122c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski mMoveToFullScreen = moveToFullScreen; 123ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale mReplacement = replacement; 12484fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski addUpdateListener(this); 12584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski addListener(this); 1260d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr 1270d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr // If we are animating from smaller to larger, we want to change the task bounds 1280d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr // to their final size immediately so we can use scaling to make the window 1290d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr // larger. Likewise if we are going from bigger to smaller, we want to wait until 1300d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr // the end so we don't have to upscale from the smaller finished size. 1310d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr if (animatingToLargerSize()) { 1320d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr mFrozenTaskWidth = mTo.width(); 1330d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr mFrozenTaskHeight = mTo.height(); 1340d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr } else { 1350d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr mFrozenTaskWidth = mFrom.width(); 1360d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr mFrozenTaskHeight = mFrom.height(); 1370d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr } 1380d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr } 1390d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr 1400d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr boolean animatingToLargerSize() { 1410d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr if (mFrom.width() * mFrom.height() > mTo.width() * mTo.height()) { 1420d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr return false; 1430d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr } 1440d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr return true; 14584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 14684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 14784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski @Override 14884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski public void onAnimationUpdate(ValueAnimator animation) { 14984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski final float value = (Float) animation.getAnimatedValue(); 15084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski final float remains = 1 - value; 151ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value + 0.5f); 152ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value + 0.5f); 153ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale mTmpRect.right = (int) (mFrom.right * remains + mTo.right * value + 0.5f); 154ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale mTmpRect.bottom = (int) (mFrom.bottom * remains + mTo.bottom * value + 0.5f); 1555658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale if (DEBUG) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + " mBounds=" 1565658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale + mTmpRect + " from=" + mFrom + " mTo=" + mTo + " value=" + value 1575658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale + " remains=" + remains); 1580d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr 159c7294607fc0debc54e92abac18bec2601a21ce27Robert Carr mTmpTaskBounds.set(mTmpRect.left, mTmpRect.top, 160c7294607fc0debc54e92abac18bec2601a21ce27Robert Carr mTmpRect.left + mFrozenTaskWidth, mTmpRect.top + mFrozenTaskHeight); 1610d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr 162c7294607fc0debc54e92abac18bec2601a21ce27Robert Carr if (!mTarget.setPinnedStackSize(mTmpRect, mTmpTaskBounds)) { 16384fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski // Whoops, the target doesn't feel like animating anymore. Let's immediately finish 16484fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski // any further animation. 16584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski animation.cancel(); 16684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 16784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 16884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 16984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 17084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski @Override 17184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski public void onAnimationStart(Animator animation) { 1725658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget 1735658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale + " mReplacement=" + mReplacement); 174f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr mFinishAnimationAfterTransition = false; 17569016e3472e9ba1144bfccd0217f7cf73b84f9efRobert Carr // Ensure that we have prepared the target for animation before 17669016e3472e9ba1144bfccd0217f7cf73b84f9efRobert Carr // we trigger any size changes, so it can swap surfaces 17769016e3472e9ba1144bfccd0217f7cf73b84f9efRobert Carr // in to appropriate modes, or do as it wishes otherwise. 178ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale if (!mReplacement) { 179ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale mTarget.onAnimationStart(); 180ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale } 1811ca6a33f36357281b3445e85d9e67cacd1a12edeRobert Carr 18269016e3472e9ba1144bfccd0217f7cf73b84f9efRobert Carr // Immediately update the task bounds if they have to become larger, but preserve 18369016e3472e9ba1144bfccd0217f7cf73b84f9efRobert Carr // the starting position so we don't jump at the beginning of the animation. 1841ca6a33f36357281b3445e85d9e67cacd1a12edeRobert Carr if (animatingToLargerSize()) { 18569016e3472e9ba1144bfccd0217f7cf73b84f9efRobert Carr mTmpRect.set(mFrom.left, mFrom.top, 18669016e3472e9ba1144bfccd0217f7cf73b84f9efRobert Carr mFrom.left + mFrozenTaskWidth, mFrom.top + mFrozenTaskHeight); 18769016e3472e9ba1144bfccd0217f7cf73b84f9efRobert Carr mTarget.setPinnedStackSize(mFrom, mTmpRect); 1881ca6a33f36357281b3445e85d9e67cacd1a12edeRobert Carr } 18984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 19084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 19184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski @Override 19284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski public void onAnimationEnd(Animator animation) { 1935658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget 1945658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale + " mMoveToFullScreen=" + mMoveToFullScreen + " mWillReplace=" + mWillReplace); 195b003364bc7e31e7f85865ef298d399ed61c372a2Jaewan Kim 196f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr // There could be another animation running. For example in the 197f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr // move to fullscreen case, recents will also be closing while the 198f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr // previous task will be taking its place in the fullscreen stack. 199f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr // we have to ensure this is completed before we finish the animation 200f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr // and take our place in the fullscreen stack. 201f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr if (mAppTransition.isRunning() && !mFinishAnimationAfterTransition) { 202f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr mFinishAnimationAfterTransition = true; 203f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr return; 204f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr } 205f9aa2a966eefb464775287aa4966c82641fac5f1Robert Carr 206c7294607fc0debc54e92abac18bec2601a21ce27Robert Carr finishAnimation(); 207c7294607fc0debc54e92abac18bec2601a21ce27Robert Carr 208c7294607fc0debc54e92abac18bec2601a21ce27Robert Carr mTarget.setPinnedStackSize(mTo, null); 209ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale if (mMoveToFullScreen && !mWillReplace) { 210c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski mTarget.moveToFullscreen(); 211c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski } 21284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 21384fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 21484fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski @Override 21584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski public void onAnimationCancel(Animator animation) { 21684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski finishAnimation(); 21784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 21884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 219ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale @Override 220ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale public void cancel() { 221ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale mWillReplace = true; 2225658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale if (DEBUG) Slog.d(TAG, "cancel: willReplace mTarget=" + mTarget); 223ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale super.cancel(); 224ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale } 225ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale 2265658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale /** Returns true if the animation target is the same as the input bounds. */ 2275658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale public boolean isAnimatingTo(Rect bounds) { 2285658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale return mTo.equals(bounds); 2295658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale } 2305658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale 23184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski private void finishAnimation() { 2325658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale if (DEBUG) Slog.d(TAG, "finishAnimation: mTarget=" + mTarget 2335658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale + " callers" + Debug.getCallers(2)); 234ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale if (!mWillReplace) { 235ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale mTarget.onAnimationEnd(); 236ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale } 23784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski removeListener(this); 23884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski removeUpdateListener(this); 23984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski mRunningAnimations.remove(mTarget); 24084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 24184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 24284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski @Override 24384fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski public void onAnimationRepeat(Animator animation) { 24484fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 24584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 24684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 24784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 24884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski public interface AnimateBoundsUser { 24984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski /** 25084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * Asks the target to directly (without any intermediate steps, like scheduling animation) 25184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * resize its bounds. 25284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * 25384fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * @return Whether the target still wants to be animated and successfully finished the 25484fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * operation. If it returns false, the animation will immediately be cancelled. The target 25584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * should return false when something abnormal happened, e.g. it was completely removed 25684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * from the hierarchy and is not valid anymore. 25784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski */ 25884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski boolean setSize(Rect bounds); 2590d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr /** 2600d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr * Behaves as setSize, but freezes the bounds of any tasks in the target at taskBounds, 2610d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr * to allow for more flexibility during resizing. Only 2620d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr * works for the pinned stack at the moment. 2630d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr */ 2640d00c2e25bf8816dbd99f4fcd5c8221e80826a95Robert Carr boolean setPinnedStackSize(Rect bounds, Rect taskBounds); 26584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 266ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale void onAnimationStart(); 267ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale 26884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski /** 269ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale * Callback for the target to inform it that the animation has ended, so it can do some 27084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski * necessary cleanup. 27184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski */ 272ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale void onAnimationEnd(); 273c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski 274c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski void moveToFullscreen(); 275c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski 276c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski void getFullScreenBounds(Rect bounds); 27784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 27884fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski 279e75a9adfbd37f9ec1a9324caceb9d5d7ceed217cWale Ogunwale void animateBounds(final AnimateBoundsUser target, Rect from, Rect to, int animationDuration) { 280c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski boolean moveToFullscreen = false; 281c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski if (to == null) { 282c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski to = new Rect(); 283c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski target.getFullScreenBounds(to); 284c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski moveToFullscreen = true; 285c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski } 286c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski 28784fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski final BoundsAnimator existing = mRunningAnimations.get(target); 288ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale final boolean replacing = existing != null; 2895658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale 2905658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale if (DEBUG) Slog.d(TAG, "animateBounds: target=" + target + " from=" + from + " to=" + to 2915658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale + " moveToFullscreen=" + moveToFullscreen + " replacing=" + replacing); 2925658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale 293ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale if (replacing) { 2945658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale if (existing.isAnimatingTo(to)) { 2955658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale // Just les the current animation complete if it has the same destination as the 2965658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale // one we are trying to start. 2975658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale if (DEBUG) Slog.d(TAG, "animateBounds: same destination as existing=" + existing 2985658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale + " ignoring..."); 2995658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale return; 3005658e4b94de91e938459e50d0f5e6ef837ffb4acWale Ogunwale } 30184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski existing.cancel(); 30284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 303ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale final BoundsAnimator animator = 304ce14452a27acf0492d799ec88c619add3a630a88Wale Ogunwale new BoundsAnimator(target, from, to, moveToFullscreen, replacing); 30584fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski mRunningAnimations.put(target, animator); 30684fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski animator.setFloatValues(0f, 1f); 307e75a9adfbd37f9ec1a9324caceb9d5d7ceed217cWale Ogunwale animator.setDuration((animationDuration != -1 ? animationDuration 308e75a9adfbd37f9ec1a9324caceb9d5d7ceed217cWale Ogunwale : DEFAULT_APP_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR); 30984fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski animator.setInterpolator(new LinearInterpolator()); 31084fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski animator.start(); 31184fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski } 31284fa3351a21b37d02fafd634a8de65cf6cd04c4dFilip Gruszczynski} 313