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.graphics.Bitmap;
     21 import android.graphics.Point;
     22 import android.os.Debug;
     23 import android.os.Handler;
     24 import android.os.IRemoteCallback;
     25 import android.util.Slog;
     26 import android.view.WindowManager;
     27 import android.view.animation.AlphaAnimation;
     28 import android.view.animation.Animation;
     29 import android.view.animation.AnimationSet;
     30 import android.view.animation.AnimationUtils;
     31 import android.view.animation.Interpolator;
     32 import android.view.animation.ScaleAnimation;
     33 
     34 import com.android.internal.util.DumpUtils.Dump;
     35 import com.android.server.AttributeCache;
     36 import com.android.server.wm.WindowManagerService.H;
     37 
     38 import java.io.PrintWriter;
     39 
     40 import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
     41 import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
     42 import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
     43 import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
     44 import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
     45 import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
     46 import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
     47 import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
     48 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
     49 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
     50 import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
     51 import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
     52 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
     53 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
     54 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
     55 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
     56 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
     57 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
     58 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
     59 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
     60 
     61 // State management of app transitions.  When we are preparing for a
     62 // transition, mNextAppTransition will be the kind of transition to
     63 // perform or TRANSIT_NONE if we are not waiting.  If we are waiting,
     64 // mOpeningApps and mClosingApps are the lists of tokens that will be
     65 // made visible or hidden at the next transition.
     66 public class AppTransition implements Dump {
     67     private static final String TAG = "AppTransition";
     68     private static final boolean DEBUG_APP_TRANSITIONS =
     69             WindowManagerService.DEBUG_APP_TRANSITIONS;
     70     private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM;
     71 
     72     /** Bit mask that is set for all enter transition. */
     73     public static final int TRANSIT_ENTER_MASK = 0x1000;
     74 
     75     /** Bit mask that is set for all exit transitions. */
     76     public static final int TRANSIT_EXIT_MASK = 0x2000;
     77 
     78     /** Not set up for a transition. */
     79     public static final int TRANSIT_UNSET = -1;
     80     /** No animation for transition. */
     81     public static final int TRANSIT_NONE = 0;
     82     /** A window in a new activity is being opened on top of an existing one in the same task. */
     83     public static final int TRANSIT_ACTIVITY_OPEN = 6 | TRANSIT_ENTER_MASK;
     84     /** The window in the top-most activity is being closed to reveal the
     85      * previous activity in the same task. */
     86     public static final int TRANSIT_ACTIVITY_CLOSE = 7 | TRANSIT_EXIT_MASK;
     87     /** A window in a new task is being opened on top of an existing one
     88      * in another activity's task. */
     89     public static final int TRANSIT_TASK_OPEN = 8 | TRANSIT_ENTER_MASK;
     90     /** A window in the top-most activity is being closed to reveal the
     91      * previous activity in a different task. */
     92     public static final int TRANSIT_TASK_CLOSE = 9 | TRANSIT_EXIT_MASK;
     93     /** A window in an existing task is being displayed on top of an existing one
     94      * in another activity's task. */
     95     public static final int TRANSIT_TASK_TO_FRONT = 10 | TRANSIT_ENTER_MASK;
     96     /** A window in an existing task is being put below all other tasks. */
     97     public static final int TRANSIT_TASK_TO_BACK = 11 | TRANSIT_EXIT_MASK;
     98     /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that
     99      * does, effectively closing the wallpaper. */
    100     public static final int TRANSIT_WALLPAPER_CLOSE = 12 | TRANSIT_EXIT_MASK;
    101     /** A window in a new activity that does have a wallpaper is being opened on one that didn't,
    102      * effectively opening the wallpaper. */
    103     public static final int TRANSIT_WALLPAPER_OPEN = 13 | TRANSIT_ENTER_MASK;
    104     /** A window in a new activity is being opened on top of an existing one, and both are on top
    105      * of the wallpaper. */
    106     public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14 | TRANSIT_ENTER_MASK;
    107     /** The window in the top-most activity is being closed to reveal the previous activity, and
    108      * both are on top of the wallpaper. */
    109     public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15 | TRANSIT_EXIT_MASK;
    110 
    111     /** Fraction of animation at which the recents thumbnail becomes completely transparent */
    112     private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.25f;
    113 
    114     private static final long DEFAULT_APP_TRANSITION_DURATION = 250;
    115 
    116     private final Context mContext;
    117     private final Handler mH;
    118 
    119     private int mNextAppTransition = TRANSIT_UNSET;
    120 
    121     private static final int NEXT_TRANSIT_TYPE_NONE = 0;
    122     private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
    123     private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
    124     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
    125     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
    126     private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
    127 
    128     private String mNextAppTransitionPackage;
    129     private Bitmap mNextAppTransitionThumbnail;
    130     // Used for thumbnail transitions. True if we're scaling up, false if scaling down
    131     private boolean mNextAppTransitionScaleUp;
    132     private IRemoteCallback mNextAppTransitionCallback;
    133     private int mNextAppTransitionEnter;
    134     private int mNextAppTransitionExit;
    135     private int mNextAppTransitionStartX;
    136     private int mNextAppTransitionStartY;
    137     private int mNextAppTransitionStartWidth;
    138     private int mNextAppTransitionStartHeight;
    139 
    140     private final static int APP_STATE_IDLE = 0;
    141     private final static int APP_STATE_READY = 1;
    142     private final static int APP_STATE_RUNNING = 2;
    143     private final static int APP_STATE_TIMEOUT = 3;
    144     private int mAppTransitionState = APP_STATE_IDLE;
    145 
    146     private final int mConfigShortAnimTime;
    147     private final Interpolator mDecelerateInterpolator;
    148     private final Interpolator mThumbnailFadeoutInterpolator;
    149 
    150     private int mCurrentUserId = 0;
    151 
    152     AppTransition(Context context, Handler h) {
    153         mContext = context;
    154         mH = h;
    155         mConfigShortAnimTime = context.getResources().getInteger(
    156                 com.android.internal.R.integer.config_shortAnimTime);
    157         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
    158                 com.android.internal.R.interpolator.decelerate_cubic);
    159         mThumbnailFadeoutInterpolator = new Interpolator() {
    160             @Override
    161             public float getInterpolation(float input) {
    162                 // Linear response for first fraction, then complete after that.
    163                 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
    164                     return input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
    165                 }
    166                 return 1.0f;
    167             }
    168         };
    169     }
    170 
    171     boolean isTransitionSet() {
    172         return mNextAppTransition != TRANSIT_UNSET;
    173     }
    174 
    175     boolean isTransitionNone() {
    176         return mNextAppTransition == TRANSIT_NONE;
    177     }
    178 
    179     boolean isTransitionEqual(int transit) {
    180         return mNextAppTransition == transit;
    181     }
    182 
    183     int getAppTransition() {
    184         return mNextAppTransition;
    185      }
    186 
    187     void setAppTransition(int transit) {
    188         mNextAppTransition = transit;
    189     }
    190 
    191     boolean isReady() {
    192         return mAppTransitionState == APP_STATE_READY
    193                 || mAppTransitionState == APP_STATE_TIMEOUT;
    194     }
    195 
    196     void setReady() {
    197         mAppTransitionState = APP_STATE_READY;
    198     }
    199 
    200     boolean isRunning() {
    201         return mAppTransitionState == APP_STATE_RUNNING;
    202     }
    203 
    204     void setIdle() {
    205         mAppTransitionState = APP_STATE_IDLE;
    206     }
    207 
    208     boolean isTimeout() {
    209         return mAppTransitionState == APP_STATE_TIMEOUT;
    210     }
    211 
    212     void setTimeout() {
    213         mAppTransitionState = APP_STATE_TIMEOUT;
    214     }
    215 
    216     Bitmap getNextAppTransitionThumbnail() {
    217         return mNextAppTransitionThumbnail;
    218     }
    219 
    220     void getStartingPoint(Point outPoint) {
    221         outPoint.x = mNextAppTransitionStartX;
    222         outPoint.y = mNextAppTransitionStartY;
    223     }
    224 
    225     void prepare() {
    226         if (!isRunning()) {
    227             mAppTransitionState = APP_STATE_IDLE;
    228         }
    229     }
    230 
    231     void goodToGo() {
    232         mNextAppTransition = TRANSIT_UNSET;
    233         mAppTransitionState = APP_STATE_RUNNING;
    234     }
    235 
    236     void clear() {
    237         mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
    238         mNextAppTransitionPackage = null;
    239         mNextAppTransitionThumbnail = null;
    240     }
    241 
    242     void freeze() {
    243         setAppTransition(AppTransition.TRANSIT_UNSET);
    244         clear();
    245         setReady();
    246     }
    247 
    248     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
    249         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
    250                 + (lp != null ? lp.packageName : null)
    251                 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
    252         if (lp != null && lp.windowAnimations != 0) {
    253             // If this is a system resource, don't try to load it from the
    254             // application resources.  It is nice to avoid loading application
    255             // resources if we can.
    256             String packageName = lp.packageName != null ? lp.packageName : "android";
    257             int resId = lp.windowAnimations;
    258             if ((resId&0xFF000000) == 0x01000000) {
    259                 packageName = "android";
    260             }
    261             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
    262                     + packageName);
    263             return AttributeCache.instance().get(packageName, resId,
    264                     com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
    265         }
    266         return null;
    267     }
    268 
    269     private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
    270         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
    271                 + packageName + " resId=0x" + Integer.toHexString(resId));
    272         if (packageName != null) {
    273             if ((resId&0xFF000000) == 0x01000000) {
    274                 packageName = "android";
    275             }
    276             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
    277                     + packageName);
    278             return AttributeCache.instance().get(packageName, resId,
    279                     com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
    280         }
    281         return null;
    282     }
    283 
    284     Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
    285         int anim = 0;
    286         Context context = mContext;
    287         if (animAttr >= 0) {
    288             AttributeCache.Entry ent = getCachedAnimations(lp);
    289             if (ent != null) {
    290                 context = ent.context;
    291                 anim = ent.array.getResourceId(animAttr, 0);
    292             }
    293         }
    294         if (anim != 0) {
    295             return AnimationUtils.loadAnimation(context, anim);
    296         }
    297         return null;
    298     }
    299 
    300     private Animation loadAnimation(String packageName, int resId) {
    301         int anim = 0;
    302         Context context = mContext;
    303         if (resId >= 0) {
    304             AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
    305             if (ent != null) {
    306                 context = ent.context;
    307                 anim = resId;
    308             }
    309         }
    310         if (anim != 0) {
    311             return AnimationUtils.loadAnimation(context, anim);
    312         }
    313         return null;
    314     }
    315 
    316     /**
    317      * Compute the pivot point for an animation that is scaling from a small
    318      * rect on screen to a larger rect.  The pivot point varies depending on
    319      * the distance between the inner and outer edges on both sides.  This
    320      * function computes the pivot point for one dimension.
    321      * @param startPos  Offset from left/top edge of outer rectangle to
    322      * left/top edge of inner rectangle.
    323      * @param finalScale The scaling factor between the size of the outer
    324      * and inner rectangles.
    325      */
    326     private static float computePivot(int startPos, float finalScale) {
    327         final float denom = finalScale-1;
    328         if (Math.abs(denom) < .0001f) {
    329             return startPos;
    330         }
    331         return -startPos / denom;
    332     }
    333 
    334     private Animation createScaleUpAnimationLocked(int transit, boolean enter,
    335                                                    int appWidth, int appHeight) {
    336         Animation a = null;
    337         if (enter) {
    338             // Entering app zooms out from the center of the initial rect.
    339             float scaleW = mNextAppTransitionStartWidth / (float) appWidth;
    340             float scaleH = mNextAppTransitionStartHeight / (float) appHeight;
    341             Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
    342                     computePivot(mNextAppTransitionStartX, scaleW),
    343                     computePivot(mNextAppTransitionStartY, scaleH));
    344             scale.setInterpolator(mDecelerateInterpolator);
    345 
    346             Animation alpha = new AlphaAnimation(0, 1);
    347             alpha.setInterpolator(mThumbnailFadeoutInterpolator);
    348 
    349             AnimationSet set = new AnimationSet(false);
    350             set.addAnimation(scale);
    351             set.addAnimation(alpha);
    352             set.setDetachWallpaper(true);
    353             a = set;
    354         } else  if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
    355                     transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
    356             // If we are on top of the wallpaper, we need an animation that
    357             // correctly handles the wallpaper staying static behind all of
    358             // the animated elements.  To do this, will just have the existing
    359             // element fade out.
    360             a = new AlphaAnimation(1, 0);
    361             a.setDetachWallpaper(true);
    362         } else {
    363             // For normal animations, the exiting element just holds in place.
    364             a = new AlphaAnimation(1, 1);
    365         }
    366 
    367         // Pick the desired duration.  If this is an inter-activity transition,
    368         // it  is the standard duration for that.  Otherwise we use the longer
    369         // task transition duration.
    370         final long duration;
    371         switch (transit) {
    372             case TRANSIT_ACTIVITY_OPEN:
    373             case TRANSIT_ACTIVITY_CLOSE:
    374                 duration = mConfigShortAnimTime;
    375                 break;
    376             default:
    377                 duration = DEFAULT_APP_TRANSITION_DURATION;
    378                 break;
    379         }
    380         a.setDuration(duration);
    381         a.setFillAfter(true);
    382         a.setInterpolator(mDecelerateInterpolator);
    383         a.initialize(appWidth, appHeight, appWidth, appHeight);
    384         return a;
    385     }
    386 
    387     Animation createThumbnailAnimationLocked(int transit, boolean enter, boolean thumb,
    388                                     int appWidth, int appHeight) {
    389         Animation a;
    390         final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
    391         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
    392         final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
    393         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
    394         if (thumb) {
    395             // Animation for zooming thumbnail from its initial size to
    396             // filling the screen.
    397             if (mNextAppTransitionScaleUp) {
    398                 float scaleW = appWidth / thumbWidth;
    399                 float scaleH = appHeight / thumbHeight;
    400                 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
    401                         computePivot(mNextAppTransitionStartX, 1 / scaleW),
    402                         computePivot(mNextAppTransitionStartY, 1 / scaleH));
    403                 scale.setInterpolator(mDecelerateInterpolator);
    404 
    405                 Animation alpha = new AlphaAnimation(1, 0);
    406                 alpha.setInterpolator(mThumbnailFadeoutInterpolator);
    407 
    408                 // This AnimationSet uses the Interpolators assigned above.
    409                 AnimationSet set = new AnimationSet(false);
    410                 set.addAnimation(scale);
    411                 set.addAnimation(alpha);
    412                 a = set;
    413             } else {
    414                 float scaleW = appWidth / thumbWidth;
    415                 float scaleH = appHeight / thumbHeight;
    416                 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
    417                         computePivot(mNextAppTransitionStartX, 1 / scaleW),
    418                         computePivot(mNextAppTransitionStartY, 1 / scaleH));
    419             }
    420         } else if (enter) {
    421             // Entering app zooms out from the center of the thumbnail.
    422             if (mNextAppTransitionScaleUp) {
    423                 float scaleW = thumbWidth / appWidth;
    424                 float scaleH = thumbHeight / appHeight;
    425                 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
    426                         computePivot(mNextAppTransitionStartX, scaleW),
    427                         computePivot(mNextAppTransitionStartY, scaleH));
    428             } else {
    429                 // noop animation
    430                 a = new AlphaAnimation(1, 1);
    431             }
    432         } else {
    433             // Exiting app
    434             if (mNextAppTransitionScaleUp) {
    435                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
    436                     // Fade out while bringing up selected activity. This keeps the
    437                     // current activity from showing through a launching wallpaper
    438                     // activity.
    439                     a = new AlphaAnimation(1, 0);
    440                 } else {
    441                     // noop animation
    442                     a = new AlphaAnimation(1, 1);
    443                 }
    444             } else {
    445                 float scaleW = thumbWidth / appWidth;
    446                 float scaleH = thumbHeight / appHeight;
    447                 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
    448                         computePivot(mNextAppTransitionStartX, scaleW),
    449                         computePivot(mNextAppTransitionStartY, scaleH));
    450 
    451                 Animation alpha = new AlphaAnimation(1, 0);
    452 
    453                 AnimationSet set = new AnimationSet(true);
    454                 set.addAnimation(scale);
    455                 set.addAnimation(alpha);
    456                 set.setZAdjustment(Animation.ZORDER_TOP);
    457                 a = set;
    458             }
    459         }
    460 
    461         // Pick the desired duration.  If this is an inter-activity transition,
    462         // it  is the standard duration for that.  Otherwise we use the longer
    463         // task transition duration.
    464         final long duration;
    465         switch (transit) {
    466             case TRANSIT_ACTIVITY_OPEN:
    467             case TRANSIT_ACTIVITY_CLOSE:
    468                 duration = mConfigShortAnimTime;
    469                 break;
    470             default:
    471                 duration = DEFAULT_APP_TRANSITION_DURATION;
    472                 break;
    473         }
    474         a.setDuration(duration);
    475         a.setFillAfter(true);
    476         a.setInterpolator(mDecelerateInterpolator);
    477         a.initialize(appWidth, appHeight, appWidth, appHeight);
    478         return a;
    479     }
    480 
    481 
    482     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
    483                             int appWidth, int appHeight) {
    484         Animation a;
    485         if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
    486             a = loadAnimation(mNextAppTransitionPackage, enter ?
    487                     mNextAppTransitionEnter : mNextAppTransitionExit);
    488             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
    489                     "applyAnimation:"
    490                     + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
    491                     + " transit=" + transit + " isEntrance=" + enter
    492                     + " Callers=" + Debug.getCallers(3));
    493         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
    494             a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
    495             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
    496                     "applyAnimation:"
    497                     + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
    498                     + " transit=" + transit + " isEntrance=" + enter
    499                     + " Callers=" + Debug.getCallers(3));
    500         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
    501                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
    502             mNextAppTransitionScaleUp =
    503                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
    504             a = createThumbnailAnimationLocked(transit, enter, false, appWidth, appHeight);
    505             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
    506                 String animName = mNextAppTransitionScaleUp ?
    507                         "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
    508                 Slog.v(TAG, "applyAnimation:"
    509                         + " anim=" + a + " nextAppTransition=" + animName
    510                         + " transit=" + transit + " isEntrance=" + enter
    511                         + " Callers=" + Debug.getCallers(3));
    512             }
    513         } else {
    514             int animAttr = 0;
    515             switch (transit) {
    516                 case TRANSIT_ACTIVITY_OPEN:
    517                     animAttr = enter
    518                             ? WindowAnimation_activityOpenEnterAnimation
    519                             : WindowAnimation_activityOpenExitAnimation;
    520                     break;
    521                 case TRANSIT_ACTIVITY_CLOSE:
    522                     animAttr = enter
    523                             ? WindowAnimation_activityCloseEnterAnimation
    524                             : WindowAnimation_activityCloseExitAnimation;
    525                     break;
    526                 case TRANSIT_TASK_OPEN:
    527                     animAttr = enter
    528                             ? WindowAnimation_taskOpenEnterAnimation
    529                             : WindowAnimation_taskOpenExitAnimation;
    530                     break;
    531                 case TRANSIT_TASK_CLOSE:
    532                     animAttr = enter
    533                             ? WindowAnimation_taskCloseEnterAnimation
    534                             : WindowAnimation_taskCloseExitAnimation;
    535                     break;
    536                 case TRANSIT_TASK_TO_FRONT:
    537                     animAttr = enter
    538                             ? WindowAnimation_taskToFrontEnterAnimation
    539                             : WindowAnimation_taskToFrontExitAnimation;
    540                     break;
    541                 case TRANSIT_TASK_TO_BACK:
    542                     animAttr = enter
    543                             ? WindowAnimation_taskToBackEnterAnimation
    544                             : WindowAnimation_taskToBackExitAnimation;
    545                     break;
    546                 case TRANSIT_WALLPAPER_OPEN:
    547                     animAttr = enter
    548                             ? WindowAnimation_wallpaperOpenEnterAnimation
    549                             : WindowAnimation_wallpaperOpenExitAnimation;
    550                     break;
    551                 case TRANSIT_WALLPAPER_CLOSE:
    552                     animAttr = enter
    553                             ? WindowAnimation_wallpaperCloseEnterAnimation
    554                             : WindowAnimation_wallpaperCloseExitAnimation;
    555                     break;
    556                 case TRANSIT_WALLPAPER_INTRA_OPEN:
    557                     animAttr = enter
    558                             ? WindowAnimation_wallpaperIntraOpenEnterAnimation
    559                             : WindowAnimation_wallpaperIntraOpenExitAnimation;
    560                     break;
    561                 case TRANSIT_WALLPAPER_INTRA_CLOSE:
    562                     animAttr = enter
    563                             ? WindowAnimation_wallpaperIntraCloseEnterAnimation
    564                             : WindowAnimation_wallpaperIntraCloseExitAnimation;
    565                     break;
    566             }
    567             a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
    568             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
    569                     "applyAnimation:"
    570                     + " anim=" + a
    571                     + " animAttr=0x" + Integer.toHexString(animAttr)
    572                     + " transit=" + transit + " isEntrance=" + enter
    573                     + " Callers=" + Debug.getCallers(3));
    574         }
    575         return a;
    576     }
    577 
    578     void postAnimationCallback() {
    579         if (mNextAppTransitionCallback != null) {
    580             mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, mNextAppTransitionCallback));
    581             mNextAppTransitionCallback = null;
    582         }
    583     }
    584 
    585     void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
    586                                              IRemoteCallback startedCallback) {
    587         if (isTransitionSet()) {
    588             mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
    589             mNextAppTransitionPackage = packageName;
    590             mNextAppTransitionThumbnail = null;
    591             mNextAppTransitionEnter = enterAnim;
    592             mNextAppTransitionExit = exitAnim;
    593             postAnimationCallback();
    594             mNextAppTransitionCallback = startedCallback;
    595         } else {
    596             postAnimationCallback();
    597         }
    598     }
    599 
    600     void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
    601                                                     int startHeight) {
    602         if (isTransitionSet()) {
    603             mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
    604             mNextAppTransitionPackage = null;
    605             mNextAppTransitionThumbnail = null;
    606             mNextAppTransitionStartX = startX;
    607             mNextAppTransitionStartY = startY;
    608             mNextAppTransitionStartWidth = startWidth;
    609             mNextAppTransitionStartHeight = startHeight;
    610             postAnimationCallback();
    611             mNextAppTransitionCallback = null;
    612         }
    613     }
    614 
    615     void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
    616                                            IRemoteCallback startedCallback, boolean scaleUp) {
    617         if (isTransitionSet()) {
    618             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
    619                     : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
    620             mNextAppTransitionPackage = null;
    621             mNextAppTransitionThumbnail = srcThumb;
    622             mNextAppTransitionScaleUp = scaleUp;
    623             mNextAppTransitionStartX = startX;
    624             mNextAppTransitionStartY = startY;
    625             postAnimationCallback();
    626             mNextAppTransitionCallback = startedCallback;
    627         } else {
    628             postAnimationCallback();
    629         }
    630     }
    631 
    632     @Override
    633     public String toString() {
    634         return "mNextAppTransition=0x" + Integer.toHexString(mNextAppTransition);
    635     }
    636 
    637     /**
    638      * Returns the human readable name of a window transition.
    639      *
    640      * @param transition The window transition.
    641      * @return The transition symbolic name.
    642      */
    643     public static String appTransitionToString(int transition) {
    644         switch (transition) {
    645             case TRANSIT_UNSET: {
    646                 return "TRANSIT_UNSET";
    647             }
    648             case TRANSIT_NONE: {
    649                 return "TRANSIT_NONE";
    650             }
    651             case TRANSIT_EXIT_MASK: {
    652                 return "TRANSIT_EXIT_MASK";
    653             }
    654             case TRANSIT_ACTIVITY_OPEN: {
    655                 return "TRANSIT_ACTIVITY_OPEN";
    656             }
    657             case TRANSIT_ACTIVITY_CLOSE: {
    658                 return "TRANSIT_ACTIVITY_CLOSE";
    659             }
    660             case TRANSIT_TASK_OPEN: {
    661                 return "TRANSIT_TASK_OPEN";
    662             }
    663             case TRANSIT_TASK_CLOSE: {
    664                 return "TRANSIT_TASK_CLOSE";
    665             }
    666             case TRANSIT_TASK_TO_FRONT: {
    667                 return "TRANSIT_TASK_TO_FRONT";
    668             }
    669             case TRANSIT_TASK_TO_BACK: {
    670                 return "TRANSIT_TASK_TO_BACK";
    671             }
    672             case TRANSIT_WALLPAPER_CLOSE: {
    673                 return "TRANSIT_WALLPAPER_CLOSE";
    674             }
    675             case TRANSIT_WALLPAPER_OPEN: {
    676                 return "TRANSIT_WALLPAPER_OPEN";
    677             }
    678             case TRANSIT_WALLPAPER_INTRA_OPEN: {
    679                 return "TRANSIT_WALLPAPER_INTRA_OPEN";
    680             }
    681             case TRANSIT_WALLPAPER_INTRA_CLOSE: {
    682                 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
    683             }
    684             default: {
    685                 return "<UNKNOWN>";
    686             }
    687         }
    688     }
    689 
    690     private String appStateToString() {
    691         switch (mAppTransitionState) {
    692             case APP_STATE_IDLE:
    693                 return "APP_STATE_IDLE";
    694             case APP_STATE_READY:
    695                 return "APP_STATE_READY";
    696             case APP_STATE_RUNNING:
    697                 return "APP_STATE_RUNNING";
    698             case APP_STATE_TIMEOUT:
    699                 return "APP_STATE_TIMEOUT";
    700             default:
    701                 return "unknown state=" + mAppTransitionState;
    702         }
    703     }
    704 
    705     private String transitTypeToString() {
    706         switch (mNextAppTransitionType) {
    707             case NEXT_TRANSIT_TYPE_NONE:
    708                 return "NEXT_TRANSIT_TYPE_NONE";
    709             case NEXT_TRANSIT_TYPE_CUSTOM:
    710                 return "NEXT_TRANSIT_TYPE_CUSTOM";
    711             case NEXT_TRANSIT_TYPE_SCALE_UP:
    712                 return "NEXT_TRANSIT_TYPE_SCALE_UP";
    713             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
    714                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
    715             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
    716                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
    717             default:
    718                 return "unknown type=" + mNextAppTransitionType;
    719         }
    720     }
    721 
    722     @Override
    723     public void dump(PrintWriter pw) {
    724         pw.print(" " + this);
    725         pw.print(" mAppTransitionState="); pw.println(appStateToString());
    726         if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
    727             pw.print("  mNextAppTransitionType="); pw.println(transitTypeToString());
    728         }
    729         switch (mNextAppTransitionType) {
    730             case NEXT_TRANSIT_TYPE_CUSTOM:
    731                 pw.print("  mNextAppTransitionPackage=");
    732                         pw.println(mNextAppTransitionPackage);
    733                 pw.print("  mNextAppTransitionEnter=0x");
    734                         pw.print(Integer.toHexString(mNextAppTransitionEnter));
    735                         pw.print(" mNextAppTransitionExit=0x");
    736                         pw.println(Integer.toHexString(mNextAppTransitionExit));
    737                 break;
    738             case NEXT_TRANSIT_TYPE_SCALE_UP:
    739                 pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
    740                         pw.print(" mNextAppTransitionStartY=");
    741                         pw.println(mNextAppTransitionStartY);
    742                 pw.print("  mNextAppTransitionStartWidth=");
    743                         pw.print(mNextAppTransitionStartWidth);
    744                         pw.print(" mNextAppTransitionStartHeight=");
    745                         pw.println(mNextAppTransitionStartHeight);
    746                 break;
    747             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
    748             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
    749                 pw.print("  mNextAppTransitionThumbnail=");
    750                         pw.print(mNextAppTransitionThumbnail);
    751                         pw.print(" mNextAppTransitionStartX=");
    752                         pw.print(mNextAppTransitionStartX);
    753                         pw.print(" mNextAppTransitionStartY=");
    754                         pw.println(mNextAppTransitionStartY);
    755                 pw.print("  mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
    756                 break;
    757         }
    758         if (mNextAppTransitionCallback != null) {
    759             pw.print("  mNextAppTransitionCallback=");
    760             pw.println(mNextAppTransitionCallback);
    761         }
    762     }
    763 
    764     public void setCurrentUser(int newUserId) {
    765         mCurrentUserId = newUserId;
    766     }
    767 }
    768