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