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