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 static android.view.WindowManagerInternal.AppTransitionListener;
20 import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
21 import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
22 import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
23 import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
24 import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
25 import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
26 import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
27 import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
28 import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
29 import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
30 import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
31 import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
32 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
33 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
34 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
35 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
36 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
37 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
38 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
39 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
40 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
41 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
42 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
43 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
44 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
45 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
46 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
47 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
48 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
49 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
50 
51 import android.annotation.Nullable;
52 import android.content.Context;
53 import android.content.res.Configuration;
54 import android.graphics.Bitmap;
55 import android.graphics.GraphicBuffer;
56 import android.graphics.Path;
57 import android.graphics.Rect;
58 import android.os.Binder;
59 import android.os.Debug;
60 import android.os.IBinder;
61 import android.os.IRemoteCallback;
62 import android.os.RemoteException;
63 import android.os.SystemProperties;
64 import android.util.ArraySet;
65 import android.util.Slog;
66 import android.util.SparseArray;
67 import android.view.AppTransitionAnimationSpec;
68 import android.view.IAppTransitionAnimationSpecsFuture;
69 import android.view.WindowManager;
70 import android.view.animation.AlphaAnimation;
71 import android.view.animation.Animation;
72 import android.view.animation.AnimationSet;
73 import android.view.animation.AnimationUtils;
74 import android.view.animation.ClipRectAnimation;
75 import android.view.animation.Interpolator;
76 import android.view.animation.PathInterpolator;
77 import android.view.animation.ScaleAnimation;
78 import android.view.animation.TranslateAnimation;
79 
80 import com.android.internal.util.DumpUtils.Dump;
81 import com.android.server.AttributeCache;
82 import com.android.server.wm.WindowManagerService.H;
83 import com.android.server.wm.animation.ClipRectLRAnimation;
84 import com.android.server.wm.animation.ClipRectTBAnimation;
85 import com.android.server.wm.animation.CurvedTranslateAnimation;
86 
87 import java.io.PrintWriter;
88 import java.util.ArrayList;
89 import java.util.concurrent.ExecutorService;
90 import java.util.concurrent.Executors;
91 
92 // State management of app transitions.  When we are preparing for a
93 // transition, mNextAppTransition will be the kind of transition to
94 // perform or TRANSIT_NONE if we are not waiting.  If we are waiting,
95 // mOpeningApps and mClosingApps are the lists of tokens that will be
96 // made visible or hidden at the next transition.
97 public class AppTransition implements Dump {
98     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM;
99     private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8;
100 
101     /** Not set up for a transition. */
102     public static final int TRANSIT_UNSET = -1;
103     /** No animation for transition. */
104     public static final int TRANSIT_NONE = 0;
105     /** A window in a new activity is being opened on top of an existing one in the same task. */
106     public static final int TRANSIT_ACTIVITY_OPEN = 6;
107     /** The window in the top-most activity is being closed to reveal the
108      * previous activity in the same task. */
109     public static final int TRANSIT_ACTIVITY_CLOSE = 7;
110     /** A window in a new task is being opened on top of an existing one
111      * in another activity's task. */
112     public static final int TRANSIT_TASK_OPEN = 8;
113     /** A window in the top-most activity is being closed to reveal the
114      * previous activity in a different task. */
115     public static final int TRANSIT_TASK_CLOSE = 9;
116     /** A window in an existing task is being displayed on top of an existing one
117      * in another activity's task. */
118     public static final int TRANSIT_TASK_TO_FRONT = 10;
119     /** A window in an existing task is being put below all other tasks. */
120     public static final int TRANSIT_TASK_TO_BACK = 11;
121     /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that
122      * does, effectively closing the wallpaper. */
123     public static final int TRANSIT_WALLPAPER_CLOSE = 12;
124     /** A window in a new activity that does have a wallpaper is being opened on one that didn't,
125      * effectively opening the wallpaper. */
126     public static final int TRANSIT_WALLPAPER_OPEN = 13;
127     /** A window in a new activity is being opened on top of an existing one, and both are on top
128      * of the wallpaper. */
129     public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14;
130     /** The window in the top-most activity is being closed to reveal the previous activity, and
131      * both are on top of the wallpaper. */
132     public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15;
133     /** A window in a new task is being opened behind an existing one in another activity's task.
134      * The new window will show briefly and then be gone. */
135     public static final int TRANSIT_TASK_OPEN_BEHIND = 16;
136     /** A window in a task is being animated in-place. */
137     public static final int TRANSIT_TASK_IN_PLACE = 17;
138     /** An activity is being relaunched (e.g. due to configuration change). */
139     public static final int TRANSIT_ACTIVITY_RELAUNCH = 18;
140     /** A task is being docked from recents. */
141     public static final int TRANSIT_DOCK_TASK_FROM_RECENTS = 19;
142     /** Keyguard is going away */
143     public static final int TRANSIT_KEYGUARD_GOING_AWAY = 20;
144     /** Keyguard is going away with showing an activity behind that requests wallpaper */
145     public static final int TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
146     /** Keyguard is being occluded */
147     public static final int TRANSIT_KEYGUARD_OCCLUDE = 22;
148     /** Keyguard is being unoccluded */
149     public static final int TRANSIT_KEYGUARD_UNOCCLUDE = 23;
150 
151     /** Transition flag: Keyguard is going away, but keeping the notification shade open */
152     public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE = 0x1;
153     /** Transition flag: Keyguard is going away, but doesn't want an animation for it */
154     public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION = 0x2;
155     /** Transition flag: Keyguard is going away while it was showing the system wallpaper. */
156     public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER = 0x4;
157 
158     /** Fraction of animation at which the recents thumbnail stays completely transparent */
159     private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
160     /** Fraction of animation at which the recents thumbnail becomes completely transparent */
161     private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
162 
163     static final int DEFAULT_APP_TRANSITION_DURATION = 336;
164 
165     /** Interpolator to be used for animations that respond directly to a touch */
166     static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
167             new PathInterpolator(0.3f, 0f, 0.1f, 1f);
168 
169     private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR =
170             new PathInterpolator(0.85f, 0f, 1f, 1f);
171 
172     /**
173      * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
174      * involved, to make it more understandable.
175      */
176     private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
177     private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
178     private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
179 
180     private final Context mContext;
181     private final WindowManagerService mService;
182 
183     private int mNextAppTransition = TRANSIT_UNSET;
184     private int mNextAppTransitionFlags = 0;
185     private int mLastUsedAppTransition = TRANSIT_UNSET;
186     private String mLastOpeningApp;
187     private String mLastClosingApp;
188 
189     private static final int NEXT_TRANSIT_TYPE_NONE = 0;
190     private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
191     private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
192     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
193     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
194     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
195     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
196     private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
197     private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
198     private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
199 
200     // These are the possible states for the enter/exit activities during a thumbnail transition
201     private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
202     private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
203     private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
204     private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
205 
206     private String mNextAppTransitionPackage;
207     // Used for thumbnail transitions. True if we're scaling up, false if scaling down
208     private boolean mNextAppTransitionScaleUp;
209     private IRemoteCallback mNextAppTransitionCallback;
210     private IRemoteCallback mNextAppTransitionFutureCallback;
211     private IRemoteCallback mAnimationFinishedCallback;
212     private int mNextAppTransitionEnter;
213     private int mNextAppTransitionExit;
214     private int mNextAppTransitionInPlace;
215 
216     // Keyed by task id.
217     private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
218             = new SparseArray<>();
219     private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
220     private boolean mNextAppTransitionAnimationsSpecsPending;
221     private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
222 
223     private Rect mNextAppTransitionInsets = new Rect();
224 
225     private Rect mTmpFromClipRect = new Rect();
226     private Rect mTmpToClipRect = new Rect();
227 
228     private final Rect mTmpRect = new Rect();
229 
230     private final static int APP_STATE_IDLE = 0;
231     private final static int APP_STATE_READY = 1;
232     private final static int APP_STATE_RUNNING = 2;
233     private final static int APP_STATE_TIMEOUT = 3;
234     private int mAppTransitionState = APP_STATE_IDLE;
235 
236     private final int mConfigShortAnimTime;
237     private final Interpolator mDecelerateInterpolator;
238     private final Interpolator mThumbnailFadeInInterpolator;
239     private final Interpolator mThumbnailFadeOutInterpolator;
240     private final Interpolator mLinearOutSlowInInterpolator;
241     private final Interpolator mFastOutLinearInInterpolator;
242     private final Interpolator mFastOutSlowInInterpolator;
243     private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
244 
245     private final int mClipRevealTranslationY;
246 
247     private int mCurrentUserId = 0;
248     private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
249 
250     private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
251     private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
252 
253     private int mLastClipRevealMaxTranslation;
254     private boolean mLastHadClipReveal;
255     private boolean mProlongedAnimationsEnded;
256 
257     private final boolean mGridLayoutRecentsEnabled;
258 
AppTransition(Context context, WindowManagerService service)259     AppTransition(Context context, WindowManagerService service) {
260         mContext = context;
261         mService = service;
262         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
263                 com.android.internal.R.interpolator.linear_out_slow_in);
264         mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
265                 com.android.internal.R.interpolator.fast_out_linear_in);
266         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
267                 com.android.internal.R.interpolator.fast_out_slow_in);
268         mConfigShortAnimTime = context.getResources().getInteger(
269                 com.android.internal.R.integer.config_shortAnimTime);
270         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
271                 com.android.internal.R.interpolator.decelerate_cubic);
272         mThumbnailFadeInInterpolator = new Interpolator() {
273             @Override
274             public float getInterpolation(float input) {
275                 // Linear response for first fraction, then complete after that.
276                 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
277                     return 0f;
278                 }
279                 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /
280                         (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
281                 return mFastOutLinearInInterpolator.getInterpolation(t);
282             }
283         };
284         mThumbnailFadeOutInterpolator = new Interpolator() {
285             @Override
286             public float getInterpolation(float input) {
287                 // Linear response for first fraction, then complete after that.
288                 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
289                     float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
290                     return mLinearOutSlowInInterpolator.getInterpolation(t);
291                 }
292                 return 1f;
293             }
294         };
295         mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP
296                 * mContext.getResources().getDisplayMetrics().density);
297         mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
298     }
299 
isTransitionSet()300     boolean isTransitionSet() {
301         return mNextAppTransition != TRANSIT_UNSET;
302     }
303 
isTransitionEqual(int transit)304     boolean isTransitionEqual(int transit) {
305         return mNextAppTransition == transit;
306     }
307 
getAppTransition()308     int getAppTransition() {
309         return mNextAppTransition;
310      }
311 
setAppTransition(int transit, int flags)312     private void setAppTransition(int transit, int flags) {
313         mNextAppTransition = transit;
314         mNextAppTransitionFlags |= flags;
315         setLastAppTransition(TRANSIT_UNSET, null, null);
316         updateBooster();
317     }
318 
setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp)319     void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp) {
320         mLastUsedAppTransition = transit;
321         mLastOpeningApp = "" + openingApp;
322         mLastClosingApp = "" + closingApp;
323     }
324 
isReady()325     boolean isReady() {
326         return mAppTransitionState == APP_STATE_READY
327                 || mAppTransitionState == APP_STATE_TIMEOUT;
328     }
329 
setReady()330     void setReady() {
331         setAppTransitionState(APP_STATE_READY);
332         fetchAppTransitionSpecsFromFuture();
333     }
334 
isRunning()335     boolean isRunning() {
336         return mAppTransitionState == APP_STATE_RUNNING;
337     }
338 
setIdle()339     void setIdle() {
340         setAppTransitionState(APP_STATE_IDLE);
341     }
342 
isTimeout()343     boolean isTimeout() {
344         return mAppTransitionState == APP_STATE_TIMEOUT;
345     }
346 
setTimeout()347     void setTimeout() {
348         setAppTransitionState(APP_STATE_TIMEOUT);
349     }
350 
getAppTransitionThumbnailHeader(int taskId)351     GraphicBuffer getAppTransitionThumbnailHeader(int taskId) {
352         AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
353         if (spec == null) {
354             spec = mDefaultNextAppTransitionAnimationSpec;
355         }
356         return spec != null ? spec.buffer : null;
357     }
358 
359     /** Returns whether the next thumbnail transition is aspect scaled up. */
isNextThumbnailTransitionAspectScaled()360     boolean isNextThumbnailTransitionAspectScaled() {
361         return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
362                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
363     }
364 
365     /** Returns whether the next thumbnail transition is scaling up. */
isNextThumbnailTransitionScaleUp()366     boolean isNextThumbnailTransitionScaleUp() {
367         return mNextAppTransitionScaleUp;
368     }
369 
isNextAppTransitionThumbnailUp()370     boolean isNextAppTransitionThumbnailUp() {
371         return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
372                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP;
373     }
374 
isNextAppTransitionThumbnailDown()375     boolean isNextAppTransitionThumbnailDown() {
376         return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN ||
377                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
378     }
379 
380     /**
381      * @return true if and only if we are currently fetching app transition specs from the future
382      *         passed into {@link #overridePendingAppTransitionMultiThumbFuture}
383      */
isFetchingAppTransitionsSpecs()384     boolean isFetchingAppTransitionsSpecs() {
385         return mNextAppTransitionAnimationsSpecsPending;
386     }
387 
prepare()388     private boolean prepare() {
389         if (!isRunning()) {
390             setAppTransitionState(APP_STATE_IDLE);
391             notifyAppTransitionPendingLocked();
392             mLastHadClipReveal = false;
393             mLastClipRevealMaxTranslation = 0;
394             mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
395             return true;
396         }
397         return false;
398     }
399 
400     /**
401      * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
402      *         layout pass needs to be done
403      */
goodToGo(int transit, AppWindowAnimator topOpeningAppAnimator, AppWindowAnimator topClosingAppAnimator, ArraySet<AppWindowToken> openingApps, ArraySet<AppWindowToken> closingApps)404     int goodToGo(int transit, AppWindowAnimator topOpeningAppAnimator,
405             AppWindowAnimator topClosingAppAnimator, ArraySet<AppWindowToken> openingApps,
406             ArraySet<AppWindowToken> closingApps) {
407         mNextAppTransition = TRANSIT_UNSET;
408         mNextAppTransitionFlags = 0;
409         setAppTransitionState(APP_STATE_RUNNING);
410         int redoLayout = notifyAppTransitionStartingLocked(transit,
411                 topOpeningAppAnimator != null ? topOpeningAppAnimator.mAppToken.token : null,
412                 topClosingAppAnimator != null ? topClosingAppAnimator.mAppToken.token : null,
413                 topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null,
414                 topClosingAppAnimator != null ? topClosingAppAnimator.animation : null);
415         mService.getDefaultDisplayContentLocked().getDockedDividerController()
416                 .notifyAppTransitionStarting(openingApps, transit);
417 
418         // Prolong the start for the transition when docking a task from recents, unless recents
419         // ended it already then we don't need to wait.
420         if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) {
421             for (int i = openingApps.size() - 1; i >= 0; i--) {
422                 final AppWindowAnimator appAnimator = openingApps.valueAt(i).mAppAnimator;
423                 appAnimator.startProlongAnimation(PROLONG_ANIMATION_AT_START);
424             }
425         }
426         return redoLayout;
427     }
428 
429     /**
430      * Let the transitions manager know that the somebody wanted to end the prolonged animations.
431      */
notifyProlongedAnimationsEnded()432     void notifyProlongedAnimationsEnded() {
433         mProlongedAnimationsEnded = true;
434     }
435 
clear()436     void clear() {
437         mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
438         mNextAppTransitionPackage = null;
439         mNextAppTransitionAnimationsSpecs.clear();
440         mNextAppTransitionAnimationsSpecsFuture = null;
441         mDefaultNextAppTransitionAnimationSpec = null;
442         mAnimationFinishedCallback = null;
443         mProlongedAnimationsEnded = false;
444     }
445 
freeze()446     void freeze() {
447         final int transit = mNextAppTransition;
448         setAppTransition(AppTransition.TRANSIT_UNSET, 0 /* flags */);
449         clear();
450         setReady();
451         notifyAppTransitionCancelledLocked(transit);
452     }
453 
setAppTransitionState(int state)454     private void setAppTransitionState(int state) {
455         mAppTransitionState = state;
456         updateBooster();
457     }
458 
459     /**
460      * Updates whether we currently boost wm locked sections and the animation thread. We want to
461      * boost the priorities to a more important value whenever an app transition is going to happen
462      * soon or an app transition is running.
463      */
updateBooster()464     private void updateBooster() {
465         WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning(
466                 mNextAppTransition != TRANSIT_UNSET || mAppTransitionState == APP_STATE_READY
467                         || mAppTransitionState == APP_STATE_RUNNING);
468     }
469 
registerListenerLocked(AppTransitionListener listener)470     void registerListenerLocked(AppTransitionListener listener) {
471         mListeners.add(listener);
472     }
473 
notifyAppTransitionFinishedLocked(IBinder token)474     public void notifyAppTransitionFinishedLocked(IBinder token) {
475         for (int i = 0; i < mListeners.size(); i++) {
476             mListeners.get(i).onAppTransitionFinishedLocked(token);
477         }
478     }
479 
notifyAppTransitionPendingLocked()480     private void notifyAppTransitionPendingLocked() {
481         for (int i = 0; i < mListeners.size(); i++) {
482             mListeners.get(i).onAppTransitionPendingLocked();
483         }
484     }
485 
notifyAppTransitionCancelledLocked(int transit)486     private void notifyAppTransitionCancelledLocked(int transit) {
487         for (int i = 0; i < mListeners.size(); i++) {
488             mListeners.get(i).onAppTransitionCancelledLocked(transit);
489         }
490     }
491 
notifyAppTransitionStartingLocked(int transit, IBinder openToken, IBinder closeToken, Animation openAnimation, Animation closeAnimation)492     private int notifyAppTransitionStartingLocked(int transit, IBinder openToken,
493             IBinder closeToken, Animation openAnimation, Animation closeAnimation) {
494         int redoLayout = 0;
495         for (int i = 0; i < mListeners.size(); i++) {
496             redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, openToken,
497                     closeToken, openAnimation, closeAnimation);
498         }
499         return redoLayout;
500     }
501 
getCachedAnimations(WindowManager.LayoutParams lp)502     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
503         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
504                 + (lp != null ? lp.packageName : null)
505                 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
506         if (lp != null && lp.windowAnimations != 0) {
507             // If this is a system resource, don't try to load it from the
508             // application resources.  It is nice to avoid loading application
509             // resources if we can.
510             String packageName = lp.packageName != null ? lp.packageName : "android";
511             int resId = lp.windowAnimations;
512             if ((resId&0xFF000000) == 0x01000000) {
513                 packageName = "android";
514             }
515             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
516                     + packageName);
517             return AttributeCache.instance().get(packageName, resId,
518                     com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
519         }
520         return null;
521     }
522 
getCachedAnimations(String packageName, int resId)523     private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
524         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
525                 + packageName + " resId=0x" + Integer.toHexString(resId));
526         if (packageName != null) {
527             if ((resId&0xFF000000) == 0x01000000) {
528                 packageName = "android";
529             }
530             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
531                     + packageName);
532             return AttributeCache.instance().get(packageName, resId,
533                     com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
534         }
535         return null;
536     }
537 
loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr)538     Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) {
539         int anim = 0;
540         Context context = mContext;
541         if (animAttr >= 0) {
542             AttributeCache.Entry ent = getCachedAnimations(lp);
543             if (ent != null) {
544                 context = ent.context;
545                 anim = ent.array.getResourceId(animAttr, 0);
546             }
547         }
548         if (anim != 0) {
549             return AnimationUtils.loadAnimation(context, anim);
550         }
551         return null;
552     }
553 
loadAnimationRes(WindowManager.LayoutParams lp, int resId)554     Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) {
555         Context context = mContext;
556         if (resId >= 0) {
557             AttributeCache.Entry ent = getCachedAnimations(lp);
558             if (ent != null) {
559                 context = ent.context;
560             }
561             return AnimationUtils.loadAnimation(context, resId);
562         }
563         return null;
564     }
565 
loadAnimationRes(String packageName, int resId)566     private Animation loadAnimationRes(String packageName, int resId) {
567         int anim = 0;
568         Context context = mContext;
569         if (resId >= 0) {
570             AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
571             if (ent != null) {
572                 context = ent.context;
573                 anim = resId;
574             }
575         }
576         if (anim != 0) {
577             return AnimationUtils.loadAnimation(context, anim);
578         }
579         return null;
580     }
581 
582     /**
583      * Compute the pivot point for an animation that is scaling from a small
584      * rect on screen to a larger rect.  The pivot point varies depending on
585      * the distance between the inner and outer edges on both sides.  This
586      * function computes the pivot point for one dimension.
587      * @param startPos  Offset from left/top edge of outer rectangle to
588      * left/top edge of inner rectangle.
589      * @param finalScale The scaling factor between the size of the outer
590      * and inner rectangles.
591      */
computePivot(int startPos, float finalScale)592     private static float computePivot(int startPos, float finalScale) {
593 
594         /*
595         Theorem of intercepting lines:
596 
597           +      +   +-----------------------------------------------+
598           |      |   |                                               |
599           |      |   |                                               |
600           |      |   |                                               |
601           |      |   |                                               |
602         x |    y |   |                                               |
603           |      |   |                                               |
604           |      |   |                                               |
605           |      |   |                                               |
606           |      |   |                                               |
607           |      +   |             +--------------------+            |
608           |          |             |                    |            |
609           |          |             |                    |            |
610           |          |             |                    |            |
611           |          |             |                    |            |
612           |          |             |                    |            |
613           |          |             |                    |            |
614           |          |             |                    |            |
615           |          |             |                    |            |
616           |          |             |                    |            |
617           |          |             |                    |            |
618           |          |             |                    |            |
619           |          |             |                    |            |
620           |          |             |                    |            |
621           |          |             |                    |            |
622           |          |             |                    |            |
623           |          |             |                    |            |
624           |          |             |                    |            |
625           |          |             +--------------------+            |
626           |          |                                               |
627           |          |                                               |
628           |          |                                               |
629           |          |                                               |
630           |          |                                               |
631           |          |                                               |
632           |          |                                               |
633           |          +-----------------------------------------------+
634           |
635           |
636           |
637           |
638           |
639           |
640           |
641           |
642           |
643           +                                 ++
644                                          p  ++
645 
646         scale = (x - y) / x
647         <=> x = -y / (scale - 1)
648         */
649         final float denom = finalScale-1;
650         if (Math.abs(denom) < .0001f) {
651             return startPos;
652         }
653         return -startPos / denom;
654     }
655 
createScaleUpAnimationLocked(int transit, boolean enter, Rect containingFrame)656     private Animation createScaleUpAnimationLocked(int transit, boolean enter,
657             Rect containingFrame) {
658         Animation a;
659         getDefaultNextAppTransitionStartRect(mTmpRect);
660         final int appWidth = containingFrame.width();
661         final int appHeight = containingFrame.height();
662         if (enter) {
663             // Entering app zooms out from the center of the initial rect.
664             float scaleW = mTmpRect.width() / (float) appWidth;
665             float scaleH = mTmpRect.height() / (float) appHeight;
666             Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
667                     computePivot(mTmpRect.left, scaleW),
668                     computePivot(mTmpRect.top, scaleH));
669             scale.setInterpolator(mDecelerateInterpolator);
670 
671             Animation alpha = new AlphaAnimation(0, 1);
672             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
673 
674             AnimationSet set = new AnimationSet(false);
675             set.addAnimation(scale);
676             set.addAnimation(alpha);
677             set.setDetachWallpaper(true);
678             a = set;
679         } else  if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
680                     transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
681             // If we are on top of the wallpaper, we need an animation that
682             // correctly handles the wallpaper staying static behind all of
683             // the animated elements.  To do this, will just have the existing
684             // element fade out.
685             a = new AlphaAnimation(1, 0);
686             a.setDetachWallpaper(true);
687         } else {
688             // For normal animations, the exiting element just holds in place.
689             a = new AlphaAnimation(1, 1);
690         }
691 
692         // Pick the desired duration.  If this is an inter-activity transition,
693         // it  is the standard duration for that.  Otherwise we use the longer
694         // task transition duration.
695         final long duration;
696         switch (transit) {
697             case TRANSIT_ACTIVITY_OPEN:
698             case TRANSIT_ACTIVITY_CLOSE:
699                 duration = mConfigShortAnimTime;
700                 break;
701             default:
702                 duration = DEFAULT_APP_TRANSITION_DURATION;
703                 break;
704         }
705         a.setDuration(duration);
706         a.setFillAfter(true);
707         a.setInterpolator(mDecelerateInterpolator);
708         a.initialize(appWidth, appHeight, appWidth, appHeight);
709         return a;
710     }
711 
getDefaultNextAppTransitionStartRect(Rect rect)712     private void getDefaultNextAppTransitionStartRect(Rect rect) {
713         if (mDefaultNextAppTransitionAnimationSpec == null ||
714                 mDefaultNextAppTransitionAnimationSpec.rect == null) {
715             Slog.e(TAG, "Starting rect for app requested, but none available", new Throwable());
716             rect.setEmpty();
717         } else {
718             rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
719         }
720     }
721 
getNextAppTransitionStartRect(int taskId, Rect rect)722     void getNextAppTransitionStartRect(int taskId, Rect rect) {
723         AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
724         if (spec == null) {
725             spec = mDefaultNextAppTransitionAnimationSpec;
726         }
727         if (spec == null || spec.rect == null) {
728             Slog.e(TAG, "Starting rect for task: " + taskId + " requested, but not available",
729                     new Throwable());
730             rect.setEmpty();
731         } else {
732             rect.set(spec.rect);
733         }
734     }
735 
putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height, GraphicBuffer buffer)736     private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height,
737             GraphicBuffer buffer) {
738         mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
739                 buffer, new Rect(left, top, left + width, top + height));
740     }
741 
742     /**
743      * @return the duration of the last clip reveal animation
744      */
getLastClipRevealTransitionDuration()745     long getLastClipRevealTransitionDuration() {
746         return mLastClipRevealTransitionDuration;
747     }
748 
749     /**
750      * @return the maximum distance the app surface is traveling of the last clip reveal animation
751      */
getLastClipRevealMaxTranslation()752     int getLastClipRevealMaxTranslation() {
753         return mLastClipRevealMaxTranslation;
754     }
755 
756     /**
757      * @return true if in the last app transition had a clip reveal animation, false otherwise
758      */
hadClipRevealAnimation()759     boolean hadClipRevealAnimation() {
760         return mLastHadClipReveal;
761     }
762 
763     /**
764      * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
765      * the start rect is outside of the target rect, and there is a lot of movement going on.
766      *
767      * @param cutOff whether the start rect was not fully contained by the end rect
768      * @param translationX the total translation the surface moves in x direction
769      * @param translationY the total translation the surfaces moves in y direction
770      * @param displayFrame our display frame
771      *
772      * @return the duration of the clip reveal animation, in milliseconds
773      */
calculateClipRevealTransitionDuration(boolean cutOff, float translationX, float translationY, Rect displayFrame)774     private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX,
775             float translationY, Rect displayFrame) {
776         if (!cutOff) {
777             return DEFAULT_APP_TRANSITION_DURATION;
778         }
779         final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(),
780                 Math.abs(translationY) / displayFrame.height());
781         return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction *
782                 (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION));
783     }
784 
createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame, Rect displayFrame)785     private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame,
786             Rect displayFrame) {
787         final Animation anim;
788         if (enter) {
789             final int appWidth = appFrame.width();
790             final int appHeight = appFrame.height();
791 
792             // mTmpRect will contain an area around the launcher icon that was pressed. We will
793             // clip reveal from that area in the final area of the app.
794             getDefaultNextAppTransitionStartRect(mTmpRect);
795 
796             float t = 0f;
797             if (appHeight > 0) {
798                 t = (float) mTmpRect.top / displayFrame.height();
799             }
800             int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t);
801             int translationX = 0;
802             int translationYCorrection = translationY;
803             int centerX = mTmpRect.centerX();
804             int centerY = mTmpRect.centerY();
805             int halfWidth = mTmpRect.width() / 2;
806             int halfHeight = mTmpRect.height() / 2;
807             int clipStartX = centerX - halfWidth - appFrame.left;
808             int clipStartY = centerY - halfHeight - appFrame.top;
809             boolean cutOff = false;
810 
811             // If the starting rectangle is fully or partially outside of the target rectangle, we
812             // need to start the clipping at the edge and then achieve the rest with translation
813             // and extending the clip rect from that edge.
814             if (appFrame.top > centerY - halfHeight) {
815                 translationY = (centerY - halfHeight) - appFrame.top;
816                 translationYCorrection = 0;
817                 clipStartY = 0;
818                 cutOff = true;
819             }
820             if (appFrame.left > centerX - halfWidth) {
821                 translationX = (centerX - halfWidth) - appFrame.left;
822                 clipStartX = 0;
823                 cutOff = true;
824             }
825             if (appFrame.right < centerX + halfWidth) {
826                 translationX = (centerX + halfWidth) - appFrame.right;
827                 clipStartX = appWidth - mTmpRect.width();
828                 cutOff = true;
829             }
830             final long duration = calculateClipRevealTransitionDuration(cutOff, translationX,
831                     translationY, displayFrame);
832 
833             // Clip third of the from size of launch icon, expand to full width/height
834             Animation clipAnimLR = new ClipRectLRAnimation(
835                     clipStartX, clipStartX + mTmpRect.width(), 0, appWidth);
836             clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
837             clipAnimLR.setDuration((long) (duration / 2.5f));
838 
839             TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0);
840             translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR
841                     : mLinearOutSlowInInterpolator);
842             translate.setDuration(duration);
843 
844             Animation clipAnimTB = new ClipRectTBAnimation(
845                     clipStartY, clipStartY + mTmpRect.height(),
846                     0, appHeight,
847                     translationYCorrection, 0,
848                     mLinearOutSlowInInterpolator);
849             clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
850             clipAnimTB.setDuration(duration);
851 
852             // Quick fade-in from icon to app window
853             final long alphaDuration = duration / 4;
854             AlphaAnimation alpha = new AlphaAnimation(0.5f, 1);
855             alpha.setDuration(alphaDuration);
856             alpha.setInterpolator(mLinearOutSlowInInterpolator);
857 
858             AnimationSet set = new AnimationSet(false);
859             set.addAnimation(clipAnimLR);
860             set.addAnimation(clipAnimTB);
861             set.addAnimation(translate);
862             set.addAnimation(alpha);
863             set.setZAdjustment(Animation.ZORDER_TOP);
864             set.initialize(appWidth, appHeight, appWidth, appHeight);
865             anim = set;
866             mLastHadClipReveal = true;
867             mLastClipRevealTransitionDuration = duration;
868 
869             // If the start rect was full inside the target rect (cutOff == false), we don't need
870             // to store the translation, because it's only used if cutOff == true.
871             mLastClipRevealMaxTranslation = cutOff
872                     ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0;
873         } else {
874             final long duration;
875             switch (transit) {
876                 case TRANSIT_ACTIVITY_OPEN:
877                 case TRANSIT_ACTIVITY_CLOSE:
878                     duration = mConfigShortAnimTime;
879                     break;
880                 default:
881                     duration = DEFAULT_APP_TRANSITION_DURATION;
882                     break;
883             }
884             if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
885                     transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
886                 // If we are on top of the wallpaper, we need an animation that
887                 // correctly handles the wallpaper staying static behind all of
888                 // the animated elements.  To do this, will just have the existing
889                 // element fade out.
890                 anim = new AlphaAnimation(1, 0);
891                 anim.setDetachWallpaper(true);
892             } else {
893                 // For normal animations, the exiting element just holds in place.
894                 anim = new AlphaAnimation(1, 1);
895             }
896             anim.setInterpolator(mDecelerateInterpolator);
897             anim.setDuration(duration);
898             anim.setFillAfter(true);
899         }
900         return anim;
901     }
902 
903     /**
904      * Prepares the specified animation with a standard duration, interpolator, etc.
905      */
prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight, long duration, Interpolator interpolator)906     Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
907             long duration, Interpolator interpolator) {
908         if (duration > 0) {
909             a.setDuration(duration);
910         }
911         a.setFillAfter(true);
912         if (interpolator != null) {
913             a.setInterpolator(interpolator);
914         }
915         a.initialize(appWidth, appHeight, appWidth, appHeight);
916         return a;
917     }
918 
919     /**
920      * Prepares the specified animation with a standard duration, interpolator, etc.
921      */
prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit)922     Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
923         // Pick the desired duration.  If this is an inter-activity transition,
924         // it  is the standard duration for that.  Otherwise we use the longer
925         // task transition duration.
926         final int duration;
927         switch (transit) {
928             case TRANSIT_ACTIVITY_OPEN:
929             case TRANSIT_ACTIVITY_CLOSE:
930                 duration = mConfigShortAnimTime;
931                 break;
932             default:
933                 duration = DEFAULT_APP_TRANSITION_DURATION;
934                 break;
935         }
936         return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
937                 mDecelerateInterpolator);
938     }
939 
940     /**
941      * Return the current thumbnail transition state.
942      */
getThumbnailTransitionState(boolean enter)943     int getThumbnailTransitionState(boolean enter) {
944         if (enter) {
945             if (mNextAppTransitionScaleUp) {
946                 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
947             } else {
948                 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
949             }
950         } else {
951             if (mNextAppTransitionScaleUp) {
952                 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
953             } else {
954                 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
955             }
956         }
957     }
958 
959     /**
960      * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
961      * when a thumbnail is specified with the pending animation override.
962      */
createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets, GraphicBuffer thumbnailHeader, final int taskId, int uiMode, int orientation)963     Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
964             GraphicBuffer thumbnailHeader, final int taskId, int uiMode, int orientation) {
965         Animation a;
966         final int thumbWidthI = thumbnailHeader.getWidth();
967         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
968         final int thumbHeightI = thumbnailHeader.getHeight();
969         final int appWidth = appRect.width();
970 
971         float scaleW = appWidth / thumbWidth;
972         getNextAppTransitionStartRect(taskId, mTmpRect);
973         final float fromX;
974         float fromY;
975         final float toX;
976         float toY;
977         final float pivotX;
978         final float pivotY;
979         if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
980             fromX = mTmpRect.left;
981             fromY = mTmpRect.top;
982 
983             // For the curved translate animation to work, the pivot points needs to be at the
984             // same absolute position as the one from the real surface.
985             toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
986             toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
987             pivotX = mTmpRect.width() / 2;
988             pivotY = appRect.height() / 2 / scaleW;
989             if (mGridLayoutRecentsEnabled) {
990                 // In the grid layout, the header is displayed above the thumbnail instead of
991                 // overlapping it.
992                 fromY -= thumbHeightI;
993                 toY -= thumbHeightI * scaleW;
994             }
995         } else {
996             pivotX = 0;
997             pivotY = 0;
998             fromX = mTmpRect.left;
999             fromY = mTmpRect.top;
1000             toX = appRect.left;
1001             toY = appRect.top;
1002         }
1003         final long duration = getAspectScaleDuration();
1004         final Interpolator interpolator = getAspectScaleInterpolator();
1005         if (mNextAppTransitionScaleUp) {
1006             // Animation up from the thumbnail to the full screen
1007             Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
1008             scale.setInterpolator(interpolator);
1009             scale.setDuration(duration);
1010             Animation alpha = new AlphaAnimation(1f, 0f);
1011             alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1012                     ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator);
1013             alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1014                     ? duration / 2
1015                     : duration);
1016             Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
1017             translate.setInterpolator(interpolator);
1018             translate.setDuration(duration);
1019 
1020             mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
1021             mTmpToClipRect.set(appRect);
1022 
1023             // Containing frame is in screen space, but we need the clip rect in the
1024             // app space.
1025             mTmpToClipRect.offsetTo(0, 0);
1026             mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
1027             mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
1028 
1029             if (contentInsets != null) {
1030                 mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
1031                         (int) (-contentInsets.top * scaleW),
1032                         (int) (-contentInsets.right * scaleW),
1033                         (int) (-contentInsets.bottom * scaleW));
1034             }
1035 
1036             Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
1037             clipAnim.setInterpolator(interpolator);
1038             clipAnim.setDuration(duration);
1039 
1040             // This AnimationSet uses the Interpolators assigned above.
1041             AnimationSet set = new AnimationSet(false);
1042             set.addAnimation(scale);
1043             if (!mGridLayoutRecentsEnabled) {
1044                 // In the grid layout, the header should be shown for the whole animation.
1045                 set.addAnimation(alpha);
1046             }
1047             set.addAnimation(translate);
1048             set.addAnimation(clipAnim);
1049             a = set;
1050         } else {
1051             // Animation down from the full screen to the thumbnail
1052             Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
1053             scale.setInterpolator(interpolator);
1054             scale.setDuration(duration);
1055             Animation alpha = new AlphaAnimation(0f, 1f);
1056             alpha.setInterpolator(mThumbnailFadeInInterpolator);
1057             alpha.setDuration(duration);
1058             Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
1059             translate.setInterpolator(interpolator);
1060             translate.setDuration(duration);
1061 
1062             // This AnimationSet uses the Interpolators assigned above.
1063             AnimationSet set = new AnimationSet(false);
1064             set.addAnimation(scale);
1065             if (!mGridLayoutRecentsEnabled) {
1066                 // In the grid layout, the header should be shown for the whole animation.
1067                 set.addAnimation(alpha);
1068             }
1069             set.addAnimation(translate);
1070             a = set;
1071 
1072         }
1073         return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
1074                 null);
1075     }
1076 
createCurvedMotion(float fromX, float toX, float fromY, float toY)1077     private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
1078 
1079         // Almost no x-change - use linear animation
1080         if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) {
1081             return new TranslateAnimation(fromX, toX, fromY, toY);
1082         } else {
1083             final Path path = createCurvedPath(fromX, toX, fromY, toY);
1084             return new CurvedTranslateAnimation(path);
1085         }
1086     }
1087 
createCurvedPath(float fromX, float toX, float fromY, float toY)1088     private Path createCurvedPath(float fromX, float toX, float fromY, float toY) {
1089         final Path path = new Path();
1090         path.moveTo(fromX, fromY);
1091 
1092         if (fromY > toY) {
1093             // If the object needs to go up, move it in horizontal direction first, then vertical.
1094             path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY);
1095         } else {
1096             // If the object needs to go down, move it in vertical direction first, then horizontal.
1097             path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY);
1098         }
1099         return path;
1100     }
1101 
getAspectScaleDuration()1102     private long getAspectScaleDuration() {
1103         if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
1104             return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f);
1105         } else {
1106             return THUMBNAIL_APP_TRANSITION_DURATION;
1107         }
1108     }
1109 
getAspectScaleInterpolator()1110     private Interpolator getAspectScaleInterpolator() {
1111         if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
1112             return mFastOutSlowInInterpolator;
1113         } else {
1114             return TOUCH_RESPONSE_INTERPOLATOR;
1115         }
1116     }
1117 
1118     /**
1119      * This alternate animation is created when we are doing a thumbnail transition, for the
1120      * activity that is leaving, and the activity that is entering.
1121      */
createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState, int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets, @Nullable Rect surfaceInsets, boolean freeform, int taskId)1122     Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
1123             int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets,
1124             @Nullable Rect surfaceInsets, boolean freeform, int taskId) {
1125         Animation a;
1126         final int appWidth = containingFrame.width();
1127         final int appHeight = containingFrame.height();
1128         getDefaultNextAppTransitionStartRect(mTmpRect);
1129         final int thumbWidthI = mTmpRect.width();
1130         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
1131         final int thumbHeightI = mTmpRect.height();
1132         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1133         final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left;
1134         final int thumbStartY = mTmpRect.top - containingFrame.top;
1135 
1136         switch (thumbTransitState) {
1137             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
1138             case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1139                 final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
1140                 if (freeform && scaleUp) {
1141                     a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
1142                             containingFrame, surfaceInsets, taskId);
1143                 } else if (freeform) {
1144                     a = createAspectScaledThumbnailExitFreeformAnimationLocked(
1145                             containingFrame, surfaceInsets, taskId);
1146                 } else {
1147                     AnimationSet set = new AnimationSet(true);
1148 
1149                     // In portrait, we scale to fit the width
1150                     mTmpFromClipRect.set(containingFrame);
1151                     mTmpToClipRect.set(containingFrame);
1152 
1153                     // Containing frame is in screen space, but we need the clip rect in the
1154                     // app space.
1155                     mTmpFromClipRect.offsetTo(0, 0);
1156                     mTmpToClipRect.offsetTo(0, 0);
1157 
1158                     // Exclude insets region from the source clip.
1159                     mTmpFromClipRect.inset(contentInsets);
1160                     mNextAppTransitionInsets.set(contentInsets);
1161 
1162                     if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
1163                         // We scale the width and clip to the top/left square
1164                         float scale = thumbWidth /
1165                                 (appWidth - contentInsets.left - contentInsets.right);
1166                         if (!mGridLayoutRecentsEnabled) {
1167                             int unscaledThumbHeight = (int) (thumbHeight / scale);
1168                             mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
1169                         }
1170 
1171                         mNextAppTransitionInsets.set(contentInsets);
1172 
1173                         Animation scaleAnim = new ScaleAnimation(
1174                                 scaleUp ? scale : 1, scaleUp ? 1 : scale,
1175                                 scaleUp ? scale : 1, scaleUp ? 1 : scale,
1176                                 containingFrame.width() / 2f,
1177                                 containingFrame.height() / 2f + contentInsets.top);
1178                         final float targetX = (mTmpRect.left - containingFrame.left);
1179                         final float x = containingFrame.width() / 2f
1180                                 - containingFrame.width() / 2f * scale;
1181                         final float targetY = (mTmpRect.top - containingFrame.top);
1182                         final float y = containingFrame.height() / 2f
1183                                 - containingFrame.height() / 2f * scale;
1184                         final float startX = targetX - x;
1185                         final float startY = targetY - y;
1186                         Animation clipAnim = scaleUp
1187                                 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1188                                 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1189                         Animation translateAnim = scaleUp
1190                                 ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0)
1191                                 : createCurvedMotion(0, startX, 0, startY - contentInsets.top);
1192 
1193                         set.addAnimation(clipAnim);
1194                         set.addAnimation(scaleAnim);
1195                         set.addAnimation(translateAnim);
1196 
1197                     } else {
1198                         // In landscape, we don't scale at all and only crop
1199                         mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI;
1200                         mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI;
1201 
1202                         Animation clipAnim = scaleUp
1203                                 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1204                                 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1205                         Animation translateAnim = scaleUp
1206                                 ? createCurvedMotion(thumbStartX, 0,
1207                                 thumbStartY - contentInsets.top, 0)
1208                                 : createCurvedMotion(0, thumbStartX, 0,
1209                                         thumbStartY - contentInsets.top);
1210 
1211                         set.addAnimation(clipAnim);
1212                         set.addAnimation(translateAnim);
1213                     }
1214                     a = set;
1215                     a.setZAdjustment(Animation.ZORDER_TOP);
1216                 }
1217                 break;
1218             }
1219             case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
1220                 // Previous app window during the scale up
1221                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1222                     // Fade out the source activity if we are animating to a wallpaper
1223                     // activity.
1224                     a = new AlphaAnimation(1, 0);
1225                 } else {
1226                     a = new AlphaAnimation(1, 1);
1227                 }
1228                 break;
1229             }
1230             case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
1231                 // Target app window during the scale down
1232                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1233                     // Fade in the destination activity if we are animating from a wallpaper
1234                     // activity.
1235                     a = new AlphaAnimation(0, 1);
1236                 } else {
1237                     a = new AlphaAnimation(1, 1);
1238                 }
1239                 break;
1240             }
1241             default:
1242                 throw new RuntimeException("Invalid thumbnail transition state");
1243         }
1244 
1245         return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
1246                 getAspectScaleDuration(), getAspectScaleInterpolator());
1247     }
1248 
createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame, @Nullable Rect surfaceInsets, int taskId)1249     private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
1250             @Nullable Rect surfaceInsets, int taskId) {
1251         getNextAppTransitionStartRect(taskId, mTmpRect);
1252         return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
1253                 true);
1254     }
1255 
createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame, @Nullable Rect surfaceInsets, int taskId)1256     private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
1257             @Nullable Rect surfaceInsets, int taskId) {
1258         getNextAppTransitionStartRect(taskId, mTmpRect);
1259         return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
1260                 false);
1261     }
1262 
createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame, Rect destFrame, @Nullable Rect surfaceInsets, boolean enter)1263     private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
1264             Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
1265         final float sourceWidth = sourceFrame.width();
1266         final float sourceHeight = sourceFrame.height();
1267         final float destWidth = destFrame.width();
1268         final float destHeight = destFrame.height();
1269         final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
1270         final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
1271         AnimationSet set = new AnimationSet(true);
1272         final int surfaceInsetsH = surfaceInsets == null
1273                 ? 0 : surfaceInsets.left + surfaceInsets.right;
1274         final int surfaceInsetsV = surfaceInsets == null
1275                 ? 0 : surfaceInsets.top + surfaceInsets.bottom;
1276         // We want the scaling to happen from the center of the surface. In order to achieve that,
1277         // we need to account for surface insets that will be used to enlarge the surface.
1278         final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
1279         final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
1280         final ScaleAnimation scale = enter ?
1281                 new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
1282                 : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
1283         final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
1284         final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
1285         final int destHCenter = destFrame.left + destFrame.width() / 2;
1286         final int destVCenter = destFrame.top + destFrame.height() / 2;
1287         final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
1288         final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
1289         final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
1290                 : new TranslateAnimation(0, fromX, 0, fromY);
1291         set.addAnimation(scale);
1292         set.addAnimation(translation);
1293 
1294         final IRemoteCallback callback = mAnimationFinishedCallback;
1295         if (callback != null) {
1296             set.setAnimationListener(new Animation.AnimationListener() {
1297                 @Override
1298                 public void onAnimationStart(Animation animation) { }
1299 
1300                 @Override
1301                 public void onAnimationEnd(Animation animation) {
1302                     mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
1303                 }
1304 
1305                 @Override
1306                 public void onAnimationRepeat(Animation animation) { }
1307             });
1308         }
1309         return set;
1310     }
1311 
1312     /**
1313      * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
1314      * when a thumbnail is specified with the pending animation override.
1315      */
createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit, GraphicBuffer thumbnailHeader)1316     Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
1317             GraphicBuffer thumbnailHeader) {
1318         Animation a;
1319         getDefaultNextAppTransitionStartRect(mTmpRect);
1320         final int thumbWidthI = thumbnailHeader.getWidth();
1321         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
1322         final int thumbHeightI = thumbnailHeader.getHeight();
1323         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1324 
1325         if (mNextAppTransitionScaleUp) {
1326             // Animation for the thumbnail zooming from its initial size to the full screen
1327             float scaleW = appWidth / thumbWidth;
1328             float scaleH = appHeight / thumbHeight;
1329             Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
1330                     computePivot(mTmpRect.left, 1 / scaleW),
1331                     computePivot(mTmpRect.top, 1 / scaleH));
1332             scale.setInterpolator(mDecelerateInterpolator);
1333 
1334             Animation alpha = new AlphaAnimation(1, 0);
1335             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
1336 
1337             // This AnimationSet uses the Interpolators assigned above.
1338             AnimationSet set = new AnimationSet(false);
1339             set.addAnimation(scale);
1340             set.addAnimation(alpha);
1341             a = set;
1342         } else {
1343             // Animation for the thumbnail zooming down from the full screen to its final size
1344             float scaleW = appWidth / thumbWidth;
1345             float scaleH = appHeight / thumbHeight;
1346             a = new ScaleAnimation(scaleW, 1, scaleH, 1,
1347                     computePivot(mTmpRect.left, 1 / scaleW),
1348                     computePivot(mTmpRect.top, 1 / scaleH));
1349         }
1350 
1351         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1352     }
1353 
1354     /**
1355      * This animation is created when we are doing a thumbnail transition, for the activity that is
1356      * leaving, and the activity that is entering.
1357      */
createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame, int transit, int taskId)1358     Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
1359             int transit, int taskId) {
1360         final int appWidth = containingFrame.width();
1361         final int appHeight = containingFrame.height();
1362         final GraphicBuffer thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
1363         Animation a;
1364         getDefaultNextAppTransitionStartRect(mTmpRect);
1365         final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
1366         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
1367         final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
1368         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1369 
1370         switch (thumbTransitState) {
1371             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
1372                 // Entering app scales up with the thumbnail
1373                 float scaleW = thumbWidth / appWidth;
1374                 float scaleH = thumbHeight / appHeight;
1375                 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
1376                         computePivot(mTmpRect.left, scaleW),
1377                         computePivot(mTmpRect.top, scaleH));
1378                 break;
1379             }
1380             case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
1381                 // Exiting app while the thumbnail is scaling up should fade or stay in place
1382                 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1383                     // Fade out while bringing up selected activity. This keeps the
1384                     // current activity from showing through a launching wallpaper
1385                     // activity.
1386                     a = new AlphaAnimation(1, 0);
1387                 } else {
1388                     // noop animation
1389                     a = new AlphaAnimation(1, 1);
1390                 }
1391                 break;
1392             }
1393             case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
1394                 // Entering the other app, it should just be visible while we scale the thumbnail
1395                 // down above it
1396                 a = new AlphaAnimation(1, 1);
1397                 break;
1398             }
1399             case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1400                 // Exiting the current app, the app should scale down with the thumbnail
1401                 float scaleW = thumbWidth / appWidth;
1402                 float scaleH = thumbHeight / appHeight;
1403                 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
1404                         computePivot(mTmpRect.left, scaleW),
1405                         computePivot(mTmpRect.top, scaleH));
1406 
1407                 Animation alpha = new AlphaAnimation(1, 0);
1408 
1409                 AnimationSet set = new AnimationSet(true);
1410                 set.addAnimation(scale);
1411                 set.addAnimation(alpha);
1412                 set.setZAdjustment(Animation.ZORDER_TOP);
1413                 a = set;
1414                 break;
1415             }
1416             default:
1417                 throw new RuntimeException("Invalid thumbnail transition state");
1418         }
1419 
1420         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1421     }
1422 
createRelaunchAnimation(Rect containingFrame, Rect contentInsets)1423     private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) {
1424         getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
1425         final int left = mTmpFromClipRect.left;
1426         final int top = mTmpFromClipRect.top;
1427         mTmpFromClipRect.offset(-left, -top);
1428         // TODO: Isn't that strange that we ignore exact position of the containingFrame?
1429         mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height());
1430         AnimationSet set = new AnimationSet(true);
1431         float fromWidth = mTmpFromClipRect.width();
1432         float toWidth = mTmpToClipRect.width();
1433         float fromHeight = mTmpFromClipRect.height();
1434         // While the window might span the whole display, the actual content will be cropped to the
1435         // system decoration frame, for example when the window is docked. We need to take into
1436         // account the visible height when constructing the animation.
1437         float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom;
1438         int translateAdjustment = 0;
1439         if (fromWidth <= toWidth && fromHeight <= toHeight) {
1440             // The final window is larger in both dimensions than current window (e.g. we are
1441             // maximizing), so we can simply unclip the new window and there will be no disappearing
1442             // frame.
1443             set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
1444         } else {
1445             // The disappearing window has one larger dimension. We need to apply scaling, so the
1446             // first frame of the entry animation matches the old window.
1447             set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
1448             // We might not be going exactly full screen, but instead be aligned under the status
1449             // bar using cropping. We still need to account for the cropped part, which will also
1450             // be scaled.
1451             translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight);
1452         }
1453 
1454         // We animate the translation from the old position of the removed window, to the new
1455         // position of the added window. The latter might not be full screen, for example docked for
1456         // docked windows.
1457         TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
1458                 0, top - containingFrame.top - translateAdjustment, 0);
1459         set.addAnimation(translate);
1460         set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
1461         set.setZAdjustment(Animation.ZORDER_TOP);
1462         return set;
1463     }
1464 
1465     /**
1466      * @return true if and only if the first frame of the transition can be skipped, i.e. the first
1467      *         frame of the transition doesn't change the visuals on screen, so we can start
1468      *         directly with the second one
1469      */
canSkipFirstFrame()1470     boolean canSkipFirstFrame() {
1471         return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
1472                 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
1473                 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
1474                 && mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY;
1475     }
1476 
1477     /**
1478      *
1479      * @param frame These are the bounds of the window when it finishes the animation. This is where
1480      *              the animation must usually finish in entrance animation, as the next frame will
1481      *              display the window at these coordinates. In case of exit animation, this is
1482      *              where the animation must start, as the frame before the animation is displaying
1483      *              the window at these bounds.
1484      * @param insets Knowing where the window will be positioned is not enough. Some parts of the
1485      *               window might be obscured, usually by the system windows (status bar and
1486      *               navigation bar) and we use content insets to convey that information. This
1487      *               usually affects the animation aspects vertically, as the system decoration is
1488      *               at the top and the bottom. For example when we animate from full screen to
1489      *               recents, we want to exclude the covered parts, because they won't match the
1490      *               thumbnail after the last frame is executed.
1491      * @param surfaceInsets In rare situation the surface is larger than the content and we need to
1492      *                      know about this to make the animation frames match. We currently use
1493      *                      this for freeform windows, which have larger surfaces to display
1494      *                      shadows. When we animate them from recents, we want to match the content
1495      *                      to the recents thumbnail and hence need to account for the surface being
1496      *                      bigger.
1497      */
loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int uiMode, int orientation, Rect frame, Rect displayFrame, Rect insets, @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform, int taskId)1498     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int uiMode,
1499             int orientation, Rect frame, Rect displayFrame, Rect insets,
1500             @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform,
1501             int taskId) {
1502         Animation a;
1503         if (isKeyguardGoingAwayTransit(transit) && enter) {
1504             a = loadKeyguardExitAnimation(transit);
1505         } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) {
1506             a = null;
1507         } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) {
1508             a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit);
1509         } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
1510                 || transit == TRANSIT_TASK_OPEN
1511                 || transit == TRANSIT_TASK_TO_FRONT)) {
1512             a = loadAnimationRes(lp, enter
1513                     ? com.android.internal.R.anim.voice_activity_open_enter
1514                     : com.android.internal.R.anim.voice_activity_open_exit);
1515             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1516                     "applyAnimation voice:"
1517                     + " anim=" + a + " transit=" + appTransitionToString(transit)
1518                     + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
1519         } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
1520                 || transit == TRANSIT_TASK_CLOSE
1521                 || transit == TRANSIT_TASK_TO_BACK)) {
1522             a = loadAnimationRes(lp, enter
1523                     ? com.android.internal.R.anim.voice_activity_close_enter
1524                     : com.android.internal.R.anim.voice_activity_close_exit);
1525             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1526                     "applyAnimation voice:"
1527                     + " anim=" + a + " transit=" + appTransitionToString(transit)
1528                     + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
1529         } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
1530             a = createRelaunchAnimation(frame, insets);
1531             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1532                     "applyAnimation:"
1533                     + " anim=" + a + " nextAppTransition=" + mNextAppTransition
1534                     + " transit=" + appTransitionToString(transit)
1535                     + " Callers=" + Debug.getCallers(3));
1536         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
1537             a = loadAnimationRes(mNextAppTransitionPackage, enter ?
1538                     mNextAppTransitionEnter : mNextAppTransitionExit);
1539             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1540                     "applyAnimation:"
1541                     + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
1542                     + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
1543                     + " Callers=" + Debug.getCallers(3));
1544         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
1545             a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
1546             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1547                     "applyAnimation:"
1548                     + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
1549                     + " transit=" + appTransitionToString(transit)
1550                     + " Callers=" + Debug.getCallers(3));
1551         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
1552             a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
1553             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1554                     "applyAnimation:"
1555                             + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
1556                             + " transit=" + appTransitionToString(transit)
1557                             + " Callers=" + Debug.getCallers(3));
1558         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
1559             a = createScaleUpAnimationLocked(transit, enter, frame);
1560             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1561                     "applyAnimation:"
1562                     + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
1563                     + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
1564                     + " Callers=" + Debug.getCallers(3));
1565         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
1566                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
1567             mNextAppTransitionScaleUp =
1568                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
1569             a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
1570                     frame, transit, taskId);
1571             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1572                 String animName = mNextAppTransitionScaleUp ?
1573                         "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
1574                 Slog.v(TAG, "applyAnimation:"
1575                         + " anim=" + a + " nextAppTransition=" + animName
1576                         + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
1577                         + " Callers=" + Debug.getCallers(3));
1578             }
1579         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
1580                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
1581             mNextAppTransitionScaleUp =
1582                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
1583             a = createAspectScaledThumbnailEnterExitAnimationLocked(
1584                     getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
1585                     insets, surfaceInsets, freeform, taskId);
1586             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1587                 String animName = mNextAppTransitionScaleUp ?
1588                         "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
1589                 Slog.v(TAG, "applyAnimation:"
1590                         + " anim=" + a + " nextAppTransition=" + animName
1591                         + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
1592                         + " Callers=" + Debug.getCallers(3));
1593             }
1594         } else {
1595             int animAttr = 0;
1596             switch (transit) {
1597                 case TRANSIT_ACTIVITY_OPEN:
1598                     animAttr = enter
1599                             ? WindowAnimation_activityOpenEnterAnimation
1600                             : WindowAnimation_activityOpenExitAnimation;
1601                     break;
1602                 case TRANSIT_ACTIVITY_CLOSE:
1603                     animAttr = enter
1604                             ? WindowAnimation_activityCloseEnterAnimation
1605                             : WindowAnimation_activityCloseExitAnimation;
1606                     break;
1607                 case TRANSIT_DOCK_TASK_FROM_RECENTS:
1608                 case TRANSIT_TASK_OPEN:
1609                     animAttr = enter
1610                             ? WindowAnimation_taskOpenEnterAnimation
1611                             : WindowAnimation_taskOpenExitAnimation;
1612                     break;
1613                 case TRANSIT_TASK_CLOSE:
1614                     animAttr = enter
1615                             ? WindowAnimation_taskCloseEnterAnimation
1616                             : WindowAnimation_taskCloseExitAnimation;
1617                     break;
1618                 case TRANSIT_TASK_TO_FRONT:
1619                     animAttr = enter
1620                             ? WindowAnimation_taskToFrontEnterAnimation
1621                             : WindowAnimation_taskToFrontExitAnimation;
1622                     break;
1623                 case TRANSIT_TASK_TO_BACK:
1624                     animAttr = enter
1625                             ? WindowAnimation_taskToBackEnterAnimation
1626                             : WindowAnimation_taskToBackExitAnimation;
1627                     break;
1628                 case TRANSIT_WALLPAPER_OPEN:
1629                     animAttr = enter
1630                             ? WindowAnimation_wallpaperOpenEnterAnimation
1631                             : WindowAnimation_wallpaperOpenExitAnimation;
1632                     break;
1633                 case TRANSIT_WALLPAPER_CLOSE:
1634                     animAttr = enter
1635                             ? WindowAnimation_wallpaperCloseEnterAnimation
1636                             : WindowAnimation_wallpaperCloseExitAnimation;
1637                     break;
1638                 case TRANSIT_WALLPAPER_INTRA_OPEN:
1639                     animAttr = enter
1640                             ? WindowAnimation_wallpaperIntraOpenEnterAnimation
1641                             : WindowAnimation_wallpaperIntraOpenExitAnimation;
1642                     break;
1643                 case TRANSIT_WALLPAPER_INTRA_CLOSE:
1644                     animAttr = enter
1645                             ? WindowAnimation_wallpaperIntraCloseEnterAnimation
1646                             : WindowAnimation_wallpaperIntraCloseExitAnimation;
1647                     break;
1648                 case TRANSIT_TASK_OPEN_BEHIND:
1649                     animAttr = enter
1650                             ? WindowAnimation_launchTaskBehindSourceAnimation
1651                             : WindowAnimation_launchTaskBehindTargetAnimation;
1652             }
1653             a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
1654             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1655                     "applyAnimation:"
1656                     + " anim=" + a
1657                     + " animAttr=0x" + Integer.toHexString(animAttr)
1658                     + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
1659                     + " Callers=" + Debug.getCallers(3));
1660         }
1661         return a;
1662     }
1663 
loadKeyguardExitAnimation(int transit)1664     private Animation loadKeyguardExitAnimation(int transit) {
1665         if ((mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) != 0) {
1666             return null;
1667         }
1668         final boolean toShade =
1669                 (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0;
1670         return mService.mPolicy.createHiddenByKeyguardExit(
1671                 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade);
1672     }
1673 
getAppStackClipMode()1674     int getAppStackClipMode() {
1675         // When dismiss keyguard animation occurs, clip before the animation to prevent docked
1676         // app from showing beyond the divider
1677         if (mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY
1678                 || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
1679             return STACK_CLIP_BEFORE_ANIM;
1680         }
1681         return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
1682                 || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1683                 || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
1684                 ? STACK_CLIP_NONE
1685                 : STACK_CLIP_AFTER_ANIM;
1686     }
1687 
getTransitFlags()1688     public int getTransitFlags() {
1689         return mNextAppTransitionFlags;
1690     }
1691 
postAnimationCallback()1692     void postAnimationCallback() {
1693         if (mNextAppTransitionCallback != null) {
1694             mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
1695                     mNextAppTransitionCallback));
1696             mNextAppTransitionCallback = null;
1697         }
1698     }
1699 
overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, IRemoteCallback startedCallback)1700     void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
1701             IRemoteCallback startedCallback) {
1702         if (isTransitionSet()) {
1703             clear();
1704             mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
1705             mNextAppTransitionPackage = packageName;
1706             mNextAppTransitionEnter = enterAnim;
1707             mNextAppTransitionExit = exitAnim;
1708             postAnimationCallback();
1709             mNextAppTransitionCallback = startedCallback;
1710         } else {
1711             postAnimationCallback();
1712         }
1713     }
1714 
overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, int startHeight)1715     void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
1716             int startHeight) {
1717         if (isTransitionSet()) {
1718             clear();
1719             mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
1720             putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
1721             postAnimationCallback();
1722         }
1723     }
1724 
overridePendingAppTransitionClipReveal(int startX, int startY, int startWidth, int startHeight)1725     void overridePendingAppTransitionClipReveal(int startX, int startY,
1726                                                 int startWidth, int startHeight) {
1727         if (isTransitionSet()) {
1728             clear();
1729             mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
1730             putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
1731             postAnimationCallback();
1732         }
1733     }
1734 
overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX, int startY, IRemoteCallback startedCallback, boolean scaleUp)1735     void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX, int startY,
1736                                            IRemoteCallback startedCallback, boolean scaleUp) {
1737         if (isTransitionSet()) {
1738             clear();
1739             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
1740                     : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
1741             mNextAppTransitionScaleUp = scaleUp;
1742             putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb);
1743             postAnimationCallback();
1744             mNextAppTransitionCallback = startedCallback;
1745         } else {
1746             postAnimationCallback();
1747         }
1748     }
1749 
overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX, int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp)1750     void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX, int startY,
1751             int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) {
1752         if (isTransitionSet()) {
1753             clear();
1754             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1755                     : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
1756             mNextAppTransitionScaleUp = scaleUp;
1757             putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight,
1758                     srcThumb);
1759             postAnimationCallback();
1760             mNextAppTransitionCallback = startedCallback;
1761         } else {
1762             postAnimationCallback();
1763         }
1764     }
1765 
overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs, IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback, boolean scaleUp)1766     public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
1767             IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
1768             boolean scaleUp) {
1769         if (isTransitionSet()) {
1770             clear();
1771             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1772                     : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
1773             mNextAppTransitionScaleUp = scaleUp;
1774             if (specs != null) {
1775                 for (int i = 0; i < specs.length; i++) {
1776                     AppTransitionAnimationSpec spec = specs[i];
1777                     if (spec != null) {
1778                         mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec);
1779                         if (i == 0) {
1780                             // In full screen mode, the transition code depends on the default spec
1781                             // to be set.
1782                             Rect rect = spec.rect;
1783                             putDefaultNextAppTransitionCoordinates(rect.left, rect.top,
1784                                     rect.width(), rect.height(), spec.buffer);
1785                         }
1786                     }
1787                 }
1788             }
1789             postAnimationCallback();
1790             mNextAppTransitionCallback = onAnimationStartedCallback;
1791             mAnimationFinishedCallback = onAnimationFinishedCallback;
1792         } else {
1793             postAnimationCallback();
1794         }
1795     }
1796 
overridePendingAppTransitionMultiThumbFuture( IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback, boolean scaleUp)1797     void overridePendingAppTransitionMultiThumbFuture(
1798             IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
1799             boolean scaleUp) {
1800         if (isTransitionSet()) {
1801             clear();
1802             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1803                     : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
1804             mNextAppTransitionAnimationsSpecsFuture = specsFuture;
1805             mNextAppTransitionScaleUp = scaleUp;
1806             mNextAppTransitionFutureCallback = callback;
1807         }
1808     }
1809 
overrideInPlaceAppTransition(String packageName, int anim)1810     void overrideInPlaceAppTransition(String packageName, int anim) {
1811         if (isTransitionSet()) {
1812             clear();
1813             mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
1814             mNextAppTransitionPackage = packageName;
1815             mNextAppTransitionInPlace = anim;
1816         } else {
1817             postAnimationCallback();
1818         }
1819     }
1820 
1821     /**
1822      * If a future is set for the app transition specs, fetch it in another thread.
1823      */
fetchAppTransitionSpecsFromFuture()1824     private void fetchAppTransitionSpecsFromFuture() {
1825         if (mNextAppTransitionAnimationsSpecsFuture != null) {
1826             mNextAppTransitionAnimationsSpecsPending = true;
1827             final IAppTransitionAnimationSpecsFuture future
1828                     = mNextAppTransitionAnimationsSpecsFuture;
1829             mNextAppTransitionAnimationsSpecsFuture = null;
1830             mDefaultExecutor.execute(() -> {
1831                 AppTransitionAnimationSpec[] specs = null;
1832                 try {
1833                     Binder.allowBlocking(future.asBinder());
1834                     specs = future.get();
1835                 } catch (RemoteException e) {
1836                     Slog.w(TAG, "Failed to fetch app transition specs: " + e);
1837                 }
1838                 synchronized (mService.mWindowMap) {
1839                     mNextAppTransitionAnimationsSpecsPending = false;
1840                     overridePendingAppTransitionMultiThumb(specs,
1841                             mNextAppTransitionFutureCallback, null /* finishedCallback */,
1842                             mNextAppTransitionScaleUp);
1843                     mNextAppTransitionFutureCallback = null;
1844                     if (specs != null) {
1845                         mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
1846                     }
1847                 }
1848                 mService.requestTraversal();
1849             });
1850         }
1851     }
1852 
1853     @Override
toString()1854     public String toString() {
1855         return "mNextAppTransition=" + appTransitionToString(mNextAppTransition);
1856     }
1857 
1858     /**
1859      * Returns the human readable name of a window transition.
1860      *
1861      * @param transition The window transition.
1862      * @return The transition symbolic name.
1863      */
appTransitionToString(int transition)1864     public static String appTransitionToString(int transition) {
1865         switch (transition) {
1866             case TRANSIT_UNSET: {
1867                 return "TRANSIT_UNSET";
1868             }
1869             case TRANSIT_NONE: {
1870                 return "TRANSIT_NONE";
1871             }
1872             case TRANSIT_ACTIVITY_OPEN: {
1873                 return "TRANSIT_ACTIVITY_OPEN";
1874             }
1875             case TRANSIT_ACTIVITY_CLOSE: {
1876                 return "TRANSIT_ACTIVITY_CLOSE";
1877             }
1878             case TRANSIT_TASK_OPEN: {
1879                 return "TRANSIT_TASK_OPEN";
1880             }
1881             case TRANSIT_TASK_CLOSE: {
1882                 return "TRANSIT_TASK_CLOSE";
1883             }
1884             case TRANSIT_TASK_TO_FRONT: {
1885                 return "TRANSIT_TASK_TO_FRONT";
1886             }
1887             case TRANSIT_TASK_TO_BACK: {
1888                 return "TRANSIT_TASK_TO_BACK";
1889             }
1890             case TRANSIT_WALLPAPER_CLOSE: {
1891                 return "TRANSIT_WALLPAPER_CLOSE";
1892             }
1893             case TRANSIT_WALLPAPER_OPEN: {
1894                 return "TRANSIT_WALLPAPER_OPEN";
1895             }
1896             case TRANSIT_WALLPAPER_INTRA_OPEN: {
1897                 return "TRANSIT_WALLPAPER_INTRA_OPEN";
1898             }
1899             case TRANSIT_WALLPAPER_INTRA_CLOSE: {
1900                 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
1901             }
1902             case TRANSIT_TASK_OPEN_BEHIND: {
1903                 return "TRANSIT_TASK_OPEN_BEHIND";
1904             }
1905             case TRANSIT_ACTIVITY_RELAUNCH: {
1906                 return "TRANSIT_ACTIVITY_RELAUNCH";
1907             }
1908             case TRANSIT_DOCK_TASK_FROM_RECENTS: {
1909                 return "TRANSIT_DOCK_TASK_FROM_RECENTS";
1910             }
1911             case TRANSIT_KEYGUARD_GOING_AWAY: {
1912                 return "TRANSIT_KEYGUARD_GOING_AWAY";
1913             }
1914             case TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
1915                 return "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
1916             }
1917             case TRANSIT_KEYGUARD_OCCLUDE: {
1918                 return "TRANSIT_KEYGUARD_OCCLUDE";
1919             }
1920             case TRANSIT_KEYGUARD_UNOCCLUDE: {
1921                 return "TRANSIT_KEYGUARD_UNOCCLUDE";
1922             }
1923             default: {
1924                 return "<UNKNOWN>";
1925             }
1926         }
1927     }
1928 
appStateToString()1929     private String appStateToString() {
1930         switch (mAppTransitionState) {
1931             case APP_STATE_IDLE:
1932                 return "APP_STATE_IDLE";
1933             case APP_STATE_READY:
1934                 return "APP_STATE_READY";
1935             case APP_STATE_RUNNING:
1936                 return "APP_STATE_RUNNING";
1937             case APP_STATE_TIMEOUT:
1938                 return "APP_STATE_TIMEOUT";
1939             default:
1940                 return "unknown state=" + mAppTransitionState;
1941         }
1942     }
1943 
transitTypeToString()1944     private String transitTypeToString() {
1945         switch (mNextAppTransitionType) {
1946             case NEXT_TRANSIT_TYPE_NONE:
1947                 return "NEXT_TRANSIT_TYPE_NONE";
1948             case NEXT_TRANSIT_TYPE_CUSTOM:
1949                 return "NEXT_TRANSIT_TYPE_CUSTOM";
1950             case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
1951                 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
1952             case NEXT_TRANSIT_TYPE_SCALE_UP:
1953                 return "NEXT_TRANSIT_TYPE_SCALE_UP";
1954             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
1955                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
1956             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
1957                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
1958             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
1959                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
1960             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
1961                 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
1962             default:
1963                 return "unknown type=" + mNextAppTransitionType;
1964         }
1965     }
1966 
1967     @Override
dump(PrintWriter pw, String prefix)1968     public void dump(PrintWriter pw, String prefix) {
1969         pw.print(prefix); pw.println(this);
1970         pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
1971         if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
1972             pw.print(prefix); pw.print("mNextAppTransitionType=");
1973                     pw.println(transitTypeToString());
1974         }
1975         switch (mNextAppTransitionType) {
1976             case NEXT_TRANSIT_TYPE_CUSTOM:
1977                 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
1978                         pw.println(mNextAppTransitionPackage);
1979                 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
1980                         pw.print(Integer.toHexString(mNextAppTransitionEnter));
1981                         pw.print(" mNextAppTransitionExit=0x");
1982                         pw.println(Integer.toHexString(mNextAppTransitionExit));
1983                 break;
1984             case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
1985                 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
1986                         pw.println(mNextAppTransitionPackage);
1987                 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
1988                         pw.print(Integer.toHexString(mNextAppTransitionInPlace));
1989                 break;
1990             case NEXT_TRANSIT_TYPE_SCALE_UP: {
1991                 getDefaultNextAppTransitionStartRect(mTmpRect);
1992                 pw.print(prefix); pw.print("mNextAppTransitionStartX=");
1993                         pw.print(mTmpRect.left);
1994                         pw.print(" mNextAppTransitionStartY=");
1995                         pw.println(mTmpRect.top);
1996                 pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
1997                         pw.print(mTmpRect.width());
1998                         pw.print(" mNextAppTransitionStartHeight=");
1999                         pw.println(mTmpRect.height());
2000                 break;
2001             }
2002             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
2003             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
2004             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
2005             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
2006                 pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
2007                         pw.println(mDefaultNextAppTransitionAnimationSpec);
2008                 pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
2009                         pw.println(mNextAppTransitionAnimationsSpecs);
2010                 pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
2011                         pw.println(mNextAppTransitionScaleUp);
2012                 break;
2013             }
2014         }
2015         if (mNextAppTransitionCallback != null) {
2016             pw.print(prefix); pw.print("mNextAppTransitionCallback=");
2017                     pw.println(mNextAppTransitionCallback);
2018         }
2019         if (mLastUsedAppTransition != TRANSIT_NONE) {
2020             pw.print(prefix); pw.print("mLastUsedAppTransition=");
2021                     pw.println(appTransitionToString(mLastUsedAppTransition));
2022             pw.print(prefix); pw.print("mLastOpeningApp=");
2023                     pw.println(mLastOpeningApp);
2024             pw.print(prefix); pw.print("mLastClosingApp=");
2025                     pw.println(mLastClosingApp);
2026         }
2027     }
2028 
setCurrentUser(int newUserId)2029     public void setCurrentUser(int newUserId) {
2030         mCurrentUserId = newUserId;
2031     }
2032 
2033     /**
2034      * @return true if transition is not running and should not be skipped, false if transition is
2035      *         already running
2036      */
prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent, int flags, boolean forceOverride)2037     boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent, int flags,
2038             boolean forceOverride) {
2039         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
2040                 + " transit=" + appTransitionToString(transit)
2041                 + " " + this
2042                 + " alwaysKeepCurrent=" + alwaysKeepCurrent
2043                 + " Callers=" + Debug.getCallers(3));
2044         if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
2045                 || mNextAppTransition == TRANSIT_NONE) {
2046             setAppTransition(transit, flags);
2047         }
2048         // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
2049         // relies on the fact that we always execute a Keyguard transition after preparing one.
2050         else if (!alwaysKeepCurrent && !isKeyguardTransit(transit)) {
2051             if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
2052                 // Opening a new task always supersedes a close for the anim.
2053                 setAppTransition(transit, flags);
2054             } else if (transit == TRANSIT_ACTIVITY_OPEN
2055                     && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
2056                 // Opening a new activity always supersedes a close for the anim.
2057                 setAppTransition(transit, flags);
2058             }
2059         }
2060         boolean prepared = prepare();
2061         if (isTransitionSet()) {
2062             mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2063             mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
2064         }
2065         return prepared;
2066     }
2067 
2068     /**
2069      * @return true if {@param transit} is representing a transition in which Keyguard is going
2070      *         away, false otherwise
2071      */
isKeyguardGoingAwayTransit(int transit)2072     public static boolean isKeyguardGoingAwayTransit(int transit) {
2073         return transit == TRANSIT_KEYGUARD_GOING_AWAY
2074                 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
2075     }
2076 
isKeyguardTransit(int transit)2077     private static boolean isKeyguardTransit(int transit) {
2078         return isKeyguardGoingAwayTransit(transit) || transit == TRANSIT_KEYGUARD_OCCLUDE
2079                 || transit == TRANSIT_KEYGUARD_UNOCCLUDE;
2080     }
2081 
2082     /**
2083      * @return whether the transition should show the thumbnail being scaled down.
2084      */
shouldScaleDownThumbnailTransition(int uiMode, int orientation)2085     private boolean shouldScaleDownThumbnailTransition(int uiMode, int orientation) {
2086         return mGridLayoutRecentsEnabled
2087                 || orientation == Configuration.ORIENTATION_PORTRAIT;
2088     }
2089 }
2090