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