FileDocCategorySizeDatePackage
AppTransition.javaAPI DocAndroid 5.1 API54905Thu Mar 12 22:22:42 GMT 2015com.android.server.wm

AppTransition

public class AppTransition extends Object implements com.android.internal.util.DumpUtils.Dump

Fields Summary
private static final String
TAG
private static final boolean
DEBUG_APP_TRANSITIONS
private static final boolean
DEBUG_ANIM
public static final int
TRANSIT_UNSET
Not set up for a transition.
public static final int
TRANSIT_NONE
No animation for transition.
public static final int
TRANSIT_ACTIVITY_OPEN
A window in a new activity is being opened on top of an existing one in the same task.
public static final int
TRANSIT_ACTIVITY_CLOSE
The window in the top-most activity is being closed to reveal the previous activity in the same task.
public static final int
TRANSIT_TASK_OPEN
A window in a new task is being opened on top of an existing one in another activity's task.
public static final int
TRANSIT_TASK_CLOSE
A window in the top-most activity is being closed to reveal the previous activity in a different task.
public static final int
TRANSIT_TASK_TO_FRONT
A window in an existing task is being displayed on top of an existing one in another activity's task.
public static final int
TRANSIT_TASK_TO_BACK
A window in an existing task is being put below all other tasks.
public static final int
TRANSIT_WALLPAPER_CLOSE
A window in a new activity that doesn't have a wallpaper is being opened on top of one that does, effectively closing the wallpaper.
public static final int
TRANSIT_WALLPAPER_OPEN
A window in a new activity that does have a wallpaper is being opened on one that didn't, effectively opening the wallpaper.
public static final int
TRANSIT_WALLPAPER_INTRA_OPEN
A window in a new activity is being opened on top of an existing one, and both are on top of the wallpaper.
public static final int
TRANSIT_WALLPAPER_INTRA_CLOSE
The window in the top-most activity is being closed to reveal the previous activity, and both are on top of the wallpaper.
public static final int
TRANSIT_TASK_OPEN_BEHIND
A window in a new task is being opened behind an existing one in another activity's task. The new window will show briefly and then be gone.
public static final int
TRANSIT_TASK_IN_PLACE
A window in a task is being animated in-place.
private static final float
RECENTS_THUMBNAIL_FADEIN_FRACTION
Fraction of animation at which the recents thumbnail stays completely transparent
private static final float
RECENTS_THUMBNAIL_FADEOUT_FRACTION
Fraction of animation at which the recents thumbnail becomes completely transparent
private static final int
DEFAULT_APP_TRANSITION_DURATION
private static final int
THUMBNAIL_APP_TRANSITION_DURATION
private static final int
THUMBNAIL_APP_TRANSITION_ALPHA_DURATION
private final android.content.Context
mContext
private final android.os.Handler
mH
private int
mNextAppTransition
private static final int
NEXT_TRANSIT_TYPE_NONE
private static final int
NEXT_TRANSIT_TYPE_CUSTOM
private static final int
NEXT_TRANSIT_TYPE_SCALE_UP
private static final int
NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
private static final int
NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN
private static final int
NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
private static final int
NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN
private static final int
NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
private int
mNextAppTransitionType
private static final int
THUMBNAIL_TRANSITION_ENTER_SCALE_UP
private static final int
THUMBNAIL_TRANSITION_EXIT_SCALE_UP
private static final int
THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN
private static final int
THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN
private String
mNextAppTransitionPackage
private android.graphics.Bitmap
mNextAppTransitionThumbnail
private boolean
mNextAppTransitionScaleUp
private android.os.IRemoteCallback
mNextAppTransitionCallback
private int
mNextAppTransitionEnter
private int
mNextAppTransitionExit
private int
mNextAppTransitionInPlace
private int
mNextAppTransitionStartX
private int
mNextAppTransitionStartY
private int
mNextAppTransitionStartWidth
private int
mNextAppTransitionStartHeight
private android.graphics.Rect
mNextAppTransitionInsets
private android.graphics.Rect
mTmpFromClipRect
private android.graphics.Rect
mTmpToClipRect
private static final int
APP_STATE_IDLE
private static final int
APP_STATE_READY
private static final int
APP_STATE_RUNNING
private static final int
APP_STATE_TIMEOUT
private int
mAppTransitionState
private final int
mConfigShortAnimTime
private final android.view.animation.Interpolator
mDecelerateInterpolator
private final android.view.animation.Interpolator
mThumbnailFadeInInterpolator
private final android.view.animation.Interpolator
mThumbnailFadeOutInterpolator
private final android.view.animation.Interpolator
mThumbnailFastOutSlowInInterpolator
private int
mCurrentUserId
Constructors Summary
AppTransition(android.content.Context context, android.os.Handler h)


        
        mContext = context;
        mH = h;
        mConfigShortAnimTime = context.getResources().getInteger(
                com.android.internal.R.integer.config_shortAnimTime);
        mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
                com.android.internal.R.interpolator.decelerate_cubic);
        mThumbnailFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                com.android.internal.R.interpolator.fast_out_slow_in);
        mThumbnailFadeInInterpolator = new Interpolator() {
            @Override
            public float getInterpolation(float input) {
                // Linear response for first fraction, then complete after that.
                if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
                    return 0f;
                }
                return (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /
                        (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
            }
        };
        mThumbnailFadeOutInterpolator = new Interpolator() {
            @Override
            public float getInterpolation(float input) {
                // Linear response for first fraction, then complete after that.
                if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
                    return input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
                }
                return 1f;
            }
        };
    
Methods Summary
private java.lang.StringappStateToString()

        switch (mAppTransitionState) {
            case APP_STATE_IDLE:
                return "APP_STATE_IDLE";
            case APP_STATE_READY:
                return "APP_STATE_READY";
            case APP_STATE_RUNNING:
                return "APP_STATE_RUNNING";
            case APP_STATE_TIMEOUT:
                return "APP_STATE_TIMEOUT";
            default:
                return "unknown state=" + mAppTransitionState;
        }
    
public static java.lang.StringappTransitionToString(int transition)
Returns the human readable name of a window transition.

param
transition The window transition.
return
The transition symbolic name.

        switch (transition) {
            case TRANSIT_UNSET: {
                return "TRANSIT_UNSET";
            }
            case TRANSIT_NONE: {
                return "TRANSIT_NONE";
            }
            case TRANSIT_ACTIVITY_OPEN: {
                return "TRANSIT_ACTIVITY_OPEN";
            }
            case TRANSIT_ACTIVITY_CLOSE: {
                return "TRANSIT_ACTIVITY_CLOSE";
            }
            case TRANSIT_TASK_OPEN: {
                return "TRANSIT_TASK_OPEN";
            }
            case TRANSIT_TASK_CLOSE: {
                return "TRANSIT_TASK_CLOSE";
            }
            case TRANSIT_TASK_TO_FRONT: {
                return "TRANSIT_TASK_TO_FRONT";
            }
            case TRANSIT_TASK_TO_BACK: {
                return "TRANSIT_TASK_TO_BACK";
            }
            case TRANSIT_WALLPAPER_CLOSE: {
                return "TRANSIT_WALLPAPER_CLOSE";
            }
            case TRANSIT_WALLPAPER_OPEN: {
                return "TRANSIT_WALLPAPER_OPEN";
            }
            case TRANSIT_WALLPAPER_INTRA_OPEN: {
                return "TRANSIT_WALLPAPER_INTRA_OPEN";
            }
            case TRANSIT_WALLPAPER_INTRA_CLOSE: {
                return "TRANSIT_WALLPAPER_INTRA_CLOSE";
            }
            case TRANSIT_TASK_OPEN_BEHIND: {
                return "TRANSIT_TASK_OPEN_BEHIND";
            }
            default: {
                return "<UNKNOWN>";
            }
        }
    
voidclear()

        mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
        mNextAppTransitionPackage = null;
        mNextAppTransitionThumbnail = null;
    
private static floatcomputePivot(int startPos, float finalScale)
Compute the pivot point for an animation that is scaling from a small rect on screen to a larger rect. The pivot point varies depending on the distance between the inner and outer edges on both sides. This function computes the pivot point for one dimension.

param
startPos Offset from left/top edge of outer rectangle to left/top edge of inner rectangle.
param
finalScale The scaling factor between the size of the outer and inner rectangles.

        final float denom = finalScale-1;
        if (Math.abs(denom) < .0001f) {
            return startPos;
        }
        return -startPos / denom;
    
android.view.animation.AnimationcreateAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth, int appHeight, int orientation, int transit, android.graphics.Rect containingFrame, android.graphics.Rect contentInsets, boolean isFullScreen)
This alternate animation is created when we are doing a thumbnail transition, for the activity that is leaving, and the activity that is entering.

        Animation a;
        final int thumbWidthI = mNextAppTransitionStartWidth;
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = mNextAppTransitionStartHeight;
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;

        // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
        float scale = 1f;
        int scaledTopDecor = 0;

        switch (thumbTransitState) {
            case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
                // App window scaling up to become full screen
                if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                    // In portrait, we scale the width and clip to the top/left square
                    scale = thumbWidth / appWidth;
                    scaledTopDecor = (int) (scale * contentInsets.top);
                    int unscaledThumbHeight = (int) (thumbHeight / scale);
                    mTmpFromClipRect.set(containingFrame);
                    if (isFullScreen) {
                        mTmpFromClipRect.top = contentInsets.top;
                    }
                    mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
                    mTmpToClipRect.set(containingFrame);
                } else {
                    // In landscape, we scale the height and clip to the top/left square
                    scale = thumbHeight / (appHeight - contentInsets.top);
                    scaledTopDecor = (int) (scale * contentInsets.top);
                    int unscaledThumbWidth = (int) (thumbWidth / scale);
                    int unscaledThumbHeight = (int) (thumbHeight / scale);
                    mTmpFromClipRect.set(containingFrame);
                    if (isFullScreen) {
                        mTmpFromClipRect.top = contentInsets.top;
                        mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
                    }
                    mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth);
                    mTmpToClipRect.set(containingFrame);
                }
                mNextAppTransitionInsets.set(contentInsets);

                Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
                        computePivot(mNextAppTransitionStartX, scale),
                        computePivot(mNextAppTransitionStartY, scale));
                Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
                Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);

                AnimationSet set = new AnimationSet(true);
                set.addAnimation(clipAnim);
                set.addAnimation(scaleAnim);
                set.addAnimation(translateAnim);
                a = set;
                break;
            }
            case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
                // Previous app window during the scale up
                if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
                    // Fade out the source activity if we are animating to a wallpaper
                    // activity.
                    a = new AlphaAnimation(1, 0);
                } else {
                    a = new AlphaAnimation(1, 1);
                }
                break;
            }
            case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
                // Target app window during the scale down
                if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
                    // Fade in the destination activity if we are animating from a wallpaper
                    // activity.
                    a = new AlphaAnimation(0, 1);
                } else {
                    a = new AlphaAnimation(1, 1);
                }
                break;
            }
            case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
                // App window scaling down from full screen
                if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                    // In portrait, we scale the width and clip to the top/left square
                    scale = thumbWidth / appWidth;
                    scaledTopDecor = (int) (scale * contentInsets.top);
                    int unscaledThumbHeight = (int) (thumbHeight / scale);
                    mTmpFromClipRect.set(containingFrame);
                    mTmpToClipRect.set(containingFrame);
                    if (isFullScreen) {
                        mTmpToClipRect.top = contentInsets.top;
                    }
                    mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight);
                } else {
                    // In landscape, we scale the height and clip to the top/left square
                    scale = thumbHeight / (appHeight - contentInsets.top);
                    scaledTopDecor = (int) (scale * contentInsets.top);
                    int unscaledThumbWidth = (int) (thumbWidth / scale);
                    int unscaledThumbHeight = (int) (thumbHeight / scale);
                    mTmpFromClipRect.set(containingFrame);
                    mTmpToClipRect.set(containingFrame);
                    if (isFullScreen) {
                        mTmpToClipRect.top = contentInsets.top;
                        mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight);
                    }
                    mTmpToClipRect.right = (mTmpToClipRect.left + unscaledThumbWidth);
                }
                mNextAppTransitionInsets.set(contentInsets);

                Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
                        computePivot(mNextAppTransitionStartX, scale),
                        computePivot(mNextAppTransitionStartY, scale));
                Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
                Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);

                AnimationSet set = new AnimationSet(true);
                set.addAnimation(clipAnim);
                set.addAnimation(scaleAnim);
                set.addAnimation(translateAnim);

                a = set;
                a.setZAdjustment(Animation.ZORDER_TOP);
                break;
            }
            default:
                throw new RuntimeException("Invalid thumbnail transition state");
        }

        int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
                THUMBNAIL_APP_TRANSITION_DURATION);
        return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
                mThumbnailFastOutSlowInInterpolator);
    
private android.view.animation.AnimationcreateScaleUpAnimationLocked(int transit, boolean enter, int appWidth, int appHeight)

        Animation a = null;
        if (enter) {
            // Entering app zooms out from the center of the initial rect.
            float scaleW = mNextAppTransitionStartWidth / (float) appWidth;
            float scaleH = mNextAppTransitionStartHeight / (float) appHeight;
            Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
                    computePivot(mNextAppTransitionStartX, scaleW),
                    computePivot(mNextAppTransitionStartY, scaleH));
            scale.setInterpolator(mDecelerateInterpolator);

            Animation alpha = new AlphaAnimation(0, 1);
            alpha.setInterpolator(mThumbnailFadeOutInterpolator);

            AnimationSet set = new AnimationSet(false);
            set.addAnimation(scale);
            set.addAnimation(alpha);
            set.setDetachWallpaper(true);
            a = set;
        } else  if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
                    transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
            // If we are on top of the wallpaper, we need an animation that
            // correctly handles the wallpaper staying static behind all of
            // the animated elements.  To do this, will just have the existing
            // element fade out.
            a = new AlphaAnimation(1, 0);
            a.setDetachWallpaper(true);
        } else {
            // For normal animations, the exiting element just holds in place.
            a = new AlphaAnimation(1, 1);
        }

        // Pick the desired duration.  If this is an inter-activity transition,
        // it  is the standard duration for that.  Otherwise we use the longer
        // task transition duration.
        final long duration;
        switch (transit) {
            case TRANSIT_ACTIVITY_OPEN:
            case TRANSIT_ACTIVITY_CLOSE:
                duration = mConfigShortAnimTime;
                break;
            default:
                duration = DEFAULT_APP_TRANSITION_DURATION;
                break;
        }
        a.setDuration(duration);
        a.setFillAfter(true);
        a.setInterpolator(mDecelerateInterpolator);
        a.initialize(appWidth, appHeight, appWidth, appHeight);
        return a;
    
android.view.animation.AnimationcreateThumbnailAspectScaleAnimationLocked(int appWidth, int appHeight, int deviceWidth, int transit)
This animation runs for the thumbnail that gets cross faded with the enter/exit activity when a thumbnail is specified with the activity options.

        Animation a;
        final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;

        float scaleW = deviceWidth / thumbWidth;
        float unscaledWidth = deviceWidth;
        float unscaledHeight = thumbHeight * scaleW;
        float unscaledStartY = mNextAppTransitionStartY - (unscaledHeight - thumbHeight) / 2f;
        if (mNextAppTransitionScaleUp) {
            // Animation up from the thumbnail to the full screen
            Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
                    mNextAppTransitionStartX + (thumbWidth / 2f),
                    mNextAppTransitionStartY + (thumbHeight / 2f));
            scale.setInterpolator(mThumbnailFastOutSlowInInterpolator);
            scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
            Animation alpha = new AlphaAnimation(1, 0);
            alpha.setInterpolator(mThumbnailFadeOutInterpolator);
            alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
            Animation translate = new TranslateAnimation(0, 0, 0, -unscaledStartY +
                    mNextAppTransitionInsets.top);
            translate.setInterpolator(mThumbnailFastOutSlowInInterpolator);
            translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);

            // This AnimationSet uses the Interpolators assigned above.
            AnimationSet set = new AnimationSet(false);
            set.addAnimation(scale);
            set.addAnimation(alpha);
            set.addAnimation(translate);
            a = set;
        } else {
            // Animation down from the full screen to the thumbnail
            Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
                    mNextAppTransitionStartX + (thumbWidth / 2f),
                    mNextAppTransitionStartY + (thumbHeight / 2f));
            scale.setInterpolator(mThumbnailFastOutSlowInInterpolator);
            scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
            Animation alpha = new AlphaAnimation(0f, 1f);
            alpha.setInterpolator(mThumbnailFadeInInterpolator);
            alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
            Animation translate = new TranslateAnimation(0, 0, -unscaledStartY +
                    mNextAppTransitionInsets.top, 0);
            translate.setInterpolator(mThumbnailFastOutSlowInInterpolator);
            translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);

            // This AnimationSet uses the Interpolators assigned above.
            AnimationSet set = new AnimationSet(false);
            set.addAnimation(scale);
            set.addAnimation(alpha);
            set.addAnimation(translate);
            a = set;

        }
        return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, 0,
                mThumbnailFastOutSlowInInterpolator);
    
android.view.animation.AnimationcreateThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth, int appHeight, int transit)
This animation is created when we are doing a thumbnail transition, for the activity that is leaving, and the activity that is entering.

        Animation a;
        final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;

        switch (thumbTransitState) {
            case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
                // Entering app scales up with the thumbnail
                float scaleW = thumbWidth / appWidth;
                float scaleH = thumbHeight / appHeight;
                a = new ScaleAnimation(scaleW, 1, scaleH, 1,
                        computePivot(mNextAppTransitionStartX, scaleW),
                        computePivot(mNextAppTransitionStartY, scaleH));
                break;
            }
            case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
                // Exiting app while the thumbnail is scaling up should fade or stay in place
                if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
                    // Fade out while bringing up selected activity. This keeps the
                    // current activity from showing through a launching wallpaper
                    // activity.
                    a = new AlphaAnimation(1, 0);
                } else {
                    // noop animation
                    a = new AlphaAnimation(1, 1);
                }
                break;
            }
            case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
                // Entering the other app, it should just be visible while we scale the thumbnail
                // down above it
                a = new AlphaAnimation(1, 1);
                break;
            }
            case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
                // Exiting the current app, the app should scale down with the thumbnail
                float scaleW = thumbWidth / appWidth;
                float scaleH = thumbHeight / appHeight;
                Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
                        computePivot(mNextAppTransitionStartX, scaleW),
                        computePivot(mNextAppTransitionStartY, scaleH));

                Animation alpha = new AlphaAnimation(1, 0);

                AnimationSet set = new AnimationSet(true);
                set.addAnimation(scale);
                set.addAnimation(alpha);
                set.setZAdjustment(Animation.ZORDER_TOP);
                a = set;
                break;
            }
            default:
                throw new RuntimeException("Invalid thumbnail transition state");
        }

        return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
    
android.view.animation.AnimationcreateThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit)
This animation runs for the thumbnail that gets cross faded with the enter/exit activity when a thumbnail is specified with the activity options.

        Animation a;
        final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;

        if (mNextAppTransitionScaleUp) {
            // Animation for the thumbnail zooming from its initial size to the full screen
            float scaleW = appWidth / thumbWidth;
            float scaleH = appHeight / thumbHeight;
            Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
                    computePivot(mNextAppTransitionStartX, 1 / scaleW),
                    computePivot(mNextAppTransitionStartY, 1 / scaleH));
            scale.setInterpolator(mDecelerateInterpolator);

            Animation alpha = new AlphaAnimation(1, 0);
            alpha.setInterpolator(mThumbnailFadeOutInterpolator);

            // This AnimationSet uses the Interpolators assigned above.
            AnimationSet set = new AnimationSet(false);
            set.addAnimation(scale);
            set.addAnimation(alpha);
            a = set;
        } else {
            // Animation for the thumbnail zooming down from the full screen to its final size
            float scaleW = appWidth / thumbWidth;
            float scaleH = appHeight / thumbHeight;
            a = new ScaleAnimation(scaleW, 1, scaleH, 1,
                    computePivot(mNextAppTransitionStartX, 1 / scaleW),
                    computePivot(mNextAppTransitionStartY, 1 / scaleH));
        }

        return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
    
public voiddump(java.io.PrintWriter pw)

        pw.print(" " + this);
        pw.print("  mAppTransitionState="); pw.println(appStateToString());
        if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
            pw.print("  mNextAppTransitionType="); pw.println(transitTypeToString());
        }
        switch (mNextAppTransitionType) {
            case NEXT_TRANSIT_TYPE_CUSTOM:
                pw.print("  mNextAppTransitionPackage=");
                        pw.println(mNextAppTransitionPackage);
                pw.print("  mNextAppTransitionEnter=0x");
                        pw.print(Integer.toHexString(mNextAppTransitionEnter));
                        pw.print(" mNextAppTransitionExit=0x");
                        pw.println(Integer.toHexString(mNextAppTransitionExit));
                break;
            case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
                pw.print("  mNextAppTransitionPackage=");
                        pw.println(mNextAppTransitionPackage);
                pw.print("  mNextAppTransitionInPlace=0x");
                        pw.print(Integer.toHexString(mNextAppTransitionInPlace));
                break;
            case NEXT_TRANSIT_TYPE_SCALE_UP:
                pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
                        pw.print(" mNextAppTransitionStartY=");
                        pw.println(mNextAppTransitionStartY);
                pw.print("  mNextAppTransitionStartWidth=");
                        pw.print(mNextAppTransitionStartWidth);
                        pw.print(" mNextAppTransitionStartHeight=");
                        pw.println(mNextAppTransitionStartHeight);
                break;
            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
                pw.print("  mNextAppTransitionThumbnail=");
                        pw.print(mNextAppTransitionThumbnail);
                        pw.print(" mNextAppTransitionStartX=");
                        pw.print(mNextAppTransitionStartX);
                        pw.print(" mNextAppTransitionStartY=");
                        pw.println(mNextAppTransitionStartY);
                        pw.print(" mNextAppTransitionStartWidth=");
                        pw.print(mNextAppTransitionStartWidth);
                        pw.print(" mNextAppTransitionStartHeight=");
                        pw.println(mNextAppTransitionStartHeight);
                pw.print("  mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
                break;
        }
        if (mNextAppTransitionCallback != null) {
            pw.print("  mNextAppTransitionCallback=");
            pw.println(mNextAppTransitionCallback);
        }
    
voidfreeze()

        setAppTransition(AppTransition.TRANSIT_UNSET);
        clear();
        setReady();
    
intgetAppTransition()

        return mNextAppTransition;
     
private AttributeCache.EntrygetCachedAnimations(WindowManager.LayoutParams lp)

        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
                + (lp != null ? lp.packageName : null)
                + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
        if (lp != null && lp.windowAnimations != 0) {
            // If this is a system resource, don't try to load it from the
            // application resources.  It is nice to avoid loading application
            // resources if we can.
            String packageName = lp.packageName != null ? lp.packageName : "android";
            int resId = lp.windowAnimations;
            if ((resId&0xFF000000) == 0x01000000) {
                packageName = "android";
            }
            if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
                    + packageName);
            return AttributeCache.instance().get(packageName, resId,
                    com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
        }
        return null;
    
private AttributeCache.EntrygetCachedAnimations(java.lang.String packageName, int resId)

        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
                + packageName + " resId=0x" + Integer.toHexString(resId));
        if (packageName != null) {
            if ((resId&0xFF000000) == 0x01000000) {
                packageName = "android";
            }
            if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
                    + packageName);
            return AttributeCache.instance().get(packageName, resId,
                    com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
        }
        return null;
    
android.graphics.BitmapgetNextAppTransitionThumbnail()

        return mNextAppTransitionThumbnail;
    
intgetStartingX()

        return mNextAppTransitionStartX;
    
intgetStartingY()

        return mNextAppTransitionStartY;
    
intgetThumbnailTransitionState(boolean enter)
Return the current thumbnail transition state.

        if (enter) {
            if (mNextAppTransitionScaleUp) {
                return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
            } else {
                return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
            }
        } else {
            if (mNextAppTransitionScaleUp) {
                return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
            } else {
                return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
            }
        }
    
voidgoodToGo()

        mNextAppTransition = TRANSIT_UNSET;
        mAppTransitionState = APP_STATE_RUNNING;
    
booleanisNextThumbnailTransitionAspectScaled()
Returns whether the next thumbnail transition is aspect scaled up.

        return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
    
booleanisNextThumbnailTransitionScaleUp()
Returns whether the next thumbnail transition is scaling up.

        return mNextAppTransitionScaleUp;
    
booleanisReady()

        return mAppTransitionState == APP_STATE_READY
                || mAppTransitionState == APP_STATE_TIMEOUT;
    
booleanisRunning()

        return mAppTransitionState == APP_STATE_RUNNING;
    
booleanisTimeout()

        return mAppTransitionState == APP_STATE_TIMEOUT;
    
booleanisTransitionEqual(int transit)

        return mNextAppTransition == transit;
    
booleanisTransitionNone()

        return mNextAppTransition == TRANSIT_NONE;
    
booleanisTransitionSet()

        return mNextAppTransition != TRANSIT_UNSET;
    
android.view.animation.AnimationloadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int appWidth, int appHeight, int orientation, android.graphics.Rect containingFrame, android.graphics.Rect contentInsets, boolean isFullScreen, boolean isVoiceInteraction)

        Animation a;
        if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
                || transit == TRANSIT_TASK_OPEN
                || transit == TRANSIT_TASK_TO_FRONT)) {
            a = loadAnimationRes(lp, enter
                    ? com.android.internal.R.anim.voice_activity_open_enter
                    : com.android.internal.R.anim.voice_activity_open_exit);
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                    "applyAnimation voice:"
                    + " anim=" + a + " transit=" + transit + " isEntrance=" + enter
                    + " Callers=" + Debug.getCallers(3));
        } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
                || transit == TRANSIT_TASK_CLOSE
                || transit == TRANSIT_TASK_TO_BACK)) {
            a = loadAnimationRes(lp, enter
                    ? com.android.internal.R.anim.voice_activity_close_enter
                    : com.android.internal.R.anim.voice_activity_close_exit);
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                    "applyAnimation voice:"
                    + " anim=" + a + " transit=" + transit + " isEntrance=" + enter
                    + " Callers=" + Debug.getCallers(3));
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
            a = loadAnimationRes(mNextAppTransitionPackage, enter ?
                    mNextAppTransitionEnter : mNextAppTransitionExit);
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                    "applyAnimation:"
                    + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
                    + " transit=" + transit + " isEntrance=" + enter
                    + " Callers=" + Debug.getCallers(3));
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
            a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                    "applyAnimation:"
                            + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
                            + " transit=" + transit + " Callers=" + Debug.getCallers(3));
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
            a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                    "applyAnimation:"
                    + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
                    + " transit=" + transit + " isEntrance=" + enter
                    + " Callers=" + Debug.getCallers(3));
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
            mNextAppTransitionScaleUp =
                    (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
            a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
                    appWidth, appHeight, transit);
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                String animName = mNextAppTransitionScaleUp ?
                        "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
                Slog.v(TAG, "applyAnimation:"
                        + " anim=" + a + " nextAppTransition=" + animName
                        + " transit=" + transit + " isEntrance=" + enter
                        + " Callers=" + Debug.getCallers(3));
            }
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
            mNextAppTransitionScaleUp =
                    (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
            a = createAspectScaledThumbnailEnterExitAnimationLocked(
                    getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
                    transit, containingFrame, contentInsets, isFullScreen);
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                String animName = mNextAppTransitionScaleUp ?
                        "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
                Slog.v(TAG, "applyAnimation:"
                        + " anim=" + a + " nextAppTransition=" + animName
                        + " transit=" + transit + " isEntrance=" + enter
                        + " Callers=" + Debug.getCallers(3));
            }
        } else {
            int animAttr = 0;
            switch (transit) {
                case TRANSIT_ACTIVITY_OPEN:
                    animAttr = enter
                            ? WindowAnimation_activityOpenEnterAnimation
                            : WindowAnimation_activityOpenExitAnimation;
                    break;
                case TRANSIT_ACTIVITY_CLOSE:
                    animAttr = enter
                            ? WindowAnimation_activityCloseEnterAnimation
                            : WindowAnimation_activityCloseExitAnimation;
                    break;
                case TRANSIT_TASK_OPEN:
                    animAttr = enter
                            ? WindowAnimation_taskOpenEnterAnimation
                            : WindowAnimation_taskOpenExitAnimation;
                    break;
                case TRANSIT_TASK_CLOSE:
                    animAttr = enter
                            ? WindowAnimation_taskCloseEnterAnimation
                            : WindowAnimation_taskCloseExitAnimation;
                    break;
                case TRANSIT_TASK_TO_FRONT:
                    animAttr = enter
                            ? WindowAnimation_taskToFrontEnterAnimation
                            : WindowAnimation_taskToFrontExitAnimation;
                    break;
                case TRANSIT_TASK_TO_BACK:
                    animAttr = enter
                            ? WindowAnimation_taskToBackEnterAnimation
                            : WindowAnimation_taskToBackExitAnimation;
                    break;
                case TRANSIT_WALLPAPER_OPEN:
                    animAttr = enter
                            ? WindowAnimation_wallpaperOpenEnterAnimation
                            : WindowAnimation_wallpaperOpenExitAnimation;
                    break;
                case TRANSIT_WALLPAPER_CLOSE:
                    animAttr = enter
                            ? WindowAnimation_wallpaperCloseEnterAnimation
                            : WindowAnimation_wallpaperCloseExitAnimation;
                    break;
                case TRANSIT_WALLPAPER_INTRA_OPEN:
                    animAttr = enter
                            ? WindowAnimation_wallpaperIntraOpenEnterAnimation
                            : WindowAnimation_wallpaperIntraOpenExitAnimation;
                    break;
                case TRANSIT_WALLPAPER_INTRA_CLOSE:
                    animAttr = enter
                            ? WindowAnimation_wallpaperIntraCloseEnterAnimation
                            : WindowAnimation_wallpaperIntraCloseExitAnimation;
                    break;
                case TRANSIT_TASK_OPEN_BEHIND:
                    animAttr = enter
                            ? WindowAnimation_launchTaskBehindSourceAnimation
                            : WindowAnimation_launchTaskBehindTargetAnimation;
            }
            a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                    "applyAnimation:"
                    + " anim=" + a
                    + " animAttr=0x" + Integer.toHexString(animAttr)
                    + " transit=" + transit + " isEntrance=" + enter
                    + " Callers=" + Debug.getCallers(3));
        }
        return a;
    
android.view.animation.AnimationloadAnimationAttr(WindowManager.LayoutParams lp, int animAttr)

        int anim = 0;
        Context context = mContext;
        if (animAttr >= 0) {
            AttributeCache.Entry ent = getCachedAnimations(lp);
            if (ent != null) {
                context = ent.context;
                anim = ent.array.getResourceId(animAttr, 0);
            }
        }
        if (anim != 0) {
            return AnimationUtils.loadAnimation(context, anim);
        }
        return null;
    
android.view.animation.AnimationloadAnimationRes(WindowManager.LayoutParams lp, int resId)

        Context context = mContext;
        if (resId >= 0) {
            AttributeCache.Entry ent = getCachedAnimations(lp);
            if (ent != null) {
                context = ent.context;
            }
            return AnimationUtils.loadAnimation(context, resId);
        }
        return null;
    
private android.view.animation.AnimationloadAnimationRes(java.lang.String packageName, int resId)

        int anim = 0;
        Context context = mContext;
        if (resId >= 0) {
            AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
            if (ent != null) {
                context = ent.context;
                anim = resId;
            }
        }
        if (anim != 0) {
            return AnimationUtils.loadAnimation(context, anim);
        }
        return null;
    
voidoverrideInPlaceAppTransition(java.lang.String packageName, int anim)

        if (isTransitionSet()) {
            mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
            mNextAppTransitionPackage = packageName;
            mNextAppTransitionInPlace = anim;
        } else {
            postAnimationCallback();
        }
    
voidoverridePendingAppTransition(java.lang.String packageName, int enterAnim, int exitAnim, android.os.IRemoteCallback startedCallback)

        if (isTransitionSet()) {
            mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
            mNextAppTransitionPackage = packageName;
            mNextAppTransitionThumbnail = null;
            mNextAppTransitionEnter = enterAnim;
            mNextAppTransitionExit = exitAnim;
            postAnimationCallback();
            mNextAppTransitionCallback = startedCallback;
        } else {
            postAnimationCallback();
        }
    
voidoverridePendingAppTransitionAspectScaledThumb(android.graphics.Bitmap srcThumb, int startX, int startY, int targetWidth, int targetHeight, android.os.IRemoteCallback startedCallback, boolean scaleUp)

        if (isTransitionSet()) {
            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
                    : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
            mNextAppTransitionPackage = null;
            mNextAppTransitionThumbnail = srcThumb;
            mNextAppTransitionScaleUp = scaleUp;
            mNextAppTransitionStartX = startX;
            mNextAppTransitionStartY = startY;
            mNextAppTransitionStartWidth = targetWidth;
            mNextAppTransitionStartHeight = targetHeight;
            postAnimationCallback();
            mNextAppTransitionCallback = startedCallback;
        } else {
            postAnimationCallback();
        }
    
voidoverridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, int startHeight)

        if (isTransitionSet()) {
            mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
            mNextAppTransitionPackage = null;
            mNextAppTransitionThumbnail = null;
            mNextAppTransitionStartX = startX;
            mNextAppTransitionStartY = startY;
            mNextAppTransitionStartWidth = startWidth;
            mNextAppTransitionStartHeight = startHeight;
            postAnimationCallback();
            mNextAppTransitionCallback = null;
        }
    
voidoverridePendingAppTransitionThumb(android.graphics.Bitmap srcThumb, int startX, int startY, android.os.IRemoteCallback startedCallback, boolean scaleUp)

        if (isTransitionSet()) {
            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
                    : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
            mNextAppTransitionPackage = null;
            mNextAppTransitionThumbnail = srcThumb;
            mNextAppTransitionScaleUp = scaleUp;
            mNextAppTransitionStartX = startX;
            mNextAppTransitionStartY = startY;
            postAnimationCallback();
            mNextAppTransitionCallback = startedCallback;
        } else {
            postAnimationCallback();
        }
    
voidpostAnimationCallback()

        if (mNextAppTransitionCallback != null) {
            mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, mNextAppTransitionCallback));
            mNextAppTransitionCallback = null;
        }
    
voidprepare()

        if (!isRunning()) {
            mAppTransitionState = APP_STATE_IDLE;
        }
    
android.view.animation.AnimationprepareThumbnailAnimation(android.view.animation.Animation a, int appWidth, int appHeight, int transit)
Prepares the specified animation with a standard duration, interpolator, etc.

        // Pick the desired duration.  If this is an inter-activity transition,
        // it  is the standard duration for that.  Otherwise we use the longer
        // task transition duration.
        final int duration;
        switch (transit) {
            case TRANSIT_ACTIVITY_OPEN:
            case TRANSIT_ACTIVITY_CLOSE:
                duration = mConfigShortAnimTime;
                break;
            default:
                duration = DEFAULT_APP_TRANSITION_DURATION;
                break;
        }
        return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
                mDecelerateInterpolator);
    
android.view.animation.AnimationprepareThumbnailAnimationWithDuration(android.view.animation.Animation a, int appWidth, int appHeight, int duration, android.view.animation.Interpolator interpolator)
Prepares the specified animation with a standard duration, interpolator, etc.

        if (duration > 0) {
            a.setDuration(duration);
        }
        a.setFillAfter(true);
        a.setInterpolator(interpolator);
        a.initialize(appWidth, appHeight, appWidth, appHeight);
        return a;
    
voidsetAppTransition(int transit)

        mNextAppTransition = transit;
    
public voidsetCurrentUser(int newUserId)

        mCurrentUserId = newUserId;
    
voidsetIdle()

        mAppTransitionState = APP_STATE_IDLE;
    
voidsetReady()

        mAppTransitionState = APP_STATE_READY;
    
voidsetTimeout()

        mAppTransitionState = APP_STATE_TIMEOUT;
    
public java.lang.StringtoString()

        return "mNextAppTransition=0x" + Integer.toHexString(mNextAppTransition);
    
private java.lang.StringtransitTypeToString()

        switch (mNextAppTransitionType) {
            case NEXT_TRANSIT_TYPE_NONE:
                return "NEXT_TRANSIT_TYPE_NONE";
            case NEXT_TRANSIT_TYPE_CUSTOM:
                return "NEXT_TRANSIT_TYPE_CUSTOM";
            case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
                return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
            case NEXT_TRANSIT_TYPE_SCALE_UP:
                return "NEXT_TRANSIT_TYPE_SCALE_UP";
            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
                return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
                return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
                return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
                return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
            default:
                return "unknown type=" + mNextAppTransitionType;
        }