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