Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2011 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 
     17 package com.android.server.wm;
     18 
     19 import static android.view.WindowManagerInternal.AppTransitionListener;
     20 import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
     21 import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
     22 import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
     23 import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
     24 import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
     25 import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
     26 import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
     27 import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
     28 import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
     29 import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
     30 import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
     31 import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
     32 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
     33 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
     34 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
     35 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
     36 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
     37 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
     38 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
     39 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
     40 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
     41 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
     42 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
     43 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
     44 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
     45 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     46 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     47 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
     48 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
     49 
     50 import android.annotation.Nullable;
     51 import android.content.Context;
     52 import android.content.res.Configuration;
     53 import android.graphics.Bitmap;
     54 import android.graphics.Path;
     55 import android.graphics.Rect;
     56 import android.os.Debug;
     57 import android.os.IBinder;
     58 import android.os.IRemoteCallback;
     59 import android.os.RemoteException;
     60 import android.util.ArraySet;
     61 import android.util.Slog;
     62 import android.util.SparseArray;
     63 import android.view.AppTransitionAnimationSpec;
     64 import android.view.IAppTransitionAnimationSpecsFuture;
     65 import android.view.WindowManager;
     66 import android.view.animation.AlphaAnimation;
     67 import android.view.animation.Animation;
     68 import android.view.animation.AnimationSet;
     69 import android.view.animation.AnimationUtils;
     70 import android.view.animation.ClipRectAnimation;
     71 import android.view.animation.Interpolator;
     72 import android.view.animation.PathInterpolator;
     73 import android.view.animation.ScaleAnimation;
     74 import android.view.animation.TranslateAnimation;
     75 
     76 import com.android.internal.util.DumpUtils.Dump;
     77 import com.android.server.AttributeCache;
     78 import com.android.server.wm.WindowManagerService.H;
     79 import com.android.server.wm.animation.ClipRectLRAnimation;
     80 import com.android.server.wm.animation.ClipRectTBAnimation;
     81 import com.android.server.wm.animation.CurvedTranslateAnimation;
     82 
     83 import java.io.PrintWriter;
     84 import java.util.ArrayList;
     85 import java.util.concurrent.ExecutorService;
     86 import java.util.concurrent.Executors;
     87 
     88 // State management of app transitions.  When we are preparing for a
     89 // transition, mNextAppTransition will be the kind of transition to
     90 // perform or TRANSIT_NONE if we are not waiting.  If we are waiting,
     91 // mOpeningApps and mClosingApps are the lists of tokens that will be
     92 // made visible or hidden at the next transition.
     93 public class AppTransition implements Dump {
     94     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM;
     95     private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8;
     96 
     97     /** Not set up for a transition. */
     98     public static final int TRANSIT_UNSET = -1;
     99     /** No animation for transition. */
    100     public static final int TRANSIT_NONE = 0;
    101     /** A window in a new activity is being opened on top of an existing one in the same task. */
    102     public static final int TRANSIT_ACTIVITY_OPEN = 6;
    103     /** The window in the top-most activity is being closed to reveal the
    104      * previous activity in the same task. */
    105     public static final int TRANSIT_ACTIVITY_CLOSE = 7;
    106     /** A window in a new task is being opened on top of an existing one
    107      * in another activity's task. */
    108     public static final int TRANSIT_TASK_OPEN = 8;
    109     /** A window in the top-most activity is being closed to reveal the
    110      * previous activity in a different task. */
    111     public static final int TRANSIT_TASK_CLOSE = 9;
    112     /** A window in an existing task is being displayed on top of an existing one
    113      * in another activity's task. */
    114     public static final int TRANSIT_TASK_TO_FRONT = 10;
    115     /** A window in an existing task is being put below all other tasks. */
    116     public static final int TRANSIT_TASK_TO_BACK = 11;
    117     /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that
    118      * does, effectively closing the wallpaper. */
    119     public static final int TRANSIT_WALLPAPER_CLOSE = 12;
    120     /** A window in a new activity that does have a wallpaper is being opened on one that didn't,
    121      * effectively opening the wallpaper. */
    122     public static final int TRANSIT_WALLPAPER_OPEN = 13;
    123     /** A window in a new activity is being opened on top of an existing one, and both are on top
    124      * of the wallpaper. */
    125     public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14;
    126     /** The window in the top-most activity is being closed to reveal the previous activity, and
    127      * both are on top of the wallpaper. */
    128     public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15;
    129     /** A window in a new task is being opened behind an existing one in another activity's task.
    130      * The new window will show briefly and then be gone. */
    131     public static final int TRANSIT_TASK_OPEN_BEHIND = 16;
    132     /** A window in a task is being animated in-place. */
    133     public static final int TRANSIT_TASK_IN_PLACE = 17;
    134     /** An activity is being relaunched (e.g. due to configuration change). */
    135     public static final int TRANSIT_ACTIVITY_RELAUNCH = 18;
    136     /** A task is being docked from recents. */
    137     public static final int TRANSIT_DOCK_TASK_FROM_RECENTS = 19;
    138 
    139     /** Fraction of animation at which the recents thumbnail stays completely transparent */
    140     private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
    141     /** Fraction of animation at which the recents thumbnail becomes completely transparent */
    142     private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
    143 
    144     static final int DEFAULT_APP_TRANSITION_DURATION = 336;
    145 
    146     /** Interpolator to be used for animations that respond directly to a touch */
    147     static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
    148             new PathInterpolator(0.3f, 0f, 0.1f, 1f);
    149 
    150     private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR =
    151             new PathInterpolator(0.85f, 0f, 1f, 1f);
    152 
    153     /**
    154      * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
    155      * involved, to make it more understandable.
    156      */
    157     private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
    158     private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
    159     private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
    160 
    161     private final Context mContext;
    162     private final WindowManagerService mService;
    163 
    164     private int mNextAppTransition = TRANSIT_UNSET;
    165 
    166     private static final int NEXT_TRANSIT_TYPE_NONE = 0;
    167     private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
    168     private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
    169     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
    170     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
    171     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
    172     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
    173     private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
    174     private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
    175     private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
    176 
    177     // These are the possible states for the enter/exit activities during a thumbnail transition
    178     private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
    179     private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
    180     private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
    181     private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
    182 
    183     private String mNextAppTransitionPackage;
    184     // Used for thumbnail transitions. True if we're scaling up, false if scaling down
    185     private boolean mNextAppTransitionScaleUp;
    186     private IRemoteCallback mNextAppTransitionCallback;
    187     private IRemoteCallback mNextAppTransitionFutureCallback;
    188     private IRemoteCallback mAnimationFinishedCallback;
    189     private int mNextAppTransitionEnter;
    190     private int mNextAppTransitionExit;
    191     private int mNextAppTransitionInPlace;
    192 
    193     // Keyed by task id.
    194     private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
    195             = new SparseArray<>();
    196     private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
    197     private boolean mNextAppTransitionAnimationsSpecsPending;
    198     private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
    199 
    200     private Rect mNextAppTransitionInsets = new Rect();
    201 
    202     private Rect mTmpFromClipRect = new Rect();
    203     private Rect mTmpToClipRect = new Rect();
    204 
    205     private final Rect mTmpRect = new Rect();
    206 
    207     private final static int APP_STATE_IDLE = 0;
    208     private final static int APP_STATE_READY = 1;
    209     private final static int APP_STATE_RUNNING = 2;
    210     private final static int APP_STATE_TIMEOUT = 3;
    211     private int mAppTransitionState = APP_STATE_IDLE;
    212 
    213     private final int mConfigShortAnimTime;
    214     private final Interpolator mDecelerateInterpolator;
    215     private final Interpolator mThumbnailFadeInInterpolator;
    216     private final Interpolator mThumbnailFadeOutInterpolator;
    217     private final Interpolator mLinearOutSlowInInterpolator;
    218     private final Interpolator mFastOutLinearInInterpolator;
    219     private final Interpolator mFastOutSlowInInterpolator;
    220     private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
    221 
    222     private final int mClipRevealTranslationY;
    223 
    224     private int mCurrentUserId = 0;
    225     private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
    226 
    227     private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
    228     private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
    229 
    230     private int mLastClipRevealMaxTranslation;
    231     private boolean mLastHadClipReveal;
    232     private boolean mProlongedAnimationsEnded;
    233 
    234     AppTransition(Context context, WindowManagerService service) {
    235         mContext = context;
    236         mService = service;
    237         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
    238                 com.android.internal.R.interpolator.linear_out_slow_in);
    239         mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
    240                 com.android.internal.R.interpolator.fast_out_linear_in);
    241         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
    242                 com.android.internal.R.interpolator.fast_out_slow_in);
    243         mConfigShortAnimTime = context.getResources().getInteger(
    244                 com.android.internal.R.integer.config_shortAnimTime);
    245         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
    246                 com.android.internal.R.interpolator.decelerate_cubic);
    247         mThumbnailFadeInInterpolator = new Interpolator() {
    248             @Override
    249             public float getInterpolation(float input) {
    250                 // Linear response for first fraction, then complete after that.
    251                 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
    252                     return 0f;
    253                 }
    254                 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /
    255                         (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
    256                 return mFastOutLinearInInterpolator.getInterpolation(t);
    257             }
    258         };
    259         mThumbnailFadeOutInterpolator = new Interpolator() {
    260             @Override
    261             public float getInterpolation(float input) {
    262                 // Linear response for first fraction, then complete after that.
    263                 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
    264                     float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
    265                     return mLinearOutSlowInInterpolator.getInterpolation(t);
    266                 }
    267                 return 1f;
    268             }
    269         };
    270         mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP
    271                 * mContext.getResources().getDisplayMetrics().density);
    272     }
    273 
    274     boolean isTransitionSet() {
    275         return mNextAppTransition != TRANSIT_UNSET;
    276     }
    277 
    278     boolean isTransitionEqual(int transit) {
    279         return mNextAppTransition == transit;
    280     }
    281 
    282     int getAppTransition() {
    283         return mNextAppTransition;
    284      }
    285 
    286     private void setAppTransition(int transit) {
    287         mNextAppTransition = transit;
    288     }
    289 
    290     boolean isReady() {
    291         return mAppTransitionState == APP_STATE_READY
    292                 || mAppTransitionState == APP_STATE_TIMEOUT;
    293     }
    294 
    295     void setReady() {
    296         mAppTransitionState = APP_STATE_READY;
    297         fetchAppTransitionSpecsFromFuture();
    298     }
    299 
    300     boolean isRunning() {
    301         return mAppTransitionState == APP_STATE_RUNNING;
    302     }
    303 
    304     void setIdle() {
    305         mAppTransitionState = APP_STATE_IDLE;
    306     }
    307 
    308     boolean isTimeout() {
    309         return mAppTransitionState == APP_STATE_TIMEOUT;
    310     }
    311 
    312     void setTimeout() {
    313         mAppTransitionState = APP_STATE_TIMEOUT;
    314     }
    315 
    316     Bitmap getAppTransitionThumbnailHeader(int taskId) {
    317         AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
    318         if (spec == null) {
    319             spec = mDefaultNextAppTransitionAnimationSpec;
    320         }
    321         return spec != null ? spec.bitmap : null;
    322     }
    323 
    324     /** Returns whether the next thumbnail transition is aspect scaled up. */
    325     boolean isNextThumbnailTransitionAspectScaled() {
    326         return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
    327                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
    328     }
    329 
    330     /** Returns whether the next thumbnail transition is scaling up. */
    331     boolean isNextThumbnailTransitionScaleUp() {
    332         return mNextAppTransitionScaleUp;
    333     }
    334 
    335     boolean isNextAppTransitionThumbnailUp() {
    336         return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
    337                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP;
    338     }
    339 
    340     boolean isNextAppTransitionThumbnailDown() {
    341         return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN ||
    342                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
    343     }
    344 
    345     /**
    346      * @return true if and only if we are currently fetching app transition specs from the future
    347      *         passed into {@link #overridePendingAppTransitionMultiThumbFuture}
    348      */
    349     boolean isFetchingAppTransitionsSpecs() {
    350         return mNextAppTransitionAnimationsSpecsPending;
    351     }
    352 
    353     private boolean prepare() {
    354         if (!isRunning()) {
    355             mAppTransitionState = APP_STATE_IDLE;
    356             notifyAppTransitionPendingLocked();
    357             mLastHadClipReveal = false;
    358             mLastClipRevealMaxTranslation = 0;
    359             mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
    360             return true;
    361         }
    362         return false;
    363     }
    364 
    365     void goodToGo(AppWindowAnimator topOpeningAppAnimator, AppWindowAnimator topClosingAppAnimator,
    366             ArraySet<AppWindowToken> openingApps, ArraySet<AppWindowToken> closingApps) {
    367         mNextAppTransition = TRANSIT_UNSET;
    368         mAppTransitionState = APP_STATE_RUNNING;
    369         notifyAppTransitionStartingLocked(
    370                 topOpeningAppAnimator != null ? topOpeningAppAnimator.mAppToken.token : null,
    371                 topClosingAppAnimator != null ? topClosingAppAnimator.mAppToken.token : null,
    372                 topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null,
    373                 topClosingAppAnimator != null ? topClosingAppAnimator.animation : null);
    374         mService.getDefaultDisplayContentLocked().getDockedDividerController()
    375                 .notifyAppTransitionStarting();
    376 
    377         // Prolong the start for the transition when docking a task from recents, unless recents
    378         // ended it already then we don't need to wait.
    379         if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) {
    380             for (int i = openingApps.size() - 1; i >= 0; i--) {
    381                 final AppWindowAnimator appAnimator = openingApps.valueAt(i).mAppAnimator;
    382                 appAnimator.startProlongAnimation(PROLONG_ANIMATION_AT_START);
    383             }
    384         }
    385     }
    386 
    387     /**
    388      * Let the transitions manager know that the somebody wanted to end the prolonged animations.
    389      */
    390     void notifyProlongedAnimationsEnded() {
    391         mProlongedAnimationsEnded = true;
    392     }
    393 
    394     void clear() {
    395         mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
    396         mNextAppTransitionPackage = null;
    397         mNextAppTransitionAnimationsSpecs.clear();
    398         mNextAppTransitionAnimationsSpecsFuture = null;
    399         mDefaultNextAppTransitionAnimationSpec = null;
    400         mAnimationFinishedCallback = null;
    401         mProlongedAnimationsEnded = false;
    402     }
    403 
    404     void freeze() {
    405         setAppTransition(AppTransition.TRANSIT_UNSET);
    406         clear();
    407         setReady();
    408         notifyAppTransitionCancelledLocked();
    409     }
    410 
    411     void registerListenerLocked(AppTransitionListener listener) {
    412         mListeners.add(listener);
    413     }
    414 
    415     public void notifyAppTransitionFinishedLocked(IBinder token) {
    416         for (int i = 0; i < mListeners.size(); i++) {
    417             mListeners.get(i).onAppTransitionFinishedLocked(token);
    418         }
    419     }
    420 
    421     private void notifyAppTransitionPendingLocked() {
    422         for (int i = 0; i < mListeners.size(); i++) {
    423             mListeners.get(i).onAppTransitionPendingLocked();
    424         }
    425     }
    426 
    427     private void notifyAppTransitionCancelledLocked() {
    428         for (int i = 0; i < mListeners.size(); i++) {
    429             mListeners.get(i).onAppTransitionCancelledLocked();
    430         }
    431     }
    432 
    433     private void notifyAppTransitionStartingLocked(IBinder openToken,
    434             IBinder closeToken, Animation openAnimation, Animation closeAnimation) {
    435         for (int i = 0; i < mListeners.size(); i++) {
    436             mListeners.get(i).onAppTransitionStartingLocked(openToken, closeToken, openAnimation,
    437                     closeAnimation);
    438         }
    439     }
    440 
    441     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
    442         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
    443                 + (lp != null ? lp.packageName : null)
    444                 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
    445         if (lp != null && lp.windowAnimations != 0) {
    446             // If this is a system resource, don't try to load it from the
    447             // application resources.  It is nice to avoid loading application
    448             // resources if we can.
    449             String packageName = lp.packageName != null ? lp.packageName : "android";
    450             int resId = lp.windowAnimations;
    451             if ((resId&0xFF000000) == 0x01000000) {
    452                 packageName = "android";
    453             }
    454             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
    455                     + packageName);
    456             return AttributeCache.instance().get(packageName, resId,
    457                     com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
    458         }
    459         return null;
    460     }
    461 
    462     private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
    463         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
    464                 + packageName + " resId=0x" + Integer.toHexString(resId));
    465         if (packageName != null) {
    466             if ((resId&0xFF000000) == 0x01000000) {
    467                 packageName = "android";
    468             }
    469             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
    470                     + packageName);
    471             return AttributeCache.instance().get(packageName, resId,
    472                     com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
    473         }
    474         return null;
    475     }
    476 
    477     Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) {
    478         int anim = 0;
    479         Context context = mContext;
    480         if (animAttr >= 0) {
    481             AttributeCache.Entry ent = getCachedAnimations(lp);
    482             if (ent != null) {
    483                 context = ent.context;
    484                 anim = ent.array.getResourceId(animAttr, 0);
    485             }
    486         }
    487         if (anim != 0) {
    488             return AnimationUtils.loadAnimation(context, anim);
    489         }
    490         return null;
    491     }
    492 
    493     Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) {
    494         Context context = mContext;
    495         if (resId >= 0) {
    496             AttributeCache.Entry ent = getCachedAnimations(lp);
    497             if (ent != null) {
    498                 context = ent.context;
    499             }
    500             return AnimationUtils.loadAnimation(context, resId);
    501         }
    502         return null;
    503     }
    504 
    505     private Animation loadAnimationRes(String packageName, int resId) {
    506         int anim = 0;
    507         Context context = mContext;
    508         if (resId >= 0) {
    509             AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
    510             if (ent != null) {
    511                 context = ent.context;
    512                 anim = resId;
    513             }
    514         }
    515         if (anim != 0) {
    516             return AnimationUtils.loadAnimation(context, anim);
    517         }
    518         return null;
    519     }
    520 
    521     /**
    522      * Compute the pivot point for an animation that is scaling from a small
    523      * rect on screen to a larger rect.  The pivot point varies depending on
    524      * the distance between the inner and outer edges on both sides.  This
    525      * function computes the pivot point for one dimension.
    526      * @param startPos  Offset from left/top edge of outer rectangle to
    527      * left/top edge of inner rectangle.
    528      * @param finalScale The scaling factor between the size of the outer
    529      * and inner rectangles.
    530      */
    531     private static float computePivot(int startPos, float finalScale) {
    532 
    533         /*
    534         Theorem of intercepting lines:
    535 
    536           +      +   +-----------------------------------------------+
    537           |      |   |                                               |
    538           |      |   |                                               |
    539           |      |   |                                               |
    540           |      |   |                                               |
    541         x |    y |   |                                               |
    542           |      |   |                                               |
    543           |      |   |                                               |
    544           |      |   |                                               |
    545           |      |   |                                               |
    546           |      +   |             +--------------------+            |
    547           |          |             |                    |            |
    548           |          |             |                    |            |
    549           |          |             |                    |            |
    550           |          |             |                    |            |
    551           |          |             |                    |            |
    552           |          |             |                    |            |
    553           |          |             |                    |            |
    554           |          |             |                    |            |
    555           |          |             |                    |            |
    556           |          |             |                    |            |
    557           |          |             |                    |            |
    558           |          |             |                    |            |
    559           |          |             |                    |            |
    560           |          |             |                    |            |
    561           |          |             |                    |            |
    562           |          |             |                    |            |
    563           |          |             |                    |            |
    564           |          |             +--------------------+            |
    565           |          |                                               |
    566           |          |                                               |
    567           |          |                                               |
    568           |          |                                               |
    569           |          |                                               |
    570           |          |                                               |
    571           |          |                                               |
    572           |          +-----------------------------------------------+
    573           |
    574           |
    575           |
    576           |
    577           |
    578           |
    579           |
    580           |
    581           |
    582           +                                 ++
    583                                          p  ++
    584 
    585         scale = (x - y) / x
    586         <=> x = -y / (scale - 1)
    587         */
    588         final float denom = finalScale-1;
    589         if (Math.abs(denom) < .0001f) {
    590             return startPos;
    591         }
    592         return -startPos / denom;
    593     }
    594 
    595     private Animation createScaleUpAnimationLocked(int transit, boolean enter,
    596             Rect containingFrame) {
    597         Animation a;
    598         getDefaultNextAppTransitionStartRect(mTmpRect);
    599         final int appWidth = containingFrame.width();
    600         final int appHeight = containingFrame.height();
    601         if (enter) {
    602             // Entering app zooms out from the center of the initial rect.
    603             float scaleW = mTmpRect.width() / (float) appWidth;
    604             float scaleH = mTmpRect.height() / (float) appHeight;
    605             Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
    606                     computePivot(mTmpRect.left, scaleW),
    607                     computePivot(mTmpRect.right, scaleH));
    608             scale.setInterpolator(mDecelerateInterpolator);
    609 
    610             Animation alpha = new AlphaAnimation(0, 1);
    611             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
    612 
    613             AnimationSet set = new AnimationSet(false);
    614             set.addAnimation(scale);
    615             set.addAnimation(alpha);
    616             set.setDetachWallpaper(true);
    617             a = set;
    618         } else  if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
    619                     transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
    620             // If we are on top of the wallpaper, we need an animation that
    621             // correctly handles the wallpaper staying static behind all of
    622             // the animated elements.  To do this, will just have the existing
    623             // element fade out.
    624             a = new AlphaAnimation(1, 0);
    625             a.setDetachWallpaper(true);
    626         } else {
    627             // For normal animations, the exiting element just holds in place.
    628             a = new AlphaAnimation(1, 1);
    629         }
    630 
    631         // Pick the desired duration.  If this is an inter-activity transition,
    632         // it  is the standard duration for that.  Otherwise we use the longer
    633         // task transition duration.
    634         final long duration;
    635         switch (transit) {
    636             case TRANSIT_ACTIVITY_OPEN:
    637             case TRANSIT_ACTIVITY_CLOSE:
    638                 duration = mConfigShortAnimTime;
    639                 break;
    640             default:
    641                 duration = DEFAULT_APP_TRANSITION_DURATION;
    642                 break;
    643         }
    644         a.setDuration(duration);
    645         a.setFillAfter(true);
    646         a.setInterpolator(mDecelerateInterpolator);
    647         a.initialize(appWidth, appHeight, appWidth, appHeight);
    648         return a;
    649     }
    650 
    651     private void getDefaultNextAppTransitionStartRect(Rect rect) {
    652         if (mDefaultNextAppTransitionAnimationSpec == null ||
    653                 mDefaultNextAppTransitionAnimationSpec.rect == null) {
    654             Slog.wtf(TAG, "Starting rect for app requested, but none available", new Throwable());
    655             rect.setEmpty();
    656         } else {
    657             rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
    658         }
    659     }
    660 
    661     void getNextAppTransitionStartRect(int taskId, Rect rect) {
    662         AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
    663         if (spec == null) {
    664             spec = mDefaultNextAppTransitionAnimationSpec;
    665         }
    666         if (spec == null || spec.rect == null) {
    667             Slog.wtf(TAG, "Starting rect for task: " + taskId + " requested, but not available",
    668                     new Throwable());
    669             rect.setEmpty();
    670         } else {
    671             rect.set(spec.rect);
    672         }
    673     }
    674 
    675     private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height,
    676             Bitmap bitmap) {
    677         mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
    678                 bitmap, new Rect(left, top, left + width, top + height));
    679     }
    680 
    681     /**
    682      * @return the duration of the last clip reveal animation
    683      */
    684     long getLastClipRevealTransitionDuration() {
    685         return mLastClipRevealTransitionDuration;
    686     }
    687 
    688     /**
    689      * @return the maximum distance the app surface is traveling of the last clip reveal animation
    690      */
    691     int getLastClipRevealMaxTranslation() {
    692         return mLastClipRevealMaxTranslation;
    693     }
    694 
    695     /**
    696      * @return true if in the last app transition had a clip reveal animation, false otherwise
    697      */
    698     boolean hadClipRevealAnimation() {
    699         return mLastHadClipReveal;
    700     }
    701 
    702     /**
    703      * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
    704      * the start rect is outside of the target rect, and there is a lot of movement going on.
    705      *
    706      * @param cutOff whether the start rect was not fully contained by the end rect
    707      * @param translationX the total translation the surface moves in x direction
    708      * @param translationY the total translation the surfaces moves in y direction
    709      * @param displayFrame our display frame
    710      *
    711      * @return the duration of the clip reveal animation, in milliseconds
    712      */
    713     private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX,
    714             float translationY, Rect displayFrame) {
    715         if (!cutOff) {
    716             return DEFAULT_APP_TRANSITION_DURATION;
    717         }
    718         final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(),
    719                 Math.abs(translationY) / displayFrame.height());
    720         return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction *
    721                 (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION));
    722     }
    723 
    724     private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame,
    725             Rect displayFrame) {
    726         final Animation anim;
    727         if (enter) {
    728             final int appWidth = appFrame.width();
    729             final int appHeight = appFrame.height();
    730 
    731             // mTmpRect will contain an area around the launcher icon that was pressed. We will
    732             // clip reveal from that area in the final area of the app.
    733             getDefaultNextAppTransitionStartRect(mTmpRect);
    734 
    735             float t = 0f;
    736             if (appHeight > 0) {
    737                 t = (float) mTmpRect.top / displayFrame.height();
    738             }
    739             int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t);
    740             int translationX = 0;
    741             int translationYCorrection = translationY;
    742             int centerX = mTmpRect.centerX();
    743             int centerY = mTmpRect.centerY();
    744             int halfWidth = mTmpRect.width() / 2;
    745             int halfHeight = mTmpRect.height() / 2;
    746             int clipStartX = centerX - halfWidth - appFrame.left;
    747             int clipStartY = centerY - halfHeight - appFrame.top;
    748             boolean cutOff = false;
    749 
    750             // If the starting rectangle is fully or partially outside of the target rectangle, we
    751             // need to start the clipping at the edge and then achieve the rest with translation
    752             // and extending the clip rect from that edge.
    753             if (appFrame.top > centerY - halfHeight) {
    754                 translationY = (centerY - halfHeight) - appFrame.top;
    755                 translationYCorrection = 0;
    756                 clipStartY = 0;
    757                 cutOff = true;
    758             }
    759             if (appFrame.left > centerX - halfWidth) {
    760                 translationX = (centerX - halfWidth) - appFrame.left;
    761                 clipStartX = 0;
    762                 cutOff = true;
    763             }
    764             if (appFrame.right < centerX + halfWidth) {
    765                 translationX = (centerX + halfWidth) - appFrame.right;
    766                 clipStartX = appWidth - mTmpRect.width();
    767                 cutOff = true;
    768             }
    769             final long duration = calculateClipRevealTransitionDuration(cutOff, translationX,
    770                     translationY, displayFrame);
    771 
    772             // Clip third of the from size of launch icon, expand to full width/height
    773             Animation clipAnimLR = new ClipRectLRAnimation(
    774                     clipStartX, clipStartX + mTmpRect.width(), 0, appWidth);
    775             clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
    776             clipAnimLR.setDuration((long) (duration / 2.5f));
    777 
    778             TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0);
    779             translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR
    780                     : mLinearOutSlowInInterpolator);
    781             translate.setDuration(duration);
    782 
    783             Animation clipAnimTB = new ClipRectTBAnimation(
    784                     clipStartY, clipStartY + mTmpRect.height(),
    785                     0, appHeight,
    786                     translationYCorrection, 0,
    787                     mLinearOutSlowInInterpolator);
    788             clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
    789             clipAnimTB.setDuration(duration);
    790 
    791             // Quick fade-in from icon to app window
    792             final long alphaDuration = duration / 4;
    793             AlphaAnimation alpha = new AlphaAnimation(0.5f, 1);
    794             alpha.setDuration(alphaDuration);
    795             alpha.setInterpolator(mLinearOutSlowInInterpolator);
    796 
    797             AnimationSet set = new AnimationSet(false);
    798             set.addAnimation(clipAnimLR);
    799             set.addAnimation(clipAnimTB);
    800             set.addAnimation(translate);
    801             set.addAnimation(alpha);
    802             set.setZAdjustment(Animation.ZORDER_TOP);
    803             set.initialize(appWidth, appHeight, appWidth, appHeight);
    804             anim = set;
    805             mLastHadClipReveal = true;
    806             mLastClipRevealTransitionDuration = duration;
    807 
    808             // If the start rect was full inside the target rect (cutOff == false), we don't need
    809             // to store the translation, because it's only used if cutOff == true.
    810             mLastClipRevealMaxTranslation = cutOff
    811                     ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0;
    812         } else {
    813             final long duration;
    814             switch (transit) {
    815                 case TRANSIT_ACTIVITY_OPEN:
    816                 case TRANSIT_ACTIVITY_CLOSE:
    817                     duration = mConfigShortAnimTime;
    818                     break;
    819                 default:
    820                     duration = DEFAULT_APP_TRANSITION_DURATION;
    821                     break;
    822             }
    823             if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
    824                     transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
    825                 // If we are on top of the wallpaper, we need an animation that
    826                 // correctly handles the wallpaper staying static behind all of
    827                 // the animated elements.  To do this, will just have the existing
    828                 // element fade out.
    829                 anim = new AlphaAnimation(1, 0);
    830                 anim.setDetachWallpaper(true);
    831             } else {
    832                 // For normal animations, the exiting element just holds in place.
    833                 anim = new AlphaAnimation(1, 1);
    834             }
    835             anim.setInterpolator(mDecelerateInterpolator);
    836             anim.setDuration(duration);
    837             anim.setFillAfter(true);
    838         }
    839         return anim;
    840     }
    841 
    842     /**
    843      * Prepares the specified animation with a standard duration, interpolator, etc.
    844      */
    845     Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
    846             long duration, Interpolator interpolator) {
    847         if (duration > 0) {
    848             a.setDuration(duration);
    849         }
    850         a.setFillAfter(true);
    851         if (interpolator != null) {
    852             a.setInterpolator(interpolator);
    853         }
    854         a.initialize(appWidth, appHeight, appWidth, appHeight);
    855         return a;
    856     }
    857 
    858     /**
    859      * Prepares the specified animation with a standard duration, interpolator, etc.
    860      */
    861     Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
    862         // Pick the desired duration.  If this is an inter-activity transition,
    863         // it  is the standard duration for that.  Otherwise we use the longer
    864         // task transition duration.
    865         final int duration;
    866         switch (transit) {
    867             case TRANSIT_ACTIVITY_OPEN:
    868             case TRANSIT_ACTIVITY_CLOSE:
    869                 duration = mConfigShortAnimTime;
    870                 break;
    871             default:
    872                 duration = DEFAULT_APP_TRANSITION_DURATION;
    873                 break;
    874         }
    875         return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
    876                 mDecelerateInterpolator);
    877     }
    878 
    879     /**
    880      * Return the current thumbnail transition state.
    881      */
    882     int getThumbnailTransitionState(boolean enter) {
    883         if (enter) {
    884             if (mNextAppTransitionScaleUp) {
    885                 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
    886             } else {
    887                 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
    888             }
    889         } else {
    890             if (mNextAppTransitionScaleUp) {
    891                 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
    892             } else {
    893                 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
    894             }
    895         }
    896     }
    897 
    898     /**
    899      * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
    900      * when a thumbnail is specified with the pending animation override.
    901      */
    902     Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
    903             Bitmap thumbnailHeader, final int taskId, int uiMode, int orientation) {
    904         Animation a;
    905         final int thumbWidthI = thumbnailHeader.getWidth();
    906         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
    907         final int thumbHeightI = thumbnailHeader.getHeight();
    908         final int appWidth = appRect.width();
    909 
    910         float scaleW = appWidth / thumbWidth;
    911         getNextAppTransitionStartRect(taskId, mTmpRect);
    912         final float fromX;
    913         final float fromY;
    914         final float toX;
    915         final float toY;
    916         final float pivotX;
    917         final float pivotY;
    918         if (isTvUiMode(uiMode) || orientation == Configuration.ORIENTATION_PORTRAIT) {
    919             fromX = mTmpRect.left;
    920             fromY = mTmpRect.top;
    921 
    922             // For the curved translate animation to work, the pivot points needs to be at the
    923             // same absolute position as the one from the real surface.
    924             toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
    925             toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
    926             pivotX = mTmpRect.width() / 2;
    927             pivotY = appRect.height() / 2 / scaleW;
    928         } else {
    929             pivotX = 0;
    930             pivotY = 0;
    931             fromX = mTmpRect.left;
    932             fromY = mTmpRect.top;
    933             toX = appRect.left;
    934             toY = appRect.top;
    935         }
    936         final long duration = getAspectScaleDuration();
    937         final Interpolator interpolator = getAspectScaleInterpolator();
    938         if (mNextAppTransitionScaleUp) {
    939             // Animation up from the thumbnail to the full screen
    940             Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
    941             scale.setInterpolator(interpolator);
    942             scale.setDuration(duration);
    943             Animation alpha = new AlphaAnimation(1f, 0f);
    944             alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
    945                     ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator);
    946             alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
    947                     ? duration / 2
    948                     : duration);
    949             Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
    950             translate.setInterpolator(interpolator);
    951             translate.setDuration(duration);
    952 
    953             mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
    954             mTmpToClipRect.set(appRect);
    955 
    956             // Containing frame is in screen space, but we need the clip rect in the
    957             // app space.
    958             mTmpToClipRect.offsetTo(0, 0);
    959             mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
    960             mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
    961 
    962             if (contentInsets != null) {
    963                 mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
    964                         (int) (-contentInsets.top * scaleW),
    965                         (int) (-contentInsets.right * scaleW),
    966                         (int) (-contentInsets.bottom * scaleW));
    967             }
    968 
    969             Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
    970             clipAnim.setInterpolator(interpolator);
    971             clipAnim.setDuration(duration);
    972 
    973             // This AnimationSet uses the Interpolators assigned above.
    974             AnimationSet set = new AnimationSet(false);
    975             set.addAnimation(scale);
    976             set.addAnimation(alpha);
    977             set.addAnimation(translate);
    978             set.addAnimation(clipAnim);
    979             a = set;
    980         } else {
    981             // Animation down from the full screen to the thumbnail
    982             Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
    983             scale.setInterpolator(interpolator);
    984             scale.setDuration(duration);
    985             Animation alpha = new AlphaAnimation(0f, 1f);
    986             alpha.setInterpolator(mThumbnailFadeInInterpolator);
    987             alpha.setDuration(duration);
    988             Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
    989             translate.setInterpolator(interpolator);
    990             translate.setDuration(duration);
    991 
    992             // This AnimationSet uses the Interpolators assigned above.
    993             AnimationSet set = new AnimationSet(false);
    994             set.addAnimation(scale);
    995             set.addAnimation(alpha);
    996             set.addAnimation(translate);
    997             a = set;
    998 
    999         }
   1000         return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
   1001                 null);
   1002     }
   1003 
   1004     private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
   1005 
   1006         // Almost no x-change - use linear animation
   1007         if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) {
   1008             return new TranslateAnimation(fromX, toX, fromY, toY);
   1009         } else {
   1010             final Path path = createCurvedPath(fromX, toX, fromY, toY);
   1011             return new CurvedTranslateAnimation(path);
   1012         }
   1013     }
   1014 
   1015     private Path createCurvedPath(float fromX, float toX, float fromY, float toY) {
   1016         final Path path = new Path();
   1017         path.moveTo(fromX, fromY);
   1018 
   1019         if (fromY > toY) {
   1020             // If the object needs to go up, move it in horizontal direction first, then vertical.
   1021             path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY);
   1022         } else {
   1023             // If the object needs to go down, move it in vertical direction first, then horizontal.
   1024             path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY);
   1025         }
   1026         return path;
   1027     }
   1028 
   1029     private long getAspectScaleDuration() {
   1030         if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
   1031             return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f);
   1032         } else {
   1033             return THUMBNAIL_APP_TRANSITION_DURATION;
   1034         }
   1035     }
   1036 
   1037     private Interpolator getAspectScaleInterpolator() {
   1038         if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
   1039             return mFastOutSlowInInterpolator;
   1040         } else {
   1041             return TOUCH_RESPONSE_INTERPOLATOR;
   1042         }
   1043     }
   1044 
   1045     /**
   1046      * This alternate animation is created when we are doing a thumbnail transition, for the
   1047      * activity that is leaving, and the activity that is entering.
   1048      */
   1049     Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
   1050             int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets,
   1051             @Nullable Rect surfaceInsets, boolean freeform, int taskId) {
   1052         Animation a;
   1053         final int appWidth = containingFrame.width();
   1054         final int appHeight = containingFrame.height();
   1055         getDefaultNextAppTransitionStartRect(mTmpRect);
   1056         final int thumbWidthI = mTmpRect.width();
   1057         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
   1058         final int thumbHeightI = mTmpRect.height();
   1059         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
   1060         final int thumbStartX = mTmpRect.left - containingFrame.left;
   1061         final int thumbStartY = mTmpRect.top - containingFrame.top;
   1062 
   1063         switch (thumbTransitState) {
   1064             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
   1065             case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
   1066                 final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
   1067                 if (freeform && scaleUp) {
   1068                     a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
   1069                             containingFrame, surfaceInsets, taskId);
   1070                 } else if (freeform) {
   1071                     a = createAspectScaledThumbnailExitFreeformAnimationLocked(
   1072                             containingFrame, surfaceInsets, taskId);
   1073                 } else {
   1074                     AnimationSet set = new AnimationSet(true);
   1075 
   1076                     // In portrait, we scale to fit the width
   1077                     mTmpFromClipRect.set(containingFrame);
   1078                     mTmpToClipRect.set(containingFrame);
   1079 
   1080                     // Containing frame is in screen space, but we need the clip rect in the
   1081                     // app space.
   1082                     mTmpFromClipRect.offsetTo(0, 0);
   1083                     mTmpToClipRect.offsetTo(0, 0);
   1084 
   1085                     // Exclude insets region from the source clip.
   1086                     mTmpFromClipRect.inset(contentInsets);
   1087                     mNextAppTransitionInsets.set(contentInsets);
   1088 
   1089                     if (isTvUiMode(uiMode) || orientation == Configuration.ORIENTATION_PORTRAIT) {
   1090                         // We scale the width and clip to the top/left square
   1091                         float scale = thumbWidth /
   1092                                 (appWidth - contentInsets.left - contentInsets.right);
   1093                         int unscaledThumbHeight = (int) (thumbHeight / scale);
   1094                         mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
   1095 
   1096                         mNextAppTransitionInsets.set(contentInsets);
   1097 
   1098                         Animation scaleAnim = new ScaleAnimation(
   1099                                 scaleUp ? scale : 1, scaleUp ? 1 : scale,
   1100                                 scaleUp ? scale : 1, scaleUp ? 1 : scale,
   1101                                 containingFrame.width() / 2f,
   1102                                 containingFrame.height() / 2f + contentInsets.top);
   1103                         final float targetX = (mTmpRect.left - containingFrame.left);
   1104                         final float x = containingFrame.width() / 2f
   1105                                 - containingFrame.width() / 2f * scale;
   1106                         final float targetY = (mTmpRect.top - containingFrame.top);
   1107                         final float y = containingFrame.height() / 2f
   1108                                 - containingFrame.height() / 2f * scale;
   1109                         final float startX = targetX - x;
   1110                         final float startY = targetY - y;
   1111                         Animation clipAnim = scaleUp
   1112                                 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
   1113                                 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
   1114                         Animation translateAnim = scaleUp
   1115                                 ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0)
   1116                                 : createCurvedMotion(0, startX, 0, startY - contentInsets.top);
   1117 
   1118                         set.addAnimation(clipAnim);
   1119                         set.addAnimation(scaleAnim);
   1120                         set.addAnimation(translateAnim);
   1121 
   1122                     } else {
   1123                         // In landscape, we don't scale at all and only crop
   1124                         mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI;
   1125                         mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI;
   1126 
   1127                         Animation clipAnim = scaleUp
   1128                                 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
   1129                                 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
   1130                         Animation translateAnim = scaleUp
   1131                                 ? createCurvedMotion(thumbStartX, 0,
   1132                                 thumbStartY - contentInsets.top, 0)
   1133                                 : createCurvedMotion(0, thumbStartX, 0,
   1134                                         thumbStartY - contentInsets.top);
   1135 
   1136                         set.addAnimation(clipAnim);
   1137                         set.addAnimation(translateAnim);
   1138                     }
   1139                     a = set;
   1140                     a.setZAdjustment(Animation.ZORDER_TOP);
   1141                 }
   1142                 break;
   1143             }
   1144             case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
   1145                 // Previous app window during the scale up
   1146                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
   1147                     // Fade out the source activity if we are animating to a wallpaper
   1148                     // activity.
   1149                     a = new AlphaAnimation(1, 0);
   1150                 } else {
   1151                     a = new AlphaAnimation(1, 1);
   1152                 }
   1153                 break;
   1154             }
   1155             case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
   1156                 // Target app window during the scale down
   1157                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
   1158                     // Fade in the destination activity if we are animating from a wallpaper
   1159                     // activity.
   1160                     a = new AlphaAnimation(0, 1);
   1161                 } else {
   1162                     a = new AlphaAnimation(1, 1);
   1163                 }
   1164                 break;
   1165             }
   1166             default:
   1167                 throw new RuntimeException("Invalid thumbnail transition state");
   1168         }
   1169 
   1170         return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
   1171                 getAspectScaleDuration(), getAspectScaleInterpolator());
   1172     }
   1173 
   1174     private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
   1175             @Nullable Rect surfaceInsets, int taskId) {
   1176         getNextAppTransitionStartRect(taskId, mTmpRect);
   1177         return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
   1178                 true);
   1179     }
   1180 
   1181     private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
   1182             @Nullable Rect surfaceInsets, int taskId) {
   1183         getNextAppTransitionStartRect(taskId, mTmpRect);
   1184         return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
   1185                 false);
   1186     }
   1187 
   1188     private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
   1189             Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
   1190         final float sourceWidth = sourceFrame.width();
   1191         final float sourceHeight = sourceFrame.height();
   1192         final float destWidth = destFrame.width();
   1193         final float destHeight = destFrame.height();
   1194         final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
   1195         final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
   1196         AnimationSet set = new AnimationSet(true);
   1197         final int surfaceInsetsH = surfaceInsets == null
   1198                 ? 0 : surfaceInsets.left + surfaceInsets.right;
   1199         final int surfaceInsetsV = surfaceInsets == null
   1200                 ? 0 : surfaceInsets.top + surfaceInsets.bottom;
   1201         // We want the scaling to happen from the center of the surface. In order to achieve that,
   1202         // we need to account for surface insets that will be used to enlarge the surface.
   1203         final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
   1204         final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
   1205         final ScaleAnimation scale = enter ?
   1206                 new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
   1207                 : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
   1208         final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
   1209         final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
   1210         final int destHCenter = destFrame.left + destFrame.width() / 2;
   1211         final int destVCenter = destFrame.top + destFrame.height() / 2;
   1212         final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
   1213         final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
   1214         final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
   1215                 : new TranslateAnimation(0, fromX, 0, fromY);
   1216         set.addAnimation(scale);
   1217         set.addAnimation(translation);
   1218 
   1219         final IRemoteCallback callback = mAnimationFinishedCallback;
   1220         if (callback != null) {
   1221             set.setAnimationListener(new Animation.AnimationListener() {
   1222                 @Override
   1223                 public void onAnimationStart(Animation animation) { }
   1224 
   1225                 @Override
   1226                 public void onAnimationEnd(Animation animation) {
   1227                     mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
   1228                 }
   1229 
   1230                 @Override
   1231                 public void onAnimationRepeat(Animation animation) { }
   1232             });
   1233         }
   1234         return set;
   1235     }
   1236 
   1237     /**
   1238      * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
   1239      * when a thumbnail is specified with the pending animation override.
   1240      */
   1241     Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
   1242             Bitmap thumbnailHeader) {
   1243         Animation a;
   1244         getDefaultNextAppTransitionStartRect(mTmpRect);
   1245         final int thumbWidthI = thumbnailHeader.getWidth();
   1246         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
   1247         final int thumbHeightI = thumbnailHeader.getHeight();
   1248         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
   1249 
   1250         if (mNextAppTransitionScaleUp) {
   1251             // Animation for the thumbnail zooming from its initial size to the full screen
   1252             float scaleW = appWidth / thumbWidth;
   1253             float scaleH = appHeight / thumbHeight;
   1254             Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
   1255                     computePivot(mTmpRect.left, 1 / scaleW),
   1256                     computePivot(mTmpRect.top, 1 / scaleH));
   1257             scale.setInterpolator(mDecelerateInterpolator);
   1258 
   1259             Animation alpha = new AlphaAnimation(1, 0);
   1260             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
   1261 
   1262             // This AnimationSet uses the Interpolators assigned above.
   1263             AnimationSet set = new AnimationSet(false);
   1264             set.addAnimation(scale);
   1265             set.addAnimation(alpha);
   1266             a = set;
   1267         } else {
   1268             // Animation for the thumbnail zooming down from the full screen to its final size
   1269             float scaleW = appWidth / thumbWidth;
   1270             float scaleH = appHeight / thumbHeight;
   1271             a = new ScaleAnimation(scaleW, 1, scaleH, 1,
   1272                     computePivot(mTmpRect.left, 1 / scaleW),
   1273                     computePivot(mTmpRect.top, 1 / scaleH));
   1274         }
   1275 
   1276         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
   1277     }
   1278 
   1279     /**
   1280      * This animation is created when we are doing a thumbnail transition, for the activity that is
   1281      * leaving, and the activity that is entering.
   1282      */
   1283     Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
   1284             int transit, int taskId) {
   1285         final int appWidth = containingFrame.width();
   1286         final int appHeight = containingFrame.height();
   1287         Bitmap thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
   1288         Animation a;
   1289         getDefaultNextAppTransitionStartRect(mTmpRect);
   1290         final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
   1291         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
   1292         final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
   1293         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
   1294 
   1295         switch (thumbTransitState) {
   1296             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
   1297                 // Entering app scales up with the thumbnail
   1298                 float scaleW = thumbWidth / appWidth;
   1299                 float scaleH = thumbHeight / appHeight;
   1300                 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
   1301                         computePivot(mTmpRect.left, scaleW),
   1302                         computePivot(mTmpRect.top, scaleH));
   1303                 break;
   1304             }
   1305             case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
   1306                 // Exiting app while the thumbnail is scaling up should fade or stay in place
   1307                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
   1308                     // Fade out while bringing up selected activity. This keeps the
   1309                     // current activity from showing through a launching wallpaper
   1310                     // activity.
   1311                     a = new AlphaAnimation(1, 0);
   1312                 } else {
   1313                     // noop animation
   1314                     a = new AlphaAnimation(1, 1);
   1315                 }
   1316                 break;
   1317             }
   1318             case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
   1319                 // Entering the other app, it should just be visible while we scale the thumbnail
   1320                 // down above it
   1321                 a = new AlphaAnimation(1, 1);
   1322                 break;
   1323             }
   1324             case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
   1325                 // Exiting the current app, the app should scale down with the thumbnail
   1326                 float scaleW = thumbWidth / appWidth;
   1327                 float scaleH = thumbHeight / appHeight;
   1328                 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
   1329                         computePivot(mTmpRect.left, scaleW),
   1330                         computePivot(mTmpRect.top, scaleH));
   1331 
   1332                 Animation alpha = new AlphaAnimation(1, 0);
   1333 
   1334                 AnimationSet set = new AnimationSet(true);
   1335                 set.addAnimation(scale);
   1336                 set.addAnimation(alpha);
   1337                 set.setZAdjustment(Animation.ZORDER_TOP);
   1338                 a = set;
   1339                 break;
   1340             }
   1341             default:
   1342                 throw new RuntimeException("Invalid thumbnail transition state");
   1343         }
   1344 
   1345         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
   1346     }
   1347 
   1348     private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) {
   1349         getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
   1350         final int left = mTmpFromClipRect.left;
   1351         final int top = mTmpFromClipRect.top;
   1352         mTmpFromClipRect.offset(-left, -top);
   1353         // TODO: Isn't that strange that we ignore exact position of the containingFrame?
   1354         mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height());
   1355         AnimationSet set = new AnimationSet(true);
   1356         float fromWidth = mTmpFromClipRect.width();
   1357         float toWidth = mTmpToClipRect.width();
   1358         float fromHeight = mTmpFromClipRect.height();
   1359         // While the window might span the whole display, the actual content will be cropped to the
   1360         // system decoration frame, for example when the window is docked. We need to take into
   1361         // account the visible height when constructing the animation.
   1362         float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom;
   1363         int translateAdjustment = 0;
   1364         if (fromWidth <= toWidth && fromHeight <= toHeight) {
   1365             // The final window is larger in both dimensions than current window (e.g. we are
   1366             // maximizing), so we can simply unclip the new window and there will be no disappearing
   1367             // frame.
   1368             set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
   1369         } else {
   1370             // The disappearing window has one larger dimension. We need to apply scaling, so the
   1371             // first frame of the entry animation matches the old window.
   1372             set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
   1373             // We might not be going exactly full screen, but instead be aligned under the status
   1374             // bar using cropping. We still need to account for the cropped part, which will also
   1375             // be scaled.
   1376             translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight);
   1377         }
   1378 
   1379         // We animate the translation from the old position of the removed window, to the new
   1380         // position of the added window. The latter might not be full screen, for example docked for
   1381         // docked windows.
   1382         TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
   1383                 0, top - containingFrame.top - translateAdjustment, 0);
   1384         set.addAnimation(translate);
   1385         set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
   1386         set.setZAdjustment(Animation.ZORDER_TOP);
   1387         return set;
   1388     }
   1389 
   1390     /**
   1391      * @return true if and only if the first frame of the transition can be skipped, i.e. the first
   1392      *         frame of the transition doesn't change the visuals on screen, so we can start
   1393      *         directly with the second one
   1394      */
   1395     boolean canSkipFirstFrame() {
   1396         return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
   1397                 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
   1398                 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL;
   1399     }
   1400 
   1401     /**
   1402      *
   1403      * @param frame These are the bounds of the window when it finishes the animation. This is where
   1404      *              the animation must usually finish in entrance animation, as the next frame will
   1405      *              display the window at these coordinates. In case of exit animation, this is
   1406      *              where the animation must start, as the frame before the animation is displaying
   1407      *              the window at these bounds.
   1408      * @param insets Knowing where the window will be positioned is not enough. Some parts of the
   1409      *               window might be obscured, usually by the system windows (status bar and
   1410      *               navigation bar) and we use content insets to convey that information. This
   1411      *               usually affects the animation aspects vertically, as the system decoration is
   1412      *               at the top and the bottom. For example when we animate from full screen to
   1413      *               recents, we want to exclude the covered parts, because they won't match the
   1414      *               thumbnail after the last frame is executed.
   1415      * @param surfaceInsets In rare situation the surface is larger than the content and we need to
   1416      *                      know about this to make the animation frames match. We currently use
   1417      *                      this for freeform windows, which have larger surfaces to display
   1418      *                      shadows. When we animate them from recents, we want to match the content
   1419      *                      to the recents thumbnail and hence need to account for the surface being
   1420      *                      bigger.
   1421      */
   1422     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int uiMode,
   1423             int orientation, Rect frame, Rect displayFrame, Rect insets,
   1424             @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform,
   1425             int taskId) {
   1426         Animation a;
   1427         if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
   1428                 || transit == TRANSIT_TASK_OPEN
   1429                 || transit == TRANSIT_TASK_TO_FRONT)) {
   1430             a = loadAnimationRes(lp, enter
   1431                     ? com.android.internal.R.anim.voice_activity_open_enter
   1432                     : com.android.internal.R.anim.voice_activity_open_exit);
   1433             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
   1434                     "applyAnimation voice:"
   1435                     + " anim=" + a + " transit=" + appTransitionToString(transit)
   1436                     + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
   1437         } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
   1438                 || transit == TRANSIT_TASK_CLOSE
   1439                 || transit == TRANSIT_TASK_TO_BACK)) {
   1440             a = loadAnimationRes(lp, enter
   1441                     ? com.android.internal.R.anim.voice_activity_close_enter
   1442                     : com.android.internal.R.anim.voice_activity_close_exit);
   1443             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
   1444                     "applyAnimation voice:"
   1445                     + " anim=" + a + " transit=" + appTransitionToString(transit)
   1446                     + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
   1447         } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
   1448             a = createRelaunchAnimation(frame, insets);
   1449             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
   1450                     "applyAnimation:"
   1451                     + " anim=" + a + " nextAppTransition=" + mNextAppTransition
   1452                     + " transit=" + appTransitionToString(transit)
   1453                     + " Callers=" + Debug.getCallers(3));
   1454         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
   1455             a = loadAnimationRes(mNextAppTransitionPackage, enter ?
   1456                     mNextAppTransitionEnter : mNextAppTransitionExit);
   1457             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
   1458                     "applyAnimation:"
   1459                     + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
   1460                     + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
   1461                     + " Callers=" + Debug.getCallers(3));
   1462         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
   1463             a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
   1464             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
   1465                     "applyAnimation:"
   1466                     + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
   1467                     + " transit=" + appTransitionToString(transit)
   1468                     + " Callers=" + Debug.getCallers(3));
   1469         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
   1470             a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
   1471             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
   1472                     "applyAnimation:"
   1473                             + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
   1474                             + " transit=" + appTransitionToString(transit)
   1475                             + " Callers=" + Debug.getCallers(3));
   1476         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
   1477             a = createScaleUpAnimationLocked(transit, enter, frame);
   1478             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
   1479                     "applyAnimation:"
   1480                     + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
   1481                     + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
   1482                     + " Callers=" + Debug.getCallers(3));
   1483         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
   1484                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
   1485             mNextAppTransitionScaleUp =
   1486                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
   1487             a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
   1488                     frame, transit, taskId);
   1489             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
   1490                 String animName = mNextAppTransitionScaleUp ?
   1491                         "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
   1492                 Slog.v(TAG, "applyAnimation:"
   1493                         + " anim=" + a + " nextAppTransition=" + animName
   1494                         + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
   1495                         + " Callers=" + Debug.getCallers(3));
   1496             }
   1497         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
   1498                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
   1499             mNextAppTransitionScaleUp =
   1500                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
   1501             a = createAspectScaledThumbnailEnterExitAnimationLocked(
   1502                     getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
   1503                     insets, surfaceInsets, freeform, taskId);
   1504             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
   1505                 String animName = mNextAppTransitionScaleUp ?
   1506                         "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
   1507                 Slog.v(TAG, "applyAnimation:"
   1508                         + " anim=" + a + " nextAppTransition=" + animName
   1509                         + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
   1510                         + " Callers=" + Debug.getCallers(3));
   1511             }
   1512         } else {
   1513             int animAttr = 0;
   1514             switch (transit) {
   1515                 case TRANSIT_ACTIVITY_OPEN:
   1516                     animAttr = enter
   1517                             ? WindowAnimation_activityOpenEnterAnimation
   1518                             : WindowAnimation_activityOpenExitAnimation;
   1519                     break;
   1520                 case TRANSIT_ACTIVITY_CLOSE:
   1521                     animAttr = enter
   1522                             ? WindowAnimation_activityCloseEnterAnimation
   1523                             : WindowAnimation_activityCloseExitAnimation;
   1524                     break;
   1525                 case TRANSIT_DOCK_TASK_FROM_RECENTS:
   1526                 case TRANSIT_TASK_OPEN:
   1527                     animAttr = enter
   1528                             ? WindowAnimation_taskOpenEnterAnimation
   1529                             : WindowAnimation_taskOpenExitAnimation;
   1530                     break;
   1531                 case TRANSIT_TASK_CLOSE:
   1532                     animAttr = enter
   1533                             ? WindowAnimation_taskCloseEnterAnimation
   1534                             : WindowAnimation_taskCloseExitAnimation;
   1535                     break;
   1536                 case TRANSIT_TASK_TO_FRONT:
   1537                     animAttr = enter
   1538                             ? WindowAnimation_taskToFrontEnterAnimation
   1539                             : WindowAnimation_taskToFrontExitAnimation;
   1540                     break;
   1541                 case TRANSIT_TASK_TO_BACK:
   1542                     animAttr = enter
   1543                             ? WindowAnimation_taskToBackEnterAnimation
   1544                             : WindowAnimation_taskToBackExitAnimation;
   1545                     break;
   1546                 case TRANSIT_WALLPAPER_OPEN:
   1547                     animAttr = enter
   1548                             ? WindowAnimation_wallpaperOpenEnterAnimation
   1549                             : WindowAnimation_wallpaperOpenExitAnimation;
   1550                     break;
   1551                 case TRANSIT_WALLPAPER_CLOSE:
   1552                     animAttr = enter
   1553                             ? WindowAnimation_wallpaperCloseEnterAnimation
   1554                             : WindowAnimation_wallpaperCloseExitAnimation;
   1555                     break;
   1556                 case TRANSIT_WALLPAPER_INTRA_OPEN:
   1557                     animAttr = enter
   1558                             ? WindowAnimation_wallpaperIntraOpenEnterAnimation
   1559                             : WindowAnimation_wallpaperIntraOpenExitAnimation;
   1560                     break;
   1561                 case TRANSIT_WALLPAPER_INTRA_CLOSE:
   1562                     animAttr = enter
   1563                             ? WindowAnimation_wallpaperIntraCloseEnterAnimation
   1564                             : WindowAnimation_wallpaperIntraCloseExitAnimation;
   1565                     break;
   1566                 case TRANSIT_TASK_OPEN_BEHIND:
   1567                     animAttr = enter
   1568                             ? WindowAnimation_launchTaskBehindSourceAnimation
   1569                             : WindowAnimation_launchTaskBehindTargetAnimation;
   1570             }
   1571             a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
   1572             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
   1573                     "applyAnimation:"
   1574                     + " anim=" + a
   1575                     + " animAttr=0x" + Integer.toHexString(animAttr)
   1576                     + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
   1577                     + " Callers=" + Debug.getCallers(3));
   1578         }
   1579         return a;
   1580     }
   1581 
   1582     int getAppStackClipMode() {
   1583         return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
   1584                 || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
   1585                 || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
   1586                 ? STACK_CLIP_NONE
   1587                 : STACK_CLIP_AFTER_ANIM;
   1588     }
   1589 
   1590     void postAnimationCallback() {
   1591         if (mNextAppTransitionCallback != null) {
   1592             mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
   1593                     mNextAppTransitionCallback));
   1594             mNextAppTransitionCallback = null;
   1595         }
   1596     }
   1597 
   1598     void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
   1599             IRemoteCallback startedCallback) {
   1600         if (isTransitionSet()) {
   1601             clear();
   1602             mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
   1603             mNextAppTransitionPackage = packageName;
   1604             mNextAppTransitionEnter = enterAnim;
   1605             mNextAppTransitionExit = exitAnim;
   1606             postAnimationCallback();
   1607             mNextAppTransitionCallback = startedCallback;
   1608         } else {
   1609             postAnimationCallback();
   1610         }
   1611     }
   1612 
   1613     void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
   1614             int startHeight) {
   1615         if (isTransitionSet()) {
   1616             clear();
   1617             mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
   1618             putDefaultNextAppTransitionCoordinates(startX, startY, startX + startWidth,
   1619                     startY + startHeight, null);
   1620             postAnimationCallback();
   1621         }
   1622     }
   1623 
   1624     void overridePendingAppTransitionClipReveal(int startX, int startY,
   1625                                                 int startWidth, int startHeight) {
   1626         if (isTransitionSet()) {
   1627             clear();
   1628             mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
   1629             putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
   1630             postAnimationCallback();
   1631         }
   1632     }
   1633 
   1634     void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
   1635                                            IRemoteCallback startedCallback, boolean scaleUp) {
   1636         if (isTransitionSet()) {
   1637             clear();
   1638             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
   1639                     : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
   1640             mNextAppTransitionScaleUp = scaleUp;
   1641             putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb);
   1642             postAnimationCallback();
   1643             mNextAppTransitionCallback = startedCallback;
   1644         } else {
   1645             postAnimationCallback();
   1646         }
   1647     }
   1648 
   1649     void overridePendingAppTransitionAspectScaledThumb(Bitmap srcThumb, int startX, int startY,
   1650             int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) {
   1651         if (isTransitionSet()) {
   1652             clear();
   1653             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
   1654                     : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
   1655             mNextAppTransitionScaleUp = scaleUp;
   1656             putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight,
   1657                     srcThumb);
   1658             postAnimationCallback();
   1659             mNextAppTransitionCallback = startedCallback;
   1660         } else {
   1661             postAnimationCallback();
   1662         }
   1663     }
   1664 
   1665     public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
   1666             IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
   1667             boolean scaleUp) {
   1668         if (isTransitionSet()) {
   1669             clear();
   1670             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
   1671                     : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
   1672             mNextAppTransitionScaleUp = scaleUp;
   1673             if (specs != null) {
   1674                 for (int i = 0; i < specs.length; i++) {
   1675                     AppTransitionAnimationSpec spec = specs[i];
   1676                     if (spec != null) {
   1677                         mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec);
   1678                         if (i == 0) {
   1679                             // In full screen mode, the transition code depends on the default spec
   1680                             // to be set.
   1681                             Rect rect = spec.rect;
   1682                             putDefaultNextAppTransitionCoordinates(rect.left, rect.top,
   1683                                     rect.width(), rect.height(), spec.bitmap);
   1684                         }
   1685                     }
   1686                 }
   1687             }
   1688             postAnimationCallback();
   1689             mNextAppTransitionCallback = onAnimationStartedCallback;
   1690             mAnimationFinishedCallback = onAnimationFinishedCallback;
   1691         } else {
   1692             postAnimationCallback();
   1693         }
   1694     }
   1695 
   1696     void overridePendingAppTransitionMultiThumbFuture(
   1697             IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
   1698             boolean scaleUp) {
   1699         if (isTransitionSet()) {
   1700             clear();
   1701             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
   1702                     : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
   1703             mNextAppTransitionAnimationsSpecsFuture = specsFuture;
   1704             mNextAppTransitionScaleUp = scaleUp;
   1705             mNextAppTransitionFutureCallback = callback;
   1706         }
   1707     }
   1708 
   1709     void overrideInPlaceAppTransition(String packageName, int anim) {
   1710         if (isTransitionSet()) {
   1711             clear();
   1712             mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
   1713             mNextAppTransitionPackage = packageName;
   1714             mNextAppTransitionInPlace = anim;
   1715         } else {
   1716             postAnimationCallback();
   1717         }
   1718     }
   1719 
   1720     /**
   1721      * If a future is set for the app transition specs, fetch it in another thread.
   1722      */
   1723     private void fetchAppTransitionSpecsFromFuture() {
   1724         if (mNextAppTransitionAnimationsSpecsFuture != null) {
   1725             mNextAppTransitionAnimationsSpecsPending = true;
   1726             final IAppTransitionAnimationSpecsFuture future
   1727                     = mNextAppTransitionAnimationsSpecsFuture;
   1728             mNextAppTransitionAnimationsSpecsFuture = null;
   1729             mDefaultExecutor.execute(new Runnable() {
   1730                 @Override
   1731                 public void run() {
   1732                     AppTransitionAnimationSpec[] specs = null;
   1733                     try {
   1734                         specs = future.get();
   1735                     } catch (RemoteException e) {
   1736                         Slog.w(TAG, "Failed to fetch app transition specs: " + e);
   1737                     }
   1738                     synchronized (mService.mWindowMap) {
   1739                         mNextAppTransitionAnimationsSpecsPending = false;
   1740                         overridePendingAppTransitionMultiThumb(specs,
   1741                                 mNextAppTransitionFutureCallback, null /* finishedCallback */,
   1742                                 mNextAppTransitionScaleUp);
   1743                         mNextAppTransitionFutureCallback = null;
   1744                         if (specs != null) {
   1745                             mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
   1746                         }
   1747                     }
   1748                     mService.requestTraversal();
   1749                 }
   1750             });
   1751         }
   1752     }
   1753 
   1754     @Override
   1755     public String toString() {
   1756         return "mNextAppTransition=" + appTransitionToString(mNextAppTransition);
   1757     }
   1758 
   1759     /**
   1760      * Returns the human readable name of a window transition.
   1761      *
   1762      * @param transition The window transition.
   1763      * @return The transition symbolic name.
   1764      */
   1765     public static String appTransitionToString(int transition) {
   1766         switch (transition) {
   1767             case TRANSIT_UNSET: {
   1768                 return "TRANSIT_UNSET";
   1769             }
   1770             case TRANSIT_NONE: {
   1771                 return "TRANSIT_NONE";
   1772             }
   1773             case TRANSIT_ACTIVITY_OPEN: {
   1774                 return "TRANSIT_ACTIVITY_OPEN";
   1775             }
   1776             case TRANSIT_ACTIVITY_CLOSE: {
   1777                 return "TRANSIT_ACTIVITY_CLOSE";
   1778             }
   1779             case TRANSIT_TASK_OPEN: {
   1780                 return "TRANSIT_TASK_OPEN";
   1781             }
   1782             case TRANSIT_TASK_CLOSE: {
   1783                 return "TRANSIT_TASK_CLOSE";
   1784             }
   1785             case TRANSIT_TASK_TO_FRONT: {
   1786                 return "TRANSIT_TASK_TO_FRONT";
   1787             }
   1788             case TRANSIT_TASK_TO_BACK: {
   1789                 return "TRANSIT_TASK_TO_BACK";
   1790             }
   1791             case TRANSIT_WALLPAPER_CLOSE: {
   1792                 return "TRANSIT_WALLPAPER_CLOSE";
   1793             }
   1794             case TRANSIT_WALLPAPER_OPEN: {
   1795                 return "TRANSIT_WALLPAPER_OPEN";
   1796             }
   1797             case TRANSIT_WALLPAPER_INTRA_OPEN: {
   1798                 return "TRANSIT_WALLPAPER_INTRA_OPEN";
   1799             }
   1800             case TRANSIT_WALLPAPER_INTRA_CLOSE: {
   1801                 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
   1802             }
   1803             case TRANSIT_TASK_OPEN_BEHIND: {
   1804                 return "TRANSIT_TASK_OPEN_BEHIND";
   1805             }
   1806             case TRANSIT_ACTIVITY_RELAUNCH: {
   1807                 return "TRANSIT_ACTIVITY_RELAUNCH";
   1808             }
   1809             case TRANSIT_DOCK_TASK_FROM_RECENTS: {
   1810                 return "TRANSIT_DOCK_TASK_FROM_RECENTS";
   1811             }
   1812             default: {
   1813                 return "<UNKNOWN>";
   1814             }
   1815         }
   1816     }
   1817 
   1818     private String appStateToString() {
   1819         switch (mAppTransitionState) {
   1820             case APP_STATE_IDLE:
   1821                 return "APP_STATE_IDLE";
   1822             case APP_STATE_READY:
   1823                 return "APP_STATE_READY";
   1824             case APP_STATE_RUNNING:
   1825                 return "APP_STATE_RUNNING";
   1826             case APP_STATE_TIMEOUT:
   1827                 return "APP_STATE_TIMEOUT";
   1828             default:
   1829                 return "unknown state=" + mAppTransitionState;
   1830         }
   1831     }
   1832 
   1833     private String transitTypeToString() {
   1834         switch (mNextAppTransitionType) {
   1835             case NEXT_TRANSIT_TYPE_NONE:
   1836                 return "NEXT_TRANSIT_TYPE_NONE";
   1837             case NEXT_TRANSIT_TYPE_CUSTOM:
   1838                 return "NEXT_TRANSIT_TYPE_CUSTOM";
   1839             case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
   1840                 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
   1841             case NEXT_TRANSIT_TYPE_SCALE_UP:
   1842                 return "NEXT_TRANSIT_TYPE_SCALE_UP";
   1843             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
   1844                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
   1845             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
   1846                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
   1847             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
   1848                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
   1849             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
   1850                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
   1851             default:
   1852                 return "unknown type=" + mNextAppTransitionType;
   1853         }
   1854     }
   1855 
   1856     @Override
   1857     public void dump(PrintWriter pw, String prefix) {
   1858         pw.print(prefix); pw.println(this);
   1859         pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
   1860         if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
   1861             pw.print(prefix); pw.print("mNextAppTransitionType=");
   1862                     pw.println(transitTypeToString());
   1863         }
   1864         switch (mNextAppTransitionType) {
   1865             case NEXT_TRANSIT_TYPE_CUSTOM:
   1866                 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
   1867                         pw.println(mNextAppTransitionPackage);
   1868                 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
   1869                         pw.print(Integer.toHexString(mNextAppTransitionEnter));
   1870                         pw.print(" mNextAppTransitionExit=0x");
   1871                         pw.println(Integer.toHexString(mNextAppTransitionExit));
   1872                 break;
   1873             case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
   1874                 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
   1875                         pw.println(mNextAppTransitionPackage);
   1876                 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
   1877                         pw.print(Integer.toHexString(mNextAppTransitionInPlace));
   1878                 break;
   1879             case NEXT_TRANSIT_TYPE_SCALE_UP: {
   1880                 getDefaultNextAppTransitionStartRect(mTmpRect);
   1881                 pw.print(prefix); pw.print("mNextAppTransitionStartX=");
   1882                         pw.print(mTmpRect.left);
   1883                         pw.print(" mNextAppTransitionStartY=");
   1884                         pw.println(mTmpRect.top);
   1885                 pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
   1886                         pw.print(mTmpRect.width());
   1887                         pw.print(" mNextAppTransitionStartHeight=");
   1888                         pw.println(mTmpRect.height());
   1889                 break;
   1890             }
   1891             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
   1892             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
   1893             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
   1894             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
   1895                 pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
   1896                         pw.println(mDefaultNextAppTransitionAnimationSpec);
   1897                 pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
   1898                         pw.println(mNextAppTransitionAnimationsSpecs);
   1899                 pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
   1900                         pw.println(mNextAppTransitionScaleUp);
   1901                 break;
   1902             }
   1903         }
   1904         if (mNextAppTransitionCallback != null) {
   1905             pw.print(prefix); pw.print("mNextAppTransitionCallback=");
   1906                     pw.println(mNextAppTransitionCallback);
   1907         }
   1908     }
   1909 
   1910     public void setCurrentUser(int newUserId) {
   1911         mCurrentUserId = newUserId;
   1912     }
   1913 
   1914     /**
   1915      * @return true if transition is not running and should not be skipped, false if transition is
   1916      *         already running
   1917      */
   1918     boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent) {
   1919         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
   1920                 + " transit=" + appTransitionToString(transit)
   1921                 + " " + this
   1922                 + " alwaysKeepCurrent=" + alwaysKeepCurrent
   1923                 + " Callers=" + Debug.getCallers(3));
   1924         if (!isTransitionSet() || mNextAppTransition == TRANSIT_NONE) {
   1925             setAppTransition(transit);
   1926         } else if (!alwaysKeepCurrent) {
   1927             if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
   1928                 // Opening a new task always supersedes a close for the anim.
   1929                 setAppTransition(transit);
   1930             } else if (transit == TRANSIT_ACTIVITY_OPEN
   1931                     && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
   1932                 // Opening a new activity always supersedes a close for the anim.
   1933                 setAppTransition(transit);
   1934             }
   1935         }
   1936         boolean prepared = prepare();
   1937         if (isTransitionSet()) {
   1938             mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
   1939             mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
   1940         }
   1941         return prepared;
   1942     }
   1943 
   1944     /**
   1945      * @return whether the specified {@param uiMode} is the TV mode.
   1946      */
   1947     private boolean isTvUiMode(int uiMode) {
   1948         return (uiMode & Configuration.UI_MODE_TYPE_TELEVISION) > 0;
   1949     }
   1950 }
   1951