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