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