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 android.content.Context;
     20 import android.content.res.Configuration;
     21 import android.graphics.Bitmap;
     22 import android.graphics.Rect;
     23 import android.os.Debug;
     24 import android.os.Handler;
     25 import android.os.IRemoteCallback;
     26 import android.util.Slog;
     27 import android.view.WindowManager;
     28 import android.view.animation.AlphaAnimation;
     29 import android.view.animation.Animation;
     30 import android.view.animation.AnimationSet;
     31 import android.view.animation.AnimationUtils;
     32 import android.view.animation.ClipRectAnimation;
     33 import android.view.animation.Interpolator;
     34 import android.view.animation.ScaleAnimation;
     35 import android.view.animation.TranslateAnimation;
     36 import com.android.internal.util.DumpUtils.Dump;
     37 import com.android.server.AttributeCache;
     38 import com.android.server.wm.WindowManagerService.H;
     39 
     40 import java.io.PrintWriter;
     41 
     42 import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
     43 import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
     44 import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
     45 import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
     46 import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
     47 import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
     48 import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
     49 import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
     50 import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
     51 import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
     52 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
     53 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
     54 import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
     55 import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
     56 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
     57 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
     58 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
     59 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
     60 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
     61 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
     62 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
     63 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
     64 
     65 // State management of app transitions.  When we are preparing for a
     66 // transition, mNextAppTransition will be the kind of transition to
     67 // perform or TRANSIT_NONE if we are not waiting.  If we are waiting,
     68 // mOpeningApps and mClosingApps are the lists of tokens that will be
     69 // made visible or hidden at the next transition.
     70 public class AppTransition implements Dump {
     71     private static final String TAG = "AppTransition";
     72     private static final boolean DEBUG_APP_TRANSITIONS =
     73             WindowManagerService.DEBUG_APP_TRANSITIONS;
     74     private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM;
     75 
     76 
     77     /** Not set up for a transition. */
     78     public static final int TRANSIT_UNSET = -1;
     79     /** No animation for transition. */
     80     public static final int TRANSIT_NONE = 0;
     81     /** A window in a new activity is being opened on top of an existing one in the same task. */
     82     public static final int TRANSIT_ACTIVITY_OPEN = 6;
     83     /** The window in the top-most activity is being closed to reveal the
     84      * previous activity in the same task. */
     85     public static final int TRANSIT_ACTIVITY_CLOSE = 7;
     86     /** A window in a new task is being opened on top of an existing one
     87      * in another activity's task. */
     88     public static final int TRANSIT_TASK_OPEN = 8;
     89     /** A window in the top-most activity is being closed to reveal the
     90      * previous activity in a different task. */
     91     public static final int TRANSIT_TASK_CLOSE = 9;
     92     /** A window in an existing task is being displayed on top of an existing one
     93      * in another activity's task. */
     94     public static final int TRANSIT_TASK_TO_FRONT = 10;
     95     /** A window in an existing task is being put below all other tasks. */
     96     public static final int TRANSIT_TASK_TO_BACK = 11;
     97     /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that
     98      * does, effectively closing the wallpaper. */
     99     public static final int TRANSIT_WALLPAPER_CLOSE = 12;
    100     /** A window in a new activity that does have a wallpaper is being opened on one that didn't,
    101      * effectively opening the wallpaper. */
    102     public static final int TRANSIT_WALLPAPER_OPEN = 13;
    103     /** A window in a new activity is being opened on top of an existing one, and both are on top
    104      * of the wallpaper. */
    105     public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14;
    106     /** The window in the top-most activity is being closed to reveal the previous activity, and
    107      * both are on top of the wallpaper. */
    108     public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15;
    109     /** A window in a new task is being opened behind an existing one in another activity's task.
    110      * The new window will show briefly and then be gone. */
    111     public static final int TRANSIT_TASK_OPEN_BEHIND = 16;
    112 
    113     /** Fraction of animation at which the recents thumbnail stays completely transparent */
    114     private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.7f;
    115     /** Fraction of animation at which the recents thumbnail becomes completely transparent */
    116     private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.3f;
    117 
    118     private static final int DEFAULT_APP_TRANSITION_DURATION = 250;
    119     private static final int THUMBNAIL_APP_TRANSITION_DURATION = 300;
    120     private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 325;
    121 
    122     private final Context mContext;
    123     private final Handler mH;
    124 
    125     private int mNextAppTransition = TRANSIT_UNSET;
    126 
    127     private static final int NEXT_TRANSIT_TYPE_NONE = 0;
    128     private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
    129     private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
    130     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
    131     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
    132     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
    133     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
    134     private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
    135 
    136     // These are the possible states for the enter/exit activities during a thumbnail transition
    137     private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
    138     private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
    139     private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
    140     private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
    141 
    142     private String mNextAppTransitionPackage;
    143     private Bitmap mNextAppTransitionThumbnail;
    144     // Used for thumbnail transitions. True if we're scaling up, false if scaling down
    145     private boolean mNextAppTransitionScaleUp;
    146     private IRemoteCallback mNextAppTransitionCallback;
    147     private int mNextAppTransitionEnter;
    148     private int mNextAppTransitionExit;
    149     private int mNextAppTransitionStartX;
    150     private int mNextAppTransitionStartY;
    151     private int mNextAppTransitionStartWidth;
    152     private int mNextAppTransitionStartHeight;
    153     private Rect mNextAppTransitionInsets = new Rect();
    154 
    155     private Rect mTmpFromClipRect = new Rect();
    156     private Rect mTmpToClipRect = new Rect();
    157 
    158     private final static int APP_STATE_IDLE = 0;
    159     private final static int APP_STATE_READY = 1;
    160     private final static int APP_STATE_RUNNING = 2;
    161     private final static int APP_STATE_TIMEOUT = 3;
    162     private int mAppTransitionState = APP_STATE_IDLE;
    163 
    164     private final int mConfigShortAnimTime;
    165     private final Interpolator mDecelerateInterpolator;
    166     private final Interpolator mThumbnailFadeInInterpolator;
    167     private final Interpolator mThumbnailFadeOutInterpolator;
    168     private final Interpolator mThumbnailFastOutSlowInInterpolator;
    169 
    170     private int mCurrentUserId = 0;
    171 
    172     AppTransition(Context context, Handler h) {
    173         mContext = context;
    174         mH = h;
    175         mConfigShortAnimTime = context.getResources().getInteger(
    176                 com.android.internal.R.integer.config_shortAnimTime);
    177         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
    178                 com.android.internal.R.interpolator.decelerate_cubic);
    179         mThumbnailFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
    180                 com.android.internal.R.interpolator.fast_out_slow_in);
    181         mThumbnailFadeInInterpolator = new Interpolator() {
    182             @Override
    183             public float getInterpolation(float input) {
    184                 // Linear response for first fraction, then complete after that.
    185                 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
    186                     return 0f;
    187                 }
    188                 return (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /
    189                         (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
    190             }
    191         };
    192         mThumbnailFadeOutInterpolator = new Interpolator() {
    193             @Override
    194             public float getInterpolation(float input) {
    195                 // Linear response for first fraction, then complete after that.
    196                 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
    197                     return input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
    198                 }
    199                 return 1f;
    200             }
    201         };
    202     }
    203 
    204     boolean isTransitionSet() {
    205         return mNextAppTransition != TRANSIT_UNSET;
    206     }
    207 
    208     boolean isTransitionNone() {
    209         return mNextAppTransition == TRANSIT_NONE;
    210     }
    211 
    212     boolean isTransitionEqual(int transit) {
    213         return mNextAppTransition == transit;
    214     }
    215 
    216     int getAppTransition() {
    217         return mNextAppTransition;
    218      }
    219 
    220     void setAppTransition(int transit) {
    221         mNextAppTransition = transit;
    222     }
    223 
    224     boolean isReady() {
    225         return mAppTransitionState == APP_STATE_READY
    226                 || mAppTransitionState == APP_STATE_TIMEOUT;
    227     }
    228 
    229     void setReady() {
    230         mAppTransitionState = APP_STATE_READY;
    231     }
    232 
    233     boolean isRunning() {
    234         return mAppTransitionState == APP_STATE_RUNNING;
    235     }
    236 
    237     void setIdle() {
    238         mAppTransitionState = APP_STATE_IDLE;
    239     }
    240 
    241     boolean isTimeout() {
    242         return mAppTransitionState == APP_STATE_TIMEOUT;
    243     }
    244 
    245     void setTimeout() {
    246         mAppTransitionState = APP_STATE_TIMEOUT;
    247     }
    248 
    249     Bitmap getNextAppTransitionThumbnail() {
    250         return mNextAppTransitionThumbnail;
    251     }
    252 
    253     /** Returns whether the next thumbnail transition is aspect scaled up. */
    254     boolean isNextThumbnailTransitionAspectScaled() {
    255         return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
    256                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
    257     }
    258 
    259     /** Returns whether the next thumbnail transition is scaling up. */
    260     boolean isNextThumbnailTransitionScaleUp() {
    261         return mNextAppTransitionScaleUp;
    262     }
    263 
    264     int getStartingX() {
    265         return mNextAppTransitionStartX;
    266     }
    267 
    268     int getStartingY() {
    269         return mNextAppTransitionStartY;
    270     }
    271 
    272     void prepare() {
    273         if (!isRunning()) {
    274             mAppTransitionState = APP_STATE_IDLE;
    275         }
    276     }
    277 
    278     void goodToGo() {
    279         mNextAppTransition = TRANSIT_UNSET;
    280         mAppTransitionState = APP_STATE_RUNNING;
    281     }
    282 
    283     void clear() {
    284         mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
    285         mNextAppTransitionPackage = null;
    286         mNextAppTransitionThumbnail = null;
    287     }
    288 
    289     void freeze() {
    290         setAppTransition(AppTransition.TRANSIT_UNSET);
    291         clear();
    292         setReady();
    293     }
    294 
    295     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
    296         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
    297                 + (lp != null ? lp.packageName : null)
    298                 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
    299         if (lp != null && lp.windowAnimations != 0) {
    300             // If this is a system resource, don't try to load it from the
    301             // application resources.  It is nice to avoid loading application
    302             // resources if we can.
    303             String packageName = lp.packageName != null ? lp.packageName : "android";
    304             int resId = lp.windowAnimations;
    305             if ((resId&0xFF000000) == 0x01000000) {
    306                 packageName = "android";
    307             }
    308             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
    309                     + packageName);
    310             return AttributeCache.instance().get(packageName, resId,
    311                     com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
    312         }
    313         return null;
    314     }
    315 
    316     private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
    317         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
    318                 + packageName + " resId=0x" + Integer.toHexString(resId));
    319         if (packageName != null) {
    320             if ((resId&0xFF000000) == 0x01000000) {
    321                 packageName = "android";
    322             }
    323             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
    324                     + packageName);
    325             return AttributeCache.instance().get(packageName, resId,
    326                     com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
    327         }
    328         return null;
    329     }
    330 
    331     Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) {
    332         int anim = 0;
    333         Context context = mContext;
    334         if (animAttr >= 0) {
    335             AttributeCache.Entry ent = getCachedAnimations(lp);
    336             if (ent != null) {
    337                 context = ent.context;
    338                 anim = ent.array.getResourceId(animAttr, 0);
    339             }
    340         }
    341         if (anim != 0) {
    342             return AnimationUtils.loadAnimation(context, anim);
    343         }
    344         return null;
    345     }
    346 
    347     Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) {
    348         Context context = mContext;
    349         if (resId >= 0) {
    350             AttributeCache.Entry ent = getCachedAnimations(lp);
    351             if (ent != null) {
    352                 context = ent.context;
    353             }
    354             return AnimationUtils.loadAnimation(context, resId);
    355         }
    356         return null;
    357     }
    358 
    359     private Animation loadAnimationRes(String packageName, int resId) {
    360         int anim = 0;
    361         Context context = mContext;
    362         if (resId >= 0) {
    363             AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
    364             if (ent != null) {
    365                 context = ent.context;
    366                 anim = resId;
    367             }
    368         }
    369         if (anim != 0) {
    370             return AnimationUtils.loadAnimation(context, anim);
    371         }
    372         return null;
    373     }
    374 
    375     /**
    376      * Compute the pivot point for an animation that is scaling from a small
    377      * rect on screen to a larger rect.  The pivot point varies depending on
    378      * the distance between the inner and outer edges on both sides.  This
    379      * function computes the pivot point for one dimension.
    380      * @param startPos  Offset from left/top edge of outer rectangle to
    381      * left/top edge of inner rectangle.
    382      * @param finalScale The scaling factor between the size of the outer
    383      * and inner rectangles.
    384      */
    385     private static float computePivot(int startPos, float finalScale) {
    386         final float denom = finalScale-1;
    387         if (Math.abs(denom) < .0001f) {
    388             return startPos;
    389         }
    390         return -startPos / denom;
    391     }
    392 
    393     private Animation createScaleUpAnimationLocked(int transit, boolean enter,
    394                                                    int appWidth, int appHeight) {
    395         Animation a = null;
    396         if (enter) {
    397             // Entering app zooms out from the center of the initial rect.
    398             float scaleW = mNextAppTransitionStartWidth / (float) appWidth;
    399             float scaleH = mNextAppTransitionStartHeight / (float) appHeight;
    400             Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
    401                     computePivot(mNextAppTransitionStartX, scaleW),
    402                     computePivot(mNextAppTransitionStartY, scaleH));
    403             scale.setInterpolator(mDecelerateInterpolator);
    404 
    405             Animation alpha = new AlphaAnimation(0, 1);
    406             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
    407 
    408             AnimationSet set = new AnimationSet(false);
    409             set.addAnimation(scale);
    410             set.addAnimation(alpha);
    411             set.setDetachWallpaper(true);
    412             a = set;
    413         } else  if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
    414                     transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
    415             // If we are on top of the wallpaper, we need an animation that
    416             // correctly handles the wallpaper staying static behind all of
    417             // the animated elements.  To do this, will just have the existing
    418             // element fade out.
    419             a = new AlphaAnimation(1, 0);
    420             a.setDetachWallpaper(true);
    421         } else {
    422             // For normal animations, the exiting element just holds in place.
    423             a = new AlphaAnimation(1, 1);
    424         }
    425 
    426         // Pick the desired duration.  If this is an inter-activity transition,
    427         // it  is the standard duration for that.  Otherwise we use the longer
    428         // task transition duration.
    429         final long duration;
    430         switch (transit) {
    431             case TRANSIT_ACTIVITY_OPEN:
    432             case TRANSIT_ACTIVITY_CLOSE:
    433                 duration = mConfigShortAnimTime;
    434                 break;
    435             default:
    436                 duration = DEFAULT_APP_TRANSITION_DURATION;
    437                 break;
    438         }
    439         a.setDuration(duration);
    440         a.setFillAfter(true);
    441         a.setInterpolator(mDecelerateInterpolator);
    442         a.initialize(appWidth, appHeight, appWidth, appHeight);
    443         return a;
    444     }
    445 
    446     /**
    447      * Prepares the specified animation with a standard duration, interpolator, etc.
    448      */
    449     Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
    450             int duration, Interpolator interpolator) {
    451         if (duration > 0) {
    452             a.setDuration(duration);
    453         }
    454         a.setFillAfter(true);
    455         a.setInterpolator(interpolator);
    456         a.initialize(appWidth, appHeight, appWidth, appHeight);
    457         return a;
    458     }
    459 
    460     /**
    461      * Prepares the specified animation with a standard duration, interpolator, etc.
    462      */
    463     Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
    464         // Pick the desired duration.  If this is an inter-activity transition,
    465         // it  is the standard duration for that.  Otherwise we use the longer
    466         // task transition duration.
    467         final int duration;
    468         switch (transit) {
    469             case TRANSIT_ACTIVITY_OPEN:
    470             case TRANSIT_ACTIVITY_CLOSE:
    471                 duration = mConfigShortAnimTime;
    472                 break;
    473             default:
    474                 duration = DEFAULT_APP_TRANSITION_DURATION;
    475                 break;
    476         }
    477         return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
    478                 mDecelerateInterpolator);
    479     }
    480 
    481     /**
    482      * Return the current thumbnail transition state.
    483      */
    484     int getThumbnailTransitionState(boolean enter) {
    485         if (enter) {
    486             if (mNextAppTransitionScaleUp) {
    487                 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
    488             } else {
    489                 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
    490             }
    491         } else {
    492             if (mNextAppTransitionScaleUp) {
    493                 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
    494             } else {
    495                 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
    496             }
    497         }
    498     }
    499 
    500     /**
    501      * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
    502      * when a thumbnail is specified with the activity options.
    503      */
    504     Animation createThumbnailAspectScaleAnimationLocked(int appWidth, int appHeight,
    505             int deviceWidth, int transit) {
    506         Animation a;
    507         final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
    508         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
    509         final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
    510         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
    511 
    512         float scaleW = deviceWidth / thumbWidth;
    513         float unscaledWidth = deviceWidth;
    514         float unscaledHeight = thumbHeight * scaleW;
    515         float unscaledStartY = mNextAppTransitionStartY - (unscaledHeight - thumbHeight) / 2f;
    516         if (mNextAppTransitionScaleUp) {
    517             // Animation up from the thumbnail to the full screen
    518             Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
    519                     mNextAppTransitionStartX + (thumbWidth / 2f),
    520                     mNextAppTransitionStartY + (thumbHeight / 2f));
    521             scale.setInterpolator(mThumbnailFastOutSlowInInterpolator);
    522             scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
    523             Animation alpha = new AlphaAnimation(1, 0);
    524             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
    525             alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
    526             Animation translate = new TranslateAnimation(0, 0, 0, -unscaledStartY +
    527                     mNextAppTransitionInsets.top);
    528             translate.setInterpolator(mThumbnailFastOutSlowInInterpolator);
    529             translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
    530 
    531             // This AnimationSet uses the Interpolators assigned above.
    532             AnimationSet set = new AnimationSet(false);
    533             set.addAnimation(scale);
    534             set.addAnimation(alpha);
    535             set.addAnimation(translate);
    536             a = set;
    537         } else {
    538             // Animation down from the full screen to the thumbnail
    539             Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
    540                     mNextAppTransitionStartX + (thumbWidth / 2f),
    541                     mNextAppTransitionStartY + (thumbHeight / 2f));
    542             scale.setInterpolator(mThumbnailFastOutSlowInInterpolator);
    543             scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
    544             Animation alpha = new AlphaAnimation(0f, 1f);
    545             alpha.setInterpolator(mThumbnailFadeInInterpolator);
    546             alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
    547             Animation translate = new TranslateAnimation(0, 0, -unscaledStartY +
    548                     mNextAppTransitionInsets.top, 0);
    549             translate.setInterpolator(mThumbnailFastOutSlowInInterpolator);
    550             translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
    551 
    552             // This AnimationSet uses the Interpolators assigned above.
    553             AnimationSet set = new AnimationSet(false);
    554             set.addAnimation(scale);
    555             set.addAnimation(alpha);
    556             set.addAnimation(translate);
    557             a = set;
    558 
    559         }
    560         return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, 0,
    561                 mThumbnailFastOutSlowInInterpolator);
    562     }
    563 
    564     /**
    565      * This alternate animation is created when we are doing a thumbnail transition, for the
    566      * activity that is leaving, and the activity that is entering.
    567      */
    568     Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
    569             int appWidth, int appHeight, int orientation, int transit, Rect containingFrame,
    570             Rect contentInsets, boolean isFullScreen) {
    571         Animation a;
    572         final int thumbWidthI = mNextAppTransitionStartWidth;
    573         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
    574         final int thumbHeightI = mNextAppTransitionStartHeight;
    575         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
    576 
    577         // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
    578         float scale = 1f;
    579         int scaledTopDecor = 0;
    580 
    581         switch (thumbTransitState) {
    582             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
    583                 // App window scaling up to become full screen
    584                 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
    585                     // In portrait, we scale the width and clip to the top/left square
    586                     scale = thumbWidth / appWidth;
    587                     scaledTopDecor = (int) (scale * contentInsets.top);
    588                     int unscaledThumbHeight = (int) (thumbHeight / scale);
    589                     mTmpFromClipRect.set(containingFrame);
    590                     if (isFullScreen) {
    591                         mTmpFromClipRect.top = contentInsets.top;
    592                     }
    593                     mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
    594                     mTmpToClipRect.set(containingFrame);
    595                 } else {
    596                     // In landscape, we scale the height and clip to the top/left square
    597                     scale = thumbHeight / (appHeight - contentInsets.top);
    598                     scaledTopDecor = (int) (scale * contentInsets.top);
    599                     int unscaledThumbWidth = (int) (thumbWidth / scale);
    600                     int unscaledThumbHeight = (int) (thumbHeight / scale);
    601                     mTmpFromClipRect.set(containingFrame);
    602                     if (isFullScreen) {
    603                         mTmpFromClipRect.top = contentInsets.top;
    604                         mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
    605                     }
    606                     mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth);
    607                     mTmpToClipRect.set(containingFrame);
    608                 }
    609                 mNextAppTransitionInsets.set(contentInsets);
    610 
    611                 Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
    612                         computePivot(mNextAppTransitionStartX, scale),
    613                         computePivot(mNextAppTransitionStartY, scale));
    614                 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
    615                 Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
    616 
    617                 AnimationSet set = new AnimationSet(true);
    618                 set.addAnimation(clipAnim);
    619                 set.addAnimation(scaleAnim);
    620                 set.addAnimation(translateAnim);
    621                 a = set;
    622                 break;
    623             }
    624             case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
    625                 // Previous app window during the scale up
    626                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
    627                     // Fade out the source activity if we are animating to a wallpaper
    628                     // activity.
    629                     a = new AlphaAnimation(1, 0);
    630                 } else {
    631                     a = new AlphaAnimation(1, 1);
    632                 }
    633                 break;
    634             }
    635             case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
    636                 // Target app window during the scale down
    637                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
    638                     // Fade in the destination activity if we are animating from a wallpaper
    639                     // activity.
    640                     a = new AlphaAnimation(0, 1);
    641                 } else {
    642                     a = new AlphaAnimation(1, 1);
    643                 }
    644                 break;
    645             }
    646             case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
    647                 // App window scaling down from full screen
    648                 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
    649                     // In portrait, we scale the width and clip to the top/left square
    650                     scale = thumbWidth / appWidth;
    651                     scaledTopDecor = (int) (scale * contentInsets.top);
    652                     int unscaledThumbHeight = (int) (thumbHeight / scale);
    653                     mTmpFromClipRect.set(containingFrame);
    654                     mTmpToClipRect.set(containingFrame);
    655                     if (isFullScreen) {
    656                         mTmpToClipRect.top = contentInsets.top;
    657                     }
    658                     mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight);
    659                 } else {
    660                     // In landscape, we scale the height and clip to the top/left square
    661                     scale = thumbHeight / (appHeight - contentInsets.top);
    662                     scaledTopDecor = (int) (scale * contentInsets.top);
    663                     int unscaledThumbWidth = (int) (thumbWidth / scale);
    664                     int unscaledThumbHeight = (int) (thumbHeight / scale);
    665                     mTmpFromClipRect.set(containingFrame);
    666                     mTmpToClipRect.set(containingFrame);
    667                     if (isFullScreen) {
    668                         mTmpToClipRect.top = contentInsets.top;
    669                         mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight);
    670                     }
    671                     mTmpToClipRect.right = (mTmpToClipRect.left + unscaledThumbWidth);
    672                 }
    673                 mNextAppTransitionInsets.set(contentInsets);
    674 
    675                 Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
    676                         computePivot(mNextAppTransitionStartX, scale),
    677                         computePivot(mNextAppTransitionStartY, scale));
    678                 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
    679                 Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
    680 
    681                 AnimationSet set = new AnimationSet(true);
    682                 set.addAnimation(clipAnim);
    683                 set.addAnimation(scaleAnim);
    684                 set.addAnimation(translateAnim);
    685 
    686                 a = set;
    687                 a.setZAdjustment(Animation.ZORDER_TOP);
    688                 break;
    689             }
    690             default:
    691                 throw new RuntimeException("Invalid thumbnail transition state");
    692         }
    693 
    694         return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
    695                 THUMBNAIL_APP_TRANSITION_DURATION, mThumbnailFastOutSlowInInterpolator);
    696     }
    697 
    698     /**
    699      * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
    700      * when a thumbnail is specified with the activity options.
    701      */
    702     Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit) {
    703         Animation a;
    704         final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
    705         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
    706         final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
    707         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
    708 
    709         if (mNextAppTransitionScaleUp) {
    710             // Animation for the thumbnail zooming from its initial size to the full screen
    711             float scaleW = appWidth / thumbWidth;
    712             float scaleH = appHeight / thumbHeight;
    713             Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
    714                     computePivot(mNextAppTransitionStartX, 1 / scaleW),
    715                     computePivot(mNextAppTransitionStartY, 1 / scaleH));
    716             scale.setInterpolator(mDecelerateInterpolator);
    717 
    718             Animation alpha = new AlphaAnimation(1, 0);
    719             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
    720 
    721             // This AnimationSet uses the Interpolators assigned above.
    722             AnimationSet set = new AnimationSet(false);
    723             set.addAnimation(scale);
    724             set.addAnimation(alpha);
    725             a = set;
    726         } else {
    727             // Animation for the thumbnail zooming down from the full screen to its final size
    728             float scaleW = appWidth / thumbWidth;
    729             float scaleH = appHeight / thumbHeight;
    730             a = new ScaleAnimation(scaleW, 1, scaleH, 1,
    731                     computePivot(mNextAppTransitionStartX, 1 / scaleW),
    732                     computePivot(mNextAppTransitionStartY, 1 / scaleH));
    733         }
    734 
    735         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
    736     }
    737 
    738     /**
    739      * This animation is created when we are doing a thumbnail transition, for the activity that is
    740      * leaving, and the activity that is entering.
    741      */
    742     Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
    743                                                     int appHeight, int transit) {
    744         Animation a;
    745         final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
    746         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
    747         final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
    748         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
    749 
    750         switch (thumbTransitState) {
    751             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
    752                 // Entering app scales up with the thumbnail
    753                 float scaleW = thumbWidth / appWidth;
    754                 float scaleH = thumbHeight / appHeight;
    755                 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
    756                         computePivot(mNextAppTransitionStartX, scaleW),
    757                         computePivot(mNextAppTransitionStartY, scaleH));
    758                 break;
    759             }
    760             case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
    761                 // Exiting app while the thumbnail is scaling up should fade or stay in place
    762                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
    763                     // Fade out while bringing up selected activity. This keeps the
    764                     // current activity from showing through a launching wallpaper
    765                     // activity.
    766                     a = new AlphaAnimation(1, 0);
    767                 } else {
    768                     // noop animation
    769                     a = new AlphaAnimation(1, 1);
    770                 }
    771                 break;
    772             }
    773             case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
    774                 // Entering the other app, it should just be visible while we scale the thumbnail
    775                 // down above it
    776                 a = new AlphaAnimation(1, 1);
    777                 break;
    778             }
    779             case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
    780                 // Exiting the current app, the app should scale down with the thumbnail
    781                 float scaleW = thumbWidth / appWidth;
    782                 float scaleH = thumbHeight / appHeight;
    783                 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
    784                         computePivot(mNextAppTransitionStartX, scaleW),
    785                         computePivot(mNextAppTransitionStartY, scaleH));
    786 
    787                 Animation alpha = new AlphaAnimation(1, 0);
    788 
    789                 AnimationSet set = new AnimationSet(true);
    790                 set.addAnimation(scale);
    791                 set.addAnimation(alpha);
    792                 set.setZAdjustment(Animation.ZORDER_TOP);
    793                 a = set;
    794                 break;
    795             }
    796             default:
    797                 throw new RuntimeException("Invalid thumbnail transition state");
    798         }
    799 
    800         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
    801     }
    802 
    803 
    804     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
    805             int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets,
    806             boolean isFullScreen, boolean isVoiceInteraction) {
    807         Animation a;
    808         if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
    809                 || transit == TRANSIT_TASK_OPEN
    810                 || transit == TRANSIT_TASK_TO_FRONT)) {
    811             a = loadAnimationRes(lp, enter
    812                     ? com.android.internal.R.anim.voice_activity_open_enter
    813                     : com.android.internal.R.anim.voice_activity_open_exit);
    814             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
    815                     "applyAnimation voice:"
    816                     + " anim=" + a + " transit=" + transit + " isEntrance=" + enter
    817                     + " Callers=" + Debug.getCallers(3));
    818         } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
    819                 || transit == TRANSIT_TASK_CLOSE
    820                 || transit == TRANSIT_TASK_TO_BACK)) {
    821             a = loadAnimationRes(lp, enter
    822                     ? com.android.internal.R.anim.voice_activity_close_enter
    823                     : com.android.internal.R.anim.voice_activity_close_exit);
    824             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
    825                     "applyAnimation voice:"
    826                     + " anim=" + a + " transit=" + transit + " isEntrance=" + enter
    827                     + " Callers=" + Debug.getCallers(3));
    828         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
    829             a = loadAnimationRes(mNextAppTransitionPackage, enter ?
    830                     mNextAppTransitionEnter : mNextAppTransitionExit);
    831             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
    832                     "applyAnimation:"
    833                     + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
    834                     + " transit=" + transit + " isEntrance=" + enter
    835                     + " Callers=" + Debug.getCallers(3));
    836         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
    837             a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
    838             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
    839                     "applyAnimation:"
    840                     + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
    841                     + " transit=" + transit + " isEntrance=" + enter
    842                     + " Callers=" + Debug.getCallers(3));
    843         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
    844                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
    845             mNextAppTransitionScaleUp =
    846                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
    847             a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
    848                     appWidth, appHeight, transit);
    849             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
    850                 String animName = mNextAppTransitionScaleUp ?
    851                         "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
    852                 Slog.v(TAG, "applyAnimation:"
    853                         + " anim=" + a + " nextAppTransition=" + animName
    854                         + " transit=" + transit + " isEntrance=" + enter
    855                         + " Callers=" + Debug.getCallers(3));
    856             }
    857         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
    858                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
    859             mNextAppTransitionScaleUp =
    860                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
    861             a = createAspectScaledThumbnailEnterExitAnimationLocked(
    862                     getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
    863                     transit, containingFrame, contentInsets, isFullScreen);
    864             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
    865                 String animName = mNextAppTransitionScaleUp ?
    866                         "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
    867                 Slog.v(TAG, "applyAnimation:"
    868                         + " anim=" + a + " nextAppTransition=" + animName
    869                         + " transit=" + transit + " isEntrance=" + enter
    870                         + " Callers=" + Debug.getCallers(3));
    871             }
    872         } else {
    873             int animAttr = 0;
    874             switch (transit) {
    875                 case TRANSIT_ACTIVITY_OPEN:
    876                     animAttr = enter
    877                             ? WindowAnimation_activityOpenEnterAnimation
    878                             : WindowAnimation_activityOpenExitAnimation;
    879                     break;
    880                 case TRANSIT_ACTIVITY_CLOSE:
    881                     animAttr = enter
    882                             ? WindowAnimation_activityCloseEnterAnimation
    883                             : WindowAnimation_activityCloseExitAnimation;
    884                     break;
    885                 case TRANSIT_TASK_OPEN:
    886                     animAttr = enter
    887                             ? WindowAnimation_taskOpenEnterAnimation
    888                             : WindowAnimation_taskOpenExitAnimation;
    889                     break;
    890                 case TRANSIT_TASK_CLOSE:
    891                     animAttr = enter
    892                             ? WindowAnimation_taskCloseEnterAnimation
    893                             : WindowAnimation_taskCloseExitAnimation;
    894                     break;
    895                 case TRANSIT_TASK_TO_FRONT:
    896                     animAttr = enter
    897                             ? WindowAnimation_taskToFrontEnterAnimation
    898                             : WindowAnimation_taskToFrontExitAnimation;
    899                     break;
    900                 case TRANSIT_TASK_TO_BACK:
    901                     animAttr = enter
    902                             ? WindowAnimation_taskToBackEnterAnimation
    903                             : WindowAnimation_taskToBackExitAnimation;
    904                     break;
    905                 case TRANSIT_WALLPAPER_OPEN:
    906                     animAttr = enter
    907                             ? WindowAnimation_wallpaperOpenEnterAnimation
    908                             : WindowAnimation_wallpaperOpenExitAnimation;
    909                     break;
    910                 case TRANSIT_WALLPAPER_CLOSE:
    911                     animAttr = enter
    912                             ? WindowAnimation_wallpaperCloseEnterAnimation
    913                             : WindowAnimation_wallpaperCloseExitAnimation;
    914                     break;
    915                 case TRANSIT_WALLPAPER_INTRA_OPEN:
    916                     animAttr = enter
    917                             ? WindowAnimation_wallpaperIntraOpenEnterAnimation
    918                             : WindowAnimation_wallpaperIntraOpenExitAnimation;
    919                     break;
    920                 case TRANSIT_WALLPAPER_INTRA_CLOSE:
    921                     animAttr = enter
    922                             ? WindowAnimation_wallpaperIntraCloseEnterAnimation
    923                             : WindowAnimation_wallpaperIntraCloseExitAnimation;
    924                     break;
    925                 case TRANSIT_TASK_OPEN_BEHIND:
    926                     animAttr = enter
    927                             ? WindowAnimation_launchTaskBehindSourceAnimation
    928                             : WindowAnimation_launchTaskBehindTargetAnimation;
    929             }
    930             a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
    931             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
    932                     "applyAnimation:"
    933                     + " anim=" + a
    934                     + " animAttr=0x" + Integer.toHexString(animAttr)
    935                     + " transit=" + transit + " isEntrance=" + enter
    936                     + " Callers=" + Debug.getCallers(3));
    937         }
    938         return a;
    939     }
    940 
    941     void postAnimationCallback() {
    942         if (mNextAppTransitionCallback != null) {
    943             mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, mNextAppTransitionCallback));
    944             mNextAppTransitionCallback = null;
    945         }
    946     }
    947 
    948     void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
    949                                              IRemoteCallback startedCallback) {
    950         if (isTransitionSet()) {
    951             mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
    952             mNextAppTransitionPackage = packageName;
    953             mNextAppTransitionThumbnail = null;
    954             mNextAppTransitionEnter = enterAnim;
    955             mNextAppTransitionExit = exitAnim;
    956             postAnimationCallback();
    957             mNextAppTransitionCallback = startedCallback;
    958         } else {
    959             postAnimationCallback();
    960         }
    961     }
    962 
    963     void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
    964                                                     int startHeight) {
    965         if (isTransitionSet()) {
    966             mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
    967             mNextAppTransitionPackage = null;
    968             mNextAppTransitionThumbnail = null;
    969             mNextAppTransitionStartX = startX;
    970             mNextAppTransitionStartY = startY;
    971             mNextAppTransitionStartWidth = startWidth;
    972             mNextAppTransitionStartHeight = startHeight;
    973             postAnimationCallback();
    974             mNextAppTransitionCallback = null;
    975         }
    976     }
    977 
    978     void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
    979                                            IRemoteCallback startedCallback, boolean scaleUp) {
    980         if (isTransitionSet()) {
    981             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
    982                     : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
    983             mNextAppTransitionPackage = null;
    984             mNextAppTransitionThumbnail = srcThumb;
    985             mNextAppTransitionScaleUp = scaleUp;
    986             mNextAppTransitionStartX = startX;
    987             mNextAppTransitionStartY = startY;
    988             postAnimationCallback();
    989             mNextAppTransitionCallback = startedCallback;
    990         } else {
    991             postAnimationCallback();
    992         }
    993     }
    994 
    995     void overridePendingAppTransitionAspectScaledThumb(Bitmap srcThumb, int startX, int startY,
    996             int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) {
    997         if (isTransitionSet()) {
    998             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
    999                     : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
   1000             mNextAppTransitionPackage = null;
   1001             mNextAppTransitionThumbnail = srcThumb;
   1002             mNextAppTransitionScaleUp = scaleUp;
   1003             mNextAppTransitionStartX = startX;
   1004             mNextAppTransitionStartY = startY;
   1005             mNextAppTransitionStartWidth = targetWidth;
   1006             mNextAppTransitionStartHeight = targetHeight;
   1007             postAnimationCallback();
   1008             mNextAppTransitionCallback = startedCallback;
   1009         } else {
   1010             postAnimationCallback();
   1011         }
   1012     }
   1013 
   1014     @Override
   1015     public String toString() {
   1016         return "mNextAppTransition=0x" + Integer.toHexString(mNextAppTransition);
   1017     }
   1018 
   1019     /**
   1020      * Returns the human readable name of a window transition.
   1021      *
   1022      * @param transition The window transition.
   1023      * @return The transition symbolic name.
   1024      */
   1025     public static String appTransitionToString(int transition) {
   1026         switch (transition) {
   1027             case TRANSIT_UNSET: {
   1028                 return "TRANSIT_UNSET";
   1029             }
   1030             case TRANSIT_NONE: {
   1031                 return "TRANSIT_NONE";
   1032             }
   1033             case TRANSIT_ACTIVITY_OPEN: {
   1034                 return "TRANSIT_ACTIVITY_OPEN";
   1035             }
   1036             case TRANSIT_ACTIVITY_CLOSE: {
   1037                 return "TRANSIT_ACTIVITY_CLOSE";
   1038             }
   1039             case TRANSIT_TASK_OPEN: {
   1040                 return "TRANSIT_TASK_OPEN";
   1041             }
   1042             case TRANSIT_TASK_CLOSE: {
   1043                 return "TRANSIT_TASK_CLOSE";
   1044             }
   1045             case TRANSIT_TASK_TO_FRONT: {
   1046                 return "TRANSIT_TASK_TO_FRONT";
   1047             }
   1048             case TRANSIT_TASK_TO_BACK: {
   1049                 return "TRANSIT_TASK_TO_BACK";
   1050             }
   1051             case TRANSIT_WALLPAPER_CLOSE: {
   1052                 return "TRANSIT_WALLPAPER_CLOSE";
   1053             }
   1054             case TRANSIT_WALLPAPER_OPEN: {
   1055                 return "TRANSIT_WALLPAPER_OPEN";
   1056             }
   1057             case TRANSIT_WALLPAPER_INTRA_OPEN: {
   1058                 return "TRANSIT_WALLPAPER_INTRA_OPEN";
   1059             }
   1060             case TRANSIT_WALLPAPER_INTRA_CLOSE: {
   1061                 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
   1062             }
   1063             case TRANSIT_TASK_OPEN_BEHIND: {
   1064                 return "TRANSIT_TASK_OPEN_BEHIND";
   1065             }
   1066             default: {
   1067                 return "<UNKNOWN>";
   1068             }
   1069         }
   1070     }
   1071 
   1072     private String appStateToString() {
   1073         switch (mAppTransitionState) {
   1074             case APP_STATE_IDLE:
   1075                 return "APP_STATE_IDLE";
   1076             case APP_STATE_READY:
   1077                 return "APP_STATE_READY";
   1078             case APP_STATE_RUNNING:
   1079                 return "APP_STATE_RUNNING";
   1080             case APP_STATE_TIMEOUT:
   1081                 return "APP_STATE_TIMEOUT";
   1082             default:
   1083                 return "unknown state=" + mAppTransitionState;
   1084         }
   1085     }
   1086 
   1087     private String transitTypeToString() {
   1088         switch (mNextAppTransitionType) {
   1089             case NEXT_TRANSIT_TYPE_NONE:
   1090                 return "NEXT_TRANSIT_TYPE_NONE";
   1091             case NEXT_TRANSIT_TYPE_CUSTOM:
   1092                 return "NEXT_TRANSIT_TYPE_CUSTOM";
   1093             case NEXT_TRANSIT_TYPE_SCALE_UP:
   1094                 return "NEXT_TRANSIT_TYPE_SCALE_UP";
   1095             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
   1096                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
   1097             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
   1098                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
   1099             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
   1100                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
   1101             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
   1102                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
   1103             default:
   1104                 return "unknown type=" + mNextAppTransitionType;
   1105         }
   1106     }
   1107 
   1108     @Override
   1109     public void dump(PrintWriter pw) {
   1110         pw.print(" " + this);
   1111         pw.print("  mAppTransitionState="); pw.println(appStateToString());
   1112         if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
   1113             pw.print("  mNextAppTransitionType="); pw.println(transitTypeToString());
   1114         }
   1115         switch (mNextAppTransitionType) {
   1116             case NEXT_TRANSIT_TYPE_CUSTOM:
   1117                 pw.print("  mNextAppTransitionPackage=");
   1118                         pw.println(mNextAppTransitionPackage);
   1119                 pw.print("  mNextAppTransitionEnter=0x");
   1120                         pw.print(Integer.toHexString(mNextAppTransitionEnter));
   1121                         pw.print(" mNextAppTransitionExit=0x");
   1122                         pw.println(Integer.toHexString(mNextAppTransitionExit));
   1123                 break;
   1124             case NEXT_TRANSIT_TYPE_SCALE_UP:
   1125                 pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
   1126                         pw.print(" mNextAppTransitionStartY=");
   1127                         pw.println(mNextAppTransitionStartY);
   1128                 pw.print("  mNextAppTransitionStartWidth=");
   1129                         pw.print(mNextAppTransitionStartWidth);
   1130                         pw.print(" mNextAppTransitionStartHeight=");
   1131                         pw.println(mNextAppTransitionStartHeight);
   1132                 break;
   1133             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
   1134             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
   1135             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
   1136             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
   1137                 pw.print("  mNextAppTransitionThumbnail=");
   1138                         pw.print(mNextAppTransitionThumbnail);
   1139                         pw.print(" mNextAppTransitionStartX=");
   1140                         pw.print(mNextAppTransitionStartX);
   1141                         pw.print(" mNextAppTransitionStartY=");
   1142                         pw.println(mNextAppTransitionStartY);
   1143                         pw.print(" mNextAppTransitionStartWidth=");
   1144                         pw.print(mNextAppTransitionStartWidth);
   1145                         pw.print(" mNextAppTransitionStartHeight=");
   1146                         pw.println(mNextAppTransitionStartHeight);
   1147                 pw.print("  mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
   1148                 break;
   1149         }
   1150         if (mNextAppTransitionCallback != null) {
   1151             pw.print("  mNextAppTransitionCallback=");
   1152             pw.println(mNextAppTransitionCallback);
   1153         }
   1154     }
   1155 
   1156     public void setCurrentUser(int newUserId) {
   1157         mCurrentUserId = newUserId;
   1158     }
   1159 }
   1160