blob: 48b6e51eacfbd5a4454ec9abd8f084ed1f07d971 [file] [log] [blame]
Craig Mautner164d4bb2012-11-26 13:51:23 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
Jorim Jaggif84e2f62018-01-16 14:17:59 +010019import static android.view.WindowManager.LayoutParams;
20import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
21import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
22import static android.view.WindowManager.TRANSIT_ACTIVITY_RELAUNCH;
Adrian Roos93577212018-04-10 14:12:10 -070023import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010024import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
25import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
26import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
27import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
28import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
29import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
30import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
31import static android.view.WindowManager.TRANSIT_NONE;
32import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
Jorim Jaggicecf4242018-02-21 18:46:53 +010033import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010034import static android.view.WindowManager.TRANSIT_TASK_OPEN;
35import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
36import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
37import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
Jorim Jaggi98a9d202018-03-26 16:17:07 +020038import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
39import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010040import static android.view.WindowManager.TRANSIT_UNSET;
41import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
42import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
43import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
44import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
Tony Mak83546a82018-01-22 13:56:20 +000045
Filip Gruszczynski82861362015-10-16 14:21:09 -070046import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
47import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
48import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
49import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
50import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
51import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
52import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
53import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
54import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
55import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
56import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
57import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
58import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
59import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
60import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
61import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
62import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
63import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
64import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
65import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
66import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
67import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
Filip Gruszczynski198dcbf2016-01-18 10:02:00 -080068import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
69import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080070import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
71import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Adrian Roose99bc052017-11-20 17:55:31 +010072import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
Tony Mak089c35e2017-12-18 20:34:14 +000073import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
Matthew Ngbf1d9852017-03-14 12:23:09 -070074import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +010075import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070076import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
77import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
Filip Gruszczynski82861362015-10-16 14:21:09 -070078
Tony Mak64b8d562017-12-28 17:44:02 +000079import android.annotation.DrawableRes;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -070080import android.annotation.Nullable;
Matthew Ng43db6d22017-06-27 15:29:39 -070081import android.app.ActivityManager;
Tony Mak089c35e2017-12-18 20:34:14 +000082import android.content.ComponentName;
Craig Mautner164d4bb2012-11-26 13:51:23 -080083import android.content.Context;
Winson21700932016-03-24 17:26:23 -070084import android.content.res.Configuration;
Todd Kennedy64c57a82018-04-19 15:17:24 -070085import android.content.res.ResourceId;
John Reck519ad482018-02-12 17:08:48 -080086import android.graphics.Bitmap;
87import android.graphics.Canvas;
Tony Mak64b8d562017-12-28 17:44:02 +000088import android.graphics.Color;
Winson Chungaa7fa012017-05-24 15:50:06 -070089import android.graphics.GraphicBuffer;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +010090import android.graphics.Path;
John Reck519ad482018-02-12 17:08:48 -080091import android.graphics.Picture;
Winson Chung399f6202014-03-19 10:47:20 -070092import android.graphics.Rect;
Tony Mak64b8d562017-12-28 17:44:02 +000093import android.graphics.drawable.Drawable;
Jorim Jaggied410b62017-05-05 15:16:14 +020094import android.os.Binder;
Craig Mautner164d4bb2012-11-26 13:51:23 -080095import android.os.Debug;
Jorim Jaggi77ba4802015-02-18 13:57:50 +010096import android.os.IBinder;
Craig Mautner164d4bb2012-11-26 13:51:23 -080097import android.os.IRemoteCallback;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +010098import android.os.RemoteException;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020099import android.os.SystemClock;
Manu Cornetd7376802017-01-13 13:44:07 -0800100import android.os.SystemProperties;
Tony Mak089c35e2017-12-18 20:34:14 +0000101import android.os.UserHandle;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800102import android.util.ArraySet;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800103import android.util.Slog;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700104import android.util.SparseArray;
Steven Timotiusaf03df62017-07-18 16:56:43 -0700105import android.util.proto.ProtoOutputStream;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700106import android.view.AppTransitionAnimationSpec;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100107import android.view.IAppTransitionAnimationSpecsFuture;
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100108import android.view.RemoteAnimationAdapter;
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100109import android.view.WindowManager.TransitionFlags;
110import android.view.WindowManager.TransitionType;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800111import android.view.animation.AlphaAnimation;
112import android.view.animation.Animation;
113import android.view.animation.AnimationSet;
114import android.view.animation.AnimationUtils;
Winson Chung399f6202014-03-19 10:47:20 -0700115import android.view.animation.ClipRectAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800116import android.view.animation.Interpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700117import android.view.animation.PathInterpolator;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800118import android.view.animation.ScaleAnimation;
Winson Chung399f6202014-03-19 10:47:20 -0700119import android.view.animation.TranslateAnimation;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700120
Jorim Jaggi98a9d202018-03-26 16:17:07 +0200121import com.android.internal.R;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800122import com.android.internal.util.DumpUtils.Dump;
123import com.android.server.AttributeCache;
124import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800125import com.android.server.wm.animation.ClipRectLRAnimation;
126import com.android.server.wm.animation.ClipRectTBAnimation;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100127import com.android.server.wm.animation.CurvedTranslateAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800128
129import java.io.PrintWriter;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100130import java.util.ArrayList;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100131import java.util.concurrent.ExecutorService;
132import java.util.concurrent.Executors;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800133
Craig Mautner164d4bb2012-11-26 13:51:23 -0800134// State management of app transitions. When we are preparing for a
135// transition, mNextAppTransition will be the kind of transition to
136// perform or TRANSIT_NONE if we are not waiting. If we are waiting,
137// mOpeningApps and mClosingApps are the lists of tokens that will be
138// made visible or hidden at the next transition.
139public class AppTransition implements Dump {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800140 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700141 private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800142
Winson Chunga4ccb862014-08-22 15:26:27 -0700143 /** Fraction of animation at which the recents thumbnail stays completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700144 private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800145 /** Fraction of animation at which the recents thumbnail becomes completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700146 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800147
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800148 static final int DEFAULT_APP_TRANSITION_DURATION = 336;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800149
150 /** Interpolator to be used for animations that respond directly to a touch */
151 static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
152 new PathInterpolator(0.3f, 0f, 0.1f, 1f);
153
Jorim Jaggic69bd222016-03-15 14:38:37 +0100154 private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR =
155 new PathInterpolator(0.85f, 0f, 1f, 1f);
156
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800157 /**
158 * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
159 * involved, to make it more understandable.
160 */
161 private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700162 private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700163 private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800164
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800165 private final Context mContext;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800166 private final WindowManagerService mService;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800167
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100168 private @TransitionType int mNextAppTransition = TRANSIT_UNSET;
169 private @TransitionFlags int mNextAppTransitionFlags = 0;
Chong Zhang60091a92016-07-27 17:52:45 -0700170 private int mLastUsedAppTransition = TRANSIT_UNSET;
171 private String mLastOpeningApp;
172 private String mLastClosingApp;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800173
174 private static final int NEXT_TRANSIT_TYPE_NONE = 0;
175 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
176 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
177 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
178 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
Winson Chunga4ccb862014-08-22 15:26:27 -0700179 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
180 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
Winson Chung044d5292014-11-06 11:05:19 -0800181 private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
Chet Haase10e23ab2015-02-11 15:08:38 -0800182 private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
Tony Mak089c35e2017-12-18 20:34:14 +0000183
184 /**
185 * Refers to the transition to activity started by using {@link
186 * android.content.pm.crossprofile.CrossProfileApps#startMainActivity(ComponentName, UserHandle)
187 * }.
188 */
189 private static final int NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS = 9;
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100190 private static final int NEXT_TRANSIT_TYPE_REMOTE = 10;
191
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800192 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
193
Winson Chung399f6202014-03-19 10:47:20 -0700194 // These are the possible states for the enter/exit activities during a thumbnail transition
195 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
196 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
197 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
198 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
199
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800200 private String mNextAppTransitionPackage;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800201 // Used for thumbnail transitions. True if we're scaling up, false if scaling down
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800202 private boolean mNextAppTransitionScaleUp;
203 private IRemoteCallback mNextAppTransitionCallback;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +0100204 private IRemoteCallback mNextAppTransitionFutureCallback;
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -0700205 private IRemoteCallback mAnimationFinishedCallback;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800206 private int mNextAppTransitionEnter;
207 private int mNextAppTransitionExit;
Winson Chung044d5292014-11-06 11:05:19 -0800208 private int mNextAppTransitionInPlace;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700209
210 // Keyed by task id.
211 private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
212 = new SparseArray<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100213 private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
214 private boolean mNextAppTransitionAnimationsSpecsPending;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700215 private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
216
Winson Chunga4ccb862014-08-22 15:26:27 -0700217 private Rect mNextAppTransitionInsets = new Rect();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800218
Winson Chung2820c452014-04-15 15:34:44 -0700219 private Rect mTmpFromClipRect = new Rect();
220 private Rect mTmpToClipRect = new Rect();
221
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700222 private final Rect mTmpRect = new Rect();
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700223
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800224 private final static int APP_STATE_IDLE = 0;
225 private final static int APP_STATE_READY = 1;
226 private final static int APP_STATE_RUNNING = 2;
227 private final static int APP_STATE_TIMEOUT = 3;
228 private int mAppTransitionState = APP_STATE_IDLE;
229
230 private final int mConfigShortAnimTime;
Craig Mautner321bdf52012-12-18 09:53:24 -0800231 private final Interpolator mDecelerateInterpolator;
Winson Chunga4ccb862014-08-22 15:26:27 -0700232 private final Interpolator mThumbnailFadeInInterpolator;
233 private final Interpolator mThumbnailFadeOutInterpolator;
Chet Haase10e23ab2015-02-11 15:08:38 -0800234 private final Interpolator mLinearOutSlowInInterpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700235 private final Interpolator mFastOutLinearInInterpolator;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100236 private final Interpolator mFastOutSlowInInterpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700237 private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
238
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700239 private final int mClipRevealTranslationY;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800240
Amith Yamasani4befbec2013-07-10 16:18:01 -0700241 private int mCurrentUserId = 0;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800242 private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
Amith Yamasani4befbec2013-07-10 16:18:01 -0700243
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100244 private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100245 private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100246
Jorim Jaggif97ed922016-02-18 18:57:07 -0800247 private int mLastClipRevealMaxTranslation;
248 private boolean mLastHadClipReveal;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700249 private boolean mProlongedAnimationsEnded;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800250
Manu Cornetd7376802017-01-13 13:44:07 -0800251 private final boolean mGridLayoutRecentsEnabled;
Matthew Ng43db6d22017-06-27 15:29:39 -0700252 private final boolean mLowRamRecentsEnabled;
Manu Cornetd7376802017-01-13 13:44:07 -0800253
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100254 private RemoteAnimationController mRemoteAnimationController;
255
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800256 AppTransition(Context context, WindowManagerService service) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800257 mContext = context;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800258 mService = service;
Chet Haase10e23ab2015-02-11 15:08:38 -0800259 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
260 com.android.internal.R.interpolator.linear_out_slow_in);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700261 mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
262 com.android.internal.R.interpolator.fast_out_linear_in);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100263 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
264 com.android.internal.R.interpolator.fast_out_slow_in);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800265 mConfigShortAnimTime = context.getResources().getInteger(
266 com.android.internal.R.integer.config_shortAnimTime);
Craig Mautner321bdf52012-12-18 09:53:24 -0800267 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
268 com.android.internal.R.interpolator.decelerate_cubic);
Winson Chunga4ccb862014-08-22 15:26:27 -0700269 mThumbnailFadeInInterpolator = new Interpolator() {
270 @Override
271 public float getInterpolation(float input) {
272 // Linear response for first fraction, then complete after that.
273 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
274 return 0f;
275 }
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700276 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /
Winson Chunga4ccb862014-08-22 15:26:27 -0700277 (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700278 return mFastOutLinearInInterpolator.getInterpolation(t);
Winson Chunga4ccb862014-08-22 15:26:27 -0700279 }
280 };
281 mThumbnailFadeOutInterpolator = new Interpolator() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800282 @Override
283 public float getInterpolation(float input) {
284 // Linear response for first fraction, then complete after that.
285 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700286 float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
287 return mLinearOutSlowInInterpolator.getInterpolation(t);
Craig Mautner321bdf52012-12-18 09:53:24 -0800288 }
Winson Chunga4ccb862014-08-22 15:26:27 -0700289 return 1f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800290 }
291 };
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700292 mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP
293 * mContext.getResources().getDisplayMetrics().density);
Manu Cornetd7376802017-01-13 13:44:07 -0800294 mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
Matthew Ng43db6d22017-06-27 15:29:39 -0700295 mLowRamRecentsEnabled = ActivityManager.isLowRamDeviceStatic();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800296 }
297
298 boolean isTransitionSet() {
299 return mNextAppTransition != TRANSIT_UNSET;
300 }
301
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100302 boolean isTransitionEqual(@TransitionType int transit) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800303 return mNextAppTransition == transit;
304 }
305
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100306 @TransitionType int getAppTransition() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800307 return mNextAppTransition;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800308 }
309
Jorim Jaggife762342016-10-13 14:33:27 +0200310 private void setAppTransition(int transit, int flags) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800311 mNextAppTransition = transit;
Jorim Jaggife762342016-10-13 14:33:27 +0200312 mNextAppTransitionFlags |= flags;
Chong Zhang60091a92016-07-27 17:52:45 -0700313 setLastAppTransition(TRANSIT_UNSET, null, null);
Jorim Jaggi245281c2017-06-07 14:33:04 -0700314 updateBooster();
Chong Zhang60091a92016-07-27 17:52:45 -0700315 }
316
317 void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp) {
318 mLastUsedAppTransition = transit;
319 mLastOpeningApp = "" + openingApp;
320 mLastClosingApp = "" + closingApp;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800321 }
322
323 boolean isReady() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800324 return mAppTransitionState == APP_STATE_READY
325 || mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800326 }
327
Craig Mautnerae446592012-12-06 19:05:05 -0800328 void setReady() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700329 setAppTransitionState(APP_STATE_READY);
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100330 fetchAppTransitionSpecsFromFuture();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800331 }
332
333 boolean isRunning() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800334 return mAppTransitionState == APP_STATE_RUNNING;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800335 }
336
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800337 void setIdle() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700338 setAppTransitionState(APP_STATE_IDLE);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800339 }
340
341 boolean isTimeout() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800342 return mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800343 }
344
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800345 void setTimeout() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700346 setAppTransitionState(APP_STATE_TIMEOUT);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800347 }
348
Winson Chungaa7fa012017-05-24 15:50:06 -0700349 GraphicBuffer getAppTransitionThumbnailHeader(int taskId) {
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700350 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800351 if (spec == null) {
352 spec = mDefaultNextAppTransitionAnimationSpec;
353 }
Winson Chungaa7fa012017-05-24 15:50:06 -0700354 return spec != null ? spec.buffer : null;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800355 }
356
Winson Chunga4ccb862014-08-22 15:26:27 -0700357 /** Returns whether the next thumbnail transition is aspect scaled up. */
358 boolean isNextThumbnailTransitionAspectScaled() {
359 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
360 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
361 }
362
363 /** Returns whether the next thumbnail transition is scaling up. */
364 boolean isNextThumbnailTransitionScaleUp() {
365 return mNextAppTransitionScaleUp;
366 }
367
Filip Gruszczynski4cbc3152015-12-07 11:50:57 -0800368 boolean isNextAppTransitionThumbnailUp() {
369 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
370 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP;
371 }
372
373 boolean isNextAppTransitionThumbnailDown() {
374 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN ||
375 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
376 }
377
Tony Mak64b8d562017-12-28 17:44:02 +0000378
379 boolean isNextAppTransitionOpenCrossProfileApps() {
380 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
381 }
382
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100383 /**
384 * @return true if and only if we are currently fetching app transition specs from the future
385 * passed into {@link #overridePendingAppTransitionMultiThumbFuture}
386 */
387 boolean isFetchingAppTransitionsSpecs() {
388 return mNextAppTransitionAnimationsSpecsPending;
389 }
390
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700391 private boolean prepare() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800392 if (!isRunning()) {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700393 setAppTransitionState(APP_STATE_IDLE);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100394 notifyAppTransitionPendingLocked();
Jorim Jaggif97ed922016-02-18 18:57:07 -0800395 mLastHadClipReveal = false;
396 mLastClipRevealMaxTranslation = 0;
397 mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700398 return true;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800399 }
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700400 return false;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800401 }
402
Jorim Jaggife762342016-10-13 14:33:27 +0200403 /**
404 * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
405 * layout pass needs to be done
406 */
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200407 int goodToGo(int transit, AppWindowToken topOpeningApp,
408 AppWindowToken topClosingApp, ArraySet<AppWindowToken> openingApps,
Jorim Jaggife762342016-10-13 14:33:27 +0200409 ArraySet<AppWindowToken> closingApps) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800410 mNextAppTransition = TRANSIT_UNSET;
Jorim Jaggife762342016-10-13 14:33:27 +0200411 mNextAppTransitionFlags = 0;
Jorim Jaggi245281c2017-06-07 14:33:04 -0700412 setAppTransitionState(APP_STATE_RUNNING);
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200413 final AnimationAdapter topOpeningAnim = topOpeningApp != null
414 ? topOpeningApp.getAnimation()
415 : null;
Jorim Jaggife762342016-10-13 14:33:27 +0200416 int redoLayout = notifyAppTransitionStartingLocked(transit,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200417 topOpeningApp != null ? topOpeningApp.token : null,
418 topClosingApp != null ? topClosingApp.token : null,
419 topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0,
420 topOpeningAnim != null
421 ? topOpeningAnim.getStatusBarTransitionsStartTime()
422 : SystemClock.uptimeMillis(),
423 AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800424 mService.getDefaultDisplayContentLocked().getDockedDividerController()
Jorim Jaggife762342016-10-13 14:33:27 +0200425 .notifyAppTransitionStarting(openingApps, transit);
Jorim Jaggi363ab982016-04-26 19:51:20 -0700426
427 // Prolong the start for the transition when docking a task from recents, unless recents
428 // ended it already then we don't need to wait.
Jorim Jaggife762342016-10-13 14:33:27 +0200429 if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) {
Jorim Jaggi363ab982016-04-26 19:51:20 -0700430 for (int i = openingApps.size() - 1; i >= 0; i--) {
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200431 final AppWindowToken app = openingApps.valueAt(i);
432 app.startDelayingAnimationStart();
Jorim Jaggi363ab982016-04-26 19:51:20 -0700433 }
434 }
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100435 if (mRemoteAnimationController != null) {
436 mRemoteAnimationController.goodToGo();
437 }
Jorim Jaggife762342016-10-13 14:33:27 +0200438 return redoLayout;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700439 }
440
441 /**
442 * Let the transitions manager know that the somebody wanted to end the prolonged animations.
443 */
444 void notifyProlongedAnimationsEnded() {
445 mProlongedAnimationsEnded = true;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800446 }
447
448 void clear() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800449 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800450 mNextAppTransitionPackage = null;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700451 mNextAppTransitionAnimationsSpecs.clear();
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100452 mRemoteAnimationController = null;
Jorim Jaggi65193992015-11-23 16:49:59 -0800453 mNextAppTransitionAnimationsSpecsFuture = null;
454 mDefaultNextAppTransitionAnimationSpec = null;
455 mAnimationFinishedCallback = null;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700456 mProlongedAnimationsEnded = false;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800457 }
458
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800459 void freeze() {
Jorim Jaggife762342016-10-13 14:33:27 +0200460 final int transit = mNextAppTransition;
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100461 setAppTransition(TRANSIT_UNSET, 0 /* flags */);
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800462 clear();
463 setReady();
Jorim Jaggife762342016-10-13 14:33:27 +0200464 notifyAppTransitionCancelledLocked(transit);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100465 }
466
Jorim Jaggi245281c2017-06-07 14:33:04 -0700467 private void setAppTransitionState(int state) {
468 mAppTransitionState = state;
469 updateBooster();
470 }
471
472 /**
473 * Updates whether we currently boost wm locked sections and the animation thread. We want to
474 * boost the priorities to a more important value whenever an app transition is going to happen
475 * soon or an app transition is running.
476 */
Jorim Jaggic8cc2292018-03-15 20:16:15 +0100477 void updateBooster() {
478 WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning(needsBoosting());
479 }
480
481 private boolean needsBoosting() {
482 final boolean recentsAnimRunning = mService.getRecentsAnimationController() != null;
483 return mNextAppTransition != TRANSIT_UNSET
484 || mAppTransitionState == APP_STATE_READY
485 || mAppTransitionState == APP_STATE_RUNNING
486 || recentsAnimRunning;
Jorim Jaggi245281c2017-06-07 14:33:04 -0700487 }
488
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100489 void registerListenerLocked(AppTransitionListener listener) {
490 mListeners.add(listener);
491 }
492
Wale Ogunwalea48eadb2015-05-14 17:43:12 -0700493 public void notifyAppTransitionFinishedLocked(IBinder token) {
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100494 for (int i = 0; i < mListeners.size(); i++) {
495 mListeners.get(i).onAppTransitionFinishedLocked(token);
496 }
497 }
498
499 private void notifyAppTransitionPendingLocked() {
500 for (int i = 0; i < mListeners.size(); i++) {
501 mListeners.get(i).onAppTransitionPendingLocked();
502 }
503 }
504
Jorim Jaggife762342016-10-13 14:33:27 +0200505 private void notifyAppTransitionCancelledLocked(int transit) {
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100506 for (int i = 0; i < mListeners.size(); i++) {
Jorim Jaggife762342016-10-13 14:33:27 +0200507 mListeners.get(i).onAppTransitionCancelledLocked(transit);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100508 }
509 }
510
Jorim Jaggife762342016-10-13 14:33:27 +0200511 private int notifyAppTransitionStartingLocked(int transit, IBinder openToken,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200512 IBinder closeToken, long duration, long statusBarAnimationStartTime,
513 long statusBarAnimationDuration) {
Jorim Jaggife762342016-10-13 14:33:27 +0200514 int redoLayout = 0;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100515 for (int i = 0; i < mListeners.size(); i++) {
Jorim Jaggife762342016-10-13 14:33:27 +0200516 redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, openToken,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200517 closeToken, duration, statusBarAnimationStartTime, statusBarAnimationDuration);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100518 }
Jorim Jaggife762342016-10-13 14:33:27 +0200519 return redoLayout;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800520 }
521
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100522 private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800523 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
524 + (lp != null ? lp.packageName : null)
525 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
526 if (lp != null && lp.windowAnimations != 0) {
527 // If this is a system resource, don't try to load it from the
528 // application resources. It is nice to avoid loading application
529 // resources if we can.
530 String packageName = lp.packageName != null ? lp.packageName : "android";
531 int resId = lp.windowAnimations;
532 if ((resId&0xFF000000) == 0x01000000) {
533 packageName = "android";
534 }
535 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
536 + packageName);
537 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700538 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800539 }
540 return null;
541 }
542
543 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
544 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
545 + packageName + " resId=0x" + Integer.toHexString(resId));
546 if (packageName != null) {
547 if ((resId&0xFF000000) == 0x01000000) {
548 packageName = "android";
549 }
550 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
551 + packageName);
552 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700553 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800554 }
555 return null;
556 }
557
Jorim Jaggi0a1523d2018-04-19 17:48:38 +0200558 Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {
Todd Kennedy64c57a82018-04-19 15:17:24 -0700559 int resId = ResourceId.ID_NULL;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800560 Context context = mContext;
Jorim Jaggi5f95b002018-04-19 13:27:52 +0000561 if (animAttr >= 0) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800562 AttributeCache.Entry ent = getCachedAnimations(lp);
563 if (ent != null) {
564 context = ent.context;
Todd Kennedy64c57a82018-04-19 15:17:24 -0700565 resId = ent.array.getResourceId(animAttr, 0);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800566 }
567 }
Todd Kennedy64c57a82018-04-19 15:17:24 -0700568 resId = updateToTranslucentAnimIfNeeded(resId, transit);
569 if (ResourceId.isValid(resId)) {
570 return AnimationUtils.loadAnimation(context, resId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800571 }
572 return null;
573 }
574
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100575 Animation loadAnimationRes(LayoutParams lp, int resId) {
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700576 Context context = mContext;
Todd Kennedy64c57a82018-04-19 15:17:24 -0700577 if (ResourceId.isValid(resId)) {
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700578 AttributeCache.Entry ent = getCachedAnimations(lp);
579 if (ent != null) {
580 context = ent.context;
581 }
582 return AnimationUtils.loadAnimation(context, resId);
583 }
584 return null;
585 }
586
587 private Animation loadAnimationRes(String packageName, int resId) {
Todd Kennedy64c57a82018-04-19 15:17:24 -0700588 if (ResourceId.isValid(resId)) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800589 AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
590 if (ent != null) {
Todd Kennedy64c57a82018-04-19 15:17:24 -0700591 return AnimationUtils.loadAnimation(ent.context, resId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800592 }
593 }
Craig Mautner164d4bb2012-11-26 13:51:23 -0800594 return null;
595 }
596
Jorim Jaggi0a1523d2018-04-19 17:48:38 +0200597 private int updateToTranslucentAnimIfNeeded(int anim, int transit) {
598 if (transit == TRANSIT_TRANSLUCENT_ACTIVITY_OPEN && anim == R.anim.activity_open_enter) {
599 return R.anim.activity_translucent_open_enter;
600 }
601 if (transit == TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE && anim == R.anim.activity_close_exit) {
602 return R.anim.activity_translucent_close_exit;
603 }
604 return anim;
605 }
606
Craig Mautner164d4bb2012-11-26 13:51:23 -0800607 /**
608 * Compute the pivot point for an animation that is scaling from a small
609 * rect on screen to a larger rect. The pivot point varies depending on
610 * the distance between the inner and outer edges on both sides. This
611 * function computes the pivot point for one dimension.
612 * @param startPos Offset from left/top edge of outer rectangle to
613 * left/top edge of inner rectangle.
614 * @param finalScale The scaling factor between the size of the outer
615 * and inner rectangles.
616 */
617 private static float computePivot(int startPos, float finalScale) {
Jorim Jaggic6c89a82016-01-28 17:48:21 -0800618
619 /*
620 Theorem of intercepting lines:
621
622 + + +-----------------------------------------------+
623 | | | |
624 | | | |
625 | | | |
626 | | | |
627 x | y | | |
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 |
663 |
664 |
665 |
666 |
667 |
668 + ++
669 p ++
670
671 scale = (x - y) / x
672 <=> x = -y / (scale - 1)
673 */
Craig Mautner164d4bb2012-11-26 13:51:23 -0800674 final float denom = finalScale-1;
675 if (Math.abs(denom) < .0001f) {
676 return startPos;
677 }
678 return -startPos / denom;
679 }
680
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700681 private Animation createScaleUpAnimationLocked(int transit, boolean enter,
682 Rect containingFrame) {
683 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700684 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700685 final int appWidth = containingFrame.width();
686 final int appHeight = containingFrame.height();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800687 if (enter) {
688 // Entering app zooms out from the center of the initial rect.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700689 float scaleW = mTmpRect.width() / (float) appWidth;
690 float scaleH = mTmpRect.height() / (float) appHeight;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800691 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700692 computePivot(mTmpRect.left, scaleW),
Winson4c3fecd2016-07-13 12:29:48 -0700693 computePivot(mTmpRect.top, scaleH));
Craig Mautner321bdf52012-12-18 09:53:24 -0800694 scale.setInterpolator(mDecelerateInterpolator);
695
Craig Mautner164d4bb2012-11-26 13:51:23 -0800696 Animation alpha = new AlphaAnimation(0, 1);
Winson Chunga4ccb862014-08-22 15:26:27 -0700697 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
Craig Mautner321bdf52012-12-18 09:53:24 -0800698
699 AnimationSet set = new AnimationSet(false);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800700 set.addAnimation(scale);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800701 set.addAnimation(alpha);
702 set.setDetachWallpaper(true);
703 a = set;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800704 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
705 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800706 // If we are on top of the wallpaper, we need an animation that
707 // correctly handles the wallpaper staying static behind all of
708 // the animated elements. To do this, will just have the existing
709 // element fade out.
710 a = new AlphaAnimation(1, 0);
711 a.setDetachWallpaper(true);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800712 } else {
Craig Mautner321bdf52012-12-18 09:53:24 -0800713 // For normal animations, the exiting element just holds in place.
714 a = new AlphaAnimation(1, 1);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800715 }
Craig Mautner321bdf52012-12-18 09:53:24 -0800716
717 // Pick the desired duration. If this is an inter-activity transition,
718 // it is the standard duration for that. Otherwise we use the longer
719 // task transition duration.
720 final long duration;
721 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800722 case TRANSIT_ACTIVITY_OPEN:
723 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800724 duration = mConfigShortAnimTime;
725 break;
726 default:
727 duration = DEFAULT_APP_TRANSITION_DURATION;
728 break;
729 }
730 a.setDuration(duration);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800731 a.setFillAfter(true);
Craig Mautner321bdf52012-12-18 09:53:24 -0800732 a.setInterpolator(mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800733 a.initialize(appWidth, appHeight, appWidth, appHeight);
734 return a;
735 }
736
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700737 private void getDefaultNextAppTransitionStartRect(Rect rect) {
738 if (mDefaultNextAppTransitionAnimationSpec == null ||
739 mDefaultNextAppTransitionAnimationSpec.rect == null) {
Jorim Jaggi2550f3f2017-03-14 20:15:59 +0100740 Slog.e(TAG, "Starting rect for app requested, but none available", new Throwable());
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700741 rect.setEmpty();
742 } else {
743 rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
744 }
745 }
746
747 void getNextAppTransitionStartRect(int taskId, Rect rect) {
748 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800749 if (spec == null) {
750 spec = mDefaultNextAppTransitionAnimationSpec;
751 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700752 if (spec == null || spec.rect == null) {
Jorim Jaggi2550f3f2017-03-14 20:15:59 +0100753 Slog.e(TAG, "Starting rect for task: " + taskId + " requested, but not available",
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700754 new Throwable());
755 rect.setEmpty();
756 } else {
757 rect.set(spec.rect);
758 }
759 }
760
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800761 private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height,
Winson Chungaa7fa012017-05-24 15:50:06 -0700762 GraphicBuffer buffer) {
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700763 mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
Winson Chungaa7fa012017-05-24 15:50:06 -0700764 buffer, new Rect(left, top, left + width, top + height));
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700765 }
766
Jorim Jaggif97ed922016-02-18 18:57:07 -0800767 /**
768 * @return the duration of the last clip reveal animation
769 */
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800770 long getLastClipRevealTransitionDuration() {
771 return mLastClipRevealTransitionDuration;
772 }
773
774 /**
Jorim Jaggif97ed922016-02-18 18:57:07 -0800775 * @return the maximum distance the app surface is traveling of the last clip reveal animation
776 */
777 int getLastClipRevealMaxTranslation() {
778 return mLastClipRevealMaxTranslation;
779 }
780
781 /**
782 * @return true if in the last app transition had a clip reveal animation, false otherwise
783 */
784 boolean hadClipRevealAnimation() {
785 return mLastHadClipReveal;
786 }
787
788 /**
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800789 * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
790 * the start rect is outside of the target rect, and there is a lot of movement going on.
791 *
792 * @param cutOff whether the start rect was not fully contained by the end rect
793 * @param translationX the total translation the surface moves in x direction
794 * @param translationY the total translation the surfaces moves in y direction
795 * @param displayFrame our display frame
796 *
797 * @return the duration of the clip reveal animation, in milliseconds
798 */
799 private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX,
800 float translationY, Rect displayFrame) {
801 if (!cutOff) {
802 return DEFAULT_APP_TRANSITION_DURATION;
803 }
804 final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(),
805 Math.abs(translationY) / displayFrame.height());
806 return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction *
807 (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION));
808 }
809
810 private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame,
811 Rect displayFrame) {
Chet Haase10e23ab2015-02-11 15:08:38 -0800812 final Animation anim;
813 if (enter) {
Craig Mautner80b1f642015-04-22 10:59:09 -0700814 final int appWidth = appFrame.width();
815 final int appHeight = appFrame.height();
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800816
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700817 // mTmpRect will contain an area around the launcher icon that was pressed. We will
Filip Gruszczynski82861362015-10-16 14:21:09 -0700818 // clip reveal from that area in the final area of the app.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700819 getDefaultNextAppTransitionStartRect(mTmpRect);
Craig Mautner80b1f642015-04-22 10:59:09 -0700820
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700821 float t = 0f;
822 if (appHeight > 0) {
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800823 t = (float) mTmpRect.top / displayFrame.height();
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700824 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800825 int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t);
826 int translationX = 0;
827 int translationYCorrection = translationY;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700828 int centerX = mTmpRect.centerX();
829 int centerY = mTmpRect.centerY();
830 int halfWidth = mTmpRect.width() / 2;
831 int halfHeight = mTmpRect.height() / 2;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800832 int clipStartX = centerX - halfWidth - appFrame.left;
833 int clipStartY = centerY - halfHeight - appFrame.top;
834 boolean cutOff = false;
835
836 // If the starting rectangle is fully or partially outside of the target rectangle, we
837 // need to start the clipping at the edge and then achieve the rest with translation
838 // and extending the clip rect from that edge.
839 if (appFrame.top > centerY - halfHeight) {
840 translationY = (centerY - halfHeight) - appFrame.top;
841 translationYCorrection = 0;
842 clipStartY = 0;
843 cutOff = true;
844 }
845 if (appFrame.left > centerX - halfWidth) {
846 translationX = (centerX - halfWidth) - appFrame.left;
847 clipStartX = 0;
848 cutOff = true;
849 }
850 if (appFrame.right < centerX + halfWidth) {
851 translationX = (centerX + halfWidth) - appFrame.right;
852 clipStartX = appWidth - mTmpRect.width();
853 cutOff = true;
854 }
855 final long duration = calculateClipRevealTransitionDuration(cutOff, translationX,
856 translationY, displayFrame);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700857
858 // Clip third of the from size of launch icon, expand to full width/height
Chet Haase10e23ab2015-02-11 15:08:38 -0800859 Animation clipAnimLR = new ClipRectLRAnimation(
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800860 clipStartX, clipStartX + mTmpRect.width(), 0, appWidth);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700861 clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800862 clipAnimLR.setDuration((long) (duration / 2.5f));
Filip Gruszczynski82861362015-10-16 14:21:09 -0700863
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800864 TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0);
865 translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR
866 : mLinearOutSlowInInterpolator);
867 translate.setDuration(duration);
Chet Haase10e23ab2015-02-11 15:08:38 -0800868
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800869 Animation clipAnimTB = new ClipRectTBAnimation(
870 clipStartY, clipStartY + mTmpRect.height(),
871 0, appHeight,
872 translationYCorrection, 0,
873 mLinearOutSlowInInterpolator);
874 clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
875 clipAnimTB.setDuration(duration);
Chet Haase10e23ab2015-02-11 15:08:38 -0800876
877 // Quick fade-in from icon to app window
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800878 final long alphaDuration = duration / 4;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700879 AlphaAnimation alpha = new AlphaAnimation(0.5f, 1);
Chet Haase10e23ab2015-02-11 15:08:38 -0800880 alpha.setDuration(alphaDuration);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700881 alpha.setInterpolator(mLinearOutSlowInInterpolator);
Chet Haase10e23ab2015-02-11 15:08:38 -0800882
883 AnimationSet set = new AnimationSet(false);
884 set.addAnimation(clipAnimLR);
885 set.addAnimation(clipAnimTB);
Filip Gruszczynski82861362015-10-16 14:21:09 -0700886 set.addAnimation(translate);
Chet Haase10e23ab2015-02-11 15:08:38 -0800887 set.addAnimation(alpha);
Filip Gruszczynski9e2cf5b2015-07-31 12:20:40 -0700888 set.setZAdjustment(Animation.ZORDER_TOP);
Chet Haase10e23ab2015-02-11 15:08:38 -0800889 set.initialize(appWidth, appHeight, appWidth, appHeight);
890 anim = set;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800891 mLastHadClipReveal = true;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800892 mLastClipRevealTransitionDuration = duration;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800893
894 // If the start rect was full inside the target rect (cutOff == false), we don't need
895 // to store the translation, because it's only used if cutOff == true.
896 mLastClipRevealMaxTranslation = cutOff
897 ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0;
Chet Haase10e23ab2015-02-11 15:08:38 -0800898 } else {
899 final long duration;
900 switch (transit) {
901 case TRANSIT_ACTIVITY_OPEN:
902 case TRANSIT_ACTIVITY_CLOSE:
903 duration = mConfigShortAnimTime;
904 break;
905 default:
906 duration = DEFAULT_APP_TRANSITION_DURATION;
907 break;
908 }
909 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
910 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
911 // If we are on top of the wallpaper, we need an animation that
912 // correctly handles the wallpaper staying static behind all of
913 // the animated elements. To do this, will just have the existing
914 // element fade out.
915 anim = new AlphaAnimation(1, 0);
916 anim.setDetachWallpaper(true);
917 } else {
918 // For normal animations, the exiting element just holds in place.
919 anim = new AlphaAnimation(1, 1);
920 }
921 anim.setInterpolator(mDecelerateInterpolator);
922 anim.setDuration(duration);
923 anim.setFillAfter(true);
924 }
925 return anim;
926 }
927
Winson Chung399f6202014-03-19 10:47:20 -0700928 /**
929 * Prepares the specified animation with a standard duration, interpolator, etc.
930 */
Winson Chung5393dff2014-05-08 14:25:43 -0700931 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100932 long duration, Interpolator interpolator) {
Winson Chunga4ccb862014-08-22 15:26:27 -0700933 if (duration > 0) {
934 a.setDuration(duration);
935 }
Winson Chung5393dff2014-05-08 14:25:43 -0700936 a.setFillAfter(true);
Jorim Jaggic69bd222016-03-15 14:38:37 +0100937 if (interpolator != null) {
938 a.setInterpolator(interpolator);
939 }
Winson Chung5393dff2014-05-08 14:25:43 -0700940 a.initialize(appWidth, appHeight, appWidth, appHeight);
941 return a;
942 }
943
944 /**
945 * Prepares the specified animation with a standard duration, interpolator, etc.
946 */
Winson Chung399f6202014-03-19 10:47:20 -0700947 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800948 // Pick the desired duration. If this is an inter-activity transition,
949 // it is the standard duration for that. Otherwise we use the longer
950 // task transition duration.
Winson Chung5393dff2014-05-08 14:25:43 -0700951 final int duration;
Craig Mautner321bdf52012-12-18 09:53:24 -0800952 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800953 case TRANSIT_ACTIVITY_OPEN:
954 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800955 duration = mConfigShortAnimTime;
956 break;
957 default:
958 duration = DEFAULT_APP_TRANSITION_DURATION;
959 break;
960 }
Winson Chung5393dff2014-05-08 14:25:43 -0700961 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
962 mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800963 }
964
Winson Chung399f6202014-03-19 10:47:20 -0700965 /**
966 * Return the current thumbnail transition state.
967 */
968 int getThumbnailTransitionState(boolean enter) {
969 if (enter) {
970 if (mNextAppTransitionScaleUp) {
971 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
972 } else {
973 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
974 }
975 } else {
976 if (mNextAppTransitionScaleUp) {
977 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
978 } else {
979 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
980 }
981 }
982 }
983
984 /**
Tony Mak64b8d562017-12-28 17:44:02 +0000985 * Creates an overlay with a background color and a thumbnail for the cross profile apps
986 * animation.
987 */
988 GraphicBuffer createCrossProfileAppsThumbnail(
989 @DrawableRes int thumbnailDrawableRes, Rect frame) {
990 final int width = frame.width();
991 final int height = frame.height();
992
John Reck519ad482018-02-12 17:08:48 -0800993 final Picture picture = new Picture();
994 final Canvas canvas = picture.beginRecording(width, height);
Tony Mak64b8d562017-12-28 17:44:02 +0000995 canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
996 final int thumbnailSize = mService.mContext.getResources().getDimensionPixelSize(
997 com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
998 final Drawable drawable = mService.mContext.getDrawable(thumbnailDrawableRes);
999 drawable.setBounds(
1000 (width - thumbnailSize) / 2,
1001 (height - thumbnailSize) / 2,
1002 (width + thumbnailSize) / 2,
1003 (height + thumbnailSize) / 2);
1004 drawable.draw(canvas);
John Reck519ad482018-02-12 17:08:48 -08001005 picture.endRecording();
Tony Mak64b8d562017-12-28 17:44:02 +00001006
John Reck519ad482018-02-12 17:08:48 -08001007 return Bitmap.createBitmap(picture).createGraphicBufferHandle();
Tony Mak64b8d562017-12-28 17:44:02 +00001008 }
1009
1010 Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
1011 final Animation animation = loadAnimationRes(
1012 "android", com.android.internal.R.anim.cross_profile_apps_thumbnail_enter);
1013 return prepareThumbnailAnimationWithDuration(animation, appRect.width(),
1014 appRect.height(), 0, null);
1015 }
1016
1017 /**
Winson Chung399f6202014-03-19 10:47:20 -07001018 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001019 * when a thumbnail is specified with the pending animation override.
Winson Chung399f6202014-03-19 10:47:20 -07001020 */
Jorim Jaggide63d442016-03-14 14:56:56 +01001021 Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
Winson Chungaa7fa012017-05-24 15:50:06 -07001022 GraphicBuffer thumbnailHeader, final int taskId, int uiMode, int orientation) {
Winson Chung399f6202014-03-19 10:47:20 -07001023 Animation a;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001024 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chung399f6202014-03-19 10:47:20 -07001025 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001026 final int thumbHeightI = thumbnailHeader.getHeight();
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001027 final int appWidth = appRect.width();
Winson Chung399f6202014-03-19 10:47:20 -07001028
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001029 float scaleW = appWidth / thumbWidth;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001030 getNextAppTransitionStartRect(taskId, mTmpRect);
Jorim Jaggi09072002016-03-25 16:48:42 -07001031 final float fromX;
Manu Cornet57b61492017-01-24 18:19:05 +09001032 float fromY;
Jorim Jaggi09072002016-03-25 16:48:42 -07001033 final float toX;
Manu Cornet57b61492017-01-24 18:19:05 +09001034 float toY;
Jorim Jaggi09072002016-03-25 16:48:42 -07001035 final float pivotX;
1036 final float pivotY;
Manu Cornetd7376802017-01-13 13:44:07 -08001037 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
Jorim Jaggi09072002016-03-25 16:48:42 -07001038 fromX = mTmpRect.left;
1039 fromY = mTmpRect.top;
1040
1041 // For the curved translate animation to work, the pivot points needs to be at the
1042 // same absolute position as the one from the real surface.
1043 toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
1044 toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
1045 pivotX = mTmpRect.width() / 2;
1046 pivotY = appRect.height() / 2 / scaleW;
Manu Cornet57b61492017-01-24 18:19:05 +09001047 if (mGridLayoutRecentsEnabled) {
1048 // In the grid layout, the header is displayed above the thumbnail instead of
1049 // overlapping it.
1050 fromY -= thumbHeightI;
1051 toY -= thumbHeightI * scaleW;
1052 }
Jorim Jaggi09072002016-03-25 16:48:42 -07001053 } else {
1054 pivotX = 0;
1055 pivotY = 0;
1056 fromX = mTmpRect.left;
1057 fromY = mTmpRect.top;
1058 toX = appRect.left;
1059 toY = appRect.top;
1060 }
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001061 final long duration = getAspectScaleDuration();
1062 final Interpolator interpolator = getAspectScaleInterpolator();
Winson Chung399f6202014-03-19 10:47:20 -07001063 if (mNextAppTransitionScaleUp) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001064 // Animation up from the thumbnail to the full screen
Jorim Jaggi8448f332016-03-14 17:50:37 +01001065 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001066 scale.setInterpolator(interpolator);
1067 scale.setDuration(duration);
Jorim Jaggic6c89a82016-01-28 17:48:21 -08001068 Animation alpha = new AlphaAnimation(1f, 0f);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001069 alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1070 ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator);
1071 alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1072 ? duration / 2
1073 : duration);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001074 Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
1075 translate.setInterpolator(interpolator);
1076 translate.setDuration(duration);
Winson Chung399f6202014-03-19 10:47:20 -07001077
Jorim Jaggide63d442016-03-14 14:56:56 +01001078 mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
1079 mTmpToClipRect.set(appRect);
1080
1081 // Containing frame is in screen space, but we need the clip rect in the
1082 // app space.
1083 mTmpToClipRect.offsetTo(0, 0);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001084 mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
1085 mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
Jorim Jaggide63d442016-03-14 14:56:56 +01001086
1087 if (contentInsets != null) {
Jorim Jaggi8448f332016-03-14 17:50:37 +01001088 mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
1089 (int) (-contentInsets.top * scaleW),
1090 (int) (-contentInsets.right * scaleW),
1091 (int) (-contentInsets.bottom * scaleW));
Jorim Jaggide63d442016-03-14 14:56:56 +01001092 }
1093
1094 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001095 clipAnim.setInterpolator(interpolator);
1096 clipAnim.setDuration(duration);
Jorim Jaggide63d442016-03-14 14:56:56 +01001097
Winson Chung399f6202014-03-19 10:47:20 -07001098 // This AnimationSet uses the Interpolators assigned above.
1099 AnimationSet set = new AnimationSet(false);
1100 set.addAnimation(scale);
Manu Cornet57b61492017-01-24 18:19:05 +09001101 if (!mGridLayoutRecentsEnabled) {
1102 // In the grid layout, the header should be shown for the whole animation.
1103 set.addAnimation(alpha);
1104 }
Winson Chunga4ccb862014-08-22 15:26:27 -07001105 set.addAnimation(translate);
Jorim Jaggide63d442016-03-14 14:56:56 +01001106 set.addAnimation(clipAnim);
Winson Chung399f6202014-03-19 10:47:20 -07001107 a = set;
1108 } else {
Winson Chunga4ccb862014-08-22 15:26:27 -07001109 // Animation down from the full screen to the thumbnail
Jorim Jaggi8448f332016-03-14 17:50:37 +01001110 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001111 scale.setInterpolator(interpolator);
1112 scale.setDuration(duration);
Winson Chunga4ccb862014-08-22 15:26:27 -07001113 Animation alpha = new AlphaAnimation(0f, 1f);
1114 alpha.setInterpolator(mThumbnailFadeInInterpolator);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001115 alpha.setDuration(duration);
1116 Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
1117 translate.setInterpolator(interpolator);
1118 translate.setDuration(duration);
Winson Chung399f6202014-03-19 10:47:20 -07001119
Winson Chunga4ccb862014-08-22 15:26:27 -07001120 // This AnimationSet uses the Interpolators assigned above.
1121 AnimationSet set = new AnimationSet(false);
1122 set.addAnimation(scale);
Manu Cornet57b61492017-01-24 18:19:05 +09001123 if (!mGridLayoutRecentsEnabled) {
1124 // In the grid layout, the header should be shown for the whole animation.
1125 set.addAnimation(alpha);
1126 }
Winson Chunga4ccb862014-08-22 15:26:27 -07001127 set.addAnimation(translate);
1128 a = set;
1129
1130 }
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001131 return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
Jorim Jaggic69bd222016-03-15 14:38:37 +01001132 null);
Winson Chung399f6202014-03-19 10:47:20 -07001133 }
1134
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001135 private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
1136
1137 // Almost no x-change - use linear animation
Jorim Jaggic69bd222016-03-15 14:38:37 +01001138 if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) {
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001139 return new TranslateAnimation(fromX, toX, fromY, toY);
1140 } else {
1141 final Path path = createCurvedPath(fromX, toX, fromY, toY);
1142 return new CurvedTranslateAnimation(path);
1143 }
1144 }
1145
1146 private Path createCurvedPath(float fromX, float toX, float fromY, float toY) {
1147 final Path path = new Path();
1148 path.moveTo(fromX, fromY);
Jorim Jaggi1f458fb2016-03-25 17:36:37 -07001149
1150 if (fromY > toY) {
1151 // If the object needs to go up, move it in horizontal direction first, then vertical.
1152 path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY);
1153 } else {
1154 // If the object needs to go down, move it in vertical direction first, then horizontal.
1155 path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY);
1156 }
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001157 return path;
1158 }
1159
1160 private long getAspectScaleDuration() {
1161 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
Jorim Jaggic69bd222016-03-15 14:38:37 +01001162 return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001163 } else {
1164 return THUMBNAIL_APP_TRANSITION_DURATION;
1165 }
1166 }
1167
1168 private Interpolator getAspectScaleInterpolator() {
1169 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
1170 return mFastOutSlowInInterpolator;
1171 } else {
1172 return TOUCH_RESPONSE_INTERPOLATOR;
1173 }
1174 }
1175
Winson Chung399f6202014-03-19 10:47:20 -07001176 /**
1177 * This alternate animation is created when we are doing a thumbnail transition, for the
1178 * activity that is leaving, and the activity that is entering.
1179 */
Winson Chunga4ccb862014-08-22 15:26:27 -07001180 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
Winsonb2024762016-04-05 17:32:30 -07001181 int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets,
Matthew Ng43db6d22017-06-27 15:29:39 -07001182 @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean freeform,
1183 int taskId) {
Winson Chung399f6202014-03-19 10:47:20 -07001184 Animation a;
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001185 final int appWidth = containingFrame.width();
1186 final int appHeight = containingFrame.height();
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001187 getDefaultNextAppTransitionStartRect(mTmpRect);
1188 final int thumbWidthI = mTmpRect.width();
Winson Chung399f6202014-03-19 10:47:20 -07001189 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001190 final int thumbHeightI = mTmpRect.height();
Winson Chung399f6202014-03-19 10:47:20 -07001191 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
Winsoncbb625b2016-07-06 15:24:15 -07001192 final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left;
Winson21700932016-03-24 17:26:23 -07001193 final int thumbStartY = mTmpRect.top - containingFrame.top;
Winson Chung399f6202014-03-19 10:47:20 -07001194
1195 switch (thumbTransitState) {
Jorim Jaggi8448f332016-03-14 17:50:37 +01001196 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
1197 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1198 final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
1199 if (freeform && scaleUp) {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001200 a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001201 containingFrame, surfaceInsets, taskId);
Jorim Jaggi8448f332016-03-14 17:50:37 +01001202 } else if (freeform) {
1203 a = createAspectScaledThumbnailExitFreeformAnimationLocked(
1204 containingFrame, surfaceInsets, taskId);
Winson Chung2820c452014-04-15 15:34:44 -07001205 } else {
Winson21700932016-03-24 17:26:23 -07001206 AnimationSet set = new AnimationSet(true);
1207
1208 // In portrait, we scale to fit the width
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -07001209 mTmpFromClipRect.set(containingFrame);
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -07001210 mTmpToClipRect.set(containingFrame);
Jorim Jaggic6c89a82016-01-28 17:48:21 -08001211
1212 // Containing frame is in screen space, but we need the clip rect in the
1213 // app space.
1214 mTmpFromClipRect.offsetTo(0, 0);
1215 mTmpToClipRect.offsetTo(0, 0);
1216
1217 // Exclude insets region from the source clip.
1218 mTmpFromClipRect.inset(contentInsets);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001219 mNextAppTransitionInsets.set(contentInsets);
1220
Manu Cornetd7376802017-01-13 13:44:07 -08001221 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
Jorim Jaggic69bd222016-03-15 14:38:37 +01001222 // We scale the width and clip to the top/left square
1223 float scale = thumbWidth /
1224 (appWidth - contentInsets.left - contentInsets.right);
Manu Cornetb68b7652017-01-23 19:37:53 +09001225 if (!mGridLayoutRecentsEnabled) {
1226 int unscaledThumbHeight = (int) (thumbHeight / scale);
1227 mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
1228 }
Jorim Jaggic69bd222016-03-15 14:38:37 +01001229
1230 mNextAppTransitionInsets.set(contentInsets);
1231
Jorim Jaggi8448f332016-03-14 17:50:37 +01001232 Animation scaleAnim = new ScaleAnimation(
1233 scaleUp ? scale : 1, scaleUp ? 1 : scale,
1234 scaleUp ? scale : 1, scaleUp ? 1 : scale,
Jorim Jaggic69bd222016-03-15 14:38:37 +01001235 containingFrame.width() / 2f,
1236 containingFrame.height() / 2f + contentInsets.top);
Jorim Jaggi8448f332016-03-14 17:50:37 +01001237 final float targetX = (mTmpRect.left - containingFrame.left);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001238 final float x = containingFrame.width() / 2f
1239 - containingFrame.width() / 2f * scale;
Jorim Jaggi8448f332016-03-14 17:50:37 +01001240 final float targetY = (mTmpRect.top - containingFrame.top);
Matthew Ng43db6d22017-06-27 15:29:39 -07001241 float y = containingFrame.height() / 2f
Jorim Jaggic69bd222016-03-15 14:38:37 +01001242 - containingFrame.height() / 2f * scale;
Matthew Ng43db6d22017-06-27 15:29:39 -07001243
1244 // During transition may require clipping offset from any top stable insets
1245 // such as the statusbar height when statusbar is hidden
1246 if (mLowRamRecentsEnabled && contentInsets.top == 0 && scaleUp) {
1247 mTmpFromClipRect.top += stableInsets.top;
1248 y += stableInsets.top;
1249 }
Jorim Jaggi8448f332016-03-14 17:50:37 +01001250 final float startX = targetX - x;
1251 final float startY = targetY - y;
1252 Animation clipAnim = scaleUp
1253 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1254 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1255 Animation translateAnim = scaleUp
Jorim Jaggic69bd222016-03-15 14:38:37 +01001256 ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0)
1257 : createCurvedMotion(0, startX, 0, startY - contentInsets.top);
1258
Winson21700932016-03-24 17:26:23 -07001259 set.addAnimation(clipAnim);
1260 set.addAnimation(scaleAnim);
1261 set.addAnimation(translateAnim);
1262
1263 } else {
1264 // In landscape, we don't scale at all and only crop
1265 mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI;
1266 mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI;
1267
Jorim Jaggi8448f332016-03-14 17:50:37 +01001268 Animation clipAnim = scaleUp
1269 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1270 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1271 Animation translateAnim = scaleUp
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001272 ? createCurvedMotion(thumbStartX, 0,
1273 thumbStartY - contentInsets.top, 0)
1274 : createCurvedMotion(0, thumbStartX, 0,
1275 thumbStartY - contentInsets.top);
Winson21700932016-03-24 17:26:23 -07001276
1277 set.addAnimation(clipAnim);
1278 set.addAnimation(translateAnim);
1279 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001280 a = set;
Winson21700932016-03-24 17:26:23 -07001281 a.setZAdjustment(Animation.ZORDER_TOP);
Winson Chung2820c452014-04-15 15:34:44 -07001282 }
Winson Chung399f6202014-03-19 10:47:20 -07001283 break;
1284 }
1285 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
Winson Chunga4ccb862014-08-22 15:26:27 -07001286 // Previous app window during the scale up
Winson Chung399f6202014-03-19 10:47:20 -07001287 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001288 // Fade out the source activity if we are animating to a wallpaper
Winson Chung399f6202014-03-19 10:47:20 -07001289 // activity.
1290 a = new AlphaAnimation(1, 0);
1291 } else {
Winson Chung399f6202014-03-19 10:47:20 -07001292 a = new AlphaAnimation(1, 1);
1293 }
1294 break;
1295 }
1296 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
Winson Chunga4ccb862014-08-22 15:26:27 -07001297 // Target app window during the scale down
1298 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1299 // Fade in the destination activity if we are animating from a wallpaper
1300 // activity.
1301 a = new AlphaAnimation(0, 1);
1302 } else {
1303 a = new AlphaAnimation(1, 1);
1304 }
Winson Chung399f6202014-03-19 10:47:20 -07001305 break;
1306 }
Winson Chung399f6202014-03-19 10:47:20 -07001307 default:
1308 throw new RuntimeException("Invalid thumbnail transition state");
1309 }
1310
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001311 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
1312 getAspectScaleDuration(), getAspectScaleInterpolator());
Winson Chung399f6202014-03-19 10:47:20 -07001313 }
1314
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001315 private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
1316 @Nullable Rect surfaceInsets, int taskId) {
1317 getNextAppTransitionStartRect(taskId, mTmpRect);
1318 return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
1319 true);
1320 }
1321
1322 private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
1323 @Nullable Rect surfaceInsets, int taskId) {
1324 getNextAppTransitionStartRect(taskId, mTmpRect);
1325 return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
1326 false);
1327 }
1328
1329 private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
1330 Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
1331 final float sourceWidth = sourceFrame.width();
1332 final float sourceHeight = sourceFrame.height();
1333 final float destWidth = destFrame.width();
1334 final float destHeight = destFrame.height();
1335 final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
1336 final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001337 AnimationSet set = new AnimationSet(true);
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001338 final int surfaceInsetsH = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001339 ? 0 : surfaceInsets.left + surfaceInsets.right;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001340 final int surfaceInsetsV = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001341 ? 0 : surfaceInsets.top + surfaceInsets.bottom;
1342 // We want the scaling to happen from the center of the surface. In order to achieve that,
1343 // we need to account for surface insets that will be used to enlarge the surface.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001344 final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
1345 final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
1346 final ScaleAnimation scale = enter ?
1347 new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
1348 : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
1349 final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
1350 final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
1351 final int destHCenter = destFrame.left + destFrame.width() / 2;
1352 final int destVCenter = destFrame.top + destFrame.height() / 2;
1353 final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
1354 final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
1355 final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
1356 : new TranslateAnimation(0, fromX, 0, fromY);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001357 set.addAnimation(scale);
1358 set.addAnimation(translation);
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001359
1360 final IRemoteCallback callback = mAnimationFinishedCallback;
1361 if (callback != null) {
1362 set.setAnimationListener(new Animation.AnimationListener() {
1363 @Override
1364 public void onAnimationStart(Animation animation) { }
1365
1366 @Override
1367 public void onAnimationEnd(Animation animation) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001368 mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001369 }
1370
1371 @Override
1372 public void onAnimationRepeat(Animation animation) { }
1373 });
1374 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001375 return set;
1376 }
1377
Winson Chung399f6202014-03-19 10:47:20 -07001378 /**
Winson Chunga4ccb862014-08-22 15:26:27 -07001379 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001380 * when a thumbnail is specified with the pending animation override.
Winson Chunga4ccb862014-08-22 15:26:27 -07001381 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001382 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
Winson Chungaa7fa012017-05-24 15:50:06 -07001383 GraphicBuffer thumbnailHeader) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001384 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001385 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001386 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chunga4ccb862014-08-22 15:26:27 -07001387 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001388 final int thumbHeightI = thumbnailHeader.getHeight();
Winson Chunga4ccb862014-08-22 15:26:27 -07001389 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1390
1391 if (mNextAppTransitionScaleUp) {
1392 // Animation for the thumbnail zooming from its initial size to the full screen
1393 float scaleW = appWidth / thumbWidth;
1394 float scaleH = appHeight / thumbHeight;
1395 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001396 computePivot(mTmpRect.left, 1 / scaleW),
1397 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001398 scale.setInterpolator(mDecelerateInterpolator);
1399
1400 Animation alpha = new AlphaAnimation(1, 0);
1401 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
1402
1403 // This AnimationSet uses the Interpolators assigned above.
1404 AnimationSet set = new AnimationSet(false);
1405 set.addAnimation(scale);
1406 set.addAnimation(alpha);
1407 a = set;
1408 } else {
1409 // Animation for the thumbnail zooming down from the full screen to its final size
1410 float scaleW = appWidth / thumbWidth;
1411 float scaleH = appHeight / thumbHeight;
1412 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001413 computePivot(mTmpRect.left, 1 / scaleW),
1414 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001415 }
1416
1417 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1418 }
1419
1420 /**
Winson Chung399f6202014-03-19 10:47:20 -07001421 * This animation is created when we are doing a thumbnail transition, for the activity that is
1422 * leaving, and the activity that is entering.
1423 */
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001424 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
1425 int transit, int taskId) {
1426 final int appWidth = containingFrame.width();
1427 final int appHeight = containingFrame.height();
Winson Chungaa7fa012017-05-24 15:50:06 -07001428 final GraphicBuffer thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
Winson Chung399f6202014-03-19 10:47:20 -07001429 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001430 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001431 final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
Winson Chung399f6202014-03-19 10:47:20 -07001432 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001433 final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
Winson Chung399f6202014-03-19 10:47:20 -07001434 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1435
1436 switch (thumbTransitState) {
1437 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
1438 // Entering app scales up with the thumbnail
1439 float scaleW = thumbWidth / appWidth;
1440 float scaleH = thumbHeight / appHeight;
1441 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001442 computePivot(mTmpRect.left, scaleW),
1443 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001444 break;
1445 }
1446 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
1447 // Exiting app while the thumbnail is scaling up should fade or stay in place
1448 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1449 // Fade out while bringing up selected activity. This keeps the
1450 // current activity from showing through a launching wallpaper
1451 // activity.
1452 a = new AlphaAnimation(1, 0);
1453 } else {
1454 // noop animation
1455 a = new AlphaAnimation(1, 1);
1456 }
1457 break;
1458 }
1459 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
1460 // Entering the other app, it should just be visible while we scale the thumbnail
1461 // down above it
1462 a = new AlphaAnimation(1, 1);
1463 break;
1464 }
1465 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1466 // Exiting the current app, the app should scale down with the thumbnail
1467 float scaleW = thumbWidth / appWidth;
1468 float scaleH = thumbHeight / appHeight;
1469 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001470 computePivot(mTmpRect.left, scaleW),
1471 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001472
1473 Animation alpha = new AlphaAnimation(1, 0);
1474
1475 AnimationSet set = new AnimationSet(true);
1476 set.addAnimation(scale);
1477 set.addAnimation(alpha);
1478 set.setZAdjustment(Animation.ZORDER_TOP);
1479 a = set;
1480 break;
1481 }
1482 default:
1483 throw new RuntimeException("Invalid thumbnail transition state");
1484 }
1485
1486 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1487 }
1488
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001489 private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) {
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001490 getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
1491 final int left = mTmpFromClipRect.left;
1492 final int top = mTmpFromClipRect.top;
1493 mTmpFromClipRect.offset(-left, -top);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001494 // TODO: Isn't that strange that we ignore exact position of the containingFrame?
1495 mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height());
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001496 AnimationSet set = new AnimationSet(true);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001497 float fromWidth = mTmpFromClipRect.width();
1498 float toWidth = mTmpToClipRect.width();
1499 float fromHeight = mTmpFromClipRect.height();
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001500 // While the window might span the whole display, the actual content will be cropped to the
1501 // system decoration frame, for example when the window is docked. We need to take into
1502 // account the visible height when constructing the animation.
1503 float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom;
1504 int translateAdjustment = 0;
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001505 if (fromWidth <= toWidth && fromHeight <= toHeight) {
1506 // The final window is larger in both dimensions than current window (e.g. we are
1507 // maximizing), so we can simply unclip the new window and there will be no disappearing
1508 // frame.
1509 set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
1510 } else {
1511 // The disappearing window has one larger dimension. We need to apply scaling, so the
1512 // first frame of the entry animation matches the old window.
1513 set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001514 // We might not be going exactly full screen, but instead be aligned under the status
1515 // bar using cropping. We still need to account for the cropped part, which will also
1516 // be scaled.
1517 translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001518 }
1519
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001520 // We animate the translation from the old position of the removed window, to the new
1521 // position of the added window. The latter might not be full screen, for example docked for
1522 // docked windows.
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001523 TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001524 0, top - containingFrame.top - translateAdjustment, 0);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001525 set.addAnimation(translate);
1526 set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
Filip Gruszczynskie95b0ae2015-09-30 10:55:33 -07001527 set.setZAdjustment(Animation.ZORDER_TOP);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001528 return set;
1529 }
1530
Jorim Jaggic554b772015-06-04 16:07:57 -07001531 /**
1532 * @return true if and only if the first frame of the transition can be skipped, i.e. the first
1533 * frame of the transition doesn't change the visuals on screen, so we can start
1534 * directly with the second one
1535 */
1536 boolean canSkipFirstFrame() {
1537 return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
1538 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
Jorim Jaggife762342016-10-13 14:33:27 +02001539 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
1540 && mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY;
Jorim Jaggic554b772015-06-04 16:07:57 -07001541 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08001542
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001543 RemoteAnimationController getRemoteAnimationController() {
1544 return mRemoteAnimationController;
1545 }
1546
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001547 /**
1548 *
1549 * @param frame These are the bounds of the window when it finishes the animation. This is where
1550 * the animation must usually finish in entrance animation, as the next frame will
1551 * display the window at these coordinates. In case of exit animation, this is
1552 * where the animation must start, as the frame before the animation is displaying
1553 * the window at these bounds.
1554 * @param insets Knowing where the window will be positioned is not enough. Some parts of the
1555 * window might be obscured, usually by the system windows (status bar and
1556 * navigation bar) and we use content insets to convey that information. This
1557 * usually affects the animation aspects vertically, as the system decoration is
1558 * at the top and the bottom. For example when we animate from full screen to
1559 * recents, we want to exclude the covered parts, because they won't match the
1560 * thumbnail after the last frame is executed.
1561 * @param surfaceInsets In rare situation the surface is larger than the content and we need to
1562 * know about this to make the animation frames match. We currently use
1563 * this for freeform windows, which have larger surfaces to display
1564 * shadows. When we animate them from recents, we want to match the content
1565 * to the recents thumbnail and hence need to account for the surface being
1566 * bigger.
1567 */
Jorim Jaggif84e2f62018-01-16 14:17:59 +01001568 Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -08001569 int orientation, Rect frame, Rect displayFrame, Rect insets,
Matthew Ng43db6d22017-06-27 15:29:39 -07001570 @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
1571 boolean freeform, int taskId) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001572 Animation a;
Jorim Jaggife762342016-10-13 14:33:27 +02001573 if (isKeyguardGoingAwayTransit(transit) && enter) {
1574 a = loadKeyguardExitAnimation(transit);
1575 } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) {
1576 a = null;
1577 } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) {
1578 a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit);
Adrian Roos93577212018-04-10 14:12:10 -07001579 } else if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
1580 a = null;
Jorim Jaggife762342016-10-13 14:33:27 +02001581 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001582 || transit == TRANSIT_TASK_OPEN
1583 || transit == TRANSIT_TASK_TO_FRONT)) {
1584 a = loadAnimationRes(lp, enter
1585 ? com.android.internal.R.anim.voice_activity_open_enter
1586 : com.android.internal.R.anim.voice_activity_open_exit);
1587 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1588 "applyAnimation voice:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001589 + " anim=" + a + " transit=" + appTransitionToString(transit)
1590 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001591 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
1592 || transit == TRANSIT_TASK_CLOSE
1593 || transit == TRANSIT_TASK_TO_BACK)) {
1594 a = loadAnimationRes(lp, enter
1595 ? com.android.internal.R.anim.voice_activity_close_enter
1596 : com.android.internal.R.anim.voice_activity_close_exit);
1597 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1598 "applyAnimation voice:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001599 + " anim=" + a + " transit=" + appTransitionToString(transit)
1600 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001601 } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001602 a = createRelaunchAnimation(frame, insets);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001603 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1604 "applyAnimation:"
1605 + " anim=" + a + " nextAppTransition=" + mNextAppTransition
1606 + " transit=" + appTransitionToString(transit)
1607 + " Callers=" + Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001608 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
1609 a = loadAnimationRes(mNextAppTransitionPackage, enter ?
Craig Mautner164d4bb2012-11-26 13:51:23 -08001610 mNextAppTransitionEnter : mNextAppTransitionExit);
1611 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1612 "applyAnimation:"
1613 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001614 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001615 + " Callers=" + Debug.getCallers(3));
Winson Chung044d5292014-11-06 11:05:19 -08001616 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
1617 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
1618 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1619 "applyAnimation:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001620 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
1621 + " transit=" + appTransitionToString(transit)
1622 + " Callers=" + Debug.getCallers(3));
Chet Haase10e23ab2015-02-11 15:08:38 -08001623 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -08001624 a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
Chet Haase10e23ab2015-02-11 15:08:38 -08001625 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1626 "applyAnimation:"
1627 + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001628 + " transit=" + appTransitionToString(transit)
Chet Haase10e23ab2015-02-11 15:08:38 -08001629 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001630 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001631 a = createScaleUpAnimationLocked(transit, enter, frame);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001632 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1633 "applyAnimation:"
1634 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001635 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001636 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001637 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
1638 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001639 mNextAppTransitionScaleUp =
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001640 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
Winson Chunga4ccb862014-08-22 15:26:27 -07001641 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001642 frame, transit, taskId);
Winson Chunga4ccb862014-08-22 15:26:27 -07001643 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1644 String animName = mNextAppTransitionScaleUp ?
1645 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
1646 Slog.v(TAG, "applyAnimation:"
1647 + " anim=" + a + " nextAppTransition=" + animName
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001648 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Winson Chunga4ccb862014-08-22 15:26:27 -07001649 + " Callers=" + Debug.getCallers(3));
1650 }
1651 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
1652 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
1653 mNextAppTransitionScaleUp =
1654 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
1655 a = createAspectScaledThumbnailEnterExitAnimationLocked(
Winsonb2024762016-04-05 17:32:30 -07001656 getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
Matthew Ng43db6d22017-06-27 15:29:39 -07001657 insets, surfaceInsets, stableInsets, freeform, taskId);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001658 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1659 String animName = mNextAppTransitionScaleUp ?
Winson Chunga4ccb862014-08-22 15:26:27 -07001660 "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
Craig Mautner164d4bb2012-11-26 13:51:23 -08001661 Slog.v(TAG, "applyAnimation:"
1662 + " anim=" + a + " nextAppTransition=" + animName
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001663 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001664 + " Callers=" + Debug.getCallers(3));
1665 }
Tony Mak83546a82018-01-22 13:56:20 +00001666 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {
Jorim Jaggi98a9d202018-03-26 16:17:07 +02001667 a = loadAnimationRes("android",
1668 com.android.internal.R.anim.task_open_enter_cross_profile_apps);
Tony Mak089c35e2017-12-18 20:34:14 +00001669 Slog.v(TAG,
1670 "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:"
1671 + " anim=" + a + " transit=" + appTransitionToString(transit)
Jorim Jaggi98a9d202018-03-26 16:17:07 +02001672 + " isEntrance=true" + " Callers=" + Debug.getCallers(3));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001673 } else {
1674 int animAttr = 0;
1675 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -08001676 case TRANSIT_ACTIVITY_OPEN:
Jorim Jaggi0a1523d2018-04-19 17:48:38 +02001677 case TRANSIT_TRANSLUCENT_ACTIVITY_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001678 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001679 ? WindowAnimation_activityOpenEnterAnimation
1680 : WindowAnimation_activityOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001681 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001682 case TRANSIT_ACTIVITY_CLOSE:
Jorim Jaggi0a1523d2018-04-19 17:48:38 +02001683 case TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001684 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001685 ? WindowAnimation_activityCloseEnterAnimation
1686 : WindowAnimation_activityCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001687 break;
Jorim Jaggi192086e2016-03-11 17:17:03 +01001688 case TRANSIT_DOCK_TASK_FROM_RECENTS:
Craig Mautner4b71aa12012-12-27 17:20:01 -08001689 case TRANSIT_TASK_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001690 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001691 ? WindowAnimation_taskOpenEnterAnimation
1692 : WindowAnimation_taskOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001693 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001694 case TRANSIT_TASK_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001695 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001696 ? WindowAnimation_taskCloseEnterAnimation
1697 : WindowAnimation_taskCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001698 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001699 case TRANSIT_TASK_TO_FRONT:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001700 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001701 ? WindowAnimation_taskToFrontEnterAnimation
1702 : WindowAnimation_taskToFrontExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001703 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001704 case TRANSIT_TASK_TO_BACK:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001705 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001706 ? WindowAnimation_taskToBackEnterAnimation
1707 : WindowAnimation_taskToBackExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001708 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001709 case TRANSIT_WALLPAPER_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001710 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001711 ? WindowAnimation_wallpaperOpenEnterAnimation
1712 : WindowAnimation_wallpaperOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001713 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001714 case TRANSIT_WALLPAPER_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001715 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001716 ? WindowAnimation_wallpaperCloseEnterAnimation
1717 : WindowAnimation_wallpaperCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001718 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001719 case TRANSIT_WALLPAPER_INTRA_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001720 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001721 ? WindowAnimation_wallpaperIntraOpenEnterAnimation
1722 : WindowAnimation_wallpaperIntraOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001723 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001724 case TRANSIT_WALLPAPER_INTRA_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001725 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001726 ? WindowAnimation_wallpaperIntraCloseEnterAnimation
1727 : WindowAnimation_wallpaperIntraCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001728 break;
Craig Mautnerbb742462014-07-07 15:28:55 -07001729 case TRANSIT_TASK_OPEN_BEHIND:
1730 animAttr = enter
1731 ? WindowAnimation_launchTaskBehindSourceAnimation
Craig Mautner3b2cd1d2014-08-25 14:25:54 -07001732 : WindowAnimation_launchTaskBehindTargetAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001733 }
Jorim Jaggi0a1523d2018-04-19 17:48:38 +02001734 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001735 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1736 "applyAnimation:"
1737 + " anim=" + a
1738 + " animAttr=0x" + Integer.toHexString(animAttr)
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001739 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001740 + " Callers=" + Debug.getCallers(3));
1741 }
1742 return a;
1743 }
1744
Jorim Jaggife762342016-10-13 14:33:27 +02001745 private Animation loadKeyguardExitAnimation(int transit) {
1746 if ((mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) != 0) {
1747 return null;
1748 }
1749 final boolean toShade =
1750 (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0;
1751 return mService.mPolicy.createHiddenByKeyguardExit(
1752 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade);
1753 }
1754
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001755 int getAppStackClipMode() {
Matthew Ngbf1d9852017-03-14 12:23:09 -07001756 // When dismiss keyguard animation occurs, clip before the animation to prevent docked
1757 // app from showing beyond the divider
1758 if (mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY
1759 || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
1760 return STACK_CLIP_BEFORE_ANIM;
1761 }
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001762 return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
Jorim Jaggic69bd222016-03-15 14:38:37 +01001763 || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
Jorim Jaggi1f458fb2016-03-25 17:36:37 -07001764 || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001765 ? STACK_CLIP_NONE
1766 : STACK_CLIP_AFTER_ANIM;
1767 }
1768
Jorim Jaggife762342016-10-13 14:33:27 +02001769 public int getTransitFlags() {
1770 return mNextAppTransitionFlags;
1771 }
1772
Craig Mautner164d4bb2012-11-26 13:51:23 -08001773 void postAnimationCallback() {
1774 if (mNextAppTransitionCallback != null) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001775 mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
1776 mNextAppTransitionCallback));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001777 mNextAppTransitionCallback = null;
1778 }
1779 }
1780
1781 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001782 IRemoteCallback startedCallback) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001783 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001784 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001785 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001786 mNextAppTransitionPackage = packageName;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001787 mNextAppTransitionEnter = enterAnim;
1788 mNextAppTransitionExit = exitAnim;
1789 postAnimationCallback();
1790 mNextAppTransitionCallback = startedCallback;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001791 }
1792 }
1793
1794 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001795 int startHeight) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001796 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001797 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001798 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
Winson4c3fecd2016-07-13 12:29:48 -07001799 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001800 postAnimationCallback();
Craig Mautner164d4bb2012-11-26 13:51:23 -08001801 }
1802 }
1803
Chet Haase10e23ab2015-02-11 15:08:38 -08001804 void overridePendingAppTransitionClipReveal(int startX, int startY,
1805 int startWidth, int startHeight) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001806 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001807 clear();
Chet Haase10e23ab2015-02-11 15:08:38 -08001808 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001809 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
Chet Haase10e23ab2015-02-11 15:08:38 -08001810 postAnimationCallback();
Chet Haase10e23ab2015-02-11 15:08:38 -08001811 }
1812 }
1813
Winson Chungaa7fa012017-05-24 15:50:06 -07001814 void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX, int startY,
Craig Mautner164d4bb2012-11-26 13:51:23 -08001815 IRemoteCallback startedCallback, boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001816 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001817 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001818 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
1819 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001820 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001821 putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001822 postAnimationCallback();
1823 mNextAppTransitionCallback = startedCallback;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001824 }
1825 }
1826
Winson Chungaa7fa012017-05-24 15:50:06 -07001827 void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX, int startY,
Winson Chung2e7f3bd2014-09-05 13:17:22 +02001828 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001829 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001830 clear();
Winson Chunga4ccb862014-08-22 15:26:27 -07001831 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1832 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Winson Chunga4ccb862014-08-22 15:26:27 -07001833 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001834 putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight,
1835 srcThumb);
Winson Chunga4ccb862014-08-22 15:26:27 -07001836 postAnimationCallback();
1837 mNextAppTransitionCallback = startedCallback;
Winson Chunga4ccb862014-08-22 15:26:27 -07001838 }
1839 }
1840
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001841 void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001842 IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
1843 boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001844 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001845 clear();
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001846 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1847 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001848 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi43102412015-11-11 16:28:37 +01001849 if (specs != null) {
1850 for (int i = 0; i < specs.length; i++) {
1851 AppTransitionAnimationSpec spec = specs[i];
1852 if (spec != null) {
1853 mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec);
1854 if (i == 0) {
1855 // In full screen mode, the transition code depends on the default spec
1856 // to be set.
1857 Rect rect = spec.rect;
1858 putDefaultNextAppTransitionCoordinates(rect.left, rect.top,
Winson Chungaa7fa012017-05-24 15:50:06 -07001859 rect.width(), rect.height(), spec.buffer);
Jorim Jaggi43102412015-11-11 16:28:37 +01001860 }
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001861 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001862 }
1863 }
1864 postAnimationCallback();
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001865 mNextAppTransitionCallback = onAnimationStartedCallback;
1866 mAnimationFinishedCallback = onAnimationFinishedCallback;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001867 }
1868 }
1869
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001870 void overridePendingAppTransitionMultiThumbFuture(
1871 IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
1872 boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001873 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001874 clear();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001875 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1876 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001877 mNextAppTransitionAnimationsSpecsFuture = specsFuture;
1878 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +01001879 mNextAppTransitionFutureCallback = callback;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001880 }
1881 }
1882
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001883 void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter) {
Winson Chung044d5292014-11-06 11:05:19 -08001884 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001885 clear();
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001886 mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE;
1887 mRemoteAnimationController = new RemoteAnimationController(mService,
1888 remoteAnimationAdapter, mService.mH);
1889 }
1890 }
1891
1892 void overrideInPlaceAppTransition(String packageName, int anim) {
1893 if (canOverridePendingAppTransition()) {
1894 clear();
Winson Chung044d5292014-11-06 11:05:19 -08001895 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
1896 mNextAppTransitionPackage = packageName;
1897 mNextAppTransitionInPlace = anim;
Winson Chung044d5292014-11-06 11:05:19 -08001898 }
1899 }
1900
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001901 /**
Tony Mak089c35e2017-12-18 20:34:14 +00001902 * @see {@link #NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS}
1903 */
1904 void overridePendingAppTransitionStartCrossProfileApps() {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001905 if (canOverridePendingAppTransition()) {
Tony Mak089c35e2017-12-18 20:34:14 +00001906 clear();
1907 mNextAppTransitionType = NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
1908 postAnimationCallback();
1909 }
1910 }
1911
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001912 private boolean canOverridePendingAppTransition() {
1913 // Remote animations always take precedence
1914 return isTransitionSet() && mNextAppTransitionType != NEXT_TRANSIT_TYPE_REMOTE;
1915 }
1916
Tony Mak089c35e2017-12-18 20:34:14 +00001917 /**
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001918 * If a future is set for the app transition specs, fetch it in another thread.
1919 */
1920 private void fetchAppTransitionSpecsFromFuture() {
1921 if (mNextAppTransitionAnimationsSpecsFuture != null) {
1922 mNextAppTransitionAnimationsSpecsPending = true;
1923 final IAppTransitionAnimationSpecsFuture future
1924 = mNextAppTransitionAnimationsSpecsFuture;
1925 mNextAppTransitionAnimationsSpecsFuture = null;
Jorim Jaggied410b62017-05-05 15:16:14 +02001926 mDefaultExecutor.execute(() -> {
1927 AppTransitionAnimationSpec[] specs = null;
1928 try {
1929 Binder.allowBlocking(future.asBinder());
1930 specs = future.get();
1931 } catch (RemoteException e) {
1932 Slog.w(TAG, "Failed to fetch app transition specs: " + e);
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001933 }
Jorim Jaggied410b62017-05-05 15:16:14 +02001934 synchronized (mService.mWindowMap) {
1935 mNextAppTransitionAnimationsSpecsPending = false;
1936 overridePendingAppTransitionMultiThumb(specs,
1937 mNextAppTransitionFutureCallback, null /* finishedCallback */,
1938 mNextAppTransitionScaleUp);
1939 mNextAppTransitionFutureCallback = null;
Jorim Jaggied410b62017-05-05 15:16:14 +02001940 }
1941 mService.requestTraversal();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001942 });
1943 }
1944 }
1945
Craig Mautner164d4bb2012-11-26 13:51:23 -08001946 @Override
1947 public String toString() {
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001948 return "mNextAppTransition=" + appTransitionToString(mNextAppTransition);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001949 }
1950
Craig Mautner4b71aa12012-12-27 17:20:01 -08001951 /**
1952 * Returns the human readable name of a window transition.
1953 *
1954 * @param transition The window transition.
1955 * @return The transition symbolic name.
1956 */
1957 public static String appTransitionToString(int transition) {
1958 switch (transition) {
1959 case TRANSIT_UNSET: {
1960 return "TRANSIT_UNSET";
1961 }
1962 case TRANSIT_NONE: {
1963 return "TRANSIT_NONE";
1964 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08001965 case TRANSIT_ACTIVITY_OPEN: {
1966 return "TRANSIT_ACTIVITY_OPEN";
1967 }
1968 case TRANSIT_ACTIVITY_CLOSE: {
1969 return "TRANSIT_ACTIVITY_CLOSE";
1970 }
1971 case TRANSIT_TASK_OPEN: {
1972 return "TRANSIT_TASK_OPEN";
1973 }
1974 case TRANSIT_TASK_CLOSE: {
1975 return "TRANSIT_TASK_CLOSE";
1976 }
1977 case TRANSIT_TASK_TO_FRONT: {
1978 return "TRANSIT_TASK_TO_FRONT";
1979 }
1980 case TRANSIT_TASK_TO_BACK: {
1981 return "TRANSIT_TASK_TO_BACK";
1982 }
1983 case TRANSIT_WALLPAPER_CLOSE: {
1984 return "TRANSIT_WALLPAPER_CLOSE";
1985 }
1986 case TRANSIT_WALLPAPER_OPEN: {
1987 return "TRANSIT_WALLPAPER_OPEN";
1988 }
1989 case TRANSIT_WALLPAPER_INTRA_OPEN: {
1990 return "TRANSIT_WALLPAPER_INTRA_OPEN";
1991 }
1992 case TRANSIT_WALLPAPER_INTRA_CLOSE: {
1993 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
1994 }
Craig Mautnerbb742462014-07-07 15:28:55 -07001995 case TRANSIT_TASK_OPEN_BEHIND: {
1996 return "TRANSIT_TASK_OPEN_BEHIND";
1997 }
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001998 case TRANSIT_ACTIVITY_RELAUNCH: {
1999 return "TRANSIT_ACTIVITY_RELAUNCH";
2000 }
Jorim Jaggi192086e2016-03-11 17:17:03 +01002001 case TRANSIT_DOCK_TASK_FROM_RECENTS: {
2002 return "TRANSIT_DOCK_TASK_FROM_RECENTS";
2003 }
Jorim Jaggife762342016-10-13 14:33:27 +02002004 case TRANSIT_KEYGUARD_GOING_AWAY: {
2005 return "TRANSIT_KEYGUARD_GOING_AWAY";
2006 }
2007 case TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
2008 return "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
2009 }
2010 case TRANSIT_KEYGUARD_OCCLUDE: {
2011 return "TRANSIT_KEYGUARD_OCCLUDE";
2012 }
2013 case TRANSIT_KEYGUARD_UNOCCLUDE: {
2014 return "TRANSIT_KEYGUARD_UNOCCLUDE";
2015 }
Jorim Jaggi98a9d202018-03-26 16:17:07 +02002016 case TRANSIT_TRANSLUCENT_ACTIVITY_OPEN: {
2017 return "TRANSIT_TRANSLUCENT_ACTIVITY_OPEN";
2018 }
2019 case TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE: {
2020 return "TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE";
2021 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08002022 default: {
2023 return "<UNKNOWN>";
2024 }
2025 }
2026 }
2027
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002028 private String appStateToString() {
2029 switch (mAppTransitionState) {
2030 case APP_STATE_IDLE:
2031 return "APP_STATE_IDLE";
2032 case APP_STATE_READY:
2033 return "APP_STATE_READY";
2034 case APP_STATE_RUNNING:
2035 return "APP_STATE_RUNNING";
2036 case APP_STATE_TIMEOUT:
2037 return "APP_STATE_TIMEOUT";
2038 default:
2039 return "unknown state=" + mAppTransitionState;
2040 }
2041 }
2042
2043 private String transitTypeToString() {
2044 switch (mNextAppTransitionType) {
2045 case NEXT_TRANSIT_TYPE_NONE:
2046 return "NEXT_TRANSIT_TYPE_NONE";
2047 case NEXT_TRANSIT_TYPE_CUSTOM:
2048 return "NEXT_TRANSIT_TYPE_CUSTOM";
Winson Chung044d5292014-11-06 11:05:19 -08002049 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
2050 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002051 case NEXT_TRANSIT_TYPE_SCALE_UP:
2052 return "NEXT_TRANSIT_TYPE_SCALE_UP";
2053 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
2054 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
2055 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
2056 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
Winson Chunga4ccb862014-08-22 15:26:27 -07002057 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
2058 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
2059 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
2060 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
Tony Mak64b8d562017-12-28 17:44:02 +00002061 case NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:
2062 return "NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002063 default:
2064 return "unknown type=" + mNextAppTransitionType;
2065 }
2066 }
2067
Steven Timotiusaf03df62017-07-18 16:56:43 -07002068 void writeToProto(ProtoOutputStream proto, long fieldId) {
2069 final long token = proto.start(fieldId);
2070 proto.write(APP_TRANSITION_STATE, mAppTransitionState);
2071 proto.write(LAST_USED_APP_TRANSITION, mLastUsedAppTransition);
2072 proto.end(token);
2073 }
2074
Craig Mautner164d4bb2012-11-26 13:51:23 -08002075 @Override
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002076 public void dump(PrintWriter pw, String prefix) {
2077 pw.print(prefix); pw.println(this);
2078 pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002079 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002080 pw.print(prefix); pw.print("mNextAppTransitionType=");
2081 pw.println(transitTypeToString());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002082 }
2083 switch (mNextAppTransitionType) {
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002084 case NEXT_TRANSIT_TYPE_CUSTOM:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002085 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Craig Mautner164d4bb2012-11-26 13:51:23 -08002086 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002087 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
Craig Mautner164d4bb2012-11-26 13:51:23 -08002088 pw.print(Integer.toHexString(mNextAppTransitionEnter));
2089 pw.print(" mNextAppTransitionExit=0x");
2090 pw.println(Integer.toHexString(mNextAppTransitionExit));
2091 break;
Winson Chung044d5292014-11-06 11:05:19 -08002092 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002093 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Winson Chung044d5292014-11-06 11:05:19 -08002094 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002095 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
Winson Chung044d5292014-11-06 11:05:19 -08002096 pw.print(Integer.toHexString(mNextAppTransitionInPlace));
2097 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002098 case NEXT_TRANSIT_TYPE_SCALE_UP: {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002099 getDefaultNextAppTransitionStartRect(mTmpRect);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002100 pw.print(prefix); pw.print("mNextAppTransitionStartX=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002101 pw.print(mTmpRect.left);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002102 pw.print(" mNextAppTransitionStartY=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002103 pw.println(mTmpRect.top);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002104 pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002105 pw.print(mTmpRect.width());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002106 pw.print(" mNextAppTransitionStartHeight=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002107 pw.println(mTmpRect.height());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002108 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002109 }
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002110 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
2111 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
Winson Chunga4ccb862014-08-22 15:26:27 -07002112 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002113 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
2114 pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
2115 pw.println(mDefaultNextAppTransitionAnimationSpec);
2116 pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
2117 pw.println(mNextAppTransitionAnimationsSpecs);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002118 pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
2119 pw.println(mNextAppTransitionScaleUp);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002120 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002121 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002122 }
2123 if (mNextAppTransitionCallback != null) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002124 pw.print(prefix); pw.print("mNextAppTransitionCallback=");
2125 pw.println(mNextAppTransitionCallback);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002126 }
Chong Zhang60091a92016-07-27 17:52:45 -07002127 if (mLastUsedAppTransition != TRANSIT_NONE) {
2128 pw.print(prefix); pw.print("mLastUsedAppTransition=");
2129 pw.println(appTransitionToString(mLastUsedAppTransition));
2130 pw.print(prefix); pw.print("mLastOpeningApp=");
2131 pw.println(mLastOpeningApp);
2132 pw.print(prefix); pw.print("mLastClosingApp=");
2133 pw.println(mLastClosingApp);
2134 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002135 }
Amith Yamasani4befbec2013-07-10 16:18:01 -07002136
2137 public void setCurrentUser(int newUserId) {
2138 mCurrentUserId = newUserId;
2139 }
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002140
2141 /**
2142 * @return true if transition is not running and should not be skipped, false if transition is
2143 * already running
2144 */
Jorim Jaggif84e2f62018-01-16 14:17:59 +01002145 boolean prepareAppTransitionLocked(@TransitionType int transit, boolean alwaysKeepCurrent,
2146 @TransitionFlags int flags, boolean forceOverride) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002147 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
2148 + " transit=" + appTransitionToString(transit)
2149 + " " + this
2150 + " alwaysKeepCurrent=" + alwaysKeepCurrent
2151 + " Callers=" + Debug.getCallers(3));
Jorim Jaggife762342016-10-13 14:33:27 +02002152 if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
2153 || mNextAppTransition == TRANSIT_NONE) {
2154 setAppTransition(transit, flags);
Jorim Jaggia69243a2017-06-15 15:10:38 -04002155 }
2156 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
Adrian Roos93577212018-04-10 14:12:10 -07002157 // relies on the fact that we always execute a Keyguard transition after preparing one. We
2158 // also don't want to change away from a crashing transition.
2159 else if (!alwaysKeepCurrent && !isKeyguardTransit(transit)
2160 && transit != TRANSIT_CRASHING_ACTIVITY_CLOSE) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002161 if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
2162 // Opening a new task always supersedes a close for the anim.
Jorim Jaggife762342016-10-13 14:33:27 +02002163 setAppTransition(transit, flags);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002164 } else if (transit == TRANSIT_ACTIVITY_OPEN
2165 && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
2166 // Opening a new activity always supersedes a close for the anim.
Jorim Jaggife762342016-10-13 14:33:27 +02002167 setAppTransition(transit, flags);
Jorim Jaggicecf4242018-02-21 18:46:53 +01002168 } else if (isTaskTransit(transit) && isActivityTransit(mNextAppTransition)) {
2169 // Task animations always supersede activity animations, because if we have both, it
2170 // usually means that activity transition were just trampoline activities.
2171 setAppTransition(transit, flags);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002172 }
2173 }
2174 boolean prepared = prepare();
2175 if (isTransitionSet()) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08002176 mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2177 mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002178 }
2179 return prepared;
2180 }
Winsonb2024762016-04-05 17:32:30 -07002181
2182 /**
Jorim Jaggife762342016-10-13 14:33:27 +02002183 * @return true if {@param transit} is representing a transition in which Keyguard is going
2184 * away, false otherwise
2185 */
2186 public static boolean isKeyguardGoingAwayTransit(int transit) {
2187 return transit == TRANSIT_KEYGUARD_GOING_AWAY
2188 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
2189 }
2190
2191 private static boolean isKeyguardTransit(int transit) {
2192 return isKeyguardGoingAwayTransit(transit) || transit == TRANSIT_KEYGUARD_OCCLUDE
2193 || transit == TRANSIT_KEYGUARD_UNOCCLUDE;
2194 }
2195
Jorim Jaggi98a9d202018-03-26 16:17:07 +02002196 static boolean isTaskTransit(int transit) {
2197 return isTaskOpenTransit(transit)
Jorim Jaggicecf4242018-02-21 18:46:53 +01002198 || transit == TRANSIT_TASK_CLOSE
Jorim Jaggicecf4242018-02-21 18:46:53 +01002199 || transit == TRANSIT_TASK_TO_BACK
Jorim Jaggicecf4242018-02-21 18:46:53 +01002200 || transit == TRANSIT_TASK_IN_PLACE;
2201 }
2202
Jorim Jaggi98a9d202018-03-26 16:17:07 +02002203 private static boolean isTaskOpenTransit(int transit) {
2204 return transit == TRANSIT_TASK_OPEN
2205 || transit == TRANSIT_TASK_OPEN_BEHIND
2206 || transit == TRANSIT_TASK_TO_FRONT;
2207 }
2208
2209 static boolean isActivityTransit(int transit) {
Jorim Jaggicecf4242018-02-21 18:46:53 +01002210 return transit == TRANSIT_ACTIVITY_OPEN
2211 || transit == TRANSIT_ACTIVITY_CLOSE
2212 || transit == TRANSIT_ACTIVITY_RELAUNCH;
2213 }
2214
Jorim Jaggife762342016-10-13 14:33:27 +02002215 /**
Manu Cornetd7376802017-01-13 13:44:07 -08002216 * @return whether the transition should show the thumbnail being scaled down.
2217 */
2218 private boolean shouldScaleDownThumbnailTransition(int uiMode, int orientation) {
Sid Soundararajan0e88d322017-03-07 15:37:30 -08002219 return mGridLayoutRecentsEnabled
Manu Cornetd7376802017-01-13 13:44:07 -08002220 || orientation == Configuration.ORIENTATION_PORTRAIT;
2221 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002222}