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