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