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