blob: 3a33a3d24433587f211e861eba2382f3371cc475 [file] [log] [blame]
Craig Mautner164d4bb2012-11-26 13:51:23 -08001/*
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
17package com.android.server.wm;
18
Jorim Jaggif84e2f62018-01-16 14:17:59 +010019import static android.view.WindowManager.LayoutParams;
20import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
21import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
22import static android.view.WindowManager.TRANSIT_ACTIVITY_RELAUNCH;
Adrian Roos93577212018-04-10 14:12:10 -070023import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010024import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
25import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
Issei Suzuki5609ccb2019-06-13 15:04:08 +020026import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010027import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
28import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
29import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
30import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
31import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
32import static android.view.WindowManager.TRANSIT_NONE;
Issei Suzukicac2a502019-04-16 16:52:50 +020033import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
Evan Roskycf76bed2019-01-15 10:33:58 -080034import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010035import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
36import static android.view.WindowManager.TRANSIT_TASK_OPEN;
37import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
38import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
39import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
Jorim Jaggi98a9d202018-03-26 16:17:07 +020040import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
41import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010042import static android.view.WindowManager.TRANSIT_UNSET;
43import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
44import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
45import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
46import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
Tony Mak83546a82018-01-22 13:56:20 +000047
Filip Gruszczynski82861362015-10-16 14:21:09 -070048import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
49import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
50import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
51import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
52import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
53import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
54import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
55import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
56import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
57import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
58import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
59import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
60import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
61import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
62import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
63import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
64import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
65import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
66import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
67import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
68import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
69import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
Aurimas Liutikasd8ebfef2019-01-16 12:46:42 -080070import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
71import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
Adrian Roosb125e0b2019-10-02 14:55:14 +020072import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
73import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
Filip Gruszczynski198dcbf2016-01-18 10:02:00 -080074import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080075import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
76import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Adrian Roose99bc052017-11-20 17:55:31 +010077import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
Tony Mak089c35e2017-12-18 20:34:14 +000078import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
Matthew Ngbf1d9852017-03-14 12:23:09 -070079import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +010080import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
Filip Gruszczynski82861362015-10-16 14:21:09 -070081
Tony Mak64b8d562017-12-28 17:44:02 +000082import android.annotation.DrawableRes;
lumark23b54592018-10-02 17:17:23 +080083import android.annotation.NonNull;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -070084import android.annotation.Nullable;
Matthew Ng43db6d22017-06-27 15:29:39 -070085import android.app.ActivityManager;
Tony Mak089c35e2017-12-18 20:34:14 +000086import android.content.ComponentName;
Craig Mautner164d4bb2012-11-26 13:51:23 -080087import android.content.Context;
Winson21700932016-03-24 17:26:23 -070088import android.content.res.Configuration;
Todd Kennedy64c57a82018-04-19 15:17:24 -070089import android.content.res.ResourceId;
Aurimas Liutikasd8ebfef2019-01-16 12:46:42 -080090import android.content.res.Resources;
Jorim Jaggib142f572019-03-01 16:08:54 +010091import android.content.res.Resources.NotFoundException;
lumarkce596d32019-06-12 16:58:35 +080092import android.content.res.TypedArray;
John Reck519ad482018-02-12 17:08:48 -080093import android.graphics.Bitmap;
94import android.graphics.Canvas;
Tony Mak64b8d562017-12-28 17:44:02 +000095import android.graphics.Color;
Winson Chungaa7fa012017-05-24 15:50:06 -070096import android.graphics.GraphicBuffer;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +010097import android.graphics.Path;
John Reck519ad482018-02-12 17:08:48 -080098import android.graphics.Picture;
Winson Chung399f6202014-03-19 10:47:20 -070099import android.graphics.Rect;
Tony Mak64b8d562017-12-28 17:44:02 +0000100import android.graphics.drawable.Drawable;
Jorim Jaggied410b62017-05-05 15:16:14 +0200101import android.os.Binder;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800102import android.os.Debug;
lumark23b54592018-10-02 17:17:23 +0800103import android.os.Handler;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100104import android.os.IBinder;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800105import android.os.IRemoteCallback;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100106import android.os.RemoteException;
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200107import android.os.SystemClock;
Manu Cornetd7376802017-01-13 13:44:07 -0800108import android.os.SystemProperties;
Tony Mak089c35e2017-12-18 20:34:14 +0000109import android.os.UserHandle;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800110import android.util.ArraySet;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800111import android.util.Slog;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700112import android.util.SparseArray;
Steven Timotiusaf03df62017-07-18 16:56:43 -0700113import android.util.proto.ProtoOutputStream;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700114import android.view.AppTransitionAnimationSpec;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100115import android.view.IAppTransitionAnimationSpecsFuture;
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100116import android.view.RemoteAnimationAdapter;
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100117import android.view.WindowManager.TransitionFlags;
118import android.view.WindowManager.TransitionType;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800119import android.view.animation.AlphaAnimation;
120import android.view.animation.Animation;
121import android.view.animation.AnimationSet;
122import android.view.animation.AnimationUtils;
Winson Chung399f6202014-03-19 10:47:20 -0700123import android.view.animation.ClipRectAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800124import android.view.animation.Interpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700125import android.view.animation.PathInterpolator;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800126import android.view.animation.ScaleAnimation;
Winson Chung399f6202014-03-19 10:47:20 -0700127import android.view.animation.TranslateAnimation;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700128
Jorim Jaggi98a9d202018-03-26 16:17:07 +0200129import com.android.internal.R;
Jorim Jaggib142f572019-03-01 16:08:54 +0100130import com.android.internal.annotations.VisibleForTesting;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800131import com.android.internal.util.DumpUtils.Dump;
lumark23b54592018-10-02 17:17:23 +0800132import com.android.internal.util.function.pooled.PooledLambda;
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900133import com.android.internal.util.function.pooled.PooledPredicate;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800134import com.android.server.AttributeCache;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200135import com.android.server.protolog.common.ProtoLog;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800136import com.android.server.wm.animation.ClipRectLRAnimation;
137import com.android.server.wm.animation.ClipRectTBAnimation;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100138import com.android.server.wm.animation.CurvedTranslateAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800139
140import java.io.PrintWriter;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100141import java.util.ArrayList;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100142import java.util.concurrent.ExecutorService;
143import java.util.concurrent.Executors;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800144
Craig Mautner164d4bb2012-11-26 13:51:23 -0800145// State management of app transitions. When we are preparing for a
146// transition, mNextAppTransition will be the kind of transition to
147// perform or TRANSIT_NONE if we are not waiting. If we are waiting,
148// mOpeningApps and mClosingApps are the lists of tokens that will be
149// made visible or hidden at the next transition.
150public class AppTransition implements Dump {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800151 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700152 private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800153
Winson Chunga4ccb862014-08-22 15:26:27 -0700154 /** Fraction of animation at which the recents thumbnail stays completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700155 private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800156 /** Fraction of animation at which the recents thumbnail becomes completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700157 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800158
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800159 static final int DEFAULT_APP_TRANSITION_DURATION = 336;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800160
161 /** Interpolator to be used for animations that respond directly to a touch */
162 static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
163 new PathInterpolator(0.3f, 0f, 0.1f, 1f);
164
Jorim Jaggic69bd222016-03-15 14:38:37 +0100165 private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR =
166 new PathInterpolator(0.85f, 0f, 1f, 1f);
167
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800168 /**
169 * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
170 * involved, to make it more understandable.
171 */
172 private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700173 private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700174 private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800175
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800176 private final Context mContext;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800177 private final WindowManagerService mService;
lumark588a3e82018-07-20 18:53:54 +0800178 private final DisplayContent mDisplayContent;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800179
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100180 private @TransitionType int mNextAppTransition = TRANSIT_UNSET;
181 private @TransitionFlags int mNextAppTransitionFlags = 0;
Chong Zhang60091a92016-07-27 17:52:45 -0700182 private int mLastUsedAppTransition = TRANSIT_UNSET;
183 private String mLastOpeningApp;
184 private String mLastClosingApp;
Evan Rosky2289ba12018-11-19 18:28:18 -0800185 private String mLastChangingApp;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800186
187 private static final int NEXT_TRANSIT_TYPE_NONE = 0;
188 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
189 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
190 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
191 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
Winson Chunga4ccb862014-08-22 15:26:27 -0700192 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
193 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
Winson Chung044d5292014-11-06 11:05:19 -0800194 private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
Chet Haase10e23ab2015-02-11 15:08:38 -0800195 private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
Tony Mak089c35e2017-12-18 20:34:14 +0000196
197 /**
198 * Refers to the transition to activity started by using {@link
199 * android.content.pm.crossprofile.CrossProfileApps#startMainActivity(ComponentName, UserHandle)
200 * }.
201 */
202 private static final int NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS = 9;
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100203 private static final int NEXT_TRANSIT_TYPE_REMOTE = 10;
204
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800205 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
206
Winson Chung399f6202014-03-19 10:47:20 -0700207 // These are the possible states for the enter/exit activities during a thumbnail transition
208 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
209 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
210 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
211 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
212
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800213 private String mNextAppTransitionPackage;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800214 // Used for thumbnail transitions. True if we're scaling up, false if scaling down
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800215 private boolean mNextAppTransitionScaleUp;
216 private IRemoteCallback mNextAppTransitionCallback;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +0100217 private IRemoteCallback mNextAppTransitionFutureCallback;
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -0700218 private IRemoteCallback mAnimationFinishedCallback;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800219 private int mNextAppTransitionEnter;
220 private int mNextAppTransitionExit;
Winson Chung044d5292014-11-06 11:05:19 -0800221 private int mNextAppTransitionInPlace;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700222
lumark19a5d2e2019-10-11 16:19:30 +0800223 // Keyed by WindowContainer hashCode.
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700224 private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
225 = new SparseArray<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100226 private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
227 private boolean mNextAppTransitionAnimationsSpecsPending;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700228 private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
229
Winson Chunga4ccb862014-08-22 15:26:27 -0700230 private Rect mNextAppTransitionInsets = new Rect();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800231
Winson Chung2820c452014-04-15 15:34:44 -0700232 private Rect mTmpFromClipRect = new Rect();
233 private Rect mTmpToClipRect = new Rect();
234
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700235 private final Rect mTmpRect = new Rect();
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700236
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800237 private final static int APP_STATE_IDLE = 0;
238 private final static int APP_STATE_READY = 1;
239 private final static int APP_STATE_RUNNING = 2;
240 private final static int APP_STATE_TIMEOUT = 3;
241 private int mAppTransitionState = APP_STATE_IDLE;
242
243 private final int mConfigShortAnimTime;
Craig Mautner321bdf52012-12-18 09:53:24 -0800244 private final Interpolator mDecelerateInterpolator;
Winson Chunga4ccb862014-08-22 15:26:27 -0700245 private final Interpolator mThumbnailFadeInInterpolator;
246 private final Interpolator mThumbnailFadeOutInterpolator;
Chet Haase10e23ab2015-02-11 15:08:38 -0800247 private final Interpolator mLinearOutSlowInInterpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700248 private final Interpolator mFastOutLinearInInterpolator;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100249 private final Interpolator mFastOutSlowInInterpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700250 private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
251
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700252 private final int mClipRevealTranslationY;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800253
Amith Yamasani4befbec2013-07-10 16:18:01 -0700254 private int mCurrentUserId = 0;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800255 private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
Amith Yamasani4befbec2013-07-10 16:18:01 -0700256
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100257 private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100258 private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100259
Jorim Jaggif97ed922016-02-18 18:57:07 -0800260 private int mLastClipRevealMaxTranslation;
261 private boolean mLastHadClipReveal;
262
Manu Cornetd7376802017-01-13 13:44:07 -0800263 private final boolean mGridLayoutRecentsEnabled;
Matthew Ng43db6d22017-06-27 15:29:39 -0700264 private final boolean mLowRamRecentsEnabled;
Manu Cornetd7376802017-01-13 13:44:07 -0800265
lumarkce596d32019-06-12 16:58:35 +0800266 private final int mDefaultWindowAnimationStyleResId;
267
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100268 private RemoteAnimationController mRemoteAnimationController;
269
lumark23b54592018-10-02 17:17:23 +0800270 final Handler mHandler;
271 final Runnable mHandleAppTransitionTimeoutRunnable = () -> handleAppTransitionTimeout();
272
lumark588a3e82018-07-20 18:53:54 +0800273 AppTransition(Context context, WindowManagerService service, DisplayContent displayContent) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800274 mContext = context;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800275 mService = service;
lumark23b54592018-10-02 17:17:23 +0800276 mHandler = new Handler(service.mH.getLooper());
lumark588a3e82018-07-20 18:53:54 +0800277 mDisplayContent = displayContent;
Chet Haase10e23ab2015-02-11 15:08:38 -0800278 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
279 com.android.internal.R.interpolator.linear_out_slow_in);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700280 mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
281 com.android.internal.R.interpolator.fast_out_linear_in);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100282 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
283 com.android.internal.R.interpolator.fast_out_slow_in);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800284 mConfigShortAnimTime = context.getResources().getInteger(
285 com.android.internal.R.integer.config_shortAnimTime);
Craig Mautner321bdf52012-12-18 09:53:24 -0800286 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
287 com.android.internal.R.interpolator.decelerate_cubic);
Winson Chunga4ccb862014-08-22 15:26:27 -0700288 mThumbnailFadeInInterpolator = new Interpolator() {
289 @Override
290 public float getInterpolation(float input) {
291 // Linear response for first fraction, then complete after that.
292 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
293 return 0f;
294 }
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700295 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /
Winson Chunga4ccb862014-08-22 15:26:27 -0700296 (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700297 return mFastOutLinearInInterpolator.getInterpolation(t);
Winson Chunga4ccb862014-08-22 15:26:27 -0700298 }
299 };
300 mThumbnailFadeOutInterpolator = new Interpolator() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800301 @Override
302 public float getInterpolation(float input) {
303 // Linear response for first fraction, then complete after that.
304 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700305 float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
306 return mLinearOutSlowInInterpolator.getInterpolation(t);
Craig Mautner321bdf52012-12-18 09:53:24 -0800307 }
Winson Chunga4ccb862014-08-22 15:26:27 -0700308 return 1f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800309 }
310 };
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700311 mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP
312 * mContext.getResources().getDisplayMetrics().density);
Manu Cornetd7376802017-01-13 13:44:07 -0800313 mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
Matthew Ng43db6d22017-06-27 15:29:39 -0700314 mLowRamRecentsEnabled = ActivityManager.isLowRamDeviceStatic();
lumarkce596d32019-06-12 16:58:35 +0800315
316 final TypedArray windowStyle = mContext.getTheme().obtainStyledAttributes(
317 com.android.internal.R.styleable.Window);
318 mDefaultWindowAnimationStyleResId = windowStyle.getResourceId(
319 com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
320 windowStyle.recycle();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800321 }
322
323 boolean isTransitionSet() {
324 return mNextAppTransition != TRANSIT_UNSET;
325 }
326
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100327 boolean isTransitionEqual(@TransitionType int transit) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800328 return mNextAppTransition == transit;
329 }
330
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100331 @TransitionType int getAppTransition() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800332 return mNextAppTransition;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800333 }
334
Jorim Jaggife762342016-10-13 14:33:27 +0200335 private void setAppTransition(int transit, int flags) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800336 mNextAppTransition = transit;
Jorim Jaggife762342016-10-13 14:33:27 +0200337 mNextAppTransitionFlags |= flags;
Evan Rosky2289ba12018-11-19 18:28:18 -0800338 setLastAppTransition(TRANSIT_UNSET, null, null, null);
Jorim Jaggi245281c2017-06-07 14:33:04 -0700339 updateBooster();
Chong Zhang60091a92016-07-27 17:52:45 -0700340 }
341
Garfield Tane8d84ab2019-10-11 09:49:40 -0700342 void setLastAppTransition(int transit, ActivityRecord openingApp, ActivityRecord closingApp,
343 ActivityRecord changingApp) {
Chong Zhang60091a92016-07-27 17:52:45 -0700344 mLastUsedAppTransition = transit;
345 mLastOpeningApp = "" + openingApp;
346 mLastClosingApp = "" + closingApp;
Evan Rosky2289ba12018-11-19 18:28:18 -0800347 mLastChangingApp = "" + changingApp;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800348 }
349
350 boolean isReady() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800351 return mAppTransitionState == APP_STATE_READY
352 || mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800353 }
354
Craig Mautnerae446592012-12-06 19:05:05 -0800355 void setReady() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700356 setAppTransitionState(APP_STATE_READY);
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100357 fetchAppTransitionSpecsFromFuture();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800358 }
359
360 boolean isRunning() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800361 return mAppTransitionState == APP_STATE_RUNNING;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800362 }
363
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800364 void setIdle() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700365 setAppTransitionState(APP_STATE_IDLE);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800366 }
367
368 boolean isTimeout() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800369 return mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800370 }
371
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800372 void setTimeout() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700373 setAppTransitionState(APP_STATE_TIMEOUT);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800374 }
375
lumark19a5d2e2019-10-11 16:19:30 +0800376 GraphicBuffer getAppTransitionThumbnailHeader(WindowContainer container) {
377 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
378 container.hashCode());
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800379 if (spec == null) {
380 spec = mDefaultNextAppTransitionAnimationSpec;
381 }
Winson Chungaa7fa012017-05-24 15:50:06 -0700382 return spec != null ? spec.buffer : null;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800383 }
384
Winson Chunga4ccb862014-08-22 15:26:27 -0700385 /** Returns whether the next thumbnail transition is aspect scaled up. */
386 boolean isNextThumbnailTransitionAspectScaled() {
387 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
388 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
389 }
390
391 /** Returns whether the next thumbnail transition is scaling up. */
392 boolean isNextThumbnailTransitionScaleUp() {
393 return mNextAppTransitionScaleUp;
394 }
395
Filip Gruszczynski4cbc3152015-12-07 11:50:57 -0800396 boolean isNextAppTransitionThumbnailUp() {
397 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
398 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP;
399 }
400
401 boolean isNextAppTransitionThumbnailDown() {
402 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN ||
403 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
404 }
405
Tony Mak64b8d562017-12-28 17:44:02 +0000406
407 boolean isNextAppTransitionOpenCrossProfileApps() {
408 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
409 }
410
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100411 /**
412 * @return true if and only if we are currently fetching app transition specs from the future
413 * passed into {@link #overridePendingAppTransitionMultiThumbFuture}
414 */
415 boolean isFetchingAppTransitionsSpecs() {
416 return mNextAppTransitionAnimationsSpecsPending;
417 }
418
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700419 private boolean prepare() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800420 if (!isRunning()) {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700421 setAppTransitionState(APP_STATE_IDLE);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100422 notifyAppTransitionPendingLocked();
Jorim Jaggif97ed922016-02-18 18:57:07 -0800423 mLastHadClipReveal = false;
424 mLastClipRevealMaxTranslation = 0;
425 mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700426 return true;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800427 }
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700428 return false;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800429 }
430
Jorim Jaggife762342016-10-13 14:33:27 +0200431 /**
432 * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
433 * layout pass needs to be done
434 */
Garfield Tane8d84ab2019-10-11 09:49:40 -0700435 int goodToGo(int transit, ActivityRecord topOpeningApp, ArraySet<ActivityRecord> openingApps) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800436 mNextAppTransition = TRANSIT_UNSET;
Jorim Jaggife762342016-10-13 14:33:27 +0200437 mNextAppTransitionFlags = 0;
Jorim Jaggi245281c2017-06-07 14:33:04 -0700438 setAppTransitionState(APP_STATE_RUNNING);
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200439 final AnimationAdapter topOpeningAnim = topOpeningApp != null
440 ? topOpeningApp.getAnimation()
441 : null;
Jorim Jaggife762342016-10-13 14:33:27 +0200442 int redoLayout = notifyAppTransitionStartingLocked(transit,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200443 topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0,
444 topOpeningAnim != null
445 ? topOpeningAnim.getStatusBarTransitionsStartTime()
446 : SystemClock.uptimeMillis(),
447 AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
lumark588a3e82018-07-20 18:53:54 +0800448 mDisplayContent.getDockedDividerController()
Jorim Jaggife762342016-10-13 14:33:27 +0200449 .notifyAppTransitionStarting(openingApps, transit);
Jorim Jaggi363ab982016-04-26 19:51:20 -0700450
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100451 if (mRemoteAnimationController != null) {
452 mRemoteAnimationController.goodToGo();
453 }
Jorim Jaggife762342016-10-13 14:33:27 +0200454 return redoLayout;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700455 }
456
Craig Mautner164d4bb2012-11-26 13:51:23 -0800457 void clear() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800458 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800459 mNextAppTransitionPackage = null;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700460 mNextAppTransitionAnimationsSpecs.clear();
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100461 mRemoteAnimationController = null;
Jorim Jaggi65193992015-11-23 16:49:59 -0800462 mNextAppTransitionAnimationsSpecsFuture = null;
463 mDefaultNextAppTransitionAnimationSpec = null;
464 mAnimationFinishedCallback = null;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800465 }
466
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800467 void freeze() {
Jorim Jaggife762342016-10-13 14:33:27 +0200468 final int transit = mNextAppTransition;
Arthur Hung442aff22019-05-07 19:49:31 +0800469 // The RemoteAnimationControl didn't register AppTransitionListener and
470 // only initialized the finish and timeout callback when goodToGo().
471 // So cancel the remote animation here to prevent the animation can't do
472 // finish after transition state cleared.
473 if (mRemoteAnimationController != null) {
474 mRemoteAnimationController.cancelAnimation("freeze");
475 }
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100476 setAppTransition(TRANSIT_UNSET, 0 /* flags */);
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800477 clear();
478 setReady();
Jorim Jaggife762342016-10-13 14:33:27 +0200479 notifyAppTransitionCancelledLocked(transit);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100480 }
481
Jorim Jaggi245281c2017-06-07 14:33:04 -0700482 private void setAppTransitionState(int state) {
483 mAppTransitionState = state;
484 updateBooster();
485 }
486
487 /**
488 * Updates whether we currently boost wm locked sections and the animation thread. We want to
489 * boost the priorities to a more important value whenever an app transition is going to happen
490 * soon or an app transition is running.
491 */
Jorim Jaggic8cc2292018-03-15 20:16:15 +0100492 void updateBooster() {
493 WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning(needsBoosting());
494 }
495
496 private boolean needsBoosting() {
497 final boolean recentsAnimRunning = mService.getRecentsAnimationController() != null;
498 return mNextAppTransition != TRANSIT_UNSET
499 || mAppTransitionState == APP_STATE_READY
500 || mAppTransitionState == APP_STATE_RUNNING
501 || recentsAnimRunning;
Jorim Jaggi245281c2017-06-07 14:33:04 -0700502 }
503
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100504 void registerListenerLocked(AppTransitionListener listener) {
505 mListeners.add(listener);
506 }
507
lumark54284462019-03-05 20:44:27 +0800508 void unregisterListener(AppTransitionListener listener) {
509 mListeners.remove(listener);
510 }
511
Wale Ogunwalea48eadb2015-05-14 17:43:12 -0700512 public void notifyAppTransitionFinishedLocked(IBinder token) {
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100513 for (int i = 0; i < mListeners.size(); i++) {
514 mListeners.get(i).onAppTransitionFinishedLocked(token);
515 }
516 }
517
518 private void notifyAppTransitionPendingLocked() {
519 for (int i = 0; i < mListeners.size(); i++) {
520 mListeners.get(i).onAppTransitionPendingLocked();
521 }
522 }
523
Jorim Jaggife762342016-10-13 14:33:27 +0200524 private void notifyAppTransitionCancelledLocked(int transit) {
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100525 for (int i = 0; i < mListeners.size(); i++) {
Jorim Jaggife762342016-10-13 14:33:27 +0200526 mListeners.get(i).onAppTransitionCancelledLocked(transit);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100527 }
528 }
529
Evan Rosky2289ba12018-11-19 18:28:18 -0800530 private int notifyAppTransitionStartingLocked(int transit, long duration,
531 long statusBarAnimationStartTime, long statusBarAnimationDuration) {
Jorim Jaggife762342016-10-13 14:33:27 +0200532 int redoLayout = 0;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100533 for (int i = 0; i < mListeners.size(); i++) {
Evan Rosky2289ba12018-11-19 18:28:18 -0800534 redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, duration,
535 statusBarAnimationStartTime, statusBarAnimationDuration);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100536 }
Jorim Jaggife762342016-10-13 14:33:27 +0200537 return redoLayout;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800538 }
539
lumarkce596d32019-06-12 16:58:35 +0800540 @VisibleForTesting
541 int getDefaultWindowAnimationStyleResId() {
542 return mDefaultWindowAnimationStyleResId;
543 }
544
545 /** Returns window animation style ID from {@link LayoutParams} or from system in some cases */
546 @VisibleForTesting
547 int getAnimationStyleResId(@NonNull LayoutParams lp) {
548 int resId = lp.windowAnimations;
549 if (lp.type == LayoutParams.TYPE_APPLICATION_STARTING) {
550 // Note that we don't want application to customize starting window animation.
551 // Since this window is specific for displaying while app starting,
552 // application should not change its animation directly.
553 // In this case, it will use system resource to get default animation.
554 resId = mDefaultWindowAnimationStyleResId;
555 }
556 return resId;
557 }
558
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100559 private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800560 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
561 + (lp != null ? lp.packageName : null)
562 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
563 if (lp != null && lp.windowAnimations != 0) {
564 // If this is a system resource, don't try to load it from the
565 // application resources. It is nice to avoid loading application
566 // resources if we can.
567 String packageName = lp.packageName != null ? lp.packageName : "android";
lumarkce596d32019-06-12 16:58:35 +0800568 int resId = getAnimationStyleResId(lp);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800569 if ((resId&0xFF000000) == 0x01000000) {
570 packageName = "android";
571 }
572 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
573 + packageName);
574 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700575 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800576 }
577 return null;
578 }
579
580 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
581 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
582 + packageName + " resId=0x" + Integer.toHexString(resId));
583 if (packageName != null) {
584 if ((resId&0xFF000000) == 0x01000000) {
585 packageName = "android";
586 }
587 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
588 + packageName);
589 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700590 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800591 }
592 return null;
593 }
594
Jorim Jaggi0a1523d2018-04-19 17:48:38 +0200595 Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {
Aurimas Liutikasd8ebfef2019-01-16 12:46:42 -0800596 int resId = Resources.ID_NULL;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800597 Context context = mContext;
Jorim Jaggi5f95b002018-04-19 13:27:52 +0000598 if (animAttr >= 0) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800599 AttributeCache.Entry ent = getCachedAnimations(lp);
600 if (ent != null) {
601 context = ent.context;
Todd Kennedy64c57a82018-04-19 15:17:24 -0700602 resId = ent.array.getResourceId(animAttr, 0);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800603 }
604 }
Todd Kennedy64c57a82018-04-19 15:17:24 -0700605 resId = updateToTranslucentAnimIfNeeded(resId, transit);
606 if (ResourceId.isValid(resId)) {
Jorim Jaggib142f572019-03-01 16:08:54 +0100607 return loadAnimationSafely(context, resId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800608 }
609 return null;
610 }
611
Jorim Jaggib142f572019-03-01 16:08:54 +0100612 private Animation loadAnimationRes(LayoutParams lp, int resId) {
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700613 Context context = mContext;
Todd Kennedy64c57a82018-04-19 15:17:24 -0700614 if (ResourceId.isValid(resId)) {
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700615 AttributeCache.Entry ent = getCachedAnimations(lp);
616 if (ent != null) {
617 context = ent.context;
618 }
Jorim Jaggib142f572019-03-01 16:08:54 +0100619 return loadAnimationSafely(context, resId);
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700620 }
621 return null;
622 }
623
624 private Animation loadAnimationRes(String packageName, int resId) {
Todd Kennedy64c57a82018-04-19 15:17:24 -0700625 if (ResourceId.isValid(resId)) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800626 AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
627 if (ent != null) {
Jorim Jaggib142f572019-03-01 16:08:54 +0100628 return loadAnimationSafely(ent.context, resId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800629 }
630 }
Craig Mautner164d4bb2012-11-26 13:51:23 -0800631 return null;
632 }
633
Jorim Jaggib142f572019-03-01 16:08:54 +0100634 @VisibleForTesting
635 Animation loadAnimationSafely(Context context, int resId) {
636 try {
637 return AnimationUtils.loadAnimation(context, resId);
638 } catch (NotFoundException e) {
639 Slog.w(TAG, "Unable to load animation resource", e);
640 return null;
641 }
642 }
643
Jorim Jaggi0a1523d2018-04-19 17:48:38 +0200644 private int updateToTranslucentAnimIfNeeded(int anim, int transit) {
645 if (transit == TRANSIT_TRANSLUCENT_ACTIVITY_OPEN && anim == R.anim.activity_open_enter) {
646 return R.anim.activity_translucent_open_enter;
647 }
648 if (transit == TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE && anim == R.anim.activity_close_exit) {
649 return R.anim.activity_translucent_close_exit;
650 }
651 return anim;
652 }
653
Craig Mautner164d4bb2012-11-26 13:51:23 -0800654 /**
655 * Compute the pivot point for an animation that is scaling from a small
656 * rect on screen to a larger rect. The pivot point varies depending on
657 * the distance between the inner and outer edges on both sides. This
658 * function computes the pivot point for one dimension.
659 * @param startPos Offset from left/top edge of outer rectangle to
660 * left/top edge of inner rectangle.
661 * @param finalScale The scaling factor between the size of the outer
662 * and inner rectangles.
663 */
664 private static float computePivot(int startPos, float finalScale) {
Jorim Jaggic6c89a82016-01-28 17:48:21 -0800665
666 /*
667 Theorem of intercepting lines:
668
669 + + +-----------------------------------------------+
670 | | | |
671 | | | |
672 | | | |
673 | | | |
674 x | y | | |
675 | | | |
676 | | | |
677 | | | |
678 | | | |
679 | + | +--------------------+ |
680 | | | | |
681 | | | | |
682 | | | | |
683 | | | | |
684 | | | | |
685 | | | | |
686 | | | | |
687 | | | | |
688 | | | | |
689 | | | | |
690 | | | | |
691 | | | | |
692 | | | | |
693 | | | | |
694 | | | | |
695 | | | | |
696 | | | | |
697 | | +--------------------+ |
698 | | |
699 | | |
700 | | |
701 | | |
702 | | |
703 | | |
704 | | |
705 | +-----------------------------------------------+
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 + ++
716 p ++
717
718 scale = (x - y) / x
719 <=> x = -y / (scale - 1)
720 */
Craig Mautner164d4bb2012-11-26 13:51:23 -0800721 final float denom = finalScale-1;
722 if (Math.abs(denom) < .0001f) {
723 return startPos;
724 }
725 return -startPos / denom;
726 }
727
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700728 private Animation createScaleUpAnimationLocked(int transit, boolean enter,
729 Rect containingFrame) {
730 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700731 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700732 final int appWidth = containingFrame.width();
733 final int appHeight = containingFrame.height();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800734 if (enter) {
735 // Entering app zooms out from the center of the initial rect.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700736 float scaleW = mTmpRect.width() / (float) appWidth;
737 float scaleH = mTmpRect.height() / (float) appHeight;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800738 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700739 computePivot(mTmpRect.left, scaleW),
Winson4c3fecd2016-07-13 12:29:48 -0700740 computePivot(mTmpRect.top, scaleH));
Craig Mautner321bdf52012-12-18 09:53:24 -0800741 scale.setInterpolator(mDecelerateInterpolator);
742
Craig Mautner164d4bb2012-11-26 13:51:23 -0800743 Animation alpha = new AlphaAnimation(0, 1);
Winson Chunga4ccb862014-08-22 15:26:27 -0700744 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
Craig Mautner321bdf52012-12-18 09:53:24 -0800745
746 AnimationSet set = new AnimationSet(false);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800747 set.addAnimation(scale);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800748 set.addAnimation(alpha);
749 set.setDetachWallpaper(true);
750 a = set;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800751 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
752 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800753 // If we are on top of the wallpaper, we need an animation that
754 // correctly handles the wallpaper staying static behind all of
755 // the animated elements. To do this, will just have the existing
756 // element fade out.
757 a = new AlphaAnimation(1, 0);
758 a.setDetachWallpaper(true);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800759 } else {
Craig Mautner321bdf52012-12-18 09:53:24 -0800760 // For normal animations, the exiting element just holds in place.
761 a = new AlphaAnimation(1, 1);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800762 }
Craig Mautner321bdf52012-12-18 09:53:24 -0800763
764 // Pick the desired duration. If this is an inter-activity transition,
765 // it is the standard duration for that. Otherwise we use the longer
766 // task transition duration.
767 final long duration;
768 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800769 case TRANSIT_ACTIVITY_OPEN:
770 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800771 duration = mConfigShortAnimTime;
772 break;
773 default:
774 duration = DEFAULT_APP_TRANSITION_DURATION;
775 break;
776 }
777 a.setDuration(duration);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800778 a.setFillAfter(true);
Craig Mautner321bdf52012-12-18 09:53:24 -0800779 a.setInterpolator(mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800780 a.initialize(appWidth, appHeight, appWidth, appHeight);
781 return a;
782 }
783
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700784 private void getDefaultNextAppTransitionStartRect(Rect rect) {
785 if (mDefaultNextAppTransitionAnimationSpec == null ||
786 mDefaultNextAppTransitionAnimationSpec.rect == null) {
Jorim Jaggi2550f3f2017-03-14 20:15:59 +0100787 Slog.e(TAG, "Starting rect for app requested, but none available", new Throwable());
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700788 rect.setEmpty();
789 } else {
790 rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
791 }
792 }
793
lumark19a5d2e2019-10-11 16:19:30 +0800794 void getNextAppTransitionStartRect(WindowContainer container, Rect rect) {
795 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
796 container.hashCode());
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800797 if (spec == null) {
798 spec = mDefaultNextAppTransitionAnimationSpec;
799 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700800 if (spec == null || spec.rect == null) {
lumark19a5d2e2019-10-11 16:19:30 +0800801 Slog.e(TAG, "Starting rect for container: " + container
802 + " requested, but not available", new Throwable());
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700803 rect.setEmpty();
804 } else {
805 rect.set(spec.rect);
806 }
807 }
808
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800809 private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height,
Winson Chungaa7fa012017-05-24 15:50:06 -0700810 GraphicBuffer buffer) {
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700811 mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
Winson Chungaa7fa012017-05-24 15:50:06 -0700812 buffer, new Rect(left, top, left + width, top + height));
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700813 }
814
Jorim Jaggif97ed922016-02-18 18:57:07 -0800815 /**
816 * @return the duration of the last clip reveal animation
817 */
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800818 long getLastClipRevealTransitionDuration() {
819 return mLastClipRevealTransitionDuration;
820 }
821
822 /**
Jorim Jaggif97ed922016-02-18 18:57:07 -0800823 * @return the maximum distance the app surface is traveling of the last clip reveal animation
824 */
825 int getLastClipRevealMaxTranslation() {
826 return mLastClipRevealMaxTranslation;
827 }
828
829 /**
830 * @return true if in the last app transition had a clip reveal animation, false otherwise
831 */
832 boolean hadClipRevealAnimation() {
833 return mLastHadClipReveal;
834 }
835
836 /**
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800837 * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
838 * the start rect is outside of the target rect, and there is a lot of movement going on.
839 *
840 * @param cutOff whether the start rect was not fully contained by the end rect
841 * @param translationX the total translation the surface moves in x direction
842 * @param translationY the total translation the surfaces moves in y direction
843 * @param displayFrame our display frame
844 *
845 * @return the duration of the clip reveal animation, in milliseconds
846 */
847 private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX,
848 float translationY, Rect displayFrame) {
849 if (!cutOff) {
850 return DEFAULT_APP_TRANSITION_DURATION;
851 }
852 final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(),
853 Math.abs(translationY) / displayFrame.height());
854 return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction *
855 (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION));
856 }
857
858 private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame,
859 Rect displayFrame) {
Chet Haase10e23ab2015-02-11 15:08:38 -0800860 final Animation anim;
861 if (enter) {
Craig Mautner80b1f642015-04-22 10:59:09 -0700862 final int appWidth = appFrame.width();
863 final int appHeight = appFrame.height();
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800864
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700865 // mTmpRect will contain an area around the launcher icon that was pressed. We will
Filip Gruszczynski82861362015-10-16 14:21:09 -0700866 // clip reveal from that area in the final area of the app.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700867 getDefaultNextAppTransitionStartRect(mTmpRect);
Craig Mautner80b1f642015-04-22 10:59:09 -0700868
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700869 float t = 0f;
870 if (appHeight > 0) {
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800871 t = (float) mTmpRect.top / displayFrame.height();
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700872 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800873 int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t);
874 int translationX = 0;
875 int translationYCorrection = translationY;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700876 int centerX = mTmpRect.centerX();
877 int centerY = mTmpRect.centerY();
878 int halfWidth = mTmpRect.width() / 2;
879 int halfHeight = mTmpRect.height() / 2;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800880 int clipStartX = centerX - halfWidth - appFrame.left;
881 int clipStartY = centerY - halfHeight - appFrame.top;
882 boolean cutOff = false;
883
884 // If the starting rectangle is fully or partially outside of the target rectangle, we
885 // need to start the clipping at the edge and then achieve the rest with translation
886 // and extending the clip rect from that edge.
887 if (appFrame.top > centerY - halfHeight) {
888 translationY = (centerY - halfHeight) - appFrame.top;
889 translationYCorrection = 0;
890 clipStartY = 0;
891 cutOff = true;
892 }
893 if (appFrame.left > centerX - halfWidth) {
894 translationX = (centerX - halfWidth) - appFrame.left;
895 clipStartX = 0;
896 cutOff = true;
897 }
898 if (appFrame.right < centerX + halfWidth) {
899 translationX = (centerX + halfWidth) - appFrame.right;
900 clipStartX = appWidth - mTmpRect.width();
901 cutOff = true;
902 }
903 final long duration = calculateClipRevealTransitionDuration(cutOff, translationX,
904 translationY, displayFrame);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700905
906 // Clip third of the from size of launch icon, expand to full width/height
Chet Haase10e23ab2015-02-11 15:08:38 -0800907 Animation clipAnimLR = new ClipRectLRAnimation(
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800908 clipStartX, clipStartX + mTmpRect.width(), 0, appWidth);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700909 clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800910 clipAnimLR.setDuration((long) (duration / 2.5f));
Filip Gruszczynski82861362015-10-16 14:21:09 -0700911
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800912 TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0);
913 translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR
914 : mLinearOutSlowInInterpolator);
915 translate.setDuration(duration);
Chet Haase10e23ab2015-02-11 15:08:38 -0800916
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800917 Animation clipAnimTB = new ClipRectTBAnimation(
918 clipStartY, clipStartY + mTmpRect.height(),
919 0, appHeight,
920 translationYCorrection, 0,
921 mLinearOutSlowInInterpolator);
922 clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
923 clipAnimTB.setDuration(duration);
Chet Haase10e23ab2015-02-11 15:08:38 -0800924
925 // Quick fade-in from icon to app window
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800926 final long alphaDuration = duration / 4;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700927 AlphaAnimation alpha = new AlphaAnimation(0.5f, 1);
Chet Haase10e23ab2015-02-11 15:08:38 -0800928 alpha.setDuration(alphaDuration);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700929 alpha.setInterpolator(mLinearOutSlowInInterpolator);
Chet Haase10e23ab2015-02-11 15:08:38 -0800930
931 AnimationSet set = new AnimationSet(false);
932 set.addAnimation(clipAnimLR);
933 set.addAnimation(clipAnimTB);
Filip Gruszczynski82861362015-10-16 14:21:09 -0700934 set.addAnimation(translate);
Chet Haase10e23ab2015-02-11 15:08:38 -0800935 set.addAnimation(alpha);
Filip Gruszczynski9e2cf5b2015-07-31 12:20:40 -0700936 set.setZAdjustment(Animation.ZORDER_TOP);
Chet Haase10e23ab2015-02-11 15:08:38 -0800937 set.initialize(appWidth, appHeight, appWidth, appHeight);
938 anim = set;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800939 mLastHadClipReveal = true;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800940 mLastClipRevealTransitionDuration = duration;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800941
942 // If the start rect was full inside the target rect (cutOff == false), we don't need
943 // to store the translation, because it's only used if cutOff == true.
944 mLastClipRevealMaxTranslation = cutOff
945 ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0;
Chet Haase10e23ab2015-02-11 15:08:38 -0800946 } else {
947 final long duration;
948 switch (transit) {
949 case TRANSIT_ACTIVITY_OPEN:
950 case TRANSIT_ACTIVITY_CLOSE:
951 duration = mConfigShortAnimTime;
952 break;
953 default:
954 duration = DEFAULT_APP_TRANSITION_DURATION;
955 break;
956 }
957 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
958 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
959 // If we are on top of the wallpaper, we need an animation that
960 // correctly handles the wallpaper staying static behind all of
961 // the animated elements. To do this, will just have the existing
962 // element fade out.
963 anim = new AlphaAnimation(1, 0);
964 anim.setDetachWallpaper(true);
965 } else {
966 // For normal animations, the exiting element just holds in place.
967 anim = new AlphaAnimation(1, 1);
968 }
969 anim.setInterpolator(mDecelerateInterpolator);
970 anim.setDuration(duration);
971 anim.setFillAfter(true);
972 }
973 return anim;
974 }
975
Winson Chung399f6202014-03-19 10:47:20 -0700976 /**
977 * Prepares the specified animation with a standard duration, interpolator, etc.
978 */
Winson Chung5393dff2014-05-08 14:25:43 -0700979 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100980 long duration, Interpolator interpolator) {
Winson Chunga4ccb862014-08-22 15:26:27 -0700981 if (duration > 0) {
982 a.setDuration(duration);
983 }
Winson Chung5393dff2014-05-08 14:25:43 -0700984 a.setFillAfter(true);
Jorim Jaggic69bd222016-03-15 14:38:37 +0100985 if (interpolator != null) {
986 a.setInterpolator(interpolator);
987 }
Winson Chung5393dff2014-05-08 14:25:43 -0700988 a.initialize(appWidth, appHeight, appWidth, appHeight);
989 return a;
990 }
991
992 /**
993 * Prepares the specified animation with a standard duration, interpolator, etc.
994 */
Winson Chung399f6202014-03-19 10:47:20 -0700995 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800996 // Pick the desired duration. If this is an inter-activity transition,
997 // it is the standard duration for that. Otherwise we use the longer
998 // task transition duration.
Winson Chung5393dff2014-05-08 14:25:43 -0700999 final int duration;
Craig Mautner321bdf52012-12-18 09:53:24 -08001000 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -08001001 case TRANSIT_ACTIVITY_OPEN:
1002 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -08001003 duration = mConfigShortAnimTime;
1004 break;
1005 default:
1006 duration = DEFAULT_APP_TRANSITION_DURATION;
1007 break;
1008 }
Winson Chung5393dff2014-05-08 14:25:43 -07001009 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
1010 mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001011 }
1012
Winson Chung399f6202014-03-19 10:47:20 -07001013 /**
1014 * Return the current thumbnail transition state.
1015 */
1016 int getThumbnailTransitionState(boolean enter) {
1017 if (enter) {
1018 if (mNextAppTransitionScaleUp) {
1019 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
1020 } else {
1021 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
1022 }
1023 } else {
1024 if (mNextAppTransitionScaleUp) {
1025 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
1026 } else {
1027 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
1028 }
1029 }
1030 }
1031
1032 /**
Tony Mak64b8d562017-12-28 17:44:02 +00001033 * Creates an overlay with a background color and a thumbnail for the cross profile apps
1034 * animation.
1035 */
1036 GraphicBuffer createCrossProfileAppsThumbnail(
1037 @DrawableRes int thumbnailDrawableRes, Rect frame) {
1038 final int width = frame.width();
1039 final int height = frame.height();
1040
John Reck519ad482018-02-12 17:08:48 -08001041 final Picture picture = new Picture();
1042 final Canvas canvas = picture.beginRecording(width, height);
Tony Mak64b8d562017-12-28 17:44:02 +00001043 canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
1044 final int thumbnailSize = mService.mContext.getResources().getDimensionPixelSize(
1045 com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
1046 final Drawable drawable = mService.mContext.getDrawable(thumbnailDrawableRes);
1047 drawable.setBounds(
1048 (width - thumbnailSize) / 2,
1049 (height - thumbnailSize) / 2,
1050 (width + thumbnailSize) / 2,
1051 (height + thumbnailSize) / 2);
Tony Makda4af232018-04-27 11:01:10 +01001052 drawable.setTint(mContext.getColor(android.R.color.white));
Tony Mak64b8d562017-12-28 17:44:02 +00001053 drawable.draw(canvas);
John Reck519ad482018-02-12 17:08:48 -08001054 picture.endRecording();
Tony Mak64b8d562017-12-28 17:44:02 +00001055
John Reck519ad482018-02-12 17:08:48 -08001056 return Bitmap.createBitmap(picture).createGraphicBufferHandle();
Tony Mak64b8d562017-12-28 17:44:02 +00001057 }
1058
1059 Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
1060 final Animation animation = loadAnimationRes(
1061 "android", com.android.internal.R.anim.cross_profile_apps_thumbnail_enter);
1062 return prepareThumbnailAnimationWithDuration(animation, appRect.width(),
1063 appRect.height(), 0, null);
1064 }
1065
1066 /**
Winson Chung399f6202014-03-19 10:47:20 -07001067 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001068 * when a thumbnail is specified with the pending animation override.
Winson Chung399f6202014-03-19 10:47:20 -07001069 */
Jorim Jaggide63d442016-03-14 14:56:56 +01001070 Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
lumark19a5d2e2019-10-11 16:19:30 +08001071 GraphicBuffer thumbnailHeader, WindowContainer container, int uiMode, int orientation) {
Winson Chung399f6202014-03-19 10:47:20 -07001072 Animation a;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001073 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chung399f6202014-03-19 10:47:20 -07001074 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001075 final int thumbHeightI = thumbnailHeader.getHeight();
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001076 final int appWidth = appRect.width();
Winson Chung399f6202014-03-19 10:47:20 -07001077
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001078 float scaleW = appWidth / thumbWidth;
lumark19a5d2e2019-10-11 16:19:30 +08001079 getNextAppTransitionStartRect(container, mTmpRect);
Jorim Jaggi09072002016-03-25 16:48:42 -07001080 final float fromX;
Manu Cornet57b61492017-01-24 18:19:05 +09001081 float fromY;
Jorim Jaggi09072002016-03-25 16:48:42 -07001082 final float toX;
Manu Cornet57b61492017-01-24 18:19:05 +09001083 float toY;
Jorim Jaggi09072002016-03-25 16:48:42 -07001084 final float pivotX;
1085 final float pivotY;
Manu Cornetd7376802017-01-13 13:44:07 -08001086 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
Jorim Jaggi09072002016-03-25 16:48:42 -07001087 fromX = mTmpRect.left;
1088 fromY = mTmpRect.top;
1089
1090 // For the curved translate animation to work, the pivot points needs to be at the
1091 // same absolute position as the one from the real surface.
1092 toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
1093 toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
1094 pivotX = mTmpRect.width() / 2;
1095 pivotY = appRect.height() / 2 / scaleW;
Manu Cornet57b61492017-01-24 18:19:05 +09001096 if (mGridLayoutRecentsEnabled) {
1097 // In the grid layout, the header is displayed above the thumbnail instead of
1098 // overlapping it.
1099 fromY -= thumbHeightI;
1100 toY -= thumbHeightI * scaleW;
1101 }
Jorim Jaggi09072002016-03-25 16:48:42 -07001102 } else {
1103 pivotX = 0;
1104 pivotY = 0;
1105 fromX = mTmpRect.left;
1106 fromY = mTmpRect.top;
1107 toX = appRect.left;
1108 toY = appRect.top;
1109 }
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001110 final long duration = getAspectScaleDuration();
1111 final Interpolator interpolator = getAspectScaleInterpolator();
Winson Chung399f6202014-03-19 10:47:20 -07001112 if (mNextAppTransitionScaleUp) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001113 // Animation up from the thumbnail to the full screen
Jorim Jaggi8448f332016-03-14 17:50:37 +01001114 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001115 scale.setInterpolator(interpolator);
1116 scale.setDuration(duration);
Jorim Jaggic6c89a82016-01-28 17:48:21 -08001117 Animation alpha = new AlphaAnimation(1f, 0f);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001118 alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1119 ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator);
1120 alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1121 ? duration / 2
1122 : duration);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001123 Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
1124 translate.setInterpolator(interpolator);
1125 translate.setDuration(duration);
Winson Chung399f6202014-03-19 10:47:20 -07001126
Jorim Jaggide63d442016-03-14 14:56:56 +01001127 mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
1128 mTmpToClipRect.set(appRect);
1129
1130 // Containing frame is in screen space, but we need the clip rect in the
1131 // app space.
1132 mTmpToClipRect.offsetTo(0, 0);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001133 mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
1134 mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
Jorim Jaggide63d442016-03-14 14:56:56 +01001135
1136 if (contentInsets != null) {
Jorim Jaggi8448f332016-03-14 17:50:37 +01001137 mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
1138 (int) (-contentInsets.top * scaleW),
1139 (int) (-contentInsets.right * scaleW),
1140 (int) (-contentInsets.bottom * scaleW));
Jorim Jaggide63d442016-03-14 14:56:56 +01001141 }
1142
1143 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001144 clipAnim.setInterpolator(interpolator);
1145 clipAnim.setDuration(duration);
Jorim Jaggide63d442016-03-14 14:56:56 +01001146
Winson Chung399f6202014-03-19 10:47:20 -07001147 // This AnimationSet uses the Interpolators assigned above.
1148 AnimationSet set = new AnimationSet(false);
1149 set.addAnimation(scale);
Manu Cornet57b61492017-01-24 18:19:05 +09001150 if (!mGridLayoutRecentsEnabled) {
1151 // In the grid layout, the header should be shown for the whole animation.
1152 set.addAnimation(alpha);
1153 }
Winson Chunga4ccb862014-08-22 15:26:27 -07001154 set.addAnimation(translate);
Jorim Jaggide63d442016-03-14 14:56:56 +01001155 set.addAnimation(clipAnim);
Winson Chung399f6202014-03-19 10:47:20 -07001156 a = set;
1157 } else {
Winson Chunga4ccb862014-08-22 15:26:27 -07001158 // Animation down from the full screen to the thumbnail
Jorim Jaggi8448f332016-03-14 17:50:37 +01001159 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001160 scale.setInterpolator(interpolator);
1161 scale.setDuration(duration);
Winson Chunga4ccb862014-08-22 15:26:27 -07001162 Animation alpha = new AlphaAnimation(0f, 1f);
1163 alpha.setInterpolator(mThumbnailFadeInInterpolator);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001164 alpha.setDuration(duration);
1165 Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
1166 translate.setInterpolator(interpolator);
1167 translate.setDuration(duration);
Winson Chung399f6202014-03-19 10:47:20 -07001168
Winson Chunga4ccb862014-08-22 15:26:27 -07001169 // This AnimationSet uses the Interpolators assigned above.
1170 AnimationSet set = new AnimationSet(false);
1171 set.addAnimation(scale);
Manu Cornet57b61492017-01-24 18:19:05 +09001172 if (!mGridLayoutRecentsEnabled) {
1173 // In the grid layout, the header should be shown for the whole animation.
1174 set.addAnimation(alpha);
1175 }
Winson Chunga4ccb862014-08-22 15:26:27 -07001176 set.addAnimation(translate);
1177 a = set;
1178
1179 }
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001180 return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
Jorim Jaggic69bd222016-03-15 14:38:37 +01001181 null);
Winson Chung399f6202014-03-19 10:47:20 -07001182 }
1183
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001184 private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
1185
1186 // Almost no x-change - use linear animation
Jorim Jaggic69bd222016-03-15 14:38:37 +01001187 if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) {
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001188 return new TranslateAnimation(fromX, toX, fromY, toY);
1189 } else {
1190 final Path path = createCurvedPath(fromX, toX, fromY, toY);
1191 return new CurvedTranslateAnimation(path);
1192 }
1193 }
1194
1195 private Path createCurvedPath(float fromX, float toX, float fromY, float toY) {
1196 final Path path = new Path();
1197 path.moveTo(fromX, fromY);
Jorim Jaggi1f458fb2016-03-25 17:36:37 -07001198
1199 if (fromY > toY) {
1200 // If the object needs to go up, move it in horizontal direction first, then vertical.
1201 path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY);
1202 } else {
1203 // If the object needs to go down, move it in vertical direction first, then horizontal.
1204 path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY);
1205 }
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001206 return path;
1207 }
1208
1209 private long getAspectScaleDuration() {
1210 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
Jorim Jaggic69bd222016-03-15 14:38:37 +01001211 return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001212 } else {
1213 return THUMBNAIL_APP_TRANSITION_DURATION;
1214 }
1215 }
1216
1217 private Interpolator getAspectScaleInterpolator() {
1218 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
1219 return mFastOutSlowInInterpolator;
1220 } else {
1221 return TOUCH_RESPONSE_INTERPOLATOR;
1222 }
1223 }
1224
Winson Chung399f6202014-03-19 10:47:20 -07001225 /**
1226 * This alternate animation is created when we are doing a thumbnail transition, for the
1227 * activity that is leaving, and the activity that is entering.
1228 */
Winson Chunga4ccb862014-08-22 15:26:27 -07001229 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
Winsonb2024762016-04-05 17:32:30 -07001230 int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets,
Matthew Ng43db6d22017-06-27 15:29:39 -07001231 @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean freeform,
lumark19a5d2e2019-10-11 16:19:30 +08001232 WindowContainer container) {
Winson Chung399f6202014-03-19 10:47:20 -07001233 Animation a;
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001234 final int appWidth = containingFrame.width();
1235 final int appHeight = containingFrame.height();
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001236 getDefaultNextAppTransitionStartRect(mTmpRect);
1237 final int thumbWidthI = mTmpRect.width();
Winson Chung399f6202014-03-19 10:47:20 -07001238 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001239 final int thumbHeightI = mTmpRect.height();
Winson Chung399f6202014-03-19 10:47:20 -07001240 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
Winsoncbb625b2016-07-06 15:24:15 -07001241 final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left;
Winson21700932016-03-24 17:26:23 -07001242 final int thumbStartY = mTmpRect.top - containingFrame.top;
Winson Chung399f6202014-03-19 10:47:20 -07001243
1244 switch (thumbTransitState) {
Jorim Jaggi8448f332016-03-14 17:50:37 +01001245 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
1246 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1247 final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
1248 if (freeform && scaleUp) {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001249 a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
lumark19a5d2e2019-10-11 16:19:30 +08001250 containingFrame, surfaceInsets, container);
Jorim Jaggi8448f332016-03-14 17:50:37 +01001251 } else if (freeform) {
1252 a = createAspectScaledThumbnailExitFreeformAnimationLocked(
lumark19a5d2e2019-10-11 16:19:30 +08001253 containingFrame, surfaceInsets, container);
Winson Chung2820c452014-04-15 15:34:44 -07001254 } else {
Winson21700932016-03-24 17:26:23 -07001255 AnimationSet set = new AnimationSet(true);
1256
1257 // In portrait, we scale to fit the width
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -07001258 mTmpFromClipRect.set(containingFrame);
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -07001259 mTmpToClipRect.set(containingFrame);
Jorim Jaggic6c89a82016-01-28 17:48:21 -08001260
1261 // Containing frame is in screen space, but we need the clip rect in the
1262 // app space.
1263 mTmpFromClipRect.offsetTo(0, 0);
1264 mTmpToClipRect.offsetTo(0, 0);
1265
1266 // Exclude insets region from the source clip.
1267 mTmpFromClipRect.inset(contentInsets);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001268 mNextAppTransitionInsets.set(contentInsets);
1269
Manu Cornetd7376802017-01-13 13:44:07 -08001270 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
Jorim Jaggic69bd222016-03-15 14:38:37 +01001271 // We scale the width and clip to the top/left square
1272 float scale = thumbWidth /
1273 (appWidth - contentInsets.left - contentInsets.right);
Manu Cornetb68b7652017-01-23 19:37:53 +09001274 if (!mGridLayoutRecentsEnabled) {
1275 int unscaledThumbHeight = (int) (thumbHeight / scale);
1276 mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
1277 }
Jorim Jaggic69bd222016-03-15 14:38:37 +01001278
1279 mNextAppTransitionInsets.set(contentInsets);
1280
Jorim Jaggi8448f332016-03-14 17:50:37 +01001281 Animation scaleAnim = new ScaleAnimation(
1282 scaleUp ? scale : 1, scaleUp ? 1 : scale,
1283 scaleUp ? scale : 1, scaleUp ? 1 : scale,
Jorim Jaggic69bd222016-03-15 14:38:37 +01001284 containingFrame.width() / 2f,
1285 containingFrame.height() / 2f + contentInsets.top);
Jorim Jaggi8448f332016-03-14 17:50:37 +01001286 final float targetX = (mTmpRect.left - containingFrame.left);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001287 final float x = containingFrame.width() / 2f
1288 - containingFrame.width() / 2f * scale;
Jorim Jaggi8448f332016-03-14 17:50:37 +01001289 final float targetY = (mTmpRect.top - containingFrame.top);
Matthew Ng43db6d22017-06-27 15:29:39 -07001290 float y = containingFrame.height() / 2f
Jorim Jaggic69bd222016-03-15 14:38:37 +01001291 - containingFrame.height() / 2f * scale;
Matthew Ng43db6d22017-06-27 15:29:39 -07001292
1293 // During transition may require clipping offset from any top stable insets
1294 // such as the statusbar height when statusbar is hidden
1295 if (mLowRamRecentsEnabled && contentInsets.top == 0 && scaleUp) {
1296 mTmpFromClipRect.top += stableInsets.top;
1297 y += stableInsets.top;
1298 }
Jorim Jaggi8448f332016-03-14 17:50:37 +01001299 final float startX = targetX - x;
1300 final float startY = targetY - y;
1301 Animation clipAnim = scaleUp
1302 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1303 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1304 Animation translateAnim = scaleUp
Jorim Jaggic69bd222016-03-15 14:38:37 +01001305 ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0)
1306 : createCurvedMotion(0, startX, 0, startY - contentInsets.top);
1307
Winson21700932016-03-24 17:26:23 -07001308 set.addAnimation(clipAnim);
1309 set.addAnimation(scaleAnim);
1310 set.addAnimation(translateAnim);
1311
1312 } else {
1313 // In landscape, we don't scale at all and only crop
1314 mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI;
1315 mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI;
1316
Jorim Jaggi8448f332016-03-14 17:50:37 +01001317 Animation clipAnim = scaleUp
1318 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1319 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1320 Animation translateAnim = scaleUp
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001321 ? createCurvedMotion(thumbStartX, 0,
1322 thumbStartY - contentInsets.top, 0)
1323 : createCurvedMotion(0, thumbStartX, 0,
1324 thumbStartY - contentInsets.top);
Winson21700932016-03-24 17:26:23 -07001325
1326 set.addAnimation(clipAnim);
1327 set.addAnimation(translateAnim);
1328 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001329 a = set;
Winson21700932016-03-24 17:26:23 -07001330 a.setZAdjustment(Animation.ZORDER_TOP);
Winson Chung2820c452014-04-15 15:34:44 -07001331 }
Winson Chung399f6202014-03-19 10:47:20 -07001332 break;
1333 }
1334 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
Winson Chunga4ccb862014-08-22 15:26:27 -07001335 // Previous app window during the scale up
Winson Chung399f6202014-03-19 10:47:20 -07001336 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001337 // Fade out the source activity if we are animating to a wallpaper
Winson Chung399f6202014-03-19 10:47:20 -07001338 // activity.
1339 a = new AlphaAnimation(1, 0);
1340 } else {
Winson Chung399f6202014-03-19 10:47:20 -07001341 a = new AlphaAnimation(1, 1);
1342 }
1343 break;
1344 }
1345 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
Winson Chunga4ccb862014-08-22 15:26:27 -07001346 // Target app window during the scale down
1347 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1348 // Fade in the destination activity if we are animating from a wallpaper
1349 // activity.
1350 a = new AlphaAnimation(0, 1);
1351 } else {
1352 a = new AlphaAnimation(1, 1);
1353 }
Winson Chung399f6202014-03-19 10:47:20 -07001354 break;
1355 }
Winson Chung399f6202014-03-19 10:47:20 -07001356 default:
1357 throw new RuntimeException("Invalid thumbnail transition state");
1358 }
1359
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001360 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
1361 getAspectScaleDuration(), getAspectScaleInterpolator());
Winson Chung399f6202014-03-19 10:47:20 -07001362 }
1363
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001364 private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
lumark19a5d2e2019-10-11 16:19:30 +08001365 @Nullable Rect surfaceInsets, WindowContainer container) {
1366 getNextAppTransitionStartRect(container, mTmpRect);
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001367 return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
1368 true);
1369 }
1370
1371 private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
lumark19a5d2e2019-10-11 16:19:30 +08001372 @Nullable Rect surfaceInsets, WindowContainer container) {
1373 getNextAppTransitionStartRect(container, mTmpRect);
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001374 return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
1375 false);
1376 }
1377
1378 private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
1379 Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
1380 final float sourceWidth = sourceFrame.width();
1381 final float sourceHeight = sourceFrame.height();
1382 final float destWidth = destFrame.width();
1383 final float destHeight = destFrame.height();
1384 final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
1385 final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001386 AnimationSet set = new AnimationSet(true);
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001387 final int surfaceInsetsH = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001388 ? 0 : surfaceInsets.left + surfaceInsets.right;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001389 final int surfaceInsetsV = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001390 ? 0 : surfaceInsets.top + surfaceInsets.bottom;
1391 // We want the scaling to happen from the center of the surface. In order to achieve that,
1392 // we need to account for surface insets that will be used to enlarge the surface.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001393 final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
1394 final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
1395 final ScaleAnimation scale = enter ?
1396 new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
1397 : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
1398 final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
1399 final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
1400 final int destHCenter = destFrame.left + destFrame.width() / 2;
1401 final int destVCenter = destFrame.top + destFrame.height() / 2;
1402 final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
1403 final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
1404 final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
1405 : new TranslateAnimation(0, fromX, 0, fromY);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001406 set.addAnimation(scale);
1407 set.addAnimation(translation);
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001408
1409 final IRemoteCallback callback = mAnimationFinishedCallback;
1410 if (callback != null) {
1411 set.setAnimationListener(new Animation.AnimationListener() {
1412 @Override
1413 public void onAnimationStart(Animation animation) { }
1414
1415 @Override
1416 public void onAnimationEnd(Animation animation) {
lumark23b54592018-10-02 17:17:23 +08001417 mHandler.sendMessage(PooledLambda.obtainMessage(
1418 AppTransition::doAnimationCallback, callback));
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001419 }
1420
1421 @Override
1422 public void onAnimationRepeat(Animation animation) { }
1423 });
1424 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001425 return set;
1426 }
1427
Winson Chung399f6202014-03-19 10:47:20 -07001428 /**
Winson Chunga4ccb862014-08-22 15:26:27 -07001429 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001430 * when a thumbnail is specified with the pending animation override.
Winson Chunga4ccb862014-08-22 15:26:27 -07001431 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001432 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
Winson Chungaa7fa012017-05-24 15:50:06 -07001433 GraphicBuffer thumbnailHeader) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001434 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001435 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001436 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chunga4ccb862014-08-22 15:26:27 -07001437 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001438 final int thumbHeightI = thumbnailHeader.getHeight();
Winson Chunga4ccb862014-08-22 15:26:27 -07001439 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1440
1441 if (mNextAppTransitionScaleUp) {
1442 // Animation for the thumbnail zooming from its initial size to the full screen
1443 float scaleW = appWidth / thumbWidth;
1444 float scaleH = appHeight / thumbHeight;
1445 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001446 computePivot(mTmpRect.left, 1 / scaleW),
1447 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001448 scale.setInterpolator(mDecelerateInterpolator);
1449
1450 Animation alpha = new AlphaAnimation(1, 0);
1451 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
1452
1453 // This AnimationSet uses the Interpolators assigned above.
1454 AnimationSet set = new AnimationSet(false);
1455 set.addAnimation(scale);
1456 set.addAnimation(alpha);
1457 a = set;
1458 } else {
1459 // Animation for the thumbnail zooming down from the full screen to its final size
1460 float scaleW = appWidth / thumbWidth;
1461 float scaleH = appHeight / thumbHeight;
1462 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001463 computePivot(mTmpRect.left, 1 / scaleW),
1464 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001465 }
1466
1467 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1468 }
1469
1470 /**
Winson Chung399f6202014-03-19 10:47:20 -07001471 * This animation is created when we are doing a thumbnail transition, for the activity that is
1472 * leaving, and the activity that is entering.
1473 */
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001474 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
lumark19a5d2e2019-10-11 16:19:30 +08001475 int transit, WindowContainer container) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001476 final int appWidth = containingFrame.width();
1477 final int appHeight = containingFrame.height();
lumark19a5d2e2019-10-11 16:19:30 +08001478 final GraphicBuffer thumbnailHeader = getAppTransitionThumbnailHeader(container);
Winson Chung399f6202014-03-19 10:47:20 -07001479 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001480 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001481 final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
Winson Chung399f6202014-03-19 10:47:20 -07001482 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001483 final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
Winson Chung399f6202014-03-19 10:47:20 -07001484 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1485
1486 switch (thumbTransitState) {
1487 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
1488 // Entering app scales up with the thumbnail
1489 float scaleW = thumbWidth / appWidth;
1490 float scaleH = thumbHeight / appHeight;
1491 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001492 computePivot(mTmpRect.left, scaleW),
1493 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001494 break;
1495 }
1496 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
1497 // Exiting app while the thumbnail is scaling up should fade or stay in place
1498 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1499 // Fade out while bringing up selected activity. This keeps the
1500 // current activity from showing through a launching wallpaper
1501 // activity.
1502 a = new AlphaAnimation(1, 0);
1503 } else {
1504 // noop animation
1505 a = new AlphaAnimation(1, 1);
1506 }
1507 break;
1508 }
1509 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
1510 // Entering the other app, it should just be visible while we scale the thumbnail
1511 // down above it
1512 a = new AlphaAnimation(1, 1);
1513 break;
1514 }
1515 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1516 // Exiting the current app, the app should scale down with the thumbnail
1517 float scaleW = thumbWidth / appWidth;
1518 float scaleH = thumbHeight / appHeight;
1519 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001520 computePivot(mTmpRect.left, scaleW),
1521 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001522
1523 Animation alpha = new AlphaAnimation(1, 0);
1524
1525 AnimationSet set = new AnimationSet(true);
1526 set.addAnimation(scale);
1527 set.addAnimation(alpha);
1528 set.setZAdjustment(Animation.ZORDER_TOP);
1529 a = set;
1530 break;
1531 }
1532 default:
1533 throw new RuntimeException("Invalid thumbnail transition state");
1534 }
1535
1536 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1537 }
1538
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001539 private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) {
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001540 getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
1541 final int left = mTmpFromClipRect.left;
1542 final int top = mTmpFromClipRect.top;
1543 mTmpFromClipRect.offset(-left, -top);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001544 // TODO: Isn't that strange that we ignore exact position of the containingFrame?
1545 mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height());
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001546 AnimationSet set = new AnimationSet(true);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001547 float fromWidth = mTmpFromClipRect.width();
1548 float toWidth = mTmpToClipRect.width();
1549 float fromHeight = mTmpFromClipRect.height();
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001550 // While the window might span the whole display, the actual content will be cropped to the
1551 // system decoration frame, for example when the window is docked. We need to take into
1552 // account the visible height when constructing the animation.
1553 float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom;
1554 int translateAdjustment = 0;
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001555 if (fromWidth <= toWidth && fromHeight <= toHeight) {
1556 // The final window is larger in both dimensions than current window (e.g. we are
1557 // maximizing), so we can simply unclip the new window and there will be no disappearing
1558 // frame.
1559 set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
1560 } else {
1561 // The disappearing window has one larger dimension. We need to apply scaling, so the
1562 // first frame of the entry animation matches the old window.
1563 set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001564 // We might not be going exactly full screen, but instead be aligned under the status
1565 // bar using cropping. We still need to account for the cropped part, which will also
1566 // be scaled.
1567 translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001568 }
1569
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001570 // We animate the translation from the old position of the removed window, to the new
1571 // position of the added window. The latter might not be full screen, for example docked for
1572 // docked windows.
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001573 TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001574 0, top - containingFrame.top - translateAdjustment, 0);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001575 set.addAnimation(translate);
1576 set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
Filip Gruszczynskie95b0ae2015-09-30 10:55:33 -07001577 set.setZAdjustment(Animation.ZORDER_TOP);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001578 return set;
1579 }
1580
Jorim Jaggic554b772015-06-04 16:07:57 -07001581 /**
1582 * @return true if and only if the first frame of the transition can be skipped, i.e. the first
1583 * frame of the transition doesn't change the visuals on screen, so we can start
1584 * directly with the second one
1585 */
1586 boolean canSkipFirstFrame() {
1587 return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
1588 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
Jorim Jaggife762342016-10-13 14:33:27 +02001589 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
1590 && mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY;
Jorim Jaggic554b772015-06-04 16:07:57 -07001591 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08001592
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001593 RemoteAnimationController getRemoteAnimationController() {
1594 return mRemoteAnimationController;
1595 }
1596
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001597 /**
1598 *
1599 * @param frame These are the bounds of the window when it finishes the animation. This is where
1600 * the animation must usually finish in entrance animation, as the next frame will
1601 * display the window at these coordinates. In case of exit animation, this is
1602 * where the animation must start, as the frame before the animation is displaying
1603 * the window at these bounds.
1604 * @param insets Knowing where the window will be positioned is not enough. Some parts of the
1605 * window might be obscured, usually by the system windows (status bar and
1606 * navigation bar) and we use content insets to convey that information. This
1607 * usually affects the animation aspects vertically, as the system decoration is
1608 * at the top and the bottom. For example when we animate from full screen to
1609 * recents, we want to exclude the covered parts, because they won't match the
1610 * thumbnail after the last frame is executed.
1611 * @param surfaceInsets In rare situation the surface is larger than the content and we need to
1612 * know about this to make the animation frames match. We currently use
1613 * this for freeform windows, which have larger surfaces to display
1614 * shadows. When we animate them from recents, we want to match the content
1615 * to the recents thumbnail and hence need to account for the surface being
1616 * bigger.
1617 */
Jorim Jaggif84e2f62018-01-16 14:17:59 +01001618 Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -08001619 int orientation, Rect frame, Rect displayFrame, Rect insets,
Matthew Ng43db6d22017-06-27 15:29:39 -07001620 @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
lumark19a5d2e2019-10-11 16:19:30 +08001621 boolean freeform, WindowContainer container) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001622 Animation a;
Jorim Jaggife762342016-10-13 14:33:27 +02001623 if (isKeyguardGoingAwayTransit(transit) && enter) {
1624 a = loadKeyguardExitAnimation(transit);
1625 } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) {
Selim Cinekdbf172e2018-08-08 18:31:45 +00001626 a = null;
Jorim Jaggife762342016-10-13 14:33:27 +02001627 } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) {
1628 a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit);
Adrian Roos93577212018-04-10 14:12:10 -07001629 } else if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
1630 a = null;
Jorim Jaggife762342016-10-13 14:33:27 +02001631 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001632 || transit == TRANSIT_TASK_OPEN
1633 || transit == TRANSIT_TASK_TO_FRONT)) {
1634 a = loadAnimationRes(lp, enter
1635 ? com.android.internal.R.anim.voice_activity_open_enter
1636 : com.android.internal.R.anim.voice_activity_open_exit);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001637 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1638 "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
1639 appTransitionToString(transit), enter, Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001640 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
1641 || transit == TRANSIT_TASK_CLOSE
1642 || transit == TRANSIT_TASK_TO_BACK)) {
1643 a = loadAnimationRes(lp, enter
1644 ? com.android.internal.R.anim.voice_activity_close_enter
1645 : com.android.internal.R.anim.voice_activity_close_exit);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001646 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1647 "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
1648 appTransitionToString(transit), enter, Debug.getCallers(3));
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001649 } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001650 a = createRelaunchAnimation(frame, insets);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001651 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1652 "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s", a,
1653 mNextAppTransition, appTransitionToString(transit),
1654 Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001655 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
1656 a = loadAnimationRes(mNextAppTransitionPackage, enter ?
Craig Mautner164d4bb2012-11-26 13:51:23 -08001657 mNextAppTransitionEnter : mNextAppTransitionExit);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001658 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1659 "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "
1660 + "isEntrance=%b Callers=%s",
1661 a, appTransitionToString(transit), enter, Debug.getCallers(3));
Winson Chung044d5292014-11-06 11:05:19 -08001662 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
1663 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001664 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1665 "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE "
1666 + "transit=%s Callers=%s",
1667 a, appTransitionToString(transit), Debug.getCallers(3));
Chet Haase10e23ab2015-02-11 15:08:38 -08001668 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -08001669 a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001670 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1671 "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL "
1672 + "transit=%s Callers=%s",
1673 a, appTransitionToString(transit), Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001674 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001675 a = createScaleUpAnimationLocked(transit, enter, frame);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001676 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1677 "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s "
1678 + "isEntrance=%s Callers=%s",
1679 a, appTransitionToString(transit), enter, Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001680 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
1681 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001682 mNextAppTransitionScaleUp =
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001683 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
Winson Chunga4ccb862014-08-22 15:26:27 -07001684 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
lumark19a5d2e2019-10-11 16:19:30 +08001685 frame, transit, container);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001686 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1687 "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
1688 + "Callers=%s",
1689 a, mNextAppTransitionScaleUp
1690 ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN",
1691 appTransitionToString(transit), enter, Debug.getCallers(3));
Winson Chunga4ccb862014-08-22 15:26:27 -07001692 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
1693 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
1694 mNextAppTransitionScaleUp =
1695 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
1696 a = createAspectScaledThumbnailEnterExitAnimationLocked(
Winsonb2024762016-04-05 17:32:30 -07001697 getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
lumark19a5d2e2019-10-11 16:19:30 +08001698 insets, surfaceInsets, stableInsets, freeform, container);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001699 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1700 "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
1701 + "Callers=%s",
1702 a, mNextAppTransitionScaleUp
1703 ? "ANIM_THUMBNAIL_ASPECT_SCALE_UP"
1704 : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN",
1705 appTransitionToString(transit), enter, Debug.getCallers(3));
Tony Mak83546a82018-01-22 13:56:20 +00001706 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {
Jorim Jaggi98a9d202018-03-26 16:17:07 +02001707 a = loadAnimationRes("android",
1708 com.android.internal.R.anim.task_open_enter_cross_profile_apps);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001709 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1710 "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: "
1711 + "anim=%s transit=%s isEntrance=true Callers=%s",
1712 a, appTransitionToString(transit), Debug.getCallers(3));
Evan Roskycf76bed2019-01-15 10:33:58 -08001713 } else if (transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE) {
1714 // In the absence of a specific adapter, we just want to keep everything stationary.
1715 a = new AlphaAnimation(1.f, 1.f);
1716 a.setDuration(WindowChangeAnimationSpec.ANIMATION_DURATION);
Adrian Roosb125e0b2019-10-02 14:55:14 +02001717 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1718 "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
1719 a, appTransitionToString(transit), enter, Debug.getCallers(3));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001720 } else {
1721 int animAttr = 0;
1722 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -08001723 case TRANSIT_ACTIVITY_OPEN:
Jorim Jaggi0a1523d2018-04-19 17:48:38 +02001724 case TRANSIT_TRANSLUCENT_ACTIVITY_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001725 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001726 ? WindowAnimation_activityOpenEnterAnimation
1727 : WindowAnimation_activityOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001728 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001729 case TRANSIT_ACTIVITY_CLOSE:
Jorim Jaggi0a1523d2018-04-19 17:48:38 +02001730 case TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001731 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001732 ? WindowAnimation_activityCloseEnterAnimation
1733 : WindowAnimation_activityCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001734 break;
Jorim Jaggi192086e2016-03-11 17:17:03 +01001735 case TRANSIT_DOCK_TASK_FROM_RECENTS:
Craig Mautner4b71aa12012-12-27 17:20:01 -08001736 case TRANSIT_TASK_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001737 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001738 ? WindowAnimation_taskOpenEnterAnimation
1739 : WindowAnimation_taskOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001740 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001741 case TRANSIT_TASK_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001742 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001743 ? WindowAnimation_taskCloseEnterAnimation
1744 : WindowAnimation_taskCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001745 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001746 case TRANSIT_TASK_TO_FRONT:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001747 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001748 ? WindowAnimation_taskToFrontEnterAnimation
1749 : WindowAnimation_taskToFrontExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001750 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001751 case TRANSIT_TASK_TO_BACK:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001752 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001753 ? WindowAnimation_taskToBackEnterAnimation
1754 : WindowAnimation_taskToBackExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001755 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001756 case TRANSIT_WALLPAPER_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001757 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001758 ? WindowAnimation_wallpaperOpenEnterAnimation
1759 : WindowAnimation_wallpaperOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001760 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001761 case TRANSIT_WALLPAPER_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001762 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001763 ? WindowAnimation_wallpaperCloseEnterAnimation
1764 : WindowAnimation_wallpaperCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001765 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001766 case TRANSIT_WALLPAPER_INTRA_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001767 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001768 ? WindowAnimation_wallpaperIntraOpenEnterAnimation
1769 : WindowAnimation_wallpaperIntraOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001770 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001771 case TRANSIT_WALLPAPER_INTRA_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001772 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001773 ? WindowAnimation_wallpaperIntraCloseEnterAnimation
1774 : WindowAnimation_wallpaperIntraCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001775 break;
Craig Mautnerbb742462014-07-07 15:28:55 -07001776 case TRANSIT_TASK_OPEN_BEHIND:
1777 animAttr = enter
1778 ? WindowAnimation_launchTaskBehindSourceAnimation
Craig Mautner3b2cd1d2014-08-25 14:25:54 -07001779 : WindowAnimation_launchTaskBehindTargetAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001780 }
Jorim Jaggi0a1523d2018-04-19 17:48:38 +02001781 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;
Adrian Roosb125e0b2019-10-02 14:55:14 +02001782 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
1783 "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
1784 + "Callers=%s",
1785 a, animAttr, appTransitionToString(transit), enter,
1786 Debug.getCallers(3));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001787 }
1788 return a;
1789 }
1790
Jorim Jaggife762342016-10-13 14:33:27 +02001791 private Animation loadKeyguardExitAnimation(int transit) {
1792 if ((mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) != 0) {
1793 return null;
1794 }
1795 final boolean toShade =
1796 (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0;
Issei Suzuki5609ccb2019-06-13 15:04:08 +02001797 final boolean subtle =
1798 (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0;
Jorim Jaggife762342016-10-13 14:33:27 +02001799 return mService.mPolicy.createHiddenByKeyguardExit(
Issei Suzuki5609ccb2019-06-13 15:04:08 +02001800 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade, subtle);
Jorim Jaggife762342016-10-13 14:33:27 +02001801 }
1802
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001803 int getAppStackClipMode() {
Matthew Ngbf1d9852017-03-14 12:23:09 -07001804 // When dismiss keyguard animation occurs, clip before the animation to prevent docked
1805 // app from showing beyond the divider
1806 if (mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY
1807 || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
1808 return STACK_CLIP_BEFORE_ANIM;
1809 }
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001810 return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
Jorim Jaggic69bd222016-03-15 14:38:37 +01001811 || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
Jorim Jaggi1f458fb2016-03-25 17:36:37 -07001812 || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001813 ? STACK_CLIP_NONE
1814 : STACK_CLIP_AFTER_ANIM;
1815 }
1816
Jorim Jaggife762342016-10-13 14:33:27 +02001817 public int getTransitFlags() {
1818 return mNextAppTransitionFlags;
1819 }
1820
Craig Mautner164d4bb2012-11-26 13:51:23 -08001821 void postAnimationCallback() {
1822 if (mNextAppTransitionCallback != null) {
lumark23b54592018-10-02 17:17:23 +08001823 mHandler.sendMessage(PooledLambda.obtainMessage(AppTransition::doAnimationCallback,
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001824 mNextAppTransitionCallback));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001825 mNextAppTransitionCallback = null;
1826 }
1827 }
1828
1829 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001830 IRemoteCallback startedCallback) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001831 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001832 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001833 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001834 mNextAppTransitionPackage = packageName;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001835 mNextAppTransitionEnter = enterAnim;
1836 mNextAppTransitionExit = exitAnim;
1837 postAnimationCallback();
1838 mNextAppTransitionCallback = startedCallback;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001839 }
1840 }
1841
1842 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001843 int startHeight) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001844 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001845 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001846 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
Winson4c3fecd2016-07-13 12:29:48 -07001847 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001848 postAnimationCallback();
Craig Mautner164d4bb2012-11-26 13:51:23 -08001849 }
1850 }
1851
Chet Haase10e23ab2015-02-11 15:08:38 -08001852 void overridePendingAppTransitionClipReveal(int startX, int startY,
1853 int startWidth, int startHeight) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001854 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001855 clear();
Chet Haase10e23ab2015-02-11 15:08:38 -08001856 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001857 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
Chet Haase10e23ab2015-02-11 15:08:38 -08001858 postAnimationCallback();
Chet Haase10e23ab2015-02-11 15:08:38 -08001859 }
1860 }
1861
Winson Chungaa7fa012017-05-24 15:50:06 -07001862 void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX, int startY,
Craig Mautner164d4bb2012-11-26 13:51:23 -08001863 IRemoteCallback startedCallback, boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001864 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001865 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001866 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
1867 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001868 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001869 putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001870 postAnimationCallback();
1871 mNextAppTransitionCallback = startedCallback;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001872 }
1873 }
1874
Winson Chungaa7fa012017-05-24 15:50:06 -07001875 void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX, int startY,
Winson Chung2e7f3bd2014-09-05 13:17:22 +02001876 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001877 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001878 clear();
Winson Chunga4ccb862014-08-22 15:26:27 -07001879 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1880 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Winson Chunga4ccb862014-08-22 15:26:27 -07001881 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001882 putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight,
1883 srcThumb);
Winson Chunga4ccb862014-08-22 15:26:27 -07001884 postAnimationCallback();
1885 mNextAppTransitionCallback = startedCallback;
Winson Chunga4ccb862014-08-22 15:26:27 -07001886 }
1887 }
1888
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001889 void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001890 IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
1891 boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001892 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001893 clear();
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001894 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1895 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001896 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi43102412015-11-11 16:28:37 +01001897 if (specs != null) {
1898 for (int i = 0; i < specs.length; i++) {
1899 AppTransitionAnimationSpec spec = specs[i];
1900 if (spec != null) {
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09001901 final PooledPredicate p = PooledLambda.obtainPredicate(
1902 Task::isTaskId, PooledLambda.__(Task.class), spec.taskId);
1903 final WindowContainer container = mDisplayContent.getTask(p);
1904 p.recycle();
lumark19a5d2e2019-10-11 16:19:30 +08001905 if (container == null) {
1906 continue;
1907 }
1908 mNextAppTransitionAnimationsSpecs.put(container.hashCode(), spec);
Jorim Jaggi43102412015-11-11 16:28:37 +01001909 if (i == 0) {
1910 // In full screen mode, the transition code depends on the default spec
1911 // to be set.
1912 Rect rect = spec.rect;
1913 putDefaultNextAppTransitionCoordinates(rect.left, rect.top,
Winson Chungaa7fa012017-05-24 15:50:06 -07001914 rect.width(), rect.height(), spec.buffer);
Jorim Jaggi43102412015-11-11 16:28:37 +01001915 }
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001916 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001917 }
1918 }
1919 postAnimationCallback();
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001920 mNextAppTransitionCallback = onAnimationStartedCallback;
1921 mAnimationFinishedCallback = onAnimationFinishedCallback;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001922 }
1923 }
1924
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001925 void overridePendingAppTransitionMultiThumbFuture(
1926 IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
1927 boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001928 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001929 clear();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001930 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1931 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001932 mNextAppTransitionAnimationsSpecsFuture = specsFuture;
1933 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +01001934 mNextAppTransitionFutureCallback = callback;
Riddle Hsuec6467c2019-02-15 00:10:56 +08001935 if (isReady()) {
1936 fetchAppTransitionSpecsFromFuture();
1937 }
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001938 }
1939 }
1940
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001941 void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter) {
Adrian Roosb125e0b2019-10-02 14:55:14 +02001942 ProtoLog.i(WM_DEBUG_APP_TRANSITIONS, "Override pending remote transitionSet=%b adapter=%s",
1943 isTransitionSet(), remoteAnimationAdapter);
Winson Chung044d5292014-11-06 11:05:19 -08001944 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001945 clear();
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001946 mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE;
1947 mRemoteAnimationController = new RemoteAnimationController(mService,
lumark23b54592018-10-02 17:17:23 +08001948 remoteAnimationAdapter, mHandler);
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001949 }
1950 }
1951
1952 void overrideInPlaceAppTransition(String packageName, int anim) {
1953 if (canOverridePendingAppTransition()) {
1954 clear();
Winson Chung044d5292014-11-06 11:05:19 -08001955 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
1956 mNextAppTransitionPackage = packageName;
1957 mNextAppTransitionInPlace = anim;
Winson Chung044d5292014-11-06 11:05:19 -08001958 }
1959 }
1960
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001961 /**
Tony Mak089c35e2017-12-18 20:34:14 +00001962 * @see {@link #NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS}
1963 */
1964 void overridePendingAppTransitionStartCrossProfileApps() {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001965 if (canOverridePendingAppTransition()) {
Tony Mak089c35e2017-12-18 20:34:14 +00001966 clear();
1967 mNextAppTransitionType = NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
1968 postAnimationCallback();
1969 }
1970 }
1971
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001972 private boolean canOverridePendingAppTransition() {
1973 // Remote animations always take precedence
1974 return isTransitionSet() && mNextAppTransitionType != NEXT_TRANSIT_TYPE_REMOTE;
1975 }
1976
Tony Mak089c35e2017-12-18 20:34:14 +00001977 /**
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001978 * If a future is set for the app transition specs, fetch it in another thread.
1979 */
1980 private void fetchAppTransitionSpecsFromFuture() {
1981 if (mNextAppTransitionAnimationsSpecsFuture != null) {
1982 mNextAppTransitionAnimationsSpecsPending = true;
1983 final IAppTransitionAnimationSpecsFuture future
1984 = mNextAppTransitionAnimationsSpecsFuture;
1985 mNextAppTransitionAnimationsSpecsFuture = null;
Jorim Jaggied410b62017-05-05 15:16:14 +02001986 mDefaultExecutor.execute(() -> {
1987 AppTransitionAnimationSpec[] specs = null;
1988 try {
1989 Binder.allowBlocking(future.asBinder());
1990 specs = future.get();
1991 } catch (RemoteException e) {
1992 Slog.w(TAG, "Failed to fetch app transition specs: " + e);
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001993 }
Wale Ogunwaledb485de2018-10-29 09:47:07 -07001994 synchronized (mService.mGlobalLock) {
Jorim Jaggied410b62017-05-05 15:16:14 +02001995 mNextAppTransitionAnimationsSpecsPending = false;
1996 overridePendingAppTransitionMultiThumb(specs,
1997 mNextAppTransitionFutureCallback, null /* finishedCallback */,
1998 mNextAppTransitionScaleUp);
1999 mNextAppTransitionFutureCallback = null;
Riddle Hsu8419e4b2019-09-18 23:28:01 +08002000 mService.requestTraversal();
Jorim Jaggied410b62017-05-05 15:16:14 +02002001 }
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01002002 });
2003 }
2004 }
2005
Craig Mautner164d4bb2012-11-26 13:51:23 -08002006 @Override
2007 public String toString() {
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07002008 return "mNextAppTransition=" + appTransitionToString(mNextAppTransition);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002009 }
2010
Craig Mautner4b71aa12012-12-27 17:20:01 -08002011 /**
2012 * Returns the human readable name of a window transition.
2013 *
2014 * @param transition The window transition.
2015 * @return The transition symbolic name.
2016 */
2017 public static String appTransitionToString(int transition) {
2018 switch (transition) {
2019 case TRANSIT_UNSET: {
2020 return "TRANSIT_UNSET";
2021 }
2022 case TRANSIT_NONE: {
2023 return "TRANSIT_NONE";
2024 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08002025 case TRANSIT_ACTIVITY_OPEN: {
2026 return "TRANSIT_ACTIVITY_OPEN";
2027 }
2028 case TRANSIT_ACTIVITY_CLOSE: {
2029 return "TRANSIT_ACTIVITY_CLOSE";
2030 }
2031 case TRANSIT_TASK_OPEN: {
2032 return "TRANSIT_TASK_OPEN";
2033 }
2034 case TRANSIT_TASK_CLOSE: {
2035 return "TRANSIT_TASK_CLOSE";
2036 }
2037 case TRANSIT_TASK_TO_FRONT: {
2038 return "TRANSIT_TASK_TO_FRONT";
2039 }
2040 case TRANSIT_TASK_TO_BACK: {
2041 return "TRANSIT_TASK_TO_BACK";
2042 }
2043 case TRANSIT_WALLPAPER_CLOSE: {
2044 return "TRANSIT_WALLPAPER_CLOSE";
2045 }
2046 case TRANSIT_WALLPAPER_OPEN: {
2047 return "TRANSIT_WALLPAPER_OPEN";
2048 }
2049 case TRANSIT_WALLPAPER_INTRA_OPEN: {
2050 return "TRANSIT_WALLPAPER_INTRA_OPEN";
2051 }
2052 case TRANSIT_WALLPAPER_INTRA_CLOSE: {
2053 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
2054 }
Craig Mautnerbb742462014-07-07 15:28:55 -07002055 case TRANSIT_TASK_OPEN_BEHIND: {
2056 return "TRANSIT_TASK_OPEN_BEHIND";
2057 }
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07002058 case TRANSIT_ACTIVITY_RELAUNCH: {
2059 return "TRANSIT_ACTIVITY_RELAUNCH";
2060 }
Jorim Jaggi192086e2016-03-11 17:17:03 +01002061 case TRANSIT_DOCK_TASK_FROM_RECENTS: {
2062 return "TRANSIT_DOCK_TASK_FROM_RECENTS";
2063 }
Jorim Jaggife762342016-10-13 14:33:27 +02002064 case TRANSIT_KEYGUARD_GOING_AWAY: {
2065 return "TRANSIT_KEYGUARD_GOING_AWAY";
2066 }
2067 case TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
2068 return "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
2069 }
2070 case TRANSIT_KEYGUARD_OCCLUDE: {
2071 return "TRANSIT_KEYGUARD_OCCLUDE";
2072 }
2073 case TRANSIT_KEYGUARD_UNOCCLUDE: {
2074 return "TRANSIT_KEYGUARD_UNOCCLUDE";
2075 }
Jorim Jaggi98a9d202018-03-26 16:17:07 +02002076 case TRANSIT_TRANSLUCENT_ACTIVITY_OPEN: {
2077 return "TRANSIT_TRANSLUCENT_ACTIVITY_OPEN";
2078 }
2079 case TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE: {
2080 return "TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE";
2081 }
Jorim Jaggi9c52ebb2018-06-01 14:45:24 +02002082 case TRANSIT_CRASHING_ACTIVITY_CLOSE: {
2083 return "TRANSIT_CRASHING_ACTIVITY_CLOSE";
2084 }
Issei Suzukicac2a502019-04-16 16:52:50 +02002085 case TRANSIT_SHOW_SINGLE_TASK_DISPLAY: {
2086 return "TRANSIT_SHOW_SINGLE_TASK_DISPLAY";
2087 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08002088 default: {
Jorim Jaggi9c52ebb2018-06-01 14:45:24 +02002089 return "<UNKNOWN: " + transition + ">";
Craig Mautner4b71aa12012-12-27 17:20:01 -08002090 }
2091 }
2092 }
2093
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002094 private String appStateToString() {
2095 switch (mAppTransitionState) {
2096 case APP_STATE_IDLE:
2097 return "APP_STATE_IDLE";
2098 case APP_STATE_READY:
2099 return "APP_STATE_READY";
2100 case APP_STATE_RUNNING:
2101 return "APP_STATE_RUNNING";
2102 case APP_STATE_TIMEOUT:
2103 return "APP_STATE_TIMEOUT";
2104 default:
2105 return "unknown state=" + mAppTransitionState;
2106 }
2107 }
2108
2109 private String transitTypeToString() {
2110 switch (mNextAppTransitionType) {
2111 case NEXT_TRANSIT_TYPE_NONE:
2112 return "NEXT_TRANSIT_TYPE_NONE";
2113 case NEXT_TRANSIT_TYPE_CUSTOM:
2114 return "NEXT_TRANSIT_TYPE_CUSTOM";
Winson Chung044d5292014-11-06 11:05:19 -08002115 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
2116 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002117 case NEXT_TRANSIT_TYPE_SCALE_UP:
2118 return "NEXT_TRANSIT_TYPE_SCALE_UP";
2119 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
2120 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
2121 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
2122 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
Winson Chunga4ccb862014-08-22 15:26:27 -07002123 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
2124 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
2125 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
2126 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
Tony Mak64b8d562017-12-28 17:44:02 +00002127 case NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:
2128 return "NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002129 default:
2130 return "unknown type=" + mNextAppTransitionType;
2131 }
2132 }
2133
Jeffrey Huangcb782852019-12-05 11:28:11 -08002134 void dumpDebug(ProtoOutputStream proto, long fieldId) {
Steven Timotiusaf03df62017-07-18 16:56:43 -07002135 final long token = proto.start(fieldId);
2136 proto.write(APP_TRANSITION_STATE, mAppTransitionState);
2137 proto.write(LAST_USED_APP_TRANSITION, mLastUsedAppTransition);
2138 proto.end(token);
2139 }
2140
Craig Mautner164d4bb2012-11-26 13:51:23 -08002141 @Override
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002142 public void dump(PrintWriter pw, String prefix) {
2143 pw.print(prefix); pw.println(this);
2144 pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002145 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002146 pw.print(prefix); pw.print("mNextAppTransitionType=");
2147 pw.println(transitTypeToString());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002148 }
2149 switch (mNextAppTransitionType) {
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002150 case NEXT_TRANSIT_TYPE_CUSTOM:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002151 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Craig Mautner164d4bb2012-11-26 13:51:23 -08002152 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002153 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
Craig Mautner164d4bb2012-11-26 13:51:23 -08002154 pw.print(Integer.toHexString(mNextAppTransitionEnter));
2155 pw.print(" mNextAppTransitionExit=0x");
2156 pw.println(Integer.toHexString(mNextAppTransitionExit));
2157 break;
Winson Chung044d5292014-11-06 11:05:19 -08002158 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002159 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Winson Chung044d5292014-11-06 11:05:19 -08002160 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002161 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
Winson Chung044d5292014-11-06 11:05:19 -08002162 pw.print(Integer.toHexString(mNextAppTransitionInPlace));
2163 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002164 case NEXT_TRANSIT_TYPE_SCALE_UP: {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002165 getDefaultNextAppTransitionStartRect(mTmpRect);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002166 pw.print(prefix); pw.print("mNextAppTransitionStartX=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002167 pw.print(mTmpRect.left);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002168 pw.print(" mNextAppTransitionStartY=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002169 pw.println(mTmpRect.top);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002170 pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002171 pw.print(mTmpRect.width());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002172 pw.print(" mNextAppTransitionStartHeight=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002173 pw.println(mTmpRect.height());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002174 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002175 }
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002176 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
2177 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
Winson Chunga4ccb862014-08-22 15:26:27 -07002178 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002179 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
2180 pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
2181 pw.println(mDefaultNextAppTransitionAnimationSpec);
2182 pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
2183 pw.println(mNextAppTransitionAnimationsSpecs);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002184 pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
2185 pw.println(mNextAppTransitionScaleUp);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002186 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002187 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002188 }
2189 if (mNextAppTransitionCallback != null) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002190 pw.print(prefix); pw.print("mNextAppTransitionCallback=");
2191 pw.println(mNextAppTransitionCallback);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002192 }
Chong Zhang60091a92016-07-27 17:52:45 -07002193 if (mLastUsedAppTransition != TRANSIT_NONE) {
2194 pw.print(prefix); pw.print("mLastUsedAppTransition=");
2195 pw.println(appTransitionToString(mLastUsedAppTransition));
2196 pw.print(prefix); pw.print("mLastOpeningApp=");
2197 pw.println(mLastOpeningApp);
2198 pw.print(prefix); pw.print("mLastClosingApp=");
2199 pw.println(mLastClosingApp);
Evan Rosky2289ba12018-11-19 18:28:18 -08002200 pw.print(prefix); pw.print("mLastChangingApp=");
2201 pw.println(mLastChangingApp);
Chong Zhang60091a92016-07-27 17:52:45 -07002202 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002203 }
Amith Yamasani4befbec2013-07-10 16:18:01 -07002204
2205 public void setCurrentUser(int newUserId) {
2206 mCurrentUserId = newUserId;
2207 }
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002208
2209 /**
2210 * @return true if transition is not running and should not be skipped, false if transition is
2211 * already running
2212 */
Jorim Jaggif84e2f62018-01-16 14:17:59 +01002213 boolean prepareAppTransitionLocked(@TransitionType int transit, boolean alwaysKeepCurrent,
2214 @TransitionFlags int flags, boolean forceOverride) {
Adrian Roosb125e0b2019-10-02 14:55:14 +02002215 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
2216 "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d "
2217 + "Callers=%s",
2218 appTransitionToString(transit), this, alwaysKeepCurrent,
2219 mDisplayContent.getDisplayId(), Debug.getCallers(5));
Jorim Jaggi9c52ebb2018-06-01 14:45:24 +02002220 final boolean allowSetCrashing = !isKeyguardTransit(mNextAppTransition)
2221 && transit == TRANSIT_CRASHING_ACTIVITY_CLOSE;
Jorim Jaggife762342016-10-13 14:33:27 +02002222 if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
Jorim Jaggi9c52ebb2018-06-01 14:45:24 +02002223 || mNextAppTransition == TRANSIT_NONE || allowSetCrashing) {
Jorim Jaggife762342016-10-13 14:33:27 +02002224 setAppTransition(transit, flags);
Jorim Jaggia69243a2017-06-15 15:10:38 -04002225 }
2226 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
Adrian Roos93577212018-04-10 14:12:10 -07002227 // relies on the fact that we always execute a Keyguard transition after preparing one. We
2228 // also don't want to change away from a crashing transition.
Jorim Jaggi9c52ebb2018-06-01 14:45:24 +02002229 else if (!alwaysKeepCurrent && !isKeyguardTransit(mNextAppTransition)
2230 && mNextAppTransition != TRANSIT_CRASHING_ACTIVITY_CLOSE) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002231 if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
2232 // Opening a new task always supersedes a close for the anim.
Jorim Jaggife762342016-10-13 14:33:27 +02002233 setAppTransition(transit, flags);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002234 } else if (transit == TRANSIT_ACTIVITY_OPEN
2235 && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
2236 // Opening a new activity always supersedes a close for the anim.
Jorim Jaggife762342016-10-13 14:33:27 +02002237 setAppTransition(transit, flags);
Jorim Jaggicecf4242018-02-21 18:46:53 +01002238 } else if (isTaskTransit(transit) && isActivityTransit(mNextAppTransition)) {
2239 // Task animations always supersede activity animations, because if we have both, it
2240 // usually means that activity transition were just trampoline activities.
2241 setAppTransition(transit, flags);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002242 }
2243 }
2244 boolean prepared = prepare();
2245 if (isTransitionSet()) {
lumark23b54592018-10-02 17:17:23 +08002246 removeAppTransitionTimeoutCallbacks();
2247 mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable, APP_TRANSITION_TIMEOUT_MS);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002248 }
2249 return prepared;
2250 }
Winsonb2024762016-04-05 17:32:30 -07002251
2252 /**
Jorim Jaggife762342016-10-13 14:33:27 +02002253 * @return true if {@param transit} is representing a transition in which Keyguard is going
2254 * away, false otherwise
2255 */
2256 public static boolean isKeyguardGoingAwayTransit(int transit) {
2257 return transit == TRANSIT_KEYGUARD_GOING_AWAY
2258 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
2259 }
2260
2261 private static boolean isKeyguardTransit(int transit) {
2262 return isKeyguardGoingAwayTransit(transit) || transit == TRANSIT_KEYGUARD_OCCLUDE
2263 || transit == TRANSIT_KEYGUARD_UNOCCLUDE;
2264 }
2265
Jorim Jaggi98a9d202018-03-26 16:17:07 +02002266 static boolean isTaskTransit(int transit) {
2267 return isTaskOpenTransit(transit)
Jorim Jaggicecf4242018-02-21 18:46:53 +01002268 || transit == TRANSIT_TASK_CLOSE
Issei Suzukid1966372019-10-10 15:06:20 +02002269 || transit == TRANSIT_TASK_TO_BACK;
Jorim Jaggicecf4242018-02-21 18:46:53 +01002270 }
2271
Jorim Jaggi98a9d202018-03-26 16:17:07 +02002272 private static boolean isTaskOpenTransit(int transit) {
2273 return transit == TRANSIT_TASK_OPEN
2274 || transit == TRANSIT_TASK_OPEN_BEHIND
2275 || transit == TRANSIT_TASK_TO_FRONT;
2276 }
2277
2278 static boolean isActivityTransit(int transit) {
Jorim Jaggicecf4242018-02-21 18:46:53 +01002279 return transit == TRANSIT_ACTIVITY_OPEN
2280 || transit == TRANSIT_ACTIVITY_CLOSE
2281 || transit == TRANSIT_ACTIVITY_RELAUNCH;
2282 }
2283
Evan Roskyec9488c2019-03-01 19:32:12 -08002284 static boolean isChangeTransit(int transit) {
2285 return transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE;
2286 }
2287
Jorim Jaggife762342016-10-13 14:33:27 +02002288 /**
Manu Cornetd7376802017-01-13 13:44:07 -08002289 * @return whether the transition should show the thumbnail being scaled down.
2290 */
2291 private boolean shouldScaleDownThumbnailTransition(int uiMode, int orientation) {
Sid Soundararajan0e88d322017-03-07 15:37:30 -08002292 return mGridLayoutRecentsEnabled
Manu Cornetd7376802017-01-13 13:44:07 -08002293 || orientation == Configuration.ORIENTATION_PORTRAIT;
2294 }
lumark23b54592018-10-02 17:17:23 +08002295
2296 private void handleAppTransitionTimeout() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -07002297 synchronized (mService.mGlobalLock) {
lumark588a3e82018-07-20 18:53:54 +08002298 final DisplayContent dc = mDisplayContent;
2299 if (dc == null) {
2300 return;
2301 }
Evan Rosky2289ba12018-11-19 18:28:18 -08002302 if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty()
2303 || !dc.mChangingApps.isEmpty()) {
Adrian Roosb125e0b2019-10-02 14:55:14 +02002304 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
2305 "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b "
2306 + "mOpeningApps.size()=%d mClosingApps.size()=%d "
2307 + "mChangingApps.size()=%d",
2308 dc.getDisplayId(), dc.mAppTransition.isTransitionSet(),
2309 dc.mOpeningApps.size(), dc.mClosingApps.size(),
2310 dc.mChangingApps.size());
2311
lumark23b54592018-10-02 17:17:23 +08002312 setTimeout();
2313 mService.mWindowPlacerLocked.performSurfacePlacement();
2314 }
2315 }
2316 }
2317
2318 private static void doAnimationCallback(@NonNull IRemoteCallback callback) {
2319 try {
2320 ((IRemoteCallback) callback).sendResult(null);
2321 } catch (RemoteException e) {
2322 }
2323 }
2324
2325 void removeAppTransitionTimeoutCallbacks() {
2326 mHandler.removeCallbacks(mHandleAppTransitionTimeoutRunnable);
2327 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002328}