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