blob: c6f156b9e5346e5db58369b61bfe67180acb7f74 [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;
23import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
24import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
25import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
26import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
27import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
28import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
29import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
30import static android.view.WindowManager.TRANSIT_NONE;
31import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
Jorim Jaggicecf4242018-02-21 18:46:53 +010032import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010033import static android.view.WindowManager.TRANSIT_TASK_OPEN;
34import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
35import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
36import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
Jorim Jaggi98a9d202018-03-26 16:17:07 +020037import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
38import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010039import static android.view.WindowManager.TRANSIT_UNSET;
40import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
41import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
42import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
43import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
Tony Mak83546a82018-01-22 13:56:20 +000044
Filip Gruszczynski82861362015-10-16 14:21:09 -070045import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
46import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
47import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
48import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
49import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
50import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
51import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
52import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
53import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
54import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
55import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
56import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
57import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
58import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
59import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
60import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
61import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
62import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
63import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
64import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
65import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
66import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
Filip Gruszczynski198dcbf2016-01-18 10:02:00 -080067import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
68import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080069import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
70import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Adrian Roose99bc052017-11-20 17:55:31 +010071import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
Tony Mak089c35e2017-12-18 20:34:14 +000072import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
Matthew Ngbf1d9852017-03-14 12:23:09 -070073import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +010074import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070075import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
76import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
Filip Gruszczynski82861362015-10-16 14:21:09 -070077
Tony Mak64b8d562017-12-28 17:44:02 +000078import android.annotation.DrawableRes;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -070079import android.annotation.Nullable;
Matthew Ng43db6d22017-06-27 15:29:39 -070080import android.app.ActivityManager;
Tony Mak089c35e2017-12-18 20:34:14 +000081import android.content.ComponentName;
Craig Mautner164d4bb2012-11-26 13:51:23 -080082import android.content.Context;
Winson21700932016-03-24 17:26:23 -070083import android.content.res.Configuration;
John Reck519ad482018-02-12 17:08:48 -080084import android.graphics.Bitmap;
85import android.graphics.Canvas;
Tony Mak64b8d562017-12-28 17:44:02 +000086import android.graphics.Color;
Winson Chungaa7fa012017-05-24 15:50:06 -070087import android.graphics.GraphicBuffer;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +010088import android.graphics.Path;
John Reck519ad482018-02-12 17:08:48 -080089import android.graphics.Picture;
Winson Chung399f6202014-03-19 10:47:20 -070090import android.graphics.Rect;
Tony Mak64b8d562017-12-28 17:44:02 +000091import android.graphics.drawable.Drawable;
Jorim Jaggied410b62017-05-05 15:16:14 +020092import android.os.Binder;
Craig Mautner164d4bb2012-11-26 13:51:23 -080093import android.os.Debug;
Jorim Jaggi77ba4802015-02-18 13:57:50 +010094import android.os.IBinder;
Craig Mautner164d4bb2012-11-26 13:51:23 -080095import android.os.IRemoteCallback;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +010096import android.os.RemoteException;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020097import android.os.SystemClock;
Manu Cornetd7376802017-01-13 13:44:07 -080098import android.os.SystemProperties;
Tony Mak089c35e2017-12-18 20:34:14 +000099import android.os.UserHandle;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800100import android.util.ArraySet;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800101import android.util.Slog;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700102import android.util.SparseArray;
Steven Timotiusaf03df62017-07-18 16:56:43 -0700103import android.util.proto.ProtoOutputStream;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700104import android.view.AppTransitionAnimationSpec;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100105import android.view.IAppTransitionAnimationSpecsFuture;
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100106import android.view.RemoteAnimationAdapter;
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100107import android.view.WindowManager.TransitionFlags;
108import android.view.WindowManager.TransitionType;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800109import android.view.animation.AlphaAnimation;
110import android.view.animation.Animation;
111import android.view.animation.AnimationSet;
112import android.view.animation.AnimationUtils;
Winson Chung399f6202014-03-19 10:47:20 -0700113import android.view.animation.ClipRectAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800114import android.view.animation.Interpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700115import android.view.animation.PathInterpolator;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800116import android.view.animation.ScaleAnimation;
Winson Chung399f6202014-03-19 10:47:20 -0700117import android.view.animation.TranslateAnimation;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700118
Jorim Jaggi98a9d202018-03-26 16:17:07 +0200119import com.android.internal.R;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800120import com.android.internal.util.DumpUtils.Dump;
121import com.android.server.AttributeCache;
122import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800123import com.android.server.wm.animation.ClipRectLRAnimation;
124import com.android.server.wm.animation.ClipRectTBAnimation;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100125import com.android.server.wm.animation.CurvedTranslateAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800126
127import java.io.PrintWriter;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100128import java.util.ArrayList;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100129import java.util.concurrent.ExecutorService;
130import java.util.concurrent.Executors;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800131
Craig Mautner164d4bb2012-11-26 13:51:23 -0800132// State management of app transitions. When we are preparing for a
133// transition, mNextAppTransition will be the kind of transition to
134// perform or TRANSIT_NONE if we are not waiting. If we are waiting,
135// mOpeningApps and mClosingApps are the lists of tokens that will be
136// made visible or hidden at the next transition.
137public class AppTransition implements Dump {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800138 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700139 private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800140
Winson Chunga4ccb862014-08-22 15:26:27 -0700141 /** Fraction of animation at which the recents thumbnail stays completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700142 private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800143 /** Fraction of animation at which the recents thumbnail becomes completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700144 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800145
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800146 static final int DEFAULT_APP_TRANSITION_DURATION = 336;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800147
148 /** Interpolator to be used for animations that respond directly to a touch */
149 static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
150 new PathInterpolator(0.3f, 0f, 0.1f, 1f);
151
Jorim Jaggic69bd222016-03-15 14:38:37 +0100152 private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR =
153 new PathInterpolator(0.85f, 0f, 1f, 1f);
154
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800155 /**
156 * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
157 * involved, to make it more understandable.
158 */
159 private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700160 private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700161 private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800162
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800163 private final Context mContext;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800164 private final WindowManagerService mService;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800165
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100166 private @TransitionType int mNextAppTransition = TRANSIT_UNSET;
167 private @TransitionFlags int mNextAppTransitionFlags = 0;
Chong Zhang60091a92016-07-27 17:52:45 -0700168 private int mLastUsedAppTransition = TRANSIT_UNSET;
169 private String mLastOpeningApp;
170 private String mLastClosingApp;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800171
172 private static final int NEXT_TRANSIT_TYPE_NONE = 0;
173 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
174 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
175 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
176 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
Winson Chunga4ccb862014-08-22 15:26:27 -0700177 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
178 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
Winson Chung044d5292014-11-06 11:05:19 -0800179 private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
Chet Haase10e23ab2015-02-11 15:08:38 -0800180 private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
Tony Mak089c35e2017-12-18 20:34:14 +0000181
182 /**
183 * Refers to the transition to activity started by using {@link
184 * android.content.pm.crossprofile.CrossProfileApps#startMainActivity(ComponentName, UserHandle)
185 * }.
186 */
187 private static final int NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS = 9;
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100188 private static final int NEXT_TRANSIT_TYPE_REMOTE = 10;
189
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800190 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
191
Winson Chung399f6202014-03-19 10:47:20 -0700192 // These are the possible states for the enter/exit activities during a thumbnail transition
193 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
194 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
195 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
196 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
197
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800198 private String mNextAppTransitionPackage;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800199 // Used for thumbnail transitions. True if we're scaling up, false if scaling down
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800200 private boolean mNextAppTransitionScaleUp;
201 private IRemoteCallback mNextAppTransitionCallback;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +0100202 private IRemoteCallback mNextAppTransitionFutureCallback;
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -0700203 private IRemoteCallback mAnimationFinishedCallback;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800204 private int mNextAppTransitionEnter;
205 private int mNextAppTransitionExit;
Winson Chung044d5292014-11-06 11:05:19 -0800206 private int mNextAppTransitionInPlace;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700207
208 // Keyed by task id.
209 private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
210 = new SparseArray<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100211 private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
212 private boolean mNextAppTransitionAnimationsSpecsPending;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700213 private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
214
Winson Chunga4ccb862014-08-22 15:26:27 -0700215 private Rect mNextAppTransitionInsets = new Rect();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800216
Winson Chung2820c452014-04-15 15:34:44 -0700217 private Rect mTmpFromClipRect = new Rect();
218 private Rect mTmpToClipRect = new Rect();
219
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700220 private final Rect mTmpRect = new Rect();
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700221
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800222 private final static int APP_STATE_IDLE = 0;
223 private final static int APP_STATE_READY = 1;
224 private final static int APP_STATE_RUNNING = 2;
225 private final static int APP_STATE_TIMEOUT = 3;
226 private int mAppTransitionState = APP_STATE_IDLE;
227
228 private final int mConfigShortAnimTime;
Craig Mautner321bdf52012-12-18 09:53:24 -0800229 private final Interpolator mDecelerateInterpolator;
Winson Chunga4ccb862014-08-22 15:26:27 -0700230 private final Interpolator mThumbnailFadeInInterpolator;
231 private final Interpolator mThumbnailFadeOutInterpolator;
Chet Haase10e23ab2015-02-11 15:08:38 -0800232 private final Interpolator mLinearOutSlowInInterpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700233 private final Interpolator mFastOutLinearInInterpolator;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100234 private final Interpolator mFastOutSlowInInterpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700235 private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
236
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700237 private final int mClipRevealTranslationY;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800238
Amith Yamasani4befbec2013-07-10 16:18:01 -0700239 private int mCurrentUserId = 0;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800240 private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
Amith Yamasani4befbec2013-07-10 16:18:01 -0700241
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100242 private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100243 private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100244
Jorim Jaggif97ed922016-02-18 18:57:07 -0800245 private int mLastClipRevealMaxTranslation;
246 private boolean mLastHadClipReveal;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700247 private boolean mProlongedAnimationsEnded;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800248
Manu Cornetd7376802017-01-13 13:44:07 -0800249 private final boolean mGridLayoutRecentsEnabled;
Matthew Ng43db6d22017-06-27 15:29:39 -0700250 private final boolean mLowRamRecentsEnabled;
Manu Cornetd7376802017-01-13 13:44:07 -0800251
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100252 private RemoteAnimationController mRemoteAnimationController;
253
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800254 AppTransition(Context context, WindowManagerService service) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800255 mContext = context;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800256 mService = service;
Chet Haase10e23ab2015-02-11 15:08:38 -0800257 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
258 com.android.internal.R.interpolator.linear_out_slow_in);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700259 mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
260 com.android.internal.R.interpolator.fast_out_linear_in);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100261 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
262 com.android.internal.R.interpolator.fast_out_slow_in);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800263 mConfigShortAnimTime = context.getResources().getInteger(
264 com.android.internal.R.integer.config_shortAnimTime);
Craig Mautner321bdf52012-12-18 09:53:24 -0800265 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
266 com.android.internal.R.interpolator.decelerate_cubic);
Winson Chunga4ccb862014-08-22 15:26:27 -0700267 mThumbnailFadeInInterpolator = new Interpolator() {
268 @Override
269 public float getInterpolation(float input) {
270 // Linear response for first fraction, then complete after that.
271 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
272 return 0f;
273 }
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700274 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /
Winson Chunga4ccb862014-08-22 15:26:27 -0700275 (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700276 return mFastOutLinearInInterpolator.getInterpolation(t);
Winson Chunga4ccb862014-08-22 15:26:27 -0700277 }
278 };
279 mThumbnailFadeOutInterpolator = new Interpolator() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800280 @Override
281 public float getInterpolation(float input) {
282 // Linear response for first fraction, then complete after that.
283 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700284 float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
285 return mLinearOutSlowInInterpolator.getInterpolation(t);
Craig Mautner321bdf52012-12-18 09:53:24 -0800286 }
Winson Chunga4ccb862014-08-22 15:26:27 -0700287 return 1f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800288 }
289 };
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700290 mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP
291 * mContext.getResources().getDisplayMetrics().density);
Manu Cornetd7376802017-01-13 13:44:07 -0800292 mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
Matthew Ng43db6d22017-06-27 15:29:39 -0700293 mLowRamRecentsEnabled = ActivityManager.isLowRamDeviceStatic();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800294 }
295
296 boolean isTransitionSet() {
297 return mNextAppTransition != TRANSIT_UNSET;
298 }
299
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100300 boolean isTransitionEqual(@TransitionType int transit) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800301 return mNextAppTransition == transit;
302 }
303
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100304 @TransitionType int getAppTransition() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800305 return mNextAppTransition;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800306 }
307
Jorim Jaggife762342016-10-13 14:33:27 +0200308 private void setAppTransition(int transit, int flags) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800309 mNextAppTransition = transit;
Jorim Jaggife762342016-10-13 14:33:27 +0200310 mNextAppTransitionFlags |= flags;
Chong Zhang60091a92016-07-27 17:52:45 -0700311 setLastAppTransition(TRANSIT_UNSET, null, null);
Jorim Jaggi245281c2017-06-07 14:33:04 -0700312 updateBooster();
Chong Zhang60091a92016-07-27 17:52:45 -0700313 }
314
315 void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp) {
316 mLastUsedAppTransition = transit;
317 mLastOpeningApp = "" + openingApp;
318 mLastClosingApp = "" + closingApp;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800319 }
320
321 boolean isReady() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800322 return mAppTransitionState == APP_STATE_READY
323 || mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800324 }
325
Craig Mautnerae446592012-12-06 19:05:05 -0800326 void setReady() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700327 setAppTransitionState(APP_STATE_READY);
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100328 fetchAppTransitionSpecsFromFuture();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800329 }
330
331 boolean isRunning() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800332 return mAppTransitionState == APP_STATE_RUNNING;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800333 }
334
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800335 void setIdle() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700336 setAppTransitionState(APP_STATE_IDLE);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800337 }
338
339 boolean isTimeout() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800340 return mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800341 }
342
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800343 void setTimeout() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700344 setAppTransitionState(APP_STATE_TIMEOUT);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800345 }
346
Winson Chungaa7fa012017-05-24 15:50:06 -0700347 GraphicBuffer getAppTransitionThumbnailHeader(int taskId) {
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700348 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800349 if (spec == null) {
350 spec = mDefaultNextAppTransitionAnimationSpec;
351 }
Winson Chungaa7fa012017-05-24 15:50:06 -0700352 return spec != null ? spec.buffer : null;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800353 }
354
Winson Chunga4ccb862014-08-22 15:26:27 -0700355 /** Returns whether the next thumbnail transition is aspect scaled up. */
356 boolean isNextThumbnailTransitionAspectScaled() {
357 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
358 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
359 }
360
361 /** Returns whether the next thumbnail transition is scaling up. */
362 boolean isNextThumbnailTransitionScaleUp() {
363 return mNextAppTransitionScaleUp;
364 }
365
Filip Gruszczynski4cbc3152015-12-07 11:50:57 -0800366 boolean isNextAppTransitionThumbnailUp() {
367 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
368 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP;
369 }
370
371 boolean isNextAppTransitionThumbnailDown() {
372 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN ||
373 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
374 }
375
Tony Mak64b8d562017-12-28 17:44:02 +0000376
377 boolean isNextAppTransitionOpenCrossProfileApps() {
378 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
379 }
380
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100381 /**
382 * @return true if and only if we are currently fetching app transition specs from the future
383 * passed into {@link #overridePendingAppTransitionMultiThumbFuture}
384 */
385 boolean isFetchingAppTransitionsSpecs() {
386 return mNextAppTransitionAnimationsSpecsPending;
387 }
388
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700389 private boolean prepare() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800390 if (!isRunning()) {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700391 setAppTransitionState(APP_STATE_IDLE);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100392 notifyAppTransitionPendingLocked();
Jorim Jaggif97ed922016-02-18 18:57:07 -0800393 mLastHadClipReveal = false;
394 mLastClipRevealMaxTranslation = 0;
395 mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700396 return true;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800397 }
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700398 return false;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800399 }
400
Jorim Jaggife762342016-10-13 14:33:27 +0200401 /**
402 * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
403 * layout pass needs to be done
404 */
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200405 int goodToGo(int transit, AppWindowToken topOpeningApp,
406 AppWindowToken topClosingApp, ArraySet<AppWindowToken> openingApps,
Jorim Jaggife762342016-10-13 14:33:27 +0200407 ArraySet<AppWindowToken> closingApps) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800408 mNextAppTransition = TRANSIT_UNSET;
Jorim Jaggife762342016-10-13 14:33:27 +0200409 mNextAppTransitionFlags = 0;
Jorim Jaggi245281c2017-06-07 14:33:04 -0700410 setAppTransitionState(APP_STATE_RUNNING);
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200411 final AnimationAdapter topOpeningAnim = topOpeningApp != null
412 ? topOpeningApp.getAnimation()
413 : null;
Jorim Jaggife762342016-10-13 14:33:27 +0200414 int redoLayout = notifyAppTransitionStartingLocked(transit,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200415 topOpeningApp != null ? topOpeningApp.token : null,
416 topClosingApp != null ? topClosingApp.token : null,
417 topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0,
418 topOpeningAnim != null
419 ? topOpeningAnim.getStatusBarTransitionsStartTime()
420 : SystemClock.uptimeMillis(),
421 AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800422 mService.getDefaultDisplayContentLocked().getDockedDividerController()
Jorim Jaggife762342016-10-13 14:33:27 +0200423 .notifyAppTransitionStarting(openingApps, transit);
Jorim Jaggi363ab982016-04-26 19:51:20 -0700424
425 // Prolong the start for the transition when docking a task from recents, unless recents
426 // ended it already then we don't need to wait.
Jorim Jaggife762342016-10-13 14:33:27 +0200427 if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) {
Jorim Jaggi363ab982016-04-26 19:51:20 -0700428 for (int i = openingApps.size() - 1; i >= 0; i--) {
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200429 final AppWindowToken app = openingApps.valueAt(i);
430 app.startDelayingAnimationStart();
Jorim Jaggi363ab982016-04-26 19:51:20 -0700431 }
432 }
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100433 if (mRemoteAnimationController != null) {
434 mRemoteAnimationController.goodToGo();
435 }
Jorim Jaggife762342016-10-13 14:33:27 +0200436 return redoLayout;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700437 }
438
439 /**
440 * Let the transitions manager know that the somebody wanted to end the prolonged animations.
441 */
442 void notifyProlongedAnimationsEnded() {
443 mProlongedAnimationsEnded = true;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800444 }
445
446 void clear() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800447 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800448 mNextAppTransitionPackage = null;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700449 mNextAppTransitionAnimationsSpecs.clear();
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100450 mRemoteAnimationController = null;
Jorim Jaggi65193992015-11-23 16:49:59 -0800451 mNextAppTransitionAnimationsSpecsFuture = null;
452 mDefaultNextAppTransitionAnimationSpec = null;
453 mAnimationFinishedCallback = null;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700454 mProlongedAnimationsEnded = false;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800455 }
456
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800457 void freeze() {
Jorim Jaggife762342016-10-13 14:33:27 +0200458 final int transit = mNextAppTransition;
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100459 setAppTransition(TRANSIT_UNSET, 0 /* flags */);
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800460 clear();
461 setReady();
Jorim Jaggife762342016-10-13 14:33:27 +0200462 notifyAppTransitionCancelledLocked(transit);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100463 }
464
Jorim Jaggi245281c2017-06-07 14:33:04 -0700465 private void setAppTransitionState(int state) {
466 mAppTransitionState = state;
467 updateBooster();
468 }
469
470 /**
471 * Updates whether we currently boost wm locked sections and the animation thread. We want to
472 * boost the priorities to a more important value whenever an app transition is going to happen
473 * soon or an app transition is running.
474 */
Jorim Jaggic8cc2292018-03-15 20:16:15 +0100475 void updateBooster() {
476 WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning(needsBoosting());
477 }
478
479 private boolean needsBoosting() {
480 final boolean recentsAnimRunning = mService.getRecentsAnimationController() != null;
481 return mNextAppTransition != TRANSIT_UNSET
482 || mAppTransitionState == APP_STATE_READY
483 || mAppTransitionState == APP_STATE_RUNNING
484 || recentsAnimRunning;
Jorim Jaggi245281c2017-06-07 14:33:04 -0700485 }
486
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100487 void registerListenerLocked(AppTransitionListener listener) {
488 mListeners.add(listener);
489 }
490
Wale Ogunwalea48eadb2015-05-14 17:43:12 -0700491 public void notifyAppTransitionFinishedLocked(IBinder token) {
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100492 for (int i = 0; i < mListeners.size(); i++) {
493 mListeners.get(i).onAppTransitionFinishedLocked(token);
494 }
495 }
496
497 private void notifyAppTransitionPendingLocked() {
498 for (int i = 0; i < mListeners.size(); i++) {
499 mListeners.get(i).onAppTransitionPendingLocked();
500 }
501 }
502
Jorim Jaggife762342016-10-13 14:33:27 +0200503 private void notifyAppTransitionCancelledLocked(int transit) {
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100504 for (int i = 0; i < mListeners.size(); i++) {
Jorim Jaggife762342016-10-13 14:33:27 +0200505 mListeners.get(i).onAppTransitionCancelledLocked(transit);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100506 }
507 }
508
Jorim Jaggife762342016-10-13 14:33:27 +0200509 private int notifyAppTransitionStartingLocked(int transit, IBinder openToken,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200510 IBinder closeToken, long duration, long statusBarAnimationStartTime,
511 long statusBarAnimationDuration) {
Jorim Jaggife762342016-10-13 14:33:27 +0200512 int redoLayout = 0;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100513 for (int i = 0; i < mListeners.size(); i++) {
Jorim Jaggife762342016-10-13 14:33:27 +0200514 redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, openToken,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200515 closeToken, duration, statusBarAnimationStartTime, statusBarAnimationDuration);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100516 }
Jorim Jaggife762342016-10-13 14:33:27 +0200517 return redoLayout;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800518 }
519
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100520 private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800521 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
522 + (lp != null ? lp.packageName : null)
523 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
524 if (lp != null && lp.windowAnimations != 0) {
525 // If this is a system resource, don't try to load it from the
526 // application resources. It is nice to avoid loading application
527 // resources if we can.
528 String packageName = lp.packageName != null ? lp.packageName : "android";
529 int resId = lp.windowAnimations;
530 if ((resId&0xFF000000) == 0x01000000) {
531 packageName = "android";
532 }
533 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
534 + packageName);
535 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700536 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800537 }
538 return null;
539 }
540
541 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
542 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
543 + packageName + " resId=0x" + Integer.toHexString(resId));
544 if (packageName != null) {
545 if ((resId&0xFF000000) == 0x01000000) {
546 packageName = "android";
547 }
548 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
549 + packageName);
550 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700551 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800552 }
553 return null;
554 }
555
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100556 Animation loadAnimationAttr(LayoutParams lp, int animAttr) {
Jorim Jaggi5f95b002018-04-19 13:27:52 +0000557 int anim = 0;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800558 Context context = mContext;
Jorim Jaggi5f95b002018-04-19 13:27:52 +0000559 if (animAttr >= 0) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800560 AttributeCache.Entry ent = getCachedAnimations(lp);
561 if (ent != null) {
562 context = ent.context;
563 anim = ent.array.getResourceId(animAttr, 0);
564 }
565 }
Jorim Jaggi5f95b002018-04-19 13:27:52 +0000566 if (anim != 0) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800567 return AnimationUtils.loadAnimation(context, anim);
568 }
569 return null;
570 }
571
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100572 Animation loadAnimationRes(LayoutParams lp, int resId) {
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700573 Context context = mContext;
Jorim Jaggi5f95b002018-04-19 13:27:52 +0000574 if (resId >= 0) {
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700575 AttributeCache.Entry ent = getCachedAnimations(lp);
576 if (ent != null) {
577 context = ent.context;
578 }
579 return AnimationUtils.loadAnimation(context, resId);
580 }
581 return null;
582 }
583
584 private Animation loadAnimationRes(String packageName, int resId) {
Jorim Jaggi5f95b002018-04-19 13:27:52 +0000585 int anim = 0;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800586 Context context = mContext;
Jorim Jaggi5f95b002018-04-19 13:27:52 +0000587 if (resId >= 0) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800588 AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
589 if (ent != null) {
590 context = ent.context;
591 anim = resId;
592 }
593 }
Jorim Jaggi5f95b002018-04-19 13:27:52 +0000594 if (anim != 0) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800595 return AnimationUtils.loadAnimation(context, anim);
596 }
597 return null;
598 }
599
Craig Mautner164d4bb2012-11-26 13:51:23 -0800600 /**
601 * Compute the pivot point for an animation that is scaling from a small
602 * rect on screen to a larger rect. The pivot point varies depending on
603 * the distance between the inner and outer edges on both sides. This
604 * function computes the pivot point for one dimension.
605 * @param startPos Offset from left/top edge of outer rectangle to
606 * left/top edge of inner rectangle.
607 * @param finalScale The scaling factor between the size of the outer
608 * and inner rectangles.
609 */
610 private static float computePivot(int startPos, float finalScale) {
Jorim Jaggic6c89a82016-01-28 17:48:21 -0800611
612 /*
613 Theorem of intercepting lines:
614
615 + + +-----------------------------------------------+
616 | | | |
617 | | | |
618 | | | |
619 | | | |
620 x | y | | |
621 | | | |
622 | | | |
623 | | | |
624 | | | |
625 | + | +--------------------+ |
626 | | | | |
627 | | | | |
628 | | | | |
629 | | | | |
630 | | | | |
631 | | | | |
632 | | | | |
633 | | | | |
634 | | | | |
635 | | | | |
636 | | | | |
637 | | | | |
638 | | | | |
639 | | | | |
640 | | | | |
641 | | | | |
642 | | | | |
643 | | +--------------------+ |
644 | | |
645 | | |
646 | | |
647 | | |
648 | | |
649 | | |
650 | | |
651 | +-----------------------------------------------+
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 + ++
662 p ++
663
664 scale = (x - y) / x
665 <=> x = -y / (scale - 1)
666 */
Craig Mautner164d4bb2012-11-26 13:51:23 -0800667 final float denom = finalScale-1;
668 if (Math.abs(denom) < .0001f) {
669 return startPos;
670 }
671 return -startPos / denom;
672 }
673
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700674 private Animation createScaleUpAnimationLocked(int transit, boolean enter,
675 Rect containingFrame) {
676 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700677 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700678 final int appWidth = containingFrame.width();
679 final int appHeight = containingFrame.height();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800680 if (enter) {
681 // Entering app zooms out from the center of the initial rect.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700682 float scaleW = mTmpRect.width() / (float) appWidth;
683 float scaleH = mTmpRect.height() / (float) appHeight;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800684 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700685 computePivot(mTmpRect.left, scaleW),
Winson4c3fecd2016-07-13 12:29:48 -0700686 computePivot(mTmpRect.top, scaleH));
Craig Mautner321bdf52012-12-18 09:53:24 -0800687 scale.setInterpolator(mDecelerateInterpolator);
688
Craig Mautner164d4bb2012-11-26 13:51:23 -0800689 Animation alpha = new AlphaAnimation(0, 1);
Winson Chunga4ccb862014-08-22 15:26:27 -0700690 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
Craig Mautner321bdf52012-12-18 09:53:24 -0800691
692 AnimationSet set = new AnimationSet(false);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800693 set.addAnimation(scale);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800694 set.addAnimation(alpha);
695 set.setDetachWallpaper(true);
696 a = set;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800697 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
698 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800699 // If we are on top of the wallpaper, we need an animation that
700 // correctly handles the wallpaper staying static behind all of
701 // the animated elements. To do this, will just have the existing
702 // element fade out.
703 a = new AlphaAnimation(1, 0);
704 a.setDetachWallpaper(true);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800705 } else {
Craig Mautner321bdf52012-12-18 09:53:24 -0800706 // For normal animations, the exiting element just holds in place.
707 a = new AlphaAnimation(1, 1);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800708 }
Craig Mautner321bdf52012-12-18 09:53:24 -0800709
710 // Pick the desired duration. If this is an inter-activity transition,
711 // it is the standard duration for that. Otherwise we use the longer
712 // task transition duration.
713 final long duration;
714 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800715 case TRANSIT_ACTIVITY_OPEN:
716 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800717 duration = mConfigShortAnimTime;
718 break;
719 default:
720 duration = DEFAULT_APP_TRANSITION_DURATION;
721 break;
722 }
723 a.setDuration(duration);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800724 a.setFillAfter(true);
Craig Mautner321bdf52012-12-18 09:53:24 -0800725 a.setInterpolator(mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800726 a.initialize(appWidth, appHeight, appWidth, appHeight);
727 return a;
728 }
729
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700730 private void getDefaultNextAppTransitionStartRect(Rect rect) {
731 if (mDefaultNextAppTransitionAnimationSpec == null ||
732 mDefaultNextAppTransitionAnimationSpec.rect == null) {
Jorim Jaggi2550f3f2017-03-14 20:15:59 +0100733 Slog.e(TAG, "Starting rect for app requested, but none available", new Throwable());
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700734 rect.setEmpty();
735 } else {
736 rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
737 }
738 }
739
740 void getNextAppTransitionStartRect(int taskId, Rect rect) {
741 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800742 if (spec == null) {
743 spec = mDefaultNextAppTransitionAnimationSpec;
744 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700745 if (spec == null || spec.rect == null) {
Jorim Jaggi2550f3f2017-03-14 20:15:59 +0100746 Slog.e(TAG, "Starting rect for task: " + taskId + " requested, but not available",
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700747 new Throwable());
748 rect.setEmpty();
749 } else {
750 rect.set(spec.rect);
751 }
752 }
753
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800754 private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height,
Winson Chungaa7fa012017-05-24 15:50:06 -0700755 GraphicBuffer buffer) {
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700756 mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
Winson Chungaa7fa012017-05-24 15:50:06 -0700757 buffer, new Rect(left, top, left + width, top + height));
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700758 }
759
Jorim Jaggif97ed922016-02-18 18:57:07 -0800760 /**
761 * @return the duration of the last clip reveal animation
762 */
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800763 long getLastClipRevealTransitionDuration() {
764 return mLastClipRevealTransitionDuration;
765 }
766
767 /**
Jorim Jaggif97ed922016-02-18 18:57:07 -0800768 * @return the maximum distance the app surface is traveling of the last clip reveal animation
769 */
770 int getLastClipRevealMaxTranslation() {
771 return mLastClipRevealMaxTranslation;
772 }
773
774 /**
775 * @return true if in the last app transition had a clip reveal animation, false otherwise
776 */
777 boolean hadClipRevealAnimation() {
778 return mLastHadClipReveal;
779 }
780
781 /**
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800782 * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
783 * the start rect is outside of the target rect, and there is a lot of movement going on.
784 *
785 * @param cutOff whether the start rect was not fully contained by the end rect
786 * @param translationX the total translation the surface moves in x direction
787 * @param translationY the total translation the surfaces moves in y direction
788 * @param displayFrame our display frame
789 *
790 * @return the duration of the clip reveal animation, in milliseconds
791 */
792 private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX,
793 float translationY, Rect displayFrame) {
794 if (!cutOff) {
795 return DEFAULT_APP_TRANSITION_DURATION;
796 }
797 final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(),
798 Math.abs(translationY) / displayFrame.height());
799 return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction *
800 (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION));
801 }
802
803 private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame,
804 Rect displayFrame) {
Chet Haase10e23ab2015-02-11 15:08:38 -0800805 final Animation anim;
806 if (enter) {
Craig Mautner80b1f642015-04-22 10:59:09 -0700807 final int appWidth = appFrame.width();
808 final int appHeight = appFrame.height();
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800809
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700810 // mTmpRect will contain an area around the launcher icon that was pressed. We will
Filip Gruszczynski82861362015-10-16 14:21:09 -0700811 // clip reveal from that area in the final area of the app.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700812 getDefaultNextAppTransitionStartRect(mTmpRect);
Craig Mautner80b1f642015-04-22 10:59:09 -0700813
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700814 float t = 0f;
815 if (appHeight > 0) {
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800816 t = (float) mTmpRect.top / displayFrame.height();
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700817 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800818 int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t);
819 int translationX = 0;
820 int translationYCorrection = translationY;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700821 int centerX = mTmpRect.centerX();
822 int centerY = mTmpRect.centerY();
823 int halfWidth = mTmpRect.width() / 2;
824 int halfHeight = mTmpRect.height() / 2;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800825 int clipStartX = centerX - halfWidth - appFrame.left;
826 int clipStartY = centerY - halfHeight - appFrame.top;
827 boolean cutOff = false;
828
829 // If the starting rectangle is fully or partially outside of the target rectangle, we
830 // need to start the clipping at the edge and then achieve the rest with translation
831 // and extending the clip rect from that edge.
832 if (appFrame.top > centerY - halfHeight) {
833 translationY = (centerY - halfHeight) - appFrame.top;
834 translationYCorrection = 0;
835 clipStartY = 0;
836 cutOff = true;
837 }
838 if (appFrame.left > centerX - halfWidth) {
839 translationX = (centerX - halfWidth) - appFrame.left;
840 clipStartX = 0;
841 cutOff = true;
842 }
843 if (appFrame.right < centerX + halfWidth) {
844 translationX = (centerX + halfWidth) - appFrame.right;
845 clipStartX = appWidth - mTmpRect.width();
846 cutOff = true;
847 }
848 final long duration = calculateClipRevealTransitionDuration(cutOff, translationX,
849 translationY, displayFrame);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700850
851 // Clip third of the from size of launch icon, expand to full width/height
Chet Haase10e23ab2015-02-11 15:08:38 -0800852 Animation clipAnimLR = new ClipRectLRAnimation(
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800853 clipStartX, clipStartX + mTmpRect.width(), 0, appWidth);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700854 clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800855 clipAnimLR.setDuration((long) (duration / 2.5f));
Filip Gruszczynski82861362015-10-16 14:21:09 -0700856
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800857 TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0);
858 translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR
859 : mLinearOutSlowInInterpolator);
860 translate.setDuration(duration);
Chet Haase10e23ab2015-02-11 15:08:38 -0800861
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800862 Animation clipAnimTB = new ClipRectTBAnimation(
863 clipStartY, clipStartY + mTmpRect.height(),
864 0, appHeight,
865 translationYCorrection, 0,
866 mLinearOutSlowInInterpolator);
867 clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
868 clipAnimTB.setDuration(duration);
Chet Haase10e23ab2015-02-11 15:08:38 -0800869
870 // Quick fade-in from icon to app window
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800871 final long alphaDuration = duration / 4;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700872 AlphaAnimation alpha = new AlphaAnimation(0.5f, 1);
Chet Haase10e23ab2015-02-11 15:08:38 -0800873 alpha.setDuration(alphaDuration);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700874 alpha.setInterpolator(mLinearOutSlowInInterpolator);
Chet Haase10e23ab2015-02-11 15:08:38 -0800875
876 AnimationSet set = new AnimationSet(false);
877 set.addAnimation(clipAnimLR);
878 set.addAnimation(clipAnimTB);
Filip Gruszczynski82861362015-10-16 14:21:09 -0700879 set.addAnimation(translate);
Chet Haase10e23ab2015-02-11 15:08:38 -0800880 set.addAnimation(alpha);
Filip Gruszczynski9e2cf5b2015-07-31 12:20:40 -0700881 set.setZAdjustment(Animation.ZORDER_TOP);
Chet Haase10e23ab2015-02-11 15:08:38 -0800882 set.initialize(appWidth, appHeight, appWidth, appHeight);
883 anim = set;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800884 mLastHadClipReveal = true;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800885 mLastClipRevealTransitionDuration = duration;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800886
887 // If the start rect was full inside the target rect (cutOff == false), we don't need
888 // to store the translation, because it's only used if cutOff == true.
889 mLastClipRevealMaxTranslation = cutOff
890 ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0;
Chet Haase10e23ab2015-02-11 15:08:38 -0800891 } else {
892 final long duration;
893 switch (transit) {
894 case TRANSIT_ACTIVITY_OPEN:
895 case TRANSIT_ACTIVITY_CLOSE:
896 duration = mConfigShortAnimTime;
897 break;
898 default:
899 duration = DEFAULT_APP_TRANSITION_DURATION;
900 break;
901 }
902 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
903 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
904 // If we are on top of the wallpaper, we need an animation that
905 // correctly handles the wallpaper staying static behind all of
906 // the animated elements. To do this, will just have the existing
907 // element fade out.
908 anim = new AlphaAnimation(1, 0);
909 anim.setDetachWallpaper(true);
910 } else {
911 // For normal animations, the exiting element just holds in place.
912 anim = new AlphaAnimation(1, 1);
913 }
914 anim.setInterpolator(mDecelerateInterpolator);
915 anim.setDuration(duration);
916 anim.setFillAfter(true);
917 }
918 return anim;
919 }
920
Winson Chung399f6202014-03-19 10:47:20 -0700921 /**
922 * Prepares the specified animation with a standard duration, interpolator, etc.
923 */
Winson Chung5393dff2014-05-08 14:25:43 -0700924 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100925 long duration, Interpolator interpolator) {
Winson Chunga4ccb862014-08-22 15:26:27 -0700926 if (duration > 0) {
927 a.setDuration(duration);
928 }
Winson Chung5393dff2014-05-08 14:25:43 -0700929 a.setFillAfter(true);
Jorim Jaggic69bd222016-03-15 14:38:37 +0100930 if (interpolator != null) {
931 a.setInterpolator(interpolator);
932 }
Winson Chung5393dff2014-05-08 14:25:43 -0700933 a.initialize(appWidth, appHeight, appWidth, appHeight);
934 return a;
935 }
936
937 /**
938 * Prepares the specified animation with a standard duration, interpolator, etc.
939 */
Winson Chung399f6202014-03-19 10:47:20 -0700940 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800941 // Pick the desired duration. If this is an inter-activity transition,
942 // it is the standard duration for that. Otherwise we use the longer
943 // task transition duration.
Winson Chung5393dff2014-05-08 14:25:43 -0700944 final int duration;
Craig Mautner321bdf52012-12-18 09:53:24 -0800945 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800946 case TRANSIT_ACTIVITY_OPEN:
947 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800948 duration = mConfigShortAnimTime;
949 break;
950 default:
951 duration = DEFAULT_APP_TRANSITION_DURATION;
952 break;
953 }
Winson Chung5393dff2014-05-08 14:25:43 -0700954 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
955 mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800956 }
957
Winson Chung399f6202014-03-19 10:47:20 -0700958 /**
959 * Return the current thumbnail transition state.
960 */
961 int getThumbnailTransitionState(boolean enter) {
962 if (enter) {
963 if (mNextAppTransitionScaleUp) {
964 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
965 } else {
966 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
967 }
968 } else {
969 if (mNextAppTransitionScaleUp) {
970 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
971 } else {
972 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
973 }
974 }
975 }
976
977 /**
Tony Mak64b8d562017-12-28 17:44:02 +0000978 * Creates an overlay with a background color and a thumbnail for the cross profile apps
979 * animation.
980 */
981 GraphicBuffer createCrossProfileAppsThumbnail(
982 @DrawableRes int thumbnailDrawableRes, Rect frame) {
983 final int width = frame.width();
984 final int height = frame.height();
985
John Reck519ad482018-02-12 17:08:48 -0800986 final Picture picture = new Picture();
987 final Canvas canvas = picture.beginRecording(width, height);
Tony Mak64b8d562017-12-28 17:44:02 +0000988 canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
989 final int thumbnailSize = mService.mContext.getResources().getDimensionPixelSize(
990 com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
991 final Drawable drawable = mService.mContext.getDrawable(thumbnailDrawableRes);
992 drawable.setBounds(
993 (width - thumbnailSize) / 2,
994 (height - thumbnailSize) / 2,
995 (width + thumbnailSize) / 2,
996 (height + thumbnailSize) / 2);
997 drawable.draw(canvas);
John Reck519ad482018-02-12 17:08:48 -0800998 picture.endRecording();
Tony Mak64b8d562017-12-28 17:44:02 +0000999
John Reck519ad482018-02-12 17:08:48 -08001000 return Bitmap.createBitmap(picture).createGraphicBufferHandle();
Tony Mak64b8d562017-12-28 17:44:02 +00001001 }
1002
1003 Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
1004 final Animation animation = loadAnimationRes(
1005 "android", com.android.internal.R.anim.cross_profile_apps_thumbnail_enter);
1006 return prepareThumbnailAnimationWithDuration(animation, appRect.width(),
1007 appRect.height(), 0, null);
1008 }
1009
1010 /**
Winson Chung399f6202014-03-19 10:47:20 -07001011 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001012 * when a thumbnail is specified with the pending animation override.
Winson Chung399f6202014-03-19 10:47:20 -07001013 */
Jorim Jaggide63d442016-03-14 14:56:56 +01001014 Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
Winson Chungaa7fa012017-05-24 15:50:06 -07001015 GraphicBuffer thumbnailHeader, final int taskId, int uiMode, int orientation) {
Winson Chung399f6202014-03-19 10:47:20 -07001016 Animation a;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001017 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chung399f6202014-03-19 10:47:20 -07001018 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001019 final int thumbHeightI = thumbnailHeader.getHeight();
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001020 final int appWidth = appRect.width();
Winson Chung399f6202014-03-19 10:47:20 -07001021
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001022 float scaleW = appWidth / thumbWidth;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001023 getNextAppTransitionStartRect(taskId, mTmpRect);
Jorim Jaggi09072002016-03-25 16:48:42 -07001024 final float fromX;
Manu Cornet57b61492017-01-24 18:19:05 +09001025 float fromY;
Jorim Jaggi09072002016-03-25 16:48:42 -07001026 final float toX;
Manu Cornet57b61492017-01-24 18:19:05 +09001027 float toY;
Jorim Jaggi09072002016-03-25 16:48:42 -07001028 final float pivotX;
1029 final float pivotY;
Manu Cornetd7376802017-01-13 13:44:07 -08001030 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
Jorim Jaggi09072002016-03-25 16:48:42 -07001031 fromX = mTmpRect.left;
1032 fromY = mTmpRect.top;
1033
1034 // For the curved translate animation to work, the pivot points needs to be at the
1035 // same absolute position as the one from the real surface.
1036 toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
1037 toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
1038 pivotX = mTmpRect.width() / 2;
1039 pivotY = appRect.height() / 2 / scaleW;
Manu Cornet57b61492017-01-24 18:19:05 +09001040 if (mGridLayoutRecentsEnabled) {
1041 // In the grid layout, the header is displayed above the thumbnail instead of
1042 // overlapping it.
1043 fromY -= thumbHeightI;
1044 toY -= thumbHeightI * scaleW;
1045 }
Jorim Jaggi09072002016-03-25 16:48:42 -07001046 } else {
1047 pivotX = 0;
1048 pivotY = 0;
1049 fromX = mTmpRect.left;
1050 fromY = mTmpRect.top;
1051 toX = appRect.left;
1052 toY = appRect.top;
1053 }
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001054 final long duration = getAspectScaleDuration();
1055 final Interpolator interpolator = getAspectScaleInterpolator();
Winson Chung399f6202014-03-19 10:47:20 -07001056 if (mNextAppTransitionScaleUp) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001057 // Animation up from the thumbnail to the full screen
Jorim Jaggi8448f332016-03-14 17:50:37 +01001058 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001059 scale.setInterpolator(interpolator);
1060 scale.setDuration(duration);
Jorim Jaggic6c89a82016-01-28 17:48:21 -08001061 Animation alpha = new AlphaAnimation(1f, 0f);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001062 alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1063 ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator);
1064 alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1065 ? duration / 2
1066 : duration);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001067 Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
1068 translate.setInterpolator(interpolator);
1069 translate.setDuration(duration);
Winson Chung399f6202014-03-19 10:47:20 -07001070
Jorim Jaggide63d442016-03-14 14:56:56 +01001071 mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
1072 mTmpToClipRect.set(appRect);
1073
1074 // Containing frame is in screen space, but we need the clip rect in the
1075 // app space.
1076 mTmpToClipRect.offsetTo(0, 0);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001077 mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
1078 mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
Jorim Jaggide63d442016-03-14 14:56:56 +01001079
1080 if (contentInsets != null) {
Jorim Jaggi8448f332016-03-14 17:50:37 +01001081 mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
1082 (int) (-contentInsets.top * scaleW),
1083 (int) (-contentInsets.right * scaleW),
1084 (int) (-contentInsets.bottom * scaleW));
Jorim Jaggide63d442016-03-14 14:56:56 +01001085 }
1086
1087 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001088 clipAnim.setInterpolator(interpolator);
1089 clipAnim.setDuration(duration);
Jorim Jaggide63d442016-03-14 14:56:56 +01001090
Winson Chung399f6202014-03-19 10:47:20 -07001091 // This AnimationSet uses the Interpolators assigned above.
1092 AnimationSet set = new AnimationSet(false);
1093 set.addAnimation(scale);
Manu Cornet57b61492017-01-24 18:19:05 +09001094 if (!mGridLayoutRecentsEnabled) {
1095 // In the grid layout, the header should be shown for the whole animation.
1096 set.addAnimation(alpha);
1097 }
Winson Chunga4ccb862014-08-22 15:26:27 -07001098 set.addAnimation(translate);
Jorim Jaggide63d442016-03-14 14:56:56 +01001099 set.addAnimation(clipAnim);
Winson Chung399f6202014-03-19 10:47:20 -07001100 a = set;
1101 } else {
Winson Chunga4ccb862014-08-22 15:26:27 -07001102 // Animation down from the full screen to the thumbnail
Jorim Jaggi8448f332016-03-14 17:50:37 +01001103 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001104 scale.setInterpolator(interpolator);
1105 scale.setDuration(duration);
Winson Chunga4ccb862014-08-22 15:26:27 -07001106 Animation alpha = new AlphaAnimation(0f, 1f);
1107 alpha.setInterpolator(mThumbnailFadeInInterpolator);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001108 alpha.setDuration(duration);
1109 Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
1110 translate.setInterpolator(interpolator);
1111 translate.setDuration(duration);
Winson Chung399f6202014-03-19 10:47:20 -07001112
Winson Chunga4ccb862014-08-22 15:26:27 -07001113 // This AnimationSet uses the Interpolators assigned above.
1114 AnimationSet set = new AnimationSet(false);
1115 set.addAnimation(scale);
Manu Cornet57b61492017-01-24 18:19:05 +09001116 if (!mGridLayoutRecentsEnabled) {
1117 // In the grid layout, the header should be shown for the whole animation.
1118 set.addAnimation(alpha);
1119 }
Winson Chunga4ccb862014-08-22 15:26:27 -07001120 set.addAnimation(translate);
1121 a = set;
1122
1123 }
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001124 return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
Jorim Jaggic69bd222016-03-15 14:38:37 +01001125 null);
Winson Chung399f6202014-03-19 10:47:20 -07001126 }
1127
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001128 private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
1129
1130 // Almost no x-change - use linear animation
Jorim Jaggic69bd222016-03-15 14:38:37 +01001131 if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) {
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001132 return new TranslateAnimation(fromX, toX, fromY, toY);
1133 } else {
1134 final Path path = createCurvedPath(fromX, toX, fromY, toY);
1135 return new CurvedTranslateAnimation(path);
1136 }
1137 }
1138
1139 private Path createCurvedPath(float fromX, float toX, float fromY, float toY) {
1140 final Path path = new Path();
1141 path.moveTo(fromX, fromY);
Jorim Jaggi1f458fb2016-03-25 17:36:37 -07001142
1143 if (fromY > toY) {
1144 // If the object needs to go up, move it in horizontal direction first, then vertical.
1145 path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY);
1146 } else {
1147 // If the object needs to go down, move it in vertical direction first, then horizontal.
1148 path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY);
1149 }
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001150 return path;
1151 }
1152
1153 private long getAspectScaleDuration() {
1154 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
Jorim Jaggic69bd222016-03-15 14:38:37 +01001155 return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001156 } else {
1157 return THUMBNAIL_APP_TRANSITION_DURATION;
1158 }
1159 }
1160
1161 private Interpolator getAspectScaleInterpolator() {
1162 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
1163 return mFastOutSlowInInterpolator;
1164 } else {
1165 return TOUCH_RESPONSE_INTERPOLATOR;
1166 }
1167 }
1168
Winson Chung399f6202014-03-19 10:47:20 -07001169 /**
1170 * This alternate animation is created when we are doing a thumbnail transition, for the
1171 * activity that is leaving, and the activity that is entering.
1172 */
Winson Chunga4ccb862014-08-22 15:26:27 -07001173 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
Winsonb2024762016-04-05 17:32:30 -07001174 int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets,
Matthew Ng43db6d22017-06-27 15:29:39 -07001175 @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean freeform,
1176 int taskId) {
Winson Chung399f6202014-03-19 10:47:20 -07001177 Animation a;
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001178 final int appWidth = containingFrame.width();
1179 final int appHeight = containingFrame.height();
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001180 getDefaultNextAppTransitionStartRect(mTmpRect);
1181 final int thumbWidthI = mTmpRect.width();
Winson Chung399f6202014-03-19 10:47:20 -07001182 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001183 final int thumbHeightI = mTmpRect.height();
Winson Chung399f6202014-03-19 10:47:20 -07001184 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
Winsoncbb625b2016-07-06 15:24:15 -07001185 final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left;
Winson21700932016-03-24 17:26:23 -07001186 final int thumbStartY = mTmpRect.top - containingFrame.top;
Winson Chung399f6202014-03-19 10:47:20 -07001187
1188 switch (thumbTransitState) {
Jorim Jaggi8448f332016-03-14 17:50:37 +01001189 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
1190 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1191 final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
1192 if (freeform && scaleUp) {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001193 a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001194 containingFrame, surfaceInsets, taskId);
Jorim Jaggi8448f332016-03-14 17:50:37 +01001195 } else if (freeform) {
1196 a = createAspectScaledThumbnailExitFreeformAnimationLocked(
1197 containingFrame, surfaceInsets, taskId);
Winson Chung2820c452014-04-15 15:34:44 -07001198 } else {
Winson21700932016-03-24 17:26:23 -07001199 AnimationSet set = new AnimationSet(true);
1200
1201 // In portrait, we scale to fit the width
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -07001202 mTmpFromClipRect.set(containingFrame);
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -07001203 mTmpToClipRect.set(containingFrame);
Jorim Jaggic6c89a82016-01-28 17:48:21 -08001204
1205 // Containing frame is in screen space, but we need the clip rect in the
1206 // app space.
1207 mTmpFromClipRect.offsetTo(0, 0);
1208 mTmpToClipRect.offsetTo(0, 0);
1209
1210 // Exclude insets region from the source clip.
1211 mTmpFromClipRect.inset(contentInsets);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001212 mNextAppTransitionInsets.set(contentInsets);
1213
Manu Cornetd7376802017-01-13 13:44:07 -08001214 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
Jorim Jaggic69bd222016-03-15 14:38:37 +01001215 // We scale the width and clip to the top/left square
1216 float scale = thumbWidth /
1217 (appWidth - contentInsets.left - contentInsets.right);
Manu Cornetb68b7652017-01-23 19:37:53 +09001218 if (!mGridLayoutRecentsEnabled) {
1219 int unscaledThumbHeight = (int) (thumbHeight / scale);
1220 mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
1221 }
Jorim Jaggic69bd222016-03-15 14:38:37 +01001222
1223 mNextAppTransitionInsets.set(contentInsets);
1224
Jorim Jaggi8448f332016-03-14 17:50:37 +01001225 Animation scaleAnim = new ScaleAnimation(
1226 scaleUp ? scale : 1, scaleUp ? 1 : scale,
1227 scaleUp ? scale : 1, scaleUp ? 1 : scale,
Jorim Jaggic69bd222016-03-15 14:38:37 +01001228 containingFrame.width() / 2f,
1229 containingFrame.height() / 2f + contentInsets.top);
Jorim Jaggi8448f332016-03-14 17:50:37 +01001230 final float targetX = (mTmpRect.left - containingFrame.left);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001231 final float x = containingFrame.width() / 2f
1232 - containingFrame.width() / 2f * scale;
Jorim Jaggi8448f332016-03-14 17:50:37 +01001233 final float targetY = (mTmpRect.top - containingFrame.top);
Matthew Ng43db6d22017-06-27 15:29:39 -07001234 float y = containingFrame.height() / 2f
Jorim Jaggic69bd222016-03-15 14:38:37 +01001235 - containingFrame.height() / 2f * scale;
Matthew Ng43db6d22017-06-27 15:29:39 -07001236
1237 // During transition may require clipping offset from any top stable insets
1238 // such as the statusbar height when statusbar is hidden
1239 if (mLowRamRecentsEnabled && contentInsets.top == 0 && scaleUp) {
1240 mTmpFromClipRect.top += stableInsets.top;
1241 y += stableInsets.top;
1242 }
Jorim Jaggi8448f332016-03-14 17:50:37 +01001243 final float startX = targetX - x;
1244 final float startY = targetY - y;
1245 Animation clipAnim = scaleUp
1246 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1247 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1248 Animation translateAnim = scaleUp
Jorim Jaggic69bd222016-03-15 14:38:37 +01001249 ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0)
1250 : createCurvedMotion(0, startX, 0, startY - contentInsets.top);
1251
Winson21700932016-03-24 17:26:23 -07001252 set.addAnimation(clipAnim);
1253 set.addAnimation(scaleAnim);
1254 set.addAnimation(translateAnim);
1255
1256 } else {
1257 // In landscape, we don't scale at all and only crop
1258 mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI;
1259 mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI;
1260
Jorim Jaggi8448f332016-03-14 17:50:37 +01001261 Animation clipAnim = scaleUp
1262 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1263 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1264 Animation translateAnim = scaleUp
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001265 ? createCurvedMotion(thumbStartX, 0,
1266 thumbStartY - contentInsets.top, 0)
1267 : createCurvedMotion(0, thumbStartX, 0,
1268 thumbStartY - contentInsets.top);
Winson21700932016-03-24 17:26:23 -07001269
1270 set.addAnimation(clipAnim);
1271 set.addAnimation(translateAnim);
1272 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001273 a = set;
Winson21700932016-03-24 17:26:23 -07001274 a.setZAdjustment(Animation.ZORDER_TOP);
Winson Chung2820c452014-04-15 15:34:44 -07001275 }
Winson Chung399f6202014-03-19 10:47:20 -07001276 break;
1277 }
1278 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
Winson Chunga4ccb862014-08-22 15:26:27 -07001279 // Previous app window during the scale up
Winson Chung399f6202014-03-19 10:47:20 -07001280 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001281 // Fade out the source activity if we are animating to a wallpaper
Winson Chung399f6202014-03-19 10:47:20 -07001282 // activity.
1283 a = new AlphaAnimation(1, 0);
1284 } else {
Winson Chung399f6202014-03-19 10:47:20 -07001285 a = new AlphaAnimation(1, 1);
1286 }
1287 break;
1288 }
1289 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
Winson Chunga4ccb862014-08-22 15:26:27 -07001290 // Target app window during the scale down
1291 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1292 // Fade in the destination activity if we are animating from a wallpaper
1293 // activity.
1294 a = new AlphaAnimation(0, 1);
1295 } else {
1296 a = new AlphaAnimation(1, 1);
1297 }
Winson Chung399f6202014-03-19 10:47:20 -07001298 break;
1299 }
Winson Chung399f6202014-03-19 10:47:20 -07001300 default:
1301 throw new RuntimeException("Invalid thumbnail transition state");
1302 }
1303
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001304 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
1305 getAspectScaleDuration(), getAspectScaleInterpolator());
Winson Chung399f6202014-03-19 10:47:20 -07001306 }
1307
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001308 private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
1309 @Nullable Rect surfaceInsets, int taskId) {
1310 getNextAppTransitionStartRect(taskId, mTmpRect);
1311 return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
1312 true);
1313 }
1314
1315 private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
1316 @Nullable Rect surfaceInsets, int taskId) {
1317 getNextAppTransitionStartRect(taskId, mTmpRect);
1318 return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
1319 false);
1320 }
1321
1322 private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
1323 Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
1324 final float sourceWidth = sourceFrame.width();
1325 final float sourceHeight = sourceFrame.height();
1326 final float destWidth = destFrame.width();
1327 final float destHeight = destFrame.height();
1328 final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
1329 final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001330 AnimationSet set = new AnimationSet(true);
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001331 final int surfaceInsetsH = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001332 ? 0 : surfaceInsets.left + surfaceInsets.right;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001333 final int surfaceInsetsV = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001334 ? 0 : surfaceInsets.top + surfaceInsets.bottom;
1335 // We want the scaling to happen from the center of the surface. In order to achieve that,
1336 // we need to account for surface insets that will be used to enlarge the surface.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001337 final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
1338 final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
1339 final ScaleAnimation scale = enter ?
1340 new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
1341 : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
1342 final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
1343 final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
1344 final int destHCenter = destFrame.left + destFrame.width() / 2;
1345 final int destVCenter = destFrame.top + destFrame.height() / 2;
1346 final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
1347 final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
1348 final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
1349 : new TranslateAnimation(0, fromX, 0, fromY);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001350 set.addAnimation(scale);
1351 set.addAnimation(translation);
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001352
1353 final IRemoteCallback callback = mAnimationFinishedCallback;
1354 if (callback != null) {
1355 set.setAnimationListener(new Animation.AnimationListener() {
1356 @Override
1357 public void onAnimationStart(Animation animation) { }
1358
1359 @Override
1360 public void onAnimationEnd(Animation animation) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001361 mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001362 }
1363
1364 @Override
1365 public void onAnimationRepeat(Animation animation) { }
1366 });
1367 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001368 return set;
1369 }
1370
Winson Chung399f6202014-03-19 10:47:20 -07001371 /**
Winson Chunga4ccb862014-08-22 15:26:27 -07001372 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001373 * when a thumbnail is specified with the pending animation override.
Winson Chunga4ccb862014-08-22 15:26:27 -07001374 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001375 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
Winson Chungaa7fa012017-05-24 15:50:06 -07001376 GraphicBuffer thumbnailHeader) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001377 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001378 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001379 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chunga4ccb862014-08-22 15:26:27 -07001380 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001381 final int thumbHeightI = thumbnailHeader.getHeight();
Winson Chunga4ccb862014-08-22 15:26:27 -07001382 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1383
1384 if (mNextAppTransitionScaleUp) {
1385 // Animation for the thumbnail zooming from its initial size to the full screen
1386 float scaleW = appWidth / thumbWidth;
1387 float scaleH = appHeight / thumbHeight;
1388 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001389 computePivot(mTmpRect.left, 1 / scaleW),
1390 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001391 scale.setInterpolator(mDecelerateInterpolator);
1392
1393 Animation alpha = new AlphaAnimation(1, 0);
1394 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
1395
1396 // This AnimationSet uses the Interpolators assigned above.
1397 AnimationSet set = new AnimationSet(false);
1398 set.addAnimation(scale);
1399 set.addAnimation(alpha);
1400 a = set;
1401 } else {
1402 // Animation for the thumbnail zooming down from the full screen to its final size
1403 float scaleW = appWidth / thumbWidth;
1404 float scaleH = appHeight / thumbHeight;
1405 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001406 computePivot(mTmpRect.left, 1 / scaleW),
1407 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001408 }
1409
1410 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1411 }
1412
1413 /**
Winson Chung399f6202014-03-19 10:47:20 -07001414 * This animation is created when we are doing a thumbnail transition, for the activity that is
1415 * leaving, and the activity that is entering.
1416 */
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001417 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
1418 int transit, int taskId) {
1419 final int appWidth = containingFrame.width();
1420 final int appHeight = containingFrame.height();
Winson Chungaa7fa012017-05-24 15:50:06 -07001421 final GraphicBuffer thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
Winson Chung399f6202014-03-19 10:47:20 -07001422 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001423 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001424 final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
Winson Chung399f6202014-03-19 10:47:20 -07001425 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001426 final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
Winson Chung399f6202014-03-19 10:47:20 -07001427 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1428
1429 switch (thumbTransitState) {
1430 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
1431 // Entering app scales up with the thumbnail
1432 float scaleW = thumbWidth / appWidth;
1433 float scaleH = thumbHeight / appHeight;
1434 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001435 computePivot(mTmpRect.left, scaleW),
1436 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001437 break;
1438 }
1439 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
1440 // Exiting app while the thumbnail is scaling up should fade or stay in place
1441 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1442 // Fade out while bringing up selected activity. This keeps the
1443 // current activity from showing through a launching wallpaper
1444 // activity.
1445 a = new AlphaAnimation(1, 0);
1446 } else {
1447 // noop animation
1448 a = new AlphaAnimation(1, 1);
1449 }
1450 break;
1451 }
1452 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
1453 // Entering the other app, it should just be visible while we scale the thumbnail
1454 // down above it
1455 a = new AlphaAnimation(1, 1);
1456 break;
1457 }
1458 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1459 // Exiting the current app, the app should scale down with the thumbnail
1460 float scaleW = thumbWidth / appWidth;
1461 float scaleH = thumbHeight / appHeight;
1462 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001463 computePivot(mTmpRect.left, scaleW),
1464 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001465
1466 Animation alpha = new AlphaAnimation(1, 0);
1467
1468 AnimationSet set = new AnimationSet(true);
1469 set.addAnimation(scale);
1470 set.addAnimation(alpha);
1471 set.setZAdjustment(Animation.ZORDER_TOP);
1472 a = set;
1473 break;
1474 }
1475 default:
1476 throw new RuntimeException("Invalid thumbnail transition state");
1477 }
1478
1479 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1480 }
1481
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001482 private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) {
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001483 getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
1484 final int left = mTmpFromClipRect.left;
1485 final int top = mTmpFromClipRect.top;
1486 mTmpFromClipRect.offset(-left, -top);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001487 // TODO: Isn't that strange that we ignore exact position of the containingFrame?
1488 mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height());
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001489 AnimationSet set = new AnimationSet(true);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001490 float fromWidth = mTmpFromClipRect.width();
1491 float toWidth = mTmpToClipRect.width();
1492 float fromHeight = mTmpFromClipRect.height();
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001493 // While the window might span the whole display, the actual content will be cropped to the
1494 // system decoration frame, for example when the window is docked. We need to take into
1495 // account the visible height when constructing the animation.
1496 float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom;
1497 int translateAdjustment = 0;
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001498 if (fromWidth <= toWidth && fromHeight <= toHeight) {
1499 // The final window is larger in both dimensions than current window (e.g. we are
1500 // maximizing), so we can simply unclip the new window and there will be no disappearing
1501 // frame.
1502 set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
1503 } else {
1504 // The disappearing window has one larger dimension. We need to apply scaling, so the
1505 // first frame of the entry animation matches the old window.
1506 set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001507 // We might not be going exactly full screen, but instead be aligned under the status
1508 // bar using cropping. We still need to account for the cropped part, which will also
1509 // be scaled.
1510 translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001511 }
1512
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001513 // We animate the translation from the old position of the removed window, to the new
1514 // position of the added window. The latter might not be full screen, for example docked for
1515 // docked windows.
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001516 TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001517 0, top - containingFrame.top - translateAdjustment, 0);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001518 set.addAnimation(translate);
1519 set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
Filip Gruszczynskie95b0ae2015-09-30 10:55:33 -07001520 set.setZAdjustment(Animation.ZORDER_TOP);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001521 return set;
1522 }
1523
Jorim Jaggic554b772015-06-04 16:07:57 -07001524 /**
1525 * @return true if and only if the first frame of the transition can be skipped, i.e. the first
1526 * frame of the transition doesn't change the visuals on screen, so we can start
1527 * directly with the second one
1528 */
1529 boolean canSkipFirstFrame() {
1530 return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
1531 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
Jorim Jaggife762342016-10-13 14:33:27 +02001532 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
1533 && mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY;
Jorim Jaggic554b772015-06-04 16:07:57 -07001534 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08001535
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001536 RemoteAnimationController getRemoteAnimationController() {
1537 return mRemoteAnimationController;
1538 }
1539
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001540 /**
1541 *
1542 * @param frame These are the bounds of the window when it finishes the animation. This is where
1543 * the animation must usually finish in entrance animation, as the next frame will
1544 * display the window at these coordinates. In case of exit animation, this is
1545 * where the animation must start, as the frame before the animation is displaying
1546 * the window at these bounds.
1547 * @param insets Knowing where the window will be positioned is not enough. Some parts of the
1548 * window might be obscured, usually by the system windows (status bar and
1549 * navigation bar) and we use content insets to convey that information. This
1550 * usually affects the animation aspects vertically, as the system decoration is
1551 * at the top and the bottom. For example when we animate from full screen to
1552 * recents, we want to exclude the covered parts, because they won't match the
1553 * thumbnail after the last frame is executed.
1554 * @param surfaceInsets In rare situation the surface is larger than the content and we need to
1555 * know about this to make the animation frames match. We currently use
1556 * this for freeform windows, which have larger surfaces to display
1557 * shadows. When we animate them from recents, we want to match the content
1558 * to the recents thumbnail and hence need to account for the surface being
1559 * bigger.
1560 */
Jorim Jaggif84e2f62018-01-16 14:17:59 +01001561 Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -08001562 int orientation, Rect frame, Rect displayFrame, Rect insets,
Matthew Ng43db6d22017-06-27 15:29:39 -07001563 @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
1564 boolean freeform, int taskId) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001565 Animation a;
Jorim Jaggife762342016-10-13 14:33:27 +02001566 if (isKeyguardGoingAwayTransit(transit) && enter) {
1567 a = loadKeyguardExitAnimation(transit);
1568 } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) {
1569 a = null;
1570 } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) {
1571 a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit);
1572 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001573 || transit == TRANSIT_TASK_OPEN
1574 || transit == TRANSIT_TASK_TO_FRONT)) {
1575 a = loadAnimationRes(lp, enter
1576 ? com.android.internal.R.anim.voice_activity_open_enter
1577 : com.android.internal.R.anim.voice_activity_open_exit);
1578 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1579 "applyAnimation voice:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001580 + " anim=" + a + " transit=" + appTransitionToString(transit)
1581 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001582 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
1583 || transit == TRANSIT_TASK_CLOSE
1584 || transit == TRANSIT_TASK_TO_BACK)) {
1585 a = loadAnimationRes(lp, enter
1586 ? com.android.internal.R.anim.voice_activity_close_enter
1587 : com.android.internal.R.anim.voice_activity_close_exit);
1588 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1589 "applyAnimation voice:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001590 + " anim=" + a + " transit=" + appTransitionToString(transit)
1591 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001592 } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001593 a = createRelaunchAnimation(frame, insets);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001594 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1595 "applyAnimation:"
1596 + " anim=" + a + " nextAppTransition=" + mNextAppTransition
1597 + " transit=" + appTransitionToString(transit)
1598 + " Callers=" + Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001599 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
1600 a = loadAnimationRes(mNextAppTransitionPackage, enter ?
Craig Mautner164d4bb2012-11-26 13:51:23 -08001601 mNextAppTransitionEnter : mNextAppTransitionExit);
1602 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1603 "applyAnimation:"
1604 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001605 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001606 + " Callers=" + Debug.getCallers(3));
Winson Chung044d5292014-11-06 11:05:19 -08001607 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
1608 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
1609 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1610 "applyAnimation:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001611 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
1612 + " transit=" + appTransitionToString(transit)
1613 + " Callers=" + Debug.getCallers(3));
Chet Haase10e23ab2015-02-11 15:08:38 -08001614 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -08001615 a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
Chet Haase10e23ab2015-02-11 15:08:38 -08001616 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1617 "applyAnimation:"
1618 + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001619 + " transit=" + appTransitionToString(transit)
Chet Haase10e23ab2015-02-11 15:08:38 -08001620 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001621 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001622 a = createScaleUpAnimationLocked(transit, enter, frame);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001623 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1624 "applyAnimation:"
1625 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001626 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001627 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001628 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
1629 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001630 mNextAppTransitionScaleUp =
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001631 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
Winson Chunga4ccb862014-08-22 15:26:27 -07001632 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001633 frame, transit, taskId);
Winson Chunga4ccb862014-08-22 15:26:27 -07001634 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1635 String animName = mNextAppTransitionScaleUp ?
1636 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
1637 Slog.v(TAG, "applyAnimation:"
1638 + " anim=" + a + " nextAppTransition=" + animName
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001639 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Winson Chunga4ccb862014-08-22 15:26:27 -07001640 + " Callers=" + Debug.getCallers(3));
1641 }
1642 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
1643 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
1644 mNextAppTransitionScaleUp =
1645 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
1646 a = createAspectScaledThumbnailEnterExitAnimationLocked(
Winsonb2024762016-04-05 17:32:30 -07001647 getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
Matthew Ng43db6d22017-06-27 15:29:39 -07001648 insets, surfaceInsets, stableInsets, freeform, taskId);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001649 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1650 String animName = mNextAppTransitionScaleUp ?
Winson Chunga4ccb862014-08-22 15:26:27 -07001651 "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
Craig Mautner164d4bb2012-11-26 13:51:23 -08001652 Slog.v(TAG, "applyAnimation:"
1653 + " anim=" + a + " nextAppTransition=" + animName
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001654 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001655 + " Callers=" + Debug.getCallers(3));
1656 }
Tony Mak83546a82018-01-22 13:56:20 +00001657 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {
Jorim Jaggi98a9d202018-03-26 16:17:07 +02001658 a = loadAnimationRes("android",
1659 com.android.internal.R.anim.task_open_enter_cross_profile_apps);
Tony Mak089c35e2017-12-18 20:34:14 +00001660 Slog.v(TAG,
1661 "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:"
1662 + " anim=" + a + " transit=" + appTransitionToString(transit)
Jorim Jaggi98a9d202018-03-26 16:17:07 +02001663 + " isEntrance=true" + " Callers=" + Debug.getCallers(3));
1664 } else if (transit == TRANSIT_TRANSLUCENT_ACTIVITY_OPEN && enter) {
1665 a = loadAnimationRes("android",
1666 com.android.internal.R.anim.activity_translucent_open_enter);
1667 Slog.v(TAG,
1668 "applyAnimation TRANSIT_TRANSLUCENT_ACTIVITY_OPEN:"
1669 + " anim=" + a + " transit=" + appTransitionToString(transit)
1670 + " isEntrance=true" + " Callers=" + Debug.getCallers(3));
1671 } else if (transit == TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE && !enter) {
1672 a = loadAnimationRes("android",
1673 com.android.internal.R.anim.activity_translucent_close_exit);
1674 Slog.v(TAG,
1675 "applyAnimation TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE:"
1676 + " anim=" + a + " transit=" + appTransitionToString(transit)
1677 + " isEntrance=false" + " Callers=" + Debug.getCallers(3));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001678 } else {
1679 int animAttr = 0;
1680 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -08001681 case TRANSIT_ACTIVITY_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001682 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001683 ? WindowAnimation_activityOpenEnterAnimation
1684 : WindowAnimation_activityOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001685 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001686 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001687 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001688 ? WindowAnimation_activityCloseEnterAnimation
1689 : WindowAnimation_activityCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001690 break;
Jorim Jaggi192086e2016-03-11 17:17:03 +01001691 case TRANSIT_DOCK_TASK_FROM_RECENTS:
Craig Mautner4b71aa12012-12-27 17:20:01 -08001692 case TRANSIT_TASK_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001693 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001694 ? WindowAnimation_taskOpenEnterAnimation
1695 : WindowAnimation_taskOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001696 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001697 case TRANSIT_TASK_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001698 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001699 ? WindowAnimation_taskCloseEnterAnimation
1700 : WindowAnimation_taskCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001701 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001702 case TRANSIT_TASK_TO_FRONT:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001703 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001704 ? WindowAnimation_taskToFrontEnterAnimation
1705 : WindowAnimation_taskToFrontExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001706 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001707 case TRANSIT_TASK_TO_BACK:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001708 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001709 ? WindowAnimation_taskToBackEnterAnimation
1710 : WindowAnimation_taskToBackExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001711 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001712 case TRANSIT_WALLPAPER_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001713 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001714 ? WindowAnimation_wallpaperOpenEnterAnimation
1715 : WindowAnimation_wallpaperOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001716 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001717 case TRANSIT_WALLPAPER_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001718 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001719 ? WindowAnimation_wallpaperCloseEnterAnimation
1720 : WindowAnimation_wallpaperCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001721 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001722 case TRANSIT_WALLPAPER_INTRA_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001723 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001724 ? WindowAnimation_wallpaperIntraOpenEnterAnimation
1725 : WindowAnimation_wallpaperIntraOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001726 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001727 case TRANSIT_WALLPAPER_INTRA_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001728 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001729 ? WindowAnimation_wallpaperIntraCloseEnterAnimation
1730 : WindowAnimation_wallpaperIntraCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001731 break;
Craig Mautnerbb742462014-07-07 15:28:55 -07001732 case TRANSIT_TASK_OPEN_BEHIND:
1733 animAttr = enter
1734 ? WindowAnimation_launchTaskBehindSourceAnimation
Craig Mautner3b2cd1d2014-08-25 14:25:54 -07001735 : WindowAnimation_launchTaskBehindTargetAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001736 }
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001737 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001738 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1739 "applyAnimation:"
1740 + " anim=" + a
1741 + " animAttr=0x" + Integer.toHexString(animAttr)
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001742 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001743 + " Callers=" + Debug.getCallers(3));
1744 }
1745 return a;
1746 }
1747
Jorim Jaggife762342016-10-13 14:33:27 +02001748 private Animation loadKeyguardExitAnimation(int transit) {
1749 if ((mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) != 0) {
1750 return null;
1751 }
1752 final boolean toShade =
1753 (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0;
1754 return mService.mPolicy.createHiddenByKeyguardExit(
1755 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade);
1756 }
1757
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001758 int getAppStackClipMode() {
Matthew Ngbf1d9852017-03-14 12:23:09 -07001759 // When dismiss keyguard animation occurs, clip before the animation to prevent docked
1760 // app from showing beyond the divider
1761 if (mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY
1762 || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
1763 return STACK_CLIP_BEFORE_ANIM;
1764 }
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001765 return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
Jorim Jaggic69bd222016-03-15 14:38:37 +01001766 || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
Jorim Jaggi1f458fb2016-03-25 17:36:37 -07001767 || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001768 ? STACK_CLIP_NONE
1769 : STACK_CLIP_AFTER_ANIM;
1770 }
1771
Jorim Jaggife762342016-10-13 14:33:27 +02001772 public int getTransitFlags() {
1773 return mNextAppTransitionFlags;
1774 }
1775
Craig Mautner164d4bb2012-11-26 13:51:23 -08001776 void postAnimationCallback() {
1777 if (mNextAppTransitionCallback != null) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001778 mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
1779 mNextAppTransitionCallback));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001780 mNextAppTransitionCallback = null;
1781 }
1782 }
1783
1784 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001785 IRemoteCallback startedCallback) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001786 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001787 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001788 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001789 mNextAppTransitionPackage = packageName;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001790 mNextAppTransitionEnter = enterAnim;
1791 mNextAppTransitionExit = exitAnim;
1792 postAnimationCallback();
1793 mNextAppTransitionCallback = startedCallback;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001794 }
1795 }
1796
1797 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001798 int startHeight) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001799 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001800 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001801 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
Winson4c3fecd2016-07-13 12:29:48 -07001802 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001803 postAnimationCallback();
Craig Mautner164d4bb2012-11-26 13:51:23 -08001804 }
1805 }
1806
Chet Haase10e23ab2015-02-11 15:08:38 -08001807 void overridePendingAppTransitionClipReveal(int startX, int startY,
1808 int startWidth, int startHeight) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001809 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001810 clear();
Chet Haase10e23ab2015-02-11 15:08:38 -08001811 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001812 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
Chet Haase10e23ab2015-02-11 15:08:38 -08001813 postAnimationCallback();
Chet Haase10e23ab2015-02-11 15:08:38 -08001814 }
1815 }
1816
Winson Chungaa7fa012017-05-24 15:50:06 -07001817 void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX, int startY,
Craig Mautner164d4bb2012-11-26 13:51:23 -08001818 IRemoteCallback startedCallback, boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001819 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001820 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001821 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
1822 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001823 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001824 putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001825 postAnimationCallback();
1826 mNextAppTransitionCallback = startedCallback;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001827 }
1828 }
1829
Winson Chungaa7fa012017-05-24 15:50:06 -07001830 void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX, int startY,
Winson Chung2e7f3bd2014-09-05 13:17:22 +02001831 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001832 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001833 clear();
Winson Chunga4ccb862014-08-22 15:26:27 -07001834 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1835 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Winson Chunga4ccb862014-08-22 15:26:27 -07001836 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001837 putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight,
1838 srcThumb);
Winson Chunga4ccb862014-08-22 15:26:27 -07001839 postAnimationCallback();
1840 mNextAppTransitionCallback = startedCallback;
Winson Chunga4ccb862014-08-22 15:26:27 -07001841 }
1842 }
1843
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001844 void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001845 IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
1846 boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001847 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001848 clear();
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001849 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1850 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001851 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi43102412015-11-11 16:28:37 +01001852 if (specs != null) {
1853 for (int i = 0; i < specs.length; i++) {
1854 AppTransitionAnimationSpec spec = specs[i];
1855 if (spec != null) {
1856 mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec);
1857 if (i == 0) {
1858 // In full screen mode, the transition code depends on the default spec
1859 // to be set.
1860 Rect rect = spec.rect;
1861 putDefaultNextAppTransitionCoordinates(rect.left, rect.top,
Winson Chungaa7fa012017-05-24 15:50:06 -07001862 rect.width(), rect.height(), spec.buffer);
Jorim Jaggi43102412015-11-11 16:28:37 +01001863 }
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001864 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001865 }
1866 }
1867 postAnimationCallback();
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001868 mNextAppTransitionCallback = onAnimationStartedCallback;
1869 mAnimationFinishedCallback = onAnimationFinishedCallback;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001870 }
1871 }
1872
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001873 void overridePendingAppTransitionMultiThumbFuture(
1874 IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
1875 boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001876 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001877 clear();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001878 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1879 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001880 mNextAppTransitionAnimationsSpecsFuture = specsFuture;
1881 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +01001882 mNextAppTransitionFutureCallback = callback;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001883 }
1884 }
1885
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001886 void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter) {
Winson Chung044d5292014-11-06 11:05:19 -08001887 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001888 clear();
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001889 mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE;
1890 mRemoteAnimationController = new RemoteAnimationController(mService,
1891 remoteAnimationAdapter, mService.mH);
1892 }
1893 }
1894
1895 void overrideInPlaceAppTransition(String packageName, int anim) {
1896 if (canOverridePendingAppTransition()) {
1897 clear();
Winson Chung044d5292014-11-06 11:05:19 -08001898 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
1899 mNextAppTransitionPackage = packageName;
1900 mNextAppTransitionInPlace = anim;
Winson Chung044d5292014-11-06 11:05:19 -08001901 }
1902 }
1903
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001904 /**
Tony Mak089c35e2017-12-18 20:34:14 +00001905 * @see {@link #NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS}
1906 */
1907 void overridePendingAppTransitionStartCrossProfileApps() {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001908 if (canOverridePendingAppTransition()) {
Tony Mak089c35e2017-12-18 20:34:14 +00001909 clear();
1910 mNextAppTransitionType = NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
1911 postAnimationCallback();
1912 }
1913 }
1914
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001915 private boolean canOverridePendingAppTransition() {
1916 // Remote animations always take precedence
1917 return isTransitionSet() && mNextAppTransitionType != NEXT_TRANSIT_TYPE_REMOTE;
1918 }
1919
Tony Mak089c35e2017-12-18 20:34:14 +00001920 /**
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001921 * If a future is set for the app transition specs, fetch it in another thread.
1922 */
1923 private void fetchAppTransitionSpecsFromFuture() {
1924 if (mNextAppTransitionAnimationsSpecsFuture != null) {
1925 mNextAppTransitionAnimationsSpecsPending = true;
1926 final IAppTransitionAnimationSpecsFuture future
1927 = mNextAppTransitionAnimationsSpecsFuture;
1928 mNextAppTransitionAnimationsSpecsFuture = null;
Jorim Jaggied410b62017-05-05 15:16:14 +02001929 mDefaultExecutor.execute(() -> {
1930 AppTransitionAnimationSpec[] specs = null;
1931 try {
1932 Binder.allowBlocking(future.asBinder());
1933 specs = future.get();
1934 } catch (RemoteException e) {
1935 Slog.w(TAG, "Failed to fetch app transition specs: " + e);
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001936 }
Jorim Jaggied410b62017-05-05 15:16:14 +02001937 synchronized (mService.mWindowMap) {
1938 mNextAppTransitionAnimationsSpecsPending = false;
1939 overridePendingAppTransitionMultiThumb(specs,
1940 mNextAppTransitionFutureCallback, null /* finishedCallback */,
1941 mNextAppTransitionScaleUp);
1942 mNextAppTransitionFutureCallback = null;
Jorim Jaggied410b62017-05-05 15:16:14 +02001943 }
1944 mService.requestTraversal();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001945 });
1946 }
1947 }
1948
Craig Mautner164d4bb2012-11-26 13:51:23 -08001949 @Override
1950 public String toString() {
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001951 return "mNextAppTransition=" + appTransitionToString(mNextAppTransition);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001952 }
1953
Craig Mautner4b71aa12012-12-27 17:20:01 -08001954 /**
1955 * Returns the human readable name of a window transition.
1956 *
1957 * @param transition The window transition.
1958 * @return The transition symbolic name.
1959 */
1960 public static String appTransitionToString(int transition) {
1961 switch (transition) {
1962 case TRANSIT_UNSET: {
1963 return "TRANSIT_UNSET";
1964 }
1965 case TRANSIT_NONE: {
1966 return "TRANSIT_NONE";
1967 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08001968 case TRANSIT_ACTIVITY_OPEN: {
1969 return "TRANSIT_ACTIVITY_OPEN";
1970 }
1971 case TRANSIT_ACTIVITY_CLOSE: {
1972 return "TRANSIT_ACTIVITY_CLOSE";
1973 }
1974 case TRANSIT_TASK_OPEN: {
1975 return "TRANSIT_TASK_OPEN";
1976 }
1977 case TRANSIT_TASK_CLOSE: {
1978 return "TRANSIT_TASK_CLOSE";
1979 }
1980 case TRANSIT_TASK_TO_FRONT: {
1981 return "TRANSIT_TASK_TO_FRONT";
1982 }
1983 case TRANSIT_TASK_TO_BACK: {
1984 return "TRANSIT_TASK_TO_BACK";
1985 }
1986 case TRANSIT_WALLPAPER_CLOSE: {
1987 return "TRANSIT_WALLPAPER_CLOSE";
1988 }
1989 case TRANSIT_WALLPAPER_OPEN: {
1990 return "TRANSIT_WALLPAPER_OPEN";
1991 }
1992 case TRANSIT_WALLPAPER_INTRA_OPEN: {
1993 return "TRANSIT_WALLPAPER_INTRA_OPEN";
1994 }
1995 case TRANSIT_WALLPAPER_INTRA_CLOSE: {
1996 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
1997 }
Craig Mautnerbb742462014-07-07 15:28:55 -07001998 case TRANSIT_TASK_OPEN_BEHIND: {
1999 return "TRANSIT_TASK_OPEN_BEHIND";
2000 }
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07002001 case TRANSIT_ACTIVITY_RELAUNCH: {
2002 return "TRANSIT_ACTIVITY_RELAUNCH";
2003 }
Jorim Jaggi192086e2016-03-11 17:17:03 +01002004 case TRANSIT_DOCK_TASK_FROM_RECENTS: {
2005 return "TRANSIT_DOCK_TASK_FROM_RECENTS";
2006 }
Jorim Jaggife762342016-10-13 14:33:27 +02002007 case TRANSIT_KEYGUARD_GOING_AWAY: {
2008 return "TRANSIT_KEYGUARD_GOING_AWAY";
2009 }
2010 case TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
2011 return "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
2012 }
2013 case TRANSIT_KEYGUARD_OCCLUDE: {
2014 return "TRANSIT_KEYGUARD_OCCLUDE";
2015 }
2016 case TRANSIT_KEYGUARD_UNOCCLUDE: {
2017 return "TRANSIT_KEYGUARD_UNOCCLUDE";
2018 }
Jorim Jaggi98a9d202018-03-26 16:17:07 +02002019 case TRANSIT_TRANSLUCENT_ACTIVITY_OPEN: {
2020 return "TRANSIT_TRANSLUCENT_ACTIVITY_OPEN";
2021 }
2022 case TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE: {
2023 return "TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE";
2024 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08002025 default: {
2026 return "<UNKNOWN>";
2027 }
2028 }
2029 }
2030
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002031 private String appStateToString() {
2032 switch (mAppTransitionState) {
2033 case APP_STATE_IDLE:
2034 return "APP_STATE_IDLE";
2035 case APP_STATE_READY:
2036 return "APP_STATE_READY";
2037 case APP_STATE_RUNNING:
2038 return "APP_STATE_RUNNING";
2039 case APP_STATE_TIMEOUT:
2040 return "APP_STATE_TIMEOUT";
2041 default:
2042 return "unknown state=" + mAppTransitionState;
2043 }
2044 }
2045
2046 private String transitTypeToString() {
2047 switch (mNextAppTransitionType) {
2048 case NEXT_TRANSIT_TYPE_NONE:
2049 return "NEXT_TRANSIT_TYPE_NONE";
2050 case NEXT_TRANSIT_TYPE_CUSTOM:
2051 return "NEXT_TRANSIT_TYPE_CUSTOM";
Winson Chung044d5292014-11-06 11:05:19 -08002052 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
2053 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002054 case NEXT_TRANSIT_TYPE_SCALE_UP:
2055 return "NEXT_TRANSIT_TYPE_SCALE_UP";
2056 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
2057 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
2058 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
2059 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
Winson Chunga4ccb862014-08-22 15:26:27 -07002060 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
2061 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
2062 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
2063 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
Tony Mak64b8d562017-12-28 17:44:02 +00002064 case NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:
2065 return "NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002066 default:
2067 return "unknown type=" + mNextAppTransitionType;
2068 }
2069 }
2070
Steven Timotiusaf03df62017-07-18 16:56:43 -07002071 void writeToProto(ProtoOutputStream proto, long fieldId) {
2072 final long token = proto.start(fieldId);
2073 proto.write(APP_TRANSITION_STATE, mAppTransitionState);
2074 proto.write(LAST_USED_APP_TRANSITION, mLastUsedAppTransition);
2075 proto.end(token);
2076 }
2077
Craig Mautner164d4bb2012-11-26 13:51:23 -08002078 @Override
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002079 public void dump(PrintWriter pw, String prefix) {
2080 pw.print(prefix); pw.println(this);
2081 pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002082 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002083 pw.print(prefix); pw.print("mNextAppTransitionType=");
2084 pw.println(transitTypeToString());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002085 }
2086 switch (mNextAppTransitionType) {
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002087 case NEXT_TRANSIT_TYPE_CUSTOM:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002088 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Craig Mautner164d4bb2012-11-26 13:51:23 -08002089 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002090 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
Craig Mautner164d4bb2012-11-26 13:51:23 -08002091 pw.print(Integer.toHexString(mNextAppTransitionEnter));
2092 pw.print(" mNextAppTransitionExit=0x");
2093 pw.println(Integer.toHexString(mNextAppTransitionExit));
2094 break;
Winson Chung044d5292014-11-06 11:05:19 -08002095 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002096 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Winson Chung044d5292014-11-06 11:05:19 -08002097 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002098 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
Winson Chung044d5292014-11-06 11:05:19 -08002099 pw.print(Integer.toHexString(mNextAppTransitionInPlace));
2100 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002101 case NEXT_TRANSIT_TYPE_SCALE_UP: {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002102 getDefaultNextAppTransitionStartRect(mTmpRect);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002103 pw.print(prefix); pw.print("mNextAppTransitionStartX=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002104 pw.print(mTmpRect.left);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002105 pw.print(" mNextAppTransitionStartY=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002106 pw.println(mTmpRect.top);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002107 pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002108 pw.print(mTmpRect.width());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002109 pw.print(" mNextAppTransitionStartHeight=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002110 pw.println(mTmpRect.height());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002111 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002112 }
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002113 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
2114 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
Winson Chunga4ccb862014-08-22 15:26:27 -07002115 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002116 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
2117 pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
2118 pw.println(mDefaultNextAppTransitionAnimationSpec);
2119 pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
2120 pw.println(mNextAppTransitionAnimationsSpecs);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002121 pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
2122 pw.println(mNextAppTransitionScaleUp);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002123 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002124 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002125 }
2126 if (mNextAppTransitionCallback != null) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002127 pw.print(prefix); pw.print("mNextAppTransitionCallback=");
2128 pw.println(mNextAppTransitionCallback);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002129 }
Chong Zhang60091a92016-07-27 17:52:45 -07002130 if (mLastUsedAppTransition != TRANSIT_NONE) {
2131 pw.print(prefix); pw.print("mLastUsedAppTransition=");
2132 pw.println(appTransitionToString(mLastUsedAppTransition));
2133 pw.print(prefix); pw.print("mLastOpeningApp=");
2134 pw.println(mLastOpeningApp);
2135 pw.print(prefix); pw.print("mLastClosingApp=");
2136 pw.println(mLastClosingApp);
2137 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002138 }
Amith Yamasani4befbec2013-07-10 16:18:01 -07002139
2140 public void setCurrentUser(int newUserId) {
2141 mCurrentUserId = newUserId;
2142 }
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002143
2144 /**
2145 * @return true if transition is not running and should not be skipped, false if transition is
2146 * already running
2147 */
Jorim Jaggif84e2f62018-01-16 14:17:59 +01002148 boolean prepareAppTransitionLocked(@TransitionType int transit, boolean alwaysKeepCurrent,
2149 @TransitionFlags int flags, boolean forceOverride) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002150 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
2151 + " transit=" + appTransitionToString(transit)
2152 + " " + this
2153 + " alwaysKeepCurrent=" + alwaysKeepCurrent
2154 + " Callers=" + Debug.getCallers(3));
Jorim Jaggife762342016-10-13 14:33:27 +02002155 if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
2156 || mNextAppTransition == TRANSIT_NONE) {
2157 setAppTransition(transit, flags);
Jorim Jaggia69243a2017-06-15 15:10:38 -04002158 }
2159 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
2160 // relies on the fact that we always execute a Keyguard transition after preparing one.
2161 else if (!alwaysKeepCurrent && !isKeyguardTransit(transit)) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002162 if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
2163 // Opening a new task always supersedes a close for the anim.
Jorim Jaggife762342016-10-13 14:33:27 +02002164 setAppTransition(transit, flags);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002165 } else if (transit == TRANSIT_ACTIVITY_OPEN
2166 && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
2167 // Opening a new activity always supersedes a close for the anim.
Jorim Jaggife762342016-10-13 14:33:27 +02002168 setAppTransition(transit, flags);
Jorim Jaggicecf4242018-02-21 18:46:53 +01002169 } else if (isTaskTransit(transit) && isActivityTransit(mNextAppTransition)) {
2170 // Task animations always supersede activity animations, because if we have both, it
2171 // usually means that activity transition were just trampoline activities.
2172 setAppTransition(transit, flags);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002173 }
2174 }
2175 boolean prepared = prepare();
2176 if (isTransitionSet()) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08002177 mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2178 mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002179 }
2180 return prepared;
2181 }
Winsonb2024762016-04-05 17:32:30 -07002182
2183 /**
Jorim Jaggife762342016-10-13 14:33:27 +02002184 * @return true if {@param transit} is representing a transition in which Keyguard is going
2185 * away, false otherwise
2186 */
2187 public static boolean isKeyguardGoingAwayTransit(int transit) {
2188 return transit == TRANSIT_KEYGUARD_GOING_AWAY
2189 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
2190 }
2191
2192 private static boolean isKeyguardTransit(int transit) {
2193 return isKeyguardGoingAwayTransit(transit) || transit == TRANSIT_KEYGUARD_OCCLUDE
2194 || transit == TRANSIT_KEYGUARD_UNOCCLUDE;
2195 }
2196
Jorim Jaggi98a9d202018-03-26 16:17:07 +02002197 static boolean isTaskTransit(int transit) {
2198 return isTaskOpenTransit(transit)
Jorim Jaggicecf4242018-02-21 18:46:53 +01002199 || transit == TRANSIT_TASK_CLOSE
Jorim Jaggicecf4242018-02-21 18:46:53 +01002200 || transit == TRANSIT_TASK_TO_BACK
Jorim Jaggicecf4242018-02-21 18:46:53 +01002201 || transit == TRANSIT_TASK_IN_PLACE;
2202 }
2203
Jorim Jaggi98a9d202018-03-26 16:17:07 +02002204 private static boolean isTaskOpenTransit(int transit) {
2205 return transit == TRANSIT_TASK_OPEN
2206 || transit == TRANSIT_TASK_OPEN_BEHIND
2207 || transit == TRANSIT_TASK_TO_FRONT;
2208 }
2209
2210 static boolean isActivityTransit(int transit) {
Jorim Jaggicecf4242018-02-21 18:46:53 +01002211 return transit == TRANSIT_ACTIVITY_OPEN
2212 || transit == TRANSIT_ACTIVITY_CLOSE
2213 || transit == TRANSIT_ACTIVITY_RELAUNCH;
2214 }
2215
Jorim Jaggife762342016-10-13 14:33:27 +02002216 /**
Manu Cornetd7376802017-01-13 13:44:07 -08002217 * @return whether the transition should show the thumbnail being scaled down.
2218 */
2219 private boolean shouldScaleDownThumbnailTransition(int uiMode, int orientation) {
Sid Soundararajan0e88d322017-03-07 15:37:30 -08002220 return mGridLayoutRecentsEnabled
Manu Cornetd7376802017-01-13 13:44:07 -08002221 || orientation == Configuration.ORIENTATION_PORTRAIT;
2222 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002223}