Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d64ef3ef authored by Filip Gruszczynski's avatar Filip Gruszczynski
Browse files

Freeform to recents app transition.

Bug: 24913782

Change-Id: I54fcbe38c51e5d75fa5ad2cb38de89d371b47bed
parent e978607a
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -25,10 +25,12 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.util.Pair;
import android.util.Slog;
import android.view.AppTransitionAnimationSpec;
import android.view.View;
import android.view.Window;

@@ -128,6 +130,11 @@ public class ActivityOptions {
     */
    public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener";

    /**
     * Descriptions of app transition animations to be played during the activity launch.
     */
    private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";

    /**
     * Where the docked stack should be positioned.
     * @hide
@@ -199,6 +206,7 @@ public class ActivityOptions {
    private int mExitCoordinatorIndex;
    private PendingIntent mUsageTimeReport;
    private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
    private AppTransitionAnimationSpec mAnimSpecs[];

    /**
     * Create an ActivityOptions specifying a custom animation to run when
@@ -512,6 +520,18 @@ public class ActivityOptions {
        return opts;
    }

    /** @hide */
    public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
            AppTransitionAnimationSpec[] specs, Handler handler,
            OnAnimationStartedListener listener) {
        ActivityOptions opts = new ActivityOptions();
        opts.mPackageName = source.getContext().getPackageName();
        opts.mAnimationType = ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
        opts.mAnimSpecs = specs;
        opts.setOnAnimationStartedListener(handler, listener);
        return opts;
    }

    /**
     * Create an ActivityOptions to transition between Activities using cross-Activity scene
     * animations. This method carries the position of one shared element to the started Activity.
@@ -698,6 +718,13 @@ public class ActivityOptions {
                break;
        }
        mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
        if (opts.containsKey(KEY_ANIM_SPECS)) {
            Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
            mAnimSpecs = new AppTransitionAnimationSpec[specs.length];
            for (int i = specs.length - 1; i >= 0; i--) {
                mAnimSpecs[i] = (AppTransitionAnimationSpec) specs[i];
            }
        }
    }

    /** @hide */
@@ -809,6 +836,9 @@ public class ActivityOptions {
        return mUsageTimeReport;
    }

    /** @hide */
    public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }

    /** @hide */
    public static void abort(Bundle options) {
        if (options != null) {
@@ -898,6 +928,7 @@ public class ActivityOptions {
                mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex;
                break;
        }
        mAnimSpecs = otherOptions.mAnimSpecs;
    }

    /**
@@ -964,6 +995,9 @@ public class ActivityOptions {
                break;
        }
        b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
        if (mAnimSpecs != null) {
            b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
        }

        return b;
    }
+42 −13
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.recents;

import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;

import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
@@ -31,8 +33,10 @@ import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.MutableBoolean;
import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
import android.view.View;

import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -558,12 +562,44 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
     */
    private ActivityOptions getThumbnailTransitionActivityOptions(
            ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) {

        if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
            ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
            stackView.getScroller().setStackScrollToInitialState();
            ArrayList<Task> tasks = stack.getTasks();
            for (int i = tasks.size() - 1; i >= 0; i--) {
                Task task = tasks.get(i);
                if (SystemServicesProxy.isFreeformStack(task.key.stackId)) {
                    mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
                            stackView.getScroller().getStackScroll(), mTmpTransform, null);
                    Rect toTaskRect = new Rect();
                    mTmpTransform.rect.round(toTaskRect);
                    Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform);
                    specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect));
                }
            }
            AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
            specs.toArray(specsArray);
            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
                    specsArray, mHandler, this);
        } else {
            // Update the destination rect
            Task toTask = new Task();
            TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
                    topTask.id, toTask);
            RectF toTaskRect = toTransform.rect;
            Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform);
            if (thumbnail != null) {
                return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
                        thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
                        (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, this);
            }
            // If both the screenshot and thumbnail fails, then just fall back to the default transition
            return getUnknownTransitionActivityOptions();
        }
    }

    private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask,
            TaskViewTransform toTransform) {
        Bitmap thumbnail;
        if (mThumbnailTransitionBitmapCacheKey != null
                && mThumbnailTransitionBitmapCacheKey.key != null
@@ -575,14 +611,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
            preloadIcon(topTask);
            thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
        }
        if (thumbnail != null) {
            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
                    thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
                    (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, this);
        }

        // If both the screenshot and thumbnail fails, then just fall back to the default transition
        return getUnknownTransitionActivityOptions();
        return thumbnail;
    }

    /**
+19 −11
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.TimeUtils;
import android.view.AppTransitionAnimationSpec;
import android.view.IApplicationToken;
import android.view.WindowManager;

@@ -863,6 +864,12 @@ final class ActivityRecord {
                    break;
                case ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP:
                case ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
                    final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
                    if (animationType == ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
                            && specs != null) {
                        service.mWindowManager.overridePendingAppTransitionMultiThumb(
                                specs, pendingOptions.getOnAnimationStartListener(), false);
                    } else {
                        service.mWindowManager.overridePendingAppTransitionAspectScaledThumb(
                                pendingOptions.getThumbnail(),
                                pendingOptions.getStartX(), pendingOptions.getStartY(),
@@ -875,6 +882,7 @@ final class ActivityRecord {
                                    pendingOptions.getStartX() + pendingOptions.getWidth(),
                                    pendingOptions.getStartY() + pendingOptions.getHeight()));
                        }
                    }
                    break;
                default:
                    Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
+1 −1
Original line number Diff line number Diff line
@@ -4376,7 +4376,7 @@ final class ActivityStack {

            RunningTaskInfo ci = new RunningTaskInfo();
            ci.id = task.taskId;
            ci.stackId = (task.stack == null) ? INVALID_STACK_ID : task.stack.getStackId();
            ci.stackId = mStackId;
            ci.baseActivity = r.intent.getComponent();
            ci.topActivity = top.intent.getComponent();
            ci.lastActiveTime = task.lastActiveTime;
+114 −89
Original line number Diff line number Diff line
@@ -64,7 +64,6 @@ import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.view.animation.TranslateYAnimation;

import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache;
@@ -175,7 +174,7 @@ public class AppTransition implements Dump {
    private Rect mTmpFromClipRect = new Rect();
    private Rect mTmpToClipRect = new Rect();

    private final Rect mTmpStartRect = new Rect();
    private final Rect mTmpRect = new Rect();

    private final static int APP_STATE_IDLE = 0;
    private final static int APP_STATE_READY = 1;
@@ -459,16 +458,16 @@ public class AppTransition implements Dump {
    private Animation createScaleUpAnimationLocked(int transit, boolean enter,
            Rect containingFrame) {
        Animation a;
        getDefaultNextAppTransitionStartRect(mTmpStartRect);
        getDefaultNextAppTransitionStartRect(mTmpRect);
        final int appWidth = containingFrame.width();
        final int appHeight = containingFrame.height();
        if (enter) {
            // Entering app zooms out from the center of the initial rect.
            float scaleW = mTmpStartRect.width() / (float) appWidth;
            float scaleH = mTmpStartRect.height() / (float) appHeight;
            float scaleW = mTmpRect.width() / (float) appWidth;
            float scaleH = mTmpRect.height() / (float) appHeight;
            Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
                    computePivot(mTmpStartRect.left, scaleW),
                    computePivot(mTmpStartRect.right, scaleH));
                    computePivot(mTmpRect.left, scaleW),
                    computePivot(mTmpRect.right, scaleH));
            scale.setInterpolator(mDecelerateInterpolator);

            Animation alpha = new AlphaAnimation(0, 1);
@@ -545,20 +544,20 @@ public class AppTransition implements Dump {

            final int appWidth = appFrame.width();
            final int appHeight = appFrame.height();
            // mTmpStartRect will contain an area around the launcher icon that was pressed. We will
            // mTmpRect will contain an area around the launcher icon that was pressed. We will
            // clip reveal from that area in the final area of the app.
            getDefaultNextAppTransitionStartRect(mTmpStartRect);
            getDefaultNextAppTransitionStartRect(mTmpRect);

            float t = 0f;
            if (appHeight > 0) {
                t = (float) mTmpStartRect.left / appHeight;
                t = (float) mTmpRect.left / appHeight;
            }
            int translationY = mClipRevealTranslationY + (int)(appHeight / 7f * t);

            int centerX = mTmpStartRect.centerX();
            int centerY = mTmpStartRect.centerY();
            int halfWidth = mTmpStartRect.width() / 2;
            int halfHeight = mTmpStartRect.height() / 2;
            int centerX = mTmpRect.centerX();
            int centerY = mTmpRect.centerY();
            int halfWidth = mTmpRect.width() / 2;
            int halfHeight = mTmpRect.height() / 2;

            // Clip third of the from size of launch icon, expand to full width/height
            Animation clipAnimLR = new ClipRectLRAnimation(
@@ -693,19 +692,19 @@ public class AppTransition implements Dump {

        float scaleW = appWidth / thumbWidth;
        float unscaledHeight = thumbHeight * scaleW;
        getNextAppTransitionStartRect(taskId, mTmpStartRect);
        float unscaledStartY = mTmpStartRect.top - (unscaledHeight - thumbHeight) / 2f;
        getNextAppTransitionStartRect(taskId, mTmpRect);
        float unscaledStartY = mTmpRect.top - (unscaledHeight - thumbHeight) / 2f;
        if (mNextAppTransitionScaleUp) {
            // Animation up from the thumbnail to the full screen
            Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
                    mTmpStartRect.left + (thumbWidth / 2f), mTmpStartRect.top + (thumbHeight / 2f));
                    mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
            scale.setInterpolator(mTouchResponseInterpolator);
            scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
            Animation alpha = new AlphaAnimation(1, 0);
            alpha.setInterpolator(mThumbnailFadeOutInterpolator);
            alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
            final float toX = appRect.left + appRect.width() / 2 -
                    (mTmpStartRect.left + thumbWidth / 2);
                    (mTmpRect.left + thumbWidth / 2);
            final float toY = appRect.top + mNextAppTransitionInsets.top + -unscaledStartY;
            Animation translate = new TranslateAnimation(0, toX, 0, toY);
            translate.setInterpolator(mTouchResponseInterpolator);
@@ -720,7 +719,7 @@ public class AppTransition implements Dump {
        } else {
            // Animation down from the full screen to the thumbnail
            Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
                    mTmpStartRect.left + (thumbWidth / 2f), mTmpStartRect.top + (thumbHeight / 2f));
                    mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
            scale.setInterpolator(mTouchResponseInterpolator);
            scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
            Animation alpha = new AlphaAnimation(0f, 1f);
@@ -753,10 +752,10 @@ public class AppTransition implements Dump {
        Animation a;
        final int appWidth = containingFrame.width();
        final int appHeight = containingFrame.height();
        getDefaultNextAppTransitionStartRect(mTmpStartRect);
        final int thumbWidthI = mTmpStartRect.width();
        getDefaultNextAppTransitionStartRect(mTmpRect);
        final int thumbWidthI = mTmpRect.width();
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = mTmpStartRect.height();
        final int thumbHeightI = mTmpRect.height();
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;

        // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
@@ -766,7 +765,7 @@ public class AppTransition implements Dump {
        switch (thumbTransitState) {
            case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
                if (freeform) {
                    a = createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
                    a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
                            containingFrame, surfaceInsets, taskId);
                } else {
                    mTmpFromClipRect.set(containingFrame);
@@ -797,8 +796,8 @@ public class AppTransition implements Dump {
                    mNextAppTransitionInsets.set(contentInsets);

                    Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
                            computePivot(mTmpStartRect.left, scale),
                            computePivot(mTmpStartRect.top, scale));
                            computePivot(mTmpRect.left, scale),
                            computePivot(mTmpRect.top, scale));
                    Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
                    Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);

@@ -834,6 +833,10 @@ public class AppTransition implements Dump {
            }
            case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
                // App window scaling down from full screen
                if (freeform) {
                    a = createAspectScaledThumbnailExitFreeformAnimationLocked(
                            containingFrame, surfaceInsets, taskId);
                } else {
                    mTmpFromClipRect.set(containingFrame);
                    mTmpToClipRect.set(containingFrame);
                    // exclude top screen decor (status bar) region from the destination clip.
@@ -860,8 +863,8 @@ public class AppTransition implements Dump {
                    mNextAppTransitionInsets.set(contentInsets);

                    Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
                        computePivot(mTmpStartRect.left, scale),
                        computePivot(mTmpStartRect.top, scale));
                            computePivot(mTmpRect.left, scale),
                            computePivot(mTmpRect.top, scale));
                    Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
                    Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);

@@ -872,6 +875,7 @@ public class AppTransition implements Dump {

                    a = set;
                    a.setZAdjustment(Animation.ZORDER_TOP);
                }
                break;
            }
            default:
@@ -884,27 +888,48 @@ public class AppTransition implements Dump {
                mTouchResponseInterpolator);
    }

    private Animation createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
            Rect frame, @Nullable Rect surfaceInsets, int taskId) {
        getNextAppTransitionStartRect(taskId, mTmpStartRect);
        float width = frame.width();
        float height = frame.height();
        float scaleWidth = mTmpStartRect.width() / width;
        float scaleHeight = mTmpStartRect.height() / height;
    private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
            @Nullable Rect surfaceInsets, int taskId) {
        getNextAppTransitionStartRect(taskId, mTmpRect);
        return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
                true);
    }

    private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
            @Nullable Rect surfaceInsets, int taskId) {
        getNextAppTransitionStartRect(taskId, mTmpRect);
        return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
                false);
    }

    private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
            Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
        final float sourceWidth = sourceFrame.width();
        final float sourceHeight = sourceFrame.height();
        final float destWidth = destFrame.width();
        final float destHeight = destFrame.height();
        final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
        final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
        AnimationSet set = new AnimationSet(true);
        int surfaceInsetsHorizontal = surfaceInsets == null
        final int surfaceInsetsH = surfaceInsets == null
                ? 0 : surfaceInsets.left + surfaceInsets.right;
        int surfaceInsetsVertical = surfaceInsets == null
        final int surfaceInsetsV = surfaceInsets == null
                ? 0 : surfaceInsets.top + surfaceInsets.bottom;
        // We want the scaling to happen from the center of the surface. In order to achieve that,
        // we need to account for surface insets that will be used to enlarge the surface.
        ScaleAnimation scale = new ScaleAnimation(scaleWidth, 1, scaleHeight, 1,
                (width + surfaceInsetsHorizontal) / 2, (height + surfaceInsetsVertical) / 2);
        int fromX = mTmpStartRect.left + mTmpStartRect.width() / 2
                - (frame.left + frame.width() / 2);
        int fromY = mTmpStartRect.top + mTmpStartRect.height() / 2
                - (frame.top + frame.height() / 2);
        TranslateAnimation translation = new TranslateAnimation(fromX, 0, fromY, 0);
        final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
        final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
        final ScaleAnimation scale = enter ?
                new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
                : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
        final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
        final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
        final int destHCenter = destFrame.left + destFrame.width() / 2;
        final int destVCenter = destFrame.top + destFrame.height() / 2;
        final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
        final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
        final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
                : new TranslateAnimation(0, fromX, 0, fromY);
        set.addAnimation(scale);
        set.addAnimation(translation);
        return set;
@@ -917,7 +942,7 @@ public class AppTransition implements Dump {
    Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
            Bitmap thumbnailHeader) {
        Animation a;
        getDefaultNextAppTransitionStartRect(mTmpStartRect);
        getDefaultNextAppTransitionStartRect(mTmpRect);
        final int thumbWidthI = thumbnailHeader.getWidth();
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = thumbnailHeader.getHeight();
@@ -928,8 +953,8 @@ public class AppTransition implements Dump {
            float scaleW = appWidth / thumbWidth;
            float scaleH = appHeight / thumbHeight;
            Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
                    computePivot(mTmpStartRect.left, 1 / scaleW),
                    computePivot(mTmpStartRect.top, 1 / scaleH));
                    computePivot(mTmpRect.left, 1 / scaleW),
                    computePivot(mTmpRect.top, 1 / scaleH));
            scale.setInterpolator(mDecelerateInterpolator);

            Animation alpha = new AlphaAnimation(1, 0);
@@ -945,8 +970,8 @@ public class AppTransition implements Dump {
            float scaleW = appWidth / thumbWidth;
            float scaleH = appHeight / thumbHeight;
            a = new ScaleAnimation(scaleW, 1, scaleH, 1,
                    computePivot(mTmpStartRect.left, 1 / scaleW),
                    computePivot(mTmpStartRect.top, 1 / scaleH));
                    computePivot(mTmpRect.left, 1 / scaleW),
                    computePivot(mTmpRect.top, 1 / scaleH));
        }

        return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
@@ -962,7 +987,7 @@ public class AppTransition implements Dump {
        final int appHeight = containingFrame.height();
        Bitmap thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
        Animation a;
        getDefaultNextAppTransitionStartRect(mTmpStartRect);
        getDefaultNextAppTransitionStartRect(mTmpRect);
        final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
@@ -974,8 +999,8 @@ public class AppTransition implements Dump {
                float scaleW = thumbWidth / appWidth;
                float scaleH = thumbHeight / appHeight;
                a = new ScaleAnimation(scaleW, 1, scaleH, 1,
                        computePivot(mTmpStartRect.left, scaleW),
                        computePivot(mTmpStartRect.top, scaleH));
                        computePivot(mTmpRect.left, scaleW),
                        computePivot(mTmpRect.top, scaleH));
                break;
            }
            case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
@@ -1002,8 +1027,8 @@ public class AppTransition implements Dump {
                float scaleW = thumbWidth / appWidth;
                float scaleH = thumbHeight / appHeight;
                Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
                        computePivot(mTmpStartRect.left, scaleW),
                        computePivot(mTmpStartRect.top, scaleH));
                        computePivot(mTmpRect.left, scaleW),
                        computePivot(mTmpRect.top, scaleH));

                Animation alpha = new AlphaAnimation(1, 0);

@@ -1492,15 +1517,15 @@ public class AppTransition implements Dump {
                        pw.print(Integer.toHexString(mNextAppTransitionInPlace));
                break;
            case NEXT_TRANSIT_TYPE_SCALE_UP: {
                getDefaultNextAppTransitionStartRect(mTmpStartRect);
                getDefaultNextAppTransitionStartRect(mTmpRect);
                pw.print(prefix); pw.print("mNextAppTransitionStartX=");
                        pw.print(mTmpStartRect.left);
                        pw.print(mTmpRect.left);
                        pw.print(" mNextAppTransitionStartY=");
                        pw.println(mTmpStartRect.top);
                        pw.println(mTmpRect.top);
                pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
                        pw.print(mTmpStartRect.width());
                        pw.print(mTmpRect.width());
                        pw.print(" mNextAppTransitionStartHeight=");
                        pw.println(mTmpStartRect.height());
                        pw.println(mTmpRect.height());
                break;
            }
            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: