AppTransition.java revision 9158825f9c41869689d6b1786d7c7aa8bdd524ce
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
17package com.android.server.wm;
18
19import android.content.Context;
20import android.graphics.Bitmap;
21import android.graphics.Point;
22import android.os.Debug;
23import android.os.Handler;
24import android.os.IRemoteCallback;
25import android.util.Slog;
26import android.view.WindowManager;
27import android.view.animation.AlphaAnimation;
28import android.view.animation.Animation;
29import android.view.animation.AnimationSet;
30import android.view.animation.AnimationUtils;
31import android.view.animation.Interpolator;
32import android.view.animation.ScaleAnimation;
33
34import com.android.internal.util.DumpUtils.Dump;
35import com.android.server.AttributeCache;
36import com.android.server.wm.WindowManagerService.H;
37
38import java.io.PrintWriter;
39
40import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
41import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
42import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
43import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
44import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
45import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
46import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
47import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
48import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
49import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
50import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
51import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
52import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
53import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
54import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
55import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
56import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
57import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
58import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
59import 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.
66public 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