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