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