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