OSDN Git Service

Merge "Add orientation to configuration for layoutlib." into jb-mr2-dev
[android-x86/frameworks-base.git] / services / java / com / android / server / wm / AppTransition.java
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 }