blob: f129fe161f0a3620bb774e731a26e15f2f910030 [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
Filip Gruszczynski82861362015-10-16 14:21:09 -070019import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
20import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
21import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
22import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
23import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
24import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
25import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
26import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
27import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
28import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
29import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
30import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
31import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
32import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
33import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
34import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
35import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
36import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
37import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
38import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
39import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
40import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
Filip Gruszczynski198dcbf2016-01-18 10:02:00 -080041import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
42import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080043import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
44import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Adrian Roose99bc052017-11-20 17:55:31 +010045import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
Tony Mak089c35e2017-12-18 20:34:14 +000046import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
Matthew Ngbf1d9852017-03-14 12:23:09 -070047import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +010048import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
Steven Timotiusaf03df62017-07-18 16:56:43 -070049import static com.android.server.wm.proto.AppTransitionProto.APP_TRANSITION_STATE;
50import static com.android.server.wm.proto.AppTransitionProto.LAST_USED_APP_TRANSITION;
Filip Gruszczynski82861362015-10-16 14:21:09 -070051
Tony Mak64b8d562017-12-28 17:44:02 +000052import android.annotation.DrawableRes;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -070053import android.annotation.Nullable;
Matthew Ng43db6d22017-06-27 15:29:39 -070054import android.app.ActivityManager;
Tony Mak089c35e2017-12-18 20:34:14 +000055import android.content.ComponentName;
Craig Mautner164d4bb2012-11-26 13:51:23 -080056import android.content.Context;
Winson21700932016-03-24 17:26:23 -070057import android.content.res.Configuration;
Tony Mak64b8d562017-12-28 17:44:02 +000058import android.graphics.Color;
Winson Chungaa7fa012017-05-24 15:50:06 -070059import android.graphics.GraphicBuffer;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +010060import android.graphics.Path;
Winson Chung399f6202014-03-19 10:47:20 -070061import android.graphics.Rect;
Tony Mak64b8d562017-12-28 17:44:02 +000062import android.graphics.drawable.Drawable;
Jorim Jaggied410b62017-05-05 15:16:14 +020063import android.os.Binder;
Craig Mautner164d4bb2012-11-26 13:51:23 -080064import android.os.Debug;
Jorim Jaggi77ba4802015-02-18 13:57:50 +010065import android.os.IBinder;
Craig Mautner164d4bb2012-11-26 13:51:23 -080066import android.os.IRemoteCallback;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +010067import android.os.RemoteException;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020068import android.os.SystemClock;
Manu Cornetd7376802017-01-13 13:44:07 -080069import android.os.SystemProperties;
Tony Mak089c35e2017-12-18 20:34:14 +000070import android.os.UserHandle;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -080071import android.util.ArraySet;
Craig Mautner164d4bb2012-11-26 13:51:23 -080072import android.util.Slog;
Filip Gruszczynski170192a2015-08-16 17:46:34 -070073import android.util.SparseArray;
Steven Timotiusaf03df62017-07-18 16:56:43 -070074import android.util.proto.ProtoOutputStream;
Filip Gruszczynski170192a2015-08-16 17:46:34 -070075import android.view.AppTransitionAnimationSpec;
Tony Mak64b8d562017-12-28 17:44:02 +000076import android.view.DisplayListCanvas;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +010077import android.view.IAppTransitionAnimationSpecsFuture;
Jorim Jaggi33a701a2017-12-01 14:58:18 +010078import android.view.RemoteAnimationAdapter;
Tony Mak64b8d562017-12-28 17:44:02 +000079import android.view.RenderNode;
80import android.view.ThreadedRenderer;
Craig Mautner164d4bb2012-11-26 13:51:23 -080081import android.view.WindowManager;
Craig Mautner164d4bb2012-11-26 13:51:23 -080082import android.view.animation.AlphaAnimation;
83import android.view.animation.Animation;
84import android.view.animation.AnimationSet;
85import android.view.animation.AnimationUtils;
Winson Chung399f6202014-03-19 10:47:20 -070086import android.view.animation.ClipRectAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -080087import android.view.animation.Interpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -070088import android.view.animation.PathInterpolator;
Craig Mautner164d4bb2012-11-26 13:51:23 -080089import android.view.animation.ScaleAnimation;
Winson Chung399f6202014-03-19 10:47:20 -070090import android.view.animation.TranslateAnimation;
Jorim Jaggi1d763a62015-06-02 17:07:39 -070091
Craig Mautner164d4bb2012-11-26 13:51:23 -080092import com.android.internal.util.DumpUtils.Dump;
93import com.android.server.AttributeCache;
94import com.android.server.wm.WindowManagerService.H;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -080095import com.android.server.wm.animation.ClipRectLRAnimation;
96import com.android.server.wm.animation.ClipRectTBAnimation;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +010097import com.android.server.wm.animation.CurvedTranslateAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -080098
99import java.io.PrintWriter;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100100import java.util.ArrayList;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100101import java.util.concurrent.ExecutorService;
102import java.util.concurrent.Executors;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800103
Craig Mautner164d4bb2012-11-26 13:51:23 -0800104// State management of app transitions. When we are preparing for a
105// transition, mNextAppTransition will be the kind of transition to
106// perform or TRANSIT_NONE if we are not waiting. If we are waiting,
107// mOpeningApps and mClosingApps are the lists of tokens that will be
108// made visible or hidden at the next transition.
109public class AppTransition implements Dump {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800110 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700111 private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800112
Craig Mautner4b71aa12012-12-27 17:20:01 -0800113 /** Not set up for a transition. */
114 public static final int TRANSIT_UNSET = -1;
115 /** No animation for transition. */
116 public static final int TRANSIT_NONE = 0;
117 /** A window in a new activity is being opened on top of an existing one in the same task. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700118 public static final int TRANSIT_ACTIVITY_OPEN = 6;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800119 /** The window in the top-most activity is being closed to reveal the
120 * previous activity in the same task. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700121 public static final int TRANSIT_ACTIVITY_CLOSE = 7;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800122 /** A window in a new task is being opened on top of an existing one
123 * in another activity's task. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700124 public static final int TRANSIT_TASK_OPEN = 8;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800125 /** A window in the top-most activity is being closed to reveal the
126 * previous activity in a different task. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700127 public static final int TRANSIT_TASK_CLOSE = 9;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800128 /** A window in an existing task is being displayed on top of an existing one
129 * in another activity's task. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700130 public static final int TRANSIT_TASK_TO_FRONT = 10;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800131 /** A window in an existing task is being put below all other tasks. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700132 public static final int TRANSIT_TASK_TO_BACK = 11;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800133 /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that
134 * does, effectively closing the wallpaper. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700135 public static final int TRANSIT_WALLPAPER_CLOSE = 12;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800136 /** A window in a new activity that does have a wallpaper is being opened on one that didn't,
137 * effectively opening the wallpaper. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700138 public static final int TRANSIT_WALLPAPER_OPEN = 13;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800139 /** A window in a new activity is being opened on top of an existing one, and both are on top
140 * of the wallpaper. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700141 public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800142 /** The window in the top-most activity is being closed to reveal the previous activity, and
143 * both are on top of the wallpaper. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700144 public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15;
145 /** A window in a new task is being opened behind an existing one in another activity's task.
146 * The new window will show briefly and then be gone. */
147 public static final int TRANSIT_TASK_OPEN_BEHIND = 16;
Winson Chung044d5292014-11-06 11:05:19 -0800148 /** A window in a task is being animated in-place. */
149 public static final int TRANSIT_TASK_IN_PLACE = 17;
Filip Gruszczynski55a309f2015-09-04 17:15:01 -0700150 /** An activity is being relaunched (e.g. due to configuration change). */
151 public static final int TRANSIT_ACTIVITY_RELAUNCH = 18;
Jorim Jaggi192086e2016-03-11 17:17:03 +0100152 /** A task is being docked from recents. */
153 public static final int TRANSIT_DOCK_TASK_FROM_RECENTS = 19;
Jorim Jaggife762342016-10-13 14:33:27 +0200154 /** Keyguard is going away */
155 public static final int TRANSIT_KEYGUARD_GOING_AWAY = 20;
156 /** Keyguard is going away with showing an activity behind that requests wallpaper */
157 public static final int TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
158 /** Keyguard is being occluded */
159 public static final int TRANSIT_KEYGUARD_OCCLUDE = 22;
160 /** Keyguard is being unoccluded */
161 public static final int TRANSIT_KEYGUARD_UNOCCLUDE = 23;
162
163 /** Transition flag: Keyguard is going away, but keeping the notification shade open */
164 public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE = 0x1;
165 /** Transition flag: Keyguard is going away, but doesn't want an animation for it */
166 public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION = 0x2;
167 /** Transition flag: Keyguard is going away while it was showing the system wallpaper. */
168 public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER = 0x4;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800169
Winson Chunga4ccb862014-08-22 15:26:27 -0700170 /** Fraction of animation at which the recents thumbnail stays completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700171 private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800172 /** Fraction of animation at which the recents thumbnail becomes completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700173 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800174
Filip Gruszczynski84fa3352016-01-25 16:28:49 -0800175 static final int DEFAULT_APP_TRANSITION_DURATION = 336;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800176
177 /** Interpolator to be used for animations that respond directly to a touch */
178 static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
179 new PathInterpolator(0.3f, 0f, 0.1f, 1f);
180
Jorim Jaggic69bd222016-03-15 14:38:37 +0100181 private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR =
182 new PathInterpolator(0.85f, 0f, 1f, 1f);
183
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800184 /**
185 * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
186 * involved, to make it more understandable.
187 */
188 private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700189 private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700190 private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800191
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800192 private final Context mContext;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800193 private final WindowManagerService mService;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800194
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800195 private int mNextAppTransition = TRANSIT_UNSET;
Jorim Jaggife762342016-10-13 14:33:27 +0200196 private int mNextAppTransitionFlags = 0;
Chong Zhang60091a92016-07-27 17:52:45 -0700197 private int mLastUsedAppTransition = TRANSIT_UNSET;
198 private String mLastOpeningApp;
199 private String mLastClosingApp;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800200
201 private static final int NEXT_TRANSIT_TYPE_NONE = 0;
202 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
203 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
204 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
205 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
Winson Chunga4ccb862014-08-22 15:26:27 -0700206 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
207 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
Winson Chung044d5292014-11-06 11:05:19 -0800208 private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
Chet Haase10e23ab2015-02-11 15:08:38 -0800209 private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
Tony Mak089c35e2017-12-18 20:34:14 +0000210
211 /**
212 * Refers to the transition to activity started by using {@link
213 * android.content.pm.crossprofile.CrossProfileApps#startMainActivity(ComponentName, UserHandle)
214 * }.
215 */
216 private static final int NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS = 9;
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100217 private static final int NEXT_TRANSIT_TYPE_REMOTE = 10;
218
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800219 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
220
Winson Chung399f6202014-03-19 10:47:20 -0700221 // These are the possible states for the enter/exit activities during a thumbnail transition
222 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
223 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
224 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
225 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
226
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800227 private String mNextAppTransitionPackage;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800228 // Used for thumbnail transitions. True if we're scaling up, false if scaling down
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800229 private boolean mNextAppTransitionScaleUp;
230 private IRemoteCallback mNextAppTransitionCallback;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +0100231 private IRemoteCallback mNextAppTransitionFutureCallback;
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -0700232 private IRemoteCallback mAnimationFinishedCallback;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800233 private int mNextAppTransitionEnter;
234 private int mNextAppTransitionExit;
Winson Chung044d5292014-11-06 11:05:19 -0800235 private int mNextAppTransitionInPlace;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700236
237 // Keyed by task id.
238 private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
239 = new SparseArray<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100240 private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
241 private boolean mNextAppTransitionAnimationsSpecsPending;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700242 private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
243
Winson Chunga4ccb862014-08-22 15:26:27 -0700244 private Rect mNextAppTransitionInsets = new Rect();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800245
Winson Chung2820c452014-04-15 15:34:44 -0700246 private Rect mTmpFromClipRect = new Rect();
247 private Rect mTmpToClipRect = new Rect();
248
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700249 private final Rect mTmpRect = new Rect();
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700250
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800251 private final static int APP_STATE_IDLE = 0;
252 private final static int APP_STATE_READY = 1;
253 private final static int APP_STATE_RUNNING = 2;
254 private final static int APP_STATE_TIMEOUT = 3;
255 private int mAppTransitionState = APP_STATE_IDLE;
256
257 private final int mConfigShortAnimTime;
Craig Mautner321bdf52012-12-18 09:53:24 -0800258 private final Interpolator mDecelerateInterpolator;
Winson Chunga4ccb862014-08-22 15:26:27 -0700259 private final Interpolator mThumbnailFadeInInterpolator;
260 private final Interpolator mThumbnailFadeOutInterpolator;
Chet Haase10e23ab2015-02-11 15:08:38 -0800261 private final Interpolator mLinearOutSlowInInterpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700262 private final Interpolator mFastOutLinearInInterpolator;
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100263 private final Interpolator mFastOutSlowInInterpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700264 private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
265
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700266 private final int mClipRevealTranslationY;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800267
Amith Yamasani4befbec2013-07-10 16:18:01 -0700268 private int mCurrentUserId = 0;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800269 private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
Amith Yamasani4befbec2013-07-10 16:18:01 -0700270
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100271 private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100272 private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100273
Jorim Jaggif97ed922016-02-18 18:57:07 -0800274 private int mLastClipRevealMaxTranslation;
275 private boolean mLastHadClipReveal;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700276 private boolean mProlongedAnimationsEnded;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800277
Manu Cornetd7376802017-01-13 13:44:07 -0800278 private final boolean mGridLayoutRecentsEnabled;
Matthew Ng43db6d22017-06-27 15:29:39 -0700279 private final boolean mLowRamRecentsEnabled;
Manu Cornetd7376802017-01-13 13:44:07 -0800280
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100281 private RemoteAnimationController mRemoteAnimationController;
282
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800283 AppTransition(Context context, WindowManagerService service) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800284 mContext = context;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800285 mService = service;
Chet Haase10e23ab2015-02-11 15:08:38 -0800286 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
287 com.android.internal.R.interpolator.linear_out_slow_in);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700288 mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
289 com.android.internal.R.interpolator.fast_out_linear_in);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100290 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
291 com.android.internal.R.interpolator.fast_out_slow_in);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800292 mConfigShortAnimTime = context.getResources().getInteger(
293 com.android.internal.R.integer.config_shortAnimTime);
Craig Mautner321bdf52012-12-18 09:53:24 -0800294 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
295 com.android.internal.R.interpolator.decelerate_cubic);
Winson Chunga4ccb862014-08-22 15:26:27 -0700296 mThumbnailFadeInInterpolator = new Interpolator() {
297 @Override
298 public float getInterpolation(float input) {
299 // Linear response for first fraction, then complete after that.
300 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
301 return 0f;
302 }
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700303 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /
Winson Chunga4ccb862014-08-22 15:26:27 -0700304 (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700305 return mFastOutLinearInInterpolator.getInterpolation(t);
Winson Chunga4ccb862014-08-22 15:26:27 -0700306 }
307 };
308 mThumbnailFadeOutInterpolator = new Interpolator() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800309 @Override
310 public float getInterpolation(float input) {
311 // Linear response for first fraction, then complete after that.
312 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700313 float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
314 return mLinearOutSlowInInterpolator.getInterpolation(t);
Craig Mautner321bdf52012-12-18 09:53:24 -0800315 }
Winson Chunga4ccb862014-08-22 15:26:27 -0700316 return 1f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800317 }
318 };
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700319 mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP
320 * mContext.getResources().getDisplayMetrics().density);
Manu Cornetd7376802017-01-13 13:44:07 -0800321 mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
Matthew Ng43db6d22017-06-27 15:29:39 -0700322 mLowRamRecentsEnabled = ActivityManager.isLowRamDeviceStatic();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800323 }
324
325 boolean isTransitionSet() {
326 return mNextAppTransition != TRANSIT_UNSET;
327 }
328
Craig Mautner164d4bb2012-11-26 13:51:23 -0800329 boolean isTransitionEqual(int transit) {
330 return mNextAppTransition == transit;
331 }
332
333 int getAppTransition() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800334 return mNextAppTransition;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800335 }
336
Jorim Jaggife762342016-10-13 14:33:27 +0200337 private void setAppTransition(int transit, int flags) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800338 mNextAppTransition = transit;
Jorim Jaggife762342016-10-13 14:33:27 +0200339 mNextAppTransitionFlags |= flags;
Chong Zhang60091a92016-07-27 17:52:45 -0700340 setLastAppTransition(TRANSIT_UNSET, null, null);
Jorim Jaggi245281c2017-06-07 14:33:04 -0700341 updateBooster();
Chong Zhang60091a92016-07-27 17:52:45 -0700342 }
343
344 void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp) {
345 mLastUsedAppTransition = transit;
346 mLastOpeningApp = "" + openingApp;
347 mLastClosingApp = "" + closingApp;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800348 }
349
350 boolean isReady() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800351 return mAppTransitionState == APP_STATE_READY
352 || mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800353 }
354
Craig Mautnerae446592012-12-06 19:05:05 -0800355 void setReady() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700356 setAppTransitionState(APP_STATE_READY);
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100357 fetchAppTransitionSpecsFromFuture();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800358 }
359
360 boolean isRunning() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800361 return mAppTransitionState == APP_STATE_RUNNING;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800362 }
363
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800364 void setIdle() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700365 setAppTransitionState(APP_STATE_IDLE);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800366 }
367
368 boolean isTimeout() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800369 return mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800370 }
371
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800372 void setTimeout() {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700373 setAppTransitionState(APP_STATE_TIMEOUT);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800374 }
375
Winson Chungaa7fa012017-05-24 15:50:06 -0700376 GraphicBuffer getAppTransitionThumbnailHeader(int taskId) {
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700377 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800378 if (spec == null) {
379 spec = mDefaultNextAppTransitionAnimationSpec;
380 }
Winson Chungaa7fa012017-05-24 15:50:06 -0700381 return spec != null ? spec.buffer : null;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800382 }
383
Winson Chunga4ccb862014-08-22 15:26:27 -0700384 /** Returns whether the next thumbnail transition is aspect scaled up. */
385 boolean isNextThumbnailTransitionAspectScaled() {
386 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
387 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
388 }
389
390 /** Returns whether the next thumbnail transition is scaling up. */
391 boolean isNextThumbnailTransitionScaleUp() {
392 return mNextAppTransitionScaleUp;
393 }
394
Filip Gruszczynski4cbc3152015-12-07 11:50:57 -0800395 boolean isNextAppTransitionThumbnailUp() {
396 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
397 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP;
398 }
399
400 boolean isNextAppTransitionThumbnailDown() {
401 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN ||
402 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
403 }
404
Tony Mak64b8d562017-12-28 17:44:02 +0000405
406 boolean isNextAppTransitionOpenCrossProfileApps() {
407 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
408 }
409
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100410 /**
411 * @return true if and only if we are currently fetching app transition specs from the future
412 * passed into {@link #overridePendingAppTransitionMultiThumbFuture}
413 */
414 boolean isFetchingAppTransitionsSpecs() {
415 return mNextAppTransitionAnimationsSpecsPending;
416 }
417
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700418 private boolean prepare() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800419 if (!isRunning()) {
Jorim Jaggi245281c2017-06-07 14:33:04 -0700420 setAppTransitionState(APP_STATE_IDLE);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100421 notifyAppTransitionPendingLocked();
Jorim Jaggif97ed922016-02-18 18:57:07 -0800422 mLastHadClipReveal = false;
423 mLastClipRevealMaxTranslation = 0;
424 mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700425 return true;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800426 }
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700427 return false;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800428 }
429
Jorim Jaggife762342016-10-13 14:33:27 +0200430 /**
431 * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
432 * layout pass needs to be done
433 */
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200434 int goodToGo(int transit, AppWindowToken topOpeningApp,
435 AppWindowToken topClosingApp, ArraySet<AppWindowToken> openingApps,
Jorim Jaggife762342016-10-13 14:33:27 +0200436 ArraySet<AppWindowToken> closingApps) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800437 mNextAppTransition = TRANSIT_UNSET;
Jorim Jaggife762342016-10-13 14:33:27 +0200438 mNextAppTransitionFlags = 0;
Jorim Jaggi245281c2017-06-07 14:33:04 -0700439 setAppTransitionState(APP_STATE_RUNNING);
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200440 final AnimationAdapter topOpeningAnim = topOpeningApp != null
441 ? topOpeningApp.getAnimation()
442 : null;
Jorim Jaggife762342016-10-13 14:33:27 +0200443 int redoLayout = notifyAppTransitionStartingLocked(transit,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200444 topOpeningApp != null ? topOpeningApp.token : null,
445 topClosingApp != null ? topClosingApp.token : null,
446 topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0,
447 topOpeningAnim != null
448 ? topOpeningAnim.getStatusBarTransitionsStartTime()
449 : SystemClock.uptimeMillis(),
450 AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800451 mService.getDefaultDisplayContentLocked().getDockedDividerController()
Jorim Jaggife762342016-10-13 14:33:27 +0200452 .notifyAppTransitionStarting(openingApps, transit);
Jorim Jaggi363ab982016-04-26 19:51:20 -0700453
454 // Prolong the start for the transition when docking a task from recents, unless recents
455 // ended it already then we don't need to wait.
Jorim Jaggife762342016-10-13 14:33:27 +0200456 if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) {
Jorim Jaggi363ab982016-04-26 19:51:20 -0700457 for (int i = openingApps.size() - 1; i >= 0; i--) {
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200458 final AppWindowToken app = openingApps.valueAt(i);
459 app.startDelayingAnimationStart();
Jorim Jaggi363ab982016-04-26 19:51:20 -0700460 }
461 }
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100462 if (mRemoteAnimationController != null) {
463 mRemoteAnimationController.goodToGo();
464 }
Jorim Jaggife762342016-10-13 14:33:27 +0200465 return redoLayout;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700466 }
467
468 /**
469 * Let the transitions manager know that the somebody wanted to end the prolonged animations.
470 */
471 void notifyProlongedAnimationsEnded() {
472 mProlongedAnimationsEnded = true;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800473 }
474
475 void clear() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800476 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800477 mNextAppTransitionPackage = null;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700478 mNextAppTransitionAnimationsSpecs.clear();
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100479 mRemoteAnimationController = null;
Jorim Jaggi65193992015-11-23 16:49:59 -0800480 mNextAppTransitionAnimationsSpecsFuture = null;
481 mDefaultNextAppTransitionAnimationSpec = null;
482 mAnimationFinishedCallback = null;
Jorim Jaggi363ab982016-04-26 19:51:20 -0700483 mProlongedAnimationsEnded = false;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800484 }
485
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800486 void freeze() {
Jorim Jaggife762342016-10-13 14:33:27 +0200487 final int transit = mNextAppTransition;
488 setAppTransition(AppTransition.TRANSIT_UNSET, 0 /* flags */);
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800489 clear();
490 setReady();
Jorim Jaggife762342016-10-13 14:33:27 +0200491 notifyAppTransitionCancelledLocked(transit);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100492 }
493
Jorim Jaggi245281c2017-06-07 14:33:04 -0700494 private void setAppTransitionState(int state) {
495 mAppTransitionState = state;
496 updateBooster();
497 }
498
499 /**
500 * Updates whether we currently boost wm locked sections and the animation thread. We want to
501 * boost the priorities to a more important value whenever an app transition is going to happen
502 * soon or an app transition is running.
503 */
504 private void updateBooster() {
505 WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning(
506 mNextAppTransition != TRANSIT_UNSET || mAppTransitionState == APP_STATE_READY
507 || mAppTransitionState == APP_STATE_RUNNING);
508 }
509
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100510 void registerListenerLocked(AppTransitionListener listener) {
511 mListeners.add(listener);
512 }
513
Wale Ogunwalea48eadb2015-05-14 17:43:12 -0700514 public void notifyAppTransitionFinishedLocked(IBinder token) {
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100515 for (int i = 0; i < mListeners.size(); i++) {
516 mListeners.get(i).onAppTransitionFinishedLocked(token);
517 }
518 }
519
520 private void notifyAppTransitionPendingLocked() {
521 for (int i = 0; i < mListeners.size(); i++) {
522 mListeners.get(i).onAppTransitionPendingLocked();
523 }
524 }
525
Jorim Jaggife762342016-10-13 14:33:27 +0200526 private void notifyAppTransitionCancelledLocked(int transit) {
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100527 for (int i = 0; i < mListeners.size(); i++) {
Jorim Jaggife762342016-10-13 14:33:27 +0200528 mListeners.get(i).onAppTransitionCancelledLocked(transit);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100529 }
530 }
531
Jorim Jaggife762342016-10-13 14:33:27 +0200532 private int notifyAppTransitionStartingLocked(int transit, IBinder openToken,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200533 IBinder closeToken, long duration, long statusBarAnimationStartTime,
534 long statusBarAnimationDuration) {
Jorim Jaggife762342016-10-13 14:33:27 +0200535 int redoLayout = 0;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100536 for (int i = 0; i < mListeners.size(); i++) {
Jorim Jaggife762342016-10-13 14:33:27 +0200537 redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, openToken,
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200538 closeToken, duration, statusBarAnimationStartTime, statusBarAnimationDuration);
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100539 }
Jorim Jaggife762342016-10-13 14:33:27 +0200540 return redoLayout;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800541 }
542
Craig Mautner164d4bb2012-11-26 13:51:23 -0800543 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
544 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
545 + (lp != null ? lp.packageName : null)
546 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
547 if (lp != null && lp.windowAnimations != 0) {
548 // If this is a system resource, don't try to load it from the
549 // application resources. It is nice to avoid loading application
550 // resources if we can.
551 String packageName = lp.packageName != null ? lp.packageName : "android";
552 int resId = lp.windowAnimations;
553 if ((resId&0xFF000000) == 0x01000000) {
554 packageName = "android";
555 }
556 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
557 + packageName);
558 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700559 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800560 }
561 return null;
562 }
563
564 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
565 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
566 + packageName + " resId=0x" + Integer.toHexString(resId));
567 if (packageName != null) {
568 if ((resId&0xFF000000) == 0x01000000) {
569 packageName = "android";
570 }
571 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
572 + packageName);
573 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700574 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800575 }
576 return null;
577 }
578
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700579 Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800580 int anim = 0;
581 Context context = mContext;
582 if (animAttr >= 0) {
583 AttributeCache.Entry ent = getCachedAnimations(lp);
584 if (ent != null) {
585 context = ent.context;
586 anim = ent.array.getResourceId(animAttr, 0);
587 }
588 }
589 if (anim != 0) {
590 return AnimationUtils.loadAnimation(context, anim);
591 }
592 return null;
593 }
594
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700595 Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) {
596 Context context = mContext;
597 if (resId >= 0) {
598 AttributeCache.Entry ent = getCachedAnimations(lp);
599 if (ent != null) {
600 context = ent.context;
601 }
602 return AnimationUtils.loadAnimation(context, resId);
603 }
604 return null;
605 }
606
607 private Animation loadAnimationRes(String packageName, int resId) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800608 int anim = 0;
609 Context context = mContext;
610 if (resId >= 0) {
611 AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
612 if (ent != null) {
613 context = ent.context;
614 anim = resId;
615 }
616 }
617 if (anim != 0) {
618 return AnimationUtils.loadAnimation(context, anim);
619 }
620 return null;
621 }
622
Craig Mautner164d4bb2012-11-26 13:51:23 -0800623 /**
624 * Compute the pivot point for an animation that is scaling from a small
625 * rect on screen to a larger rect. The pivot point varies depending on
626 * the distance between the inner and outer edges on both sides. This
627 * function computes the pivot point for one dimension.
628 * @param startPos Offset from left/top edge of outer rectangle to
629 * left/top edge of inner rectangle.
630 * @param finalScale The scaling factor between the size of the outer
631 * and inner rectangles.
632 */
633 private static float computePivot(int startPos, float finalScale) {
Jorim Jaggic6c89a82016-01-28 17:48:21 -0800634
635 /*
636 Theorem of intercepting lines:
637
638 + + +-----------------------------------------------+
639 | | | |
640 | | | |
641 | | | |
642 | | | |
643 x | y | | |
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 | | |
670 | | |
671 | | |
672 | | |
673 | | |
674 | +-----------------------------------------------+
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 + ++
685 p ++
686
687 scale = (x - y) / x
688 <=> x = -y / (scale - 1)
689 */
Craig Mautner164d4bb2012-11-26 13:51:23 -0800690 final float denom = finalScale-1;
691 if (Math.abs(denom) < .0001f) {
692 return startPos;
693 }
694 return -startPos / denom;
695 }
696
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700697 private Animation createScaleUpAnimationLocked(int transit, boolean enter,
698 Rect containingFrame) {
699 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700700 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700701 final int appWidth = containingFrame.width();
702 final int appHeight = containingFrame.height();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800703 if (enter) {
704 // Entering app zooms out from the center of the initial rect.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700705 float scaleW = mTmpRect.width() / (float) appWidth;
706 float scaleH = mTmpRect.height() / (float) appHeight;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800707 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700708 computePivot(mTmpRect.left, scaleW),
Winson4c3fecd2016-07-13 12:29:48 -0700709 computePivot(mTmpRect.top, scaleH));
Craig Mautner321bdf52012-12-18 09:53:24 -0800710 scale.setInterpolator(mDecelerateInterpolator);
711
Craig Mautner164d4bb2012-11-26 13:51:23 -0800712 Animation alpha = new AlphaAnimation(0, 1);
Winson Chunga4ccb862014-08-22 15:26:27 -0700713 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
Craig Mautner321bdf52012-12-18 09:53:24 -0800714
715 AnimationSet set = new AnimationSet(false);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800716 set.addAnimation(scale);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800717 set.addAnimation(alpha);
718 set.setDetachWallpaper(true);
719 a = set;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800720 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
721 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800722 // If we are on top of the wallpaper, we need an animation that
723 // correctly handles the wallpaper staying static behind all of
724 // the animated elements. To do this, will just have the existing
725 // element fade out.
726 a = new AlphaAnimation(1, 0);
727 a.setDetachWallpaper(true);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800728 } else {
Craig Mautner321bdf52012-12-18 09:53:24 -0800729 // For normal animations, the exiting element just holds in place.
730 a = new AlphaAnimation(1, 1);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800731 }
Craig Mautner321bdf52012-12-18 09:53:24 -0800732
733 // Pick the desired duration. If this is an inter-activity transition,
734 // it is the standard duration for that. Otherwise we use the longer
735 // task transition duration.
736 final long duration;
737 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800738 case TRANSIT_ACTIVITY_OPEN:
739 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800740 duration = mConfigShortAnimTime;
741 break;
742 default:
743 duration = DEFAULT_APP_TRANSITION_DURATION;
744 break;
745 }
746 a.setDuration(duration);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800747 a.setFillAfter(true);
Craig Mautner321bdf52012-12-18 09:53:24 -0800748 a.setInterpolator(mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800749 a.initialize(appWidth, appHeight, appWidth, appHeight);
750 return a;
751 }
752
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700753 private void getDefaultNextAppTransitionStartRect(Rect rect) {
754 if (mDefaultNextAppTransitionAnimationSpec == null ||
755 mDefaultNextAppTransitionAnimationSpec.rect == null) {
Jorim Jaggi2550f3f2017-03-14 20:15:59 +0100756 Slog.e(TAG, "Starting rect for app requested, but none available", new Throwable());
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700757 rect.setEmpty();
758 } else {
759 rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
760 }
761 }
762
763 void getNextAppTransitionStartRect(int taskId, Rect rect) {
764 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800765 if (spec == null) {
766 spec = mDefaultNextAppTransitionAnimationSpec;
767 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700768 if (spec == null || spec.rect == null) {
Jorim Jaggi2550f3f2017-03-14 20:15:59 +0100769 Slog.e(TAG, "Starting rect for task: " + taskId + " requested, but not available",
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700770 new Throwable());
771 rect.setEmpty();
772 } else {
773 rect.set(spec.rect);
774 }
775 }
776
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800777 private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height,
Winson Chungaa7fa012017-05-24 15:50:06 -0700778 GraphicBuffer buffer) {
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700779 mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
Winson Chungaa7fa012017-05-24 15:50:06 -0700780 buffer, new Rect(left, top, left + width, top + height));
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700781 }
782
Jorim Jaggif97ed922016-02-18 18:57:07 -0800783 /**
784 * @return the duration of the last clip reveal animation
785 */
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800786 long getLastClipRevealTransitionDuration() {
787 return mLastClipRevealTransitionDuration;
788 }
789
790 /**
Jorim Jaggif97ed922016-02-18 18:57:07 -0800791 * @return the maximum distance the app surface is traveling of the last clip reveal animation
792 */
793 int getLastClipRevealMaxTranslation() {
794 return mLastClipRevealMaxTranslation;
795 }
796
797 /**
798 * @return true if in the last app transition had a clip reveal animation, false otherwise
799 */
800 boolean hadClipRevealAnimation() {
801 return mLastHadClipReveal;
802 }
803
804 /**
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800805 * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
806 * the start rect is outside of the target rect, and there is a lot of movement going on.
807 *
808 * @param cutOff whether the start rect was not fully contained by the end rect
809 * @param translationX the total translation the surface moves in x direction
810 * @param translationY the total translation the surfaces moves in y direction
811 * @param displayFrame our display frame
812 *
813 * @return the duration of the clip reveal animation, in milliseconds
814 */
815 private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX,
816 float translationY, Rect displayFrame) {
817 if (!cutOff) {
818 return DEFAULT_APP_TRANSITION_DURATION;
819 }
820 final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(),
821 Math.abs(translationY) / displayFrame.height());
822 return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction *
823 (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION));
824 }
825
826 private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame,
827 Rect displayFrame) {
Chet Haase10e23ab2015-02-11 15:08:38 -0800828 final Animation anim;
829 if (enter) {
Craig Mautner80b1f642015-04-22 10:59:09 -0700830 final int appWidth = appFrame.width();
831 final int appHeight = appFrame.height();
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800832
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700833 // mTmpRect will contain an area around the launcher icon that was pressed. We will
Filip Gruszczynski82861362015-10-16 14:21:09 -0700834 // clip reveal from that area in the final area of the app.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700835 getDefaultNextAppTransitionStartRect(mTmpRect);
Craig Mautner80b1f642015-04-22 10:59:09 -0700836
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700837 float t = 0f;
838 if (appHeight > 0) {
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800839 t = (float) mTmpRect.top / displayFrame.height();
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700840 }
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800841 int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t);
842 int translationX = 0;
843 int translationYCorrection = translationY;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700844 int centerX = mTmpRect.centerX();
845 int centerY = mTmpRect.centerY();
846 int halfWidth = mTmpRect.width() / 2;
847 int halfHeight = mTmpRect.height() / 2;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800848 int clipStartX = centerX - halfWidth - appFrame.left;
849 int clipStartY = centerY - halfHeight - appFrame.top;
850 boolean cutOff = false;
851
852 // If the starting rectangle is fully or partially outside of the target rectangle, we
853 // need to start the clipping at the edge and then achieve the rest with translation
854 // and extending the clip rect from that edge.
855 if (appFrame.top > centerY - halfHeight) {
856 translationY = (centerY - halfHeight) - appFrame.top;
857 translationYCorrection = 0;
858 clipStartY = 0;
859 cutOff = true;
860 }
861 if (appFrame.left > centerX - halfWidth) {
862 translationX = (centerX - halfWidth) - appFrame.left;
863 clipStartX = 0;
864 cutOff = true;
865 }
866 if (appFrame.right < centerX + halfWidth) {
867 translationX = (centerX + halfWidth) - appFrame.right;
868 clipStartX = appWidth - mTmpRect.width();
869 cutOff = true;
870 }
871 final long duration = calculateClipRevealTransitionDuration(cutOff, translationX,
872 translationY, displayFrame);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700873
874 // Clip third of the from size of launch icon, expand to full width/height
Chet Haase10e23ab2015-02-11 15:08:38 -0800875 Animation clipAnimLR = new ClipRectLRAnimation(
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800876 clipStartX, clipStartX + mTmpRect.width(), 0, appWidth);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700877 clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800878 clipAnimLR.setDuration((long) (duration / 2.5f));
Filip Gruszczynski82861362015-10-16 14:21:09 -0700879
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800880 TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0);
881 translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR
882 : mLinearOutSlowInInterpolator);
883 translate.setDuration(duration);
Chet Haase10e23ab2015-02-11 15:08:38 -0800884
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800885 Animation clipAnimTB = new ClipRectTBAnimation(
886 clipStartY, clipStartY + mTmpRect.height(),
887 0, appHeight,
888 translationYCorrection, 0,
889 mLinearOutSlowInInterpolator);
890 clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
891 clipAnimTB.setDuration(duration);
Chet Haase10e23ab2015-02-11 15:08:38 -0800892
893 // Quick fade-in from icon to app window
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800894 final long alphaDuration = duration / 4;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700895 AlphaAnimation alpha = new AlphaAnimation(0.5f, 1);
Chet Haase10e23ab2015-02-11 15:08:38 -0800896 alpha.setDuration(alphaDuration);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700897 alpha.setInterpolator(mLinearOutSlowInInterpolator);
Chet Haase10e23ab2015-02-11 15:08:38 -0800898
899 AnimationSet set = new AnimationSet(false);
900 set.addAnimation(clipAnimLR);
901 set.addAnimation(clipAnimTB);
Filip Gruszczynski82861362015-10-16 14:21:09 -0700902 set.addAnimation(translate);
Chet Haase10e23ab2015-02-11 15:08:38 -0800903 set.addAnimation(alpha);
Filip Gruszczynski9e2cf5b2015-07-31 12:20:40 -0700904 set.setZAdjustment(Animation.ZORDER_TOP);
Chet Haase10e23ab2015-02-11 15:08:38 -0800905 set.initialize(appWidth, appHeight, appWidth, appHeight);
906 anim = set;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800907 mLastHadClipReveal = true;
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -0800908 mLastClipRevealTransitionDuration = duration;
Jorim Jaggif97ed922016-02-18 18:57:07 -0800909
910 // If the start rect was full inside the target rect (cutOff == false), we don't need
911 // to store the translation, because it's only used if cutOff == true.
912 mLastClipRevealMaxTranslation = cutOff
913 ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0;
Chet Haase10e23ab2015-02-11 15:08:38 -0800914 } else {
915 final long duration;
916 switch (transit) {
917 case TRANSIT_ACTIVITY_OPEN:
918 case TRANSIT_ACTIVITY_CLOSE:
919 duration = mConfigShortAnimTime;
920 break;
921 default:
922 duration = DEFAULT_APP_TRANSITION_DURATION;
923 break;
924 }
925 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
926 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
927 // If we are on top of the wallpaper, we need an animation that
928 // correctly handles the wallpaper staying static behind all of
929 // the animated elements. To do this, will just have the existing
930 // element fade out.
931 anim = new AlphaAnimation(1, 0);
932 anim.setDetachWallpaper(true);
933 } else {
934 // For normal animations, the exiting element just holds in place.
935 anim = new AlphaAnimation(1, 1);
936 }
937 anim.setInterpolator(mDecelerateInterpolator);
938 anim.setDuration(duration);
939 anim.setFillAfter(true);
940 }
941 return anim;
942 }
943
Winson Chung399f6202014-03-19 10:47:20 -0700944 /**
945 * Prepares the specified animation with a standard duration, interpolator, etc.
946 */
Winson Chung5393dff2014-05-08 14:25:43 -0700947 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
Jorim Jaggi787e9dd2016-03-15 10:52:40 +0100948 long duration, Interpolator interpolator) {
Winson Chunga4ccb862014-08-22 15:26:27 -0700949 if (duration > 0) {
950 a.setDuration(duration);
951 }
Winson Chung5393dff2014-05-08 14:25:43 -0700952 a.setFillAfter(true);
Jorim Jaggic69bd222016-03-15 14:38:37 +0100953 if (interpolator != null) {
954 a.setInterpolator(interpolator);
955 }
Winson Chung5393dff2014-05-08 14:25:43 -0700956 a.initialize(appWidth, appHeight, appWidth, appHeight);
957 return a;
958 }
959
960 /**
961 * Prepares the specified animation with a standard duration, interpolator, etc.
962 */
Winson Chung399f6202014-03-19 10:47:20 -0700963 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800964 // Pick the desired duration. If this is an inter-activity transition,
965 // it is the standard duration for that. Otherwise we use the longer
966 // task transition duration.
Winson Chung5393dff2014-05-08 14:25:43 -0700967 final int duration;
Craig Mautner321bdf52012-12-18 09:53:24 -0800968 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800969 case TRANSIT_ACTIVITY_OPEN:
970 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800971 duration = mConfigShortAnimTime;
972 break;
973 default:
974 duration = DEFAULT_APP_TRANSITION_DURATION;
975 break;
976 }
Winson Chung5393dff2014-05-08 14:25:43 -0700977 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
978 mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800979 }
980
Winson Chung399f6202014-03-19 10:47:20 -0700981 /**
982 * Return the current thumbnail transition state.
983 */
984 int getThumbnailTransitionState(boolean enter) {
985 if (enter) {
986 if (mNextAppTransitionScaleUp) {
987 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
988 } else {
989 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
990 }
991 } else {
992 if (mNextAppTransitionScaleUp) {
993 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
994 } else {
995 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
996 }
997 }
998 }
999
1000 /**
Tony Mak64b8d562017-12-28 17:44:02 +00001001 * Creates an overlay with a background color and a thumbnail for the cross profile apps
1002 * animation.
1003 */
1004 GraphicBuffer createCrossProfileAppsThumbnail(
1005 @DrawableRes int thumbnailDrawableRes, Rect frame) {
1006 final int width = frame.width();
1007 final int height = frame.height();
1008
1009 final RenderNode node = RenderNode.create("CrossProfileAppsThumbnail", null);
1010 node.setLeftTopRightBottom(0, 0, width, height);
1011 node.setClipToBounds(false);
1012
1013 final DisplayListCanvas canvas = node.start(width, height);
1014 canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
1015 final int thumbnailSize = mService.mContext.getResources().getDimensionPixelSize(
1016 com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
1017 final Drawable drawable = mService.mContext.getDrawable(thumbnailDrawableRes);
1018 drawable.setBounds(
1019 (width - thumbnailSize) / 2,
1020 (height - thumbnailSize) / 2,
1021 (width + thumbnailSize) / 2,
1022 (height + thumbnailSize) / 2);
1023 drawable.draw(canvas);
1024 node.end(canvas);
1025
1026 return ThreadedRenderer.createHardwareBitmap(node, width, height)
1027 .createGraphicBufferHandle();
1028 }
1029
1030 Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
1031 final Animation animation = loadAnimationRes(
1032 "android", com.android.internal.R.anim.cross_profile_apps_thumbnail_enter);
1033 return prepareThumbnailAnimationWithDuration(animation, appRect.width(),
1034 appRect.height(), 0, null);
1035 }
1036
1037 /**
Winson Chung399f6202014-03-19 10:47:20 -07001038 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001039 * when a thumbnail is specified with the pending animation override.
Winson Chung399f6202014-03-19 10:47:20 -07001040 */
Jorim Jaggide63d442016-03-14 14:56:56 +01001041 Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
Winson Chungaa7fa012017-05-24 15:50:06 -07001042 GraphicBuffer thumbnailHeader, final int taskId, int uiMode, int orientation) {
Winson Chung399f6202014-03-19 10:47:20 -07001043 Animation a;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001044 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chung399f6202014-03-19 10:47:20 -07001045 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001046 final int thumbHeightI = thumbnailHeader.getHeight();
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001047 final int appWidth = appRect.width();
Winson Chung399f6202014-03-19 10:47:20 -07001048
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001049 float scaleW = appWidth / thumbWidth;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001050 getNextAppTransitionStartRect(taskId, mTmpRect);
Jorim Jaggi09072002016-03-25 16:48:42 -07001051 final float fromX;
Manu Cornet57b61492017-01-24 18:19:05 +09001052 float fromY;
Jorim Jaggi09072002016-03-25 16:48:42 -07001053 final float toX;
Manu Cornet57b61492017-01-24 18:19:05 +09001054 float toY;
Jorim Jaggi09072002016-03-25 16:48:42 -07001055 final float pivotX;
1056 final float pivotY;
Manu Cornetd7376802017-01-13 13:44:07 -08001057 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
Jorim Jaggi09072002016-03-25 16:48:42 -07001058 fromX = mTmpRect.left;
1059 fromY = mTmpRect.top;
1060
1061 // For the curved translate animation to work, the pivot points needs to be at the
1062 // same absolute position as the one from the real surface.
1063 toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left;
1064 toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top;
1065 pivotX = mTmpRect.width() / 2;
1066 pivotY = appRect.height() / 2 / scaleW;
Manu Cornet57b61492017-01-24 18:19:05 +09001067 if (mGridLayoutRecentsEnabled) {
1068 // In the grid layout, the header is displayed above the thumbnail instead of
1069 // overlapping it.
1070 fromY -= thumbHeightI;
1071 toY -= thumbHeightI * scaleW;
1072 }
Jorim Jaggi09072002016-03-25 16:48:42 -07001073 } else {
1074 pivotX = 0;
1075 pivotY = 0;
1076 fromX = mTmpRect.left;
1077 fromY = mTmpRect.top;
1078 toX = appRect.left;
1079 toY = appRect.top;
1080 }
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001081 final long duration = getAspectScaleDuration();
1082 final Interpolator interpolator = getAspectScaleInterpolator();
Winson Chung399f6202014-03-19 10:47:20 -07001083 if (mNextAppTransitionScaleUp) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001084 // Animation up from the thumbnail to the full screen
Jorim Jaggi8448f332016-03-14 17:50:37 +01001085 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001086 scale.setInterpolator(interpolator);
1087 scale.setDuration(duration);
Jorim Jaggic6c89a82016-01-28 17:48:21 -08001088 Animation alpha = new AlphaAnimation(1f, 0f);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001089 alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1090 ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator);
1091 alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
1092 ? duration / 2
1093 : duration);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001094 Animation translate = createCurvedMotion(fromX, toX, fromY, toY);
1095 translate.setInterpolator(interpolator);
1096 translate.setDuration(duration);
Winson Chung399f6202014-03-19 10:47:20 -07001097
Jorim Jaggide63d442016-03-14 14:56:56 +01001098 mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI);
1099 mTmpToClipRect.set(appRect);
1100
1101 // Containing frame is in screen space, but we need the clip rect in the
1102 // app space.
1103 mTmpToClipRect.offsetTo(0, 0);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001104 mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW);
1105 mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW);
Jorim Jaggide63d442016-03-14 14:56:56 +01001106
1107 if (contentInsets != null) {
Jorim Jaggi8448f332016-03-14 17:50:37 +01001108 mTmpToClipRect.inset((int) (-contentInsets.left * scaleW),
1109 (int) (-contentInsets.top * scaleW),
1110 (int) (-contentInsets.right * scaleW),
1111 (int) (-contentInsets.bottom * scaleW));
Jorim Jaggide63d442016-03-14 14:56:56 +01001112 }
1113
1114 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001115 clipAnim.setInterpolator(interpolator);
1116 clipAnim.setDuration(duration);
Jorim Jaggide63d442016-03-14 14:56:56 +01001117
Winson Chung399f6202014-03-19 10:47:20 -07001118 // This AnimationSet uses the Interpolators assigned above.
1119 AnimationSet set = new AnimationSet(false);
1120 set.addAnimation(scale);
Manu Cornet57b61492017-01-24 18:19:05 +09001121 if (!mGridLayoutRecentsEnabled) {
1122 // In the grid layout, the header should be shown for the whole animation.
1123 set.addAnimation(alpha);
1124 }
Winson Chunga4ccb862014-08-22 15:26:27 -07001125 set.addAnimation(translate);
Jorim Jaggide63d442016-03-14 14:56:56 +01001126 set.addAnimation(clipAnim);
Winson Chung399f6202014-03-19 10:47:20 -07001127 a = set;
1128 } else {
Winson Chunga4ccb862014-08-22 15:26:27 -07001129 // Animation down from the full screen to the thumbnail
Jorim Jaggi8448f332016-03-14 17:50:37 +01001130 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001131 scale.setInterpolator(interpolator);
1132 scale.setDuration(duration);
Winson Chunga4ccb862014-08-22 15:26:27 -07001133 Animation alpha = new AlphaAnimation(0f, 1f);
1134 alpha.setInterpolator(mThumbnailFadeInInterpolator);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001135 alpha.setDuration(duration);
1136 Animation translate = createCurvedMotion(toX, fromX, toY, fromY);
1137 translate.setInterpolator(interpolator);
1138 translate.setDuration(duration);
Winson Chung399f6202014-03-19 10:47:20 -07001139
Winson Chunga4ccb862014-08-22 15:26:27 -07001140 // This AnimationSet uses the Interpolators assigned above.
1141 AnimationSet set = new AnimationSet(false);
1142 set.addAnimation(scale);
Manu Cornet57b61492017-01-24 18:19:05 +09001143 if (!mGridLayoutRecentsEnabled) {
1144 // In the grid layout, the header should be shown for the whole animation.
1145 set.addAnimation(alpha);
1146 }
Winson Chunga4ccb862014-08-22 15:26:27 -07001147 set.addAnimation(translate);
1148 a = set;
1149
1150 }
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -07001151 return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
Jorim Jaggic69bd222016-03-15 14:38:37 +01001152 null);
Winson Chung399f6202014-03-19 10:47:20 -07001153 }
1154
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001155 private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) {
1156
1157 // Almost no x-change - use linear animation
Jorim Jaggic69bd222016-03-15 14:38:37 +01001158 if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) {
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001159 return new TranslateAnimation(fromX, toX, fromY, toY);
1160 } else {
1161 final Path path = createCurvedPath(fromX, toX, fromY, toY);
1162 return new CurvedTranslateAnimation(path);
1163 }
1164 }
1165
1166 private Path createCurvedPath(float fromX, float toX, float fromY, float toY) {
1167 final Path path = new Path();
1168 path.moveTo(fromX, fromY);
Jorim Jaggi1f458fb2016-03-25 17:36:37 -07001169
1170 if (fromY > toY) {
1171 // If the object needs to go up, move it in horizontal direction first, then vertical.
1172 path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY);
1173 } else {
1174 // If the object needs to go down, move it in vertical direction first, then horizontal.
1175 path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY);
1176 }
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001177 return path;
1178 }
1179
1180 private long getAspectScaleDuration() {
1181 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
Jorim Jaggic69bd222016-03-15 14:38:37 +01001182 return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f);
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001183 } else {
1184 return THUMBNAIL_APP_TRANSITION_DURATION;
1185 }
1186 }
1187
1188 private Interpolator getAspectScaleInterpolator() {
1189 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
1190 return mFastOutSlowInInterpolator;
1191 } else {
1192 return TOUCH_RESPONSE_INTERPOLATOR;
1193 }
1194 }
1195
Winson Chung399f6202014-03-19 10:47:20 -07001196 /**
1197 * This alternate animation is created when we are doing a thumbnail transition, for the
1198 * activity that is leaving, and the activity that is entering.
1199 */
Winson Chunga4ccb862014-08-22 15:26:27 -07001200 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
Winsonb2024762016-04-05 17:32:30 -07001201 int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets,
Matthew Ng43db6d22017-06-27 15:29:39 -07001202 @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean freeform,
1203 int taskId) {
Winson Chung399f6202014-03-19 10:47:20 -07001204 Animation a;
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001205 final int appWidth = containingFrame.width();
1206 final int appHeight = containingFrame.height();
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001207 getDefaultNextAppTransitionStartRect(mTmpRect);
1208 final int thumbWidthI = mTmpRect.width();
Winson Chung399f6202014-03-19 10:47:20 -07001209 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001210 final int thumbHeightI = mTmpRect.height();
Winson Chung399f6202014-03-19 10:47:20 -07001211 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
Winsoncbb625b2016-07-06 15:24:15 -07001212 final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left;
Winson21700932016-03-24 17:26:23 -07001213 final int thumbStartY = mTmpRect.top - containingFrame.top;
Winson Chung399f6202014-03-19 10:47:20 -07001214
1215 switch (thumbTransitState) {
Jorim Jaggi8448f332016-03-14 17:50:37 +01001216 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
1217 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1218 final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
1219 if (freeform && scaleUp) {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001220 a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001221 containingFrame, surfaceInsets, taskId);
Jorim Jaggi8448f332016-03-14 17:50:37 +01001222 } else if (freeform) {
1223 a = createAspectScaledThumbnailExitFreeformAnimationLocked(
1224 containingFrame, surfaceInsets, taskId);
Winson Chung2820c452014-04-15 15:34:44 -07001225 } else {
Winson21700932016-03-24 17:26:23 -07001226 AnimationSet set = new AnimationSet(true);
1227
1228 // In portrait, we scale to fit the width
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -07001229 mTmpFromClipRect.set(containingFrame);
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -07001230 mTmpToClipRect.set(containingFrame);
Jorim Jaggic6c89a82016-01-28 17:48:21 -08001231
1232 // Containing frame is in screen space, but we need the clip rect in the
1233 // app space.
1234 mTmpFromClipRect.offsetTo(0, 0);
1235 mTmpToClipRect.offsetTo(0, 0);
1236
1237 // Exclude insets region from the source clip.
1238 mTmpFromClipRect.inset(contentInsets);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001239 mNextAppTransitionInsets.set(contentInsets);
1240
Manu Cornetd7376802017-01-13 13:44:07 -08001241 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) {
Jorim Jaggic69bd222016-03-15 14:38:37 +01001242 // We scale the width and clip to the top/left square
1243 float scale = thumbWidth /
1244 (appWidth - contentInsets.left - contentInsets.right);
Manu Cornetb68b7652017-01-23 19:37:53 +09001245 if (!mGridLayoutRecentsEnabled) {
1246 int unscaledThumbHeight = (int) (thumbHeight / scale);
1247 mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
1248 }
Jorim Jaggic69bd222016-03-15 14:38:37 +01001249
1250 mNextAppTransitionInsets.set(contentInsets);
1251
Jorim Jaggi8448f332016-03-14 17:50:37 +01001252 Animation scaleAnim = new ScaleAnimation(
1253 scaleUp ? scale : 1, scaleUp ? 1 : scale,
1254 scaleUp ? scale : 1, scaleUp ? 1 : scale,
Jorim Jaggic69bd222016-03-15 14:38:37 +01001255 containingFrame.width() / 2f,
1256 containingFrame.height() / 2f + contentInsets.top);
Jorim Jaggi8448f332016-03-14 17:50:37 +01001257 final float targetX = (mTmpRect.left - containingFrame.left);
Jorim Jaggic69bd222016-03-15 14:38:37 +01001258 final float x = containingFrame.width() / 2f
1259 - containingFrame.width() / 2f * scale;
Jorim Jaggi8448f332016-03-14 17:50:37 +01001260 final float targetY = (mTmpRect.top - containingFrame.top);
Matthew Ng43db6d22017-06-27 15:29:39 -07001261 float y = containingFrame.height() / 2f
Jorim Jaggic69bd222016-03-15 14:38:37 +01001262 - containingFrame.height() / 2f * scale;
Matthew Ng43db6d22017-06-27 15:29:39 -07001263
1264 // During transition may require clipping offset from any top stable insets
1265 // such as the statusbar height when statusbar is hidden
1266 if (mLowRamRecentsEnabled && contentInsets.top == 0 && scaleUp) {
1267 mTmpFromClipRect.top += stableInsets.top;
1268 y += stableInsets.top;
1269 }
Jorim Jaggi8448f332016-03-14 17:50:37 +01001270 final float startX = targetX - x;
1271 final float startY = targetY - y;
1272 Animation clipAnim = scaleUp
1273 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1274 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1275 Animation translateAnim = scaleUp
Jorim Jaggic69bd222016-03-15 14:38:37 +01001276 ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0)
1277 : createCurvedMotion(0, startX, 0, startY - contentInsets.top);
1278
Winson21700932016-03-24 17:26:23 -07001279 set.addAnimation(clipAnim);
1280 set.addAnimation(scaleAnim);
1281 set.addAnimation(translateAnim);
1282
1283 } else {
1284 // In landscape, we don't scale at all and only crop
1285 mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI;
1286 mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI;
1287
Jorim Jaggi8448f332016-03-14 17:50:37 +01001288 Animation clipAnim = scaleUp
1289 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)
1290 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect);
1291 Animation translateAnim = scaleUp
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001292 ? createCurvedMotion(thumbStartX, 0,
1293 thumbStartY - contentInsets.top, 0)
1294 : createCurvedMotion(0, thumbStartX, 0,
1295 thumbStartY - contentInsets.top);
Winson21700932016-03-24 17:26:23 -07001296
1297 set.addAnimation(clipAnim);
1298 set.addAnimation(translateAnim);
1299 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001300 a = set;
Winson21700932016-03-24 17:26:23 -07001301 a.setZAdjustment(Animation.ZORDER_TOP);
Winson Chung2820c452014-04-15 15:34:44 -07001302 }
Winson Chung399f6202014-03-19 10:47:20 -07001303 break;
1304 }
1305 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
Winson Chunga4ccb862014-08-22 15:26:27 -07001306 // Previous app window during the scale up
Winson Chung399f6202014-03-19 10:47:20 -07001307 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001308 // Fade out the source activity if we are animating to a wallpaper
Winson Chung399f6202014-03-19 10:47:20 -07001309 // activity.
1310 a = new AlphaAnimation(1, 0);
1311 } else {
Winson Chung399f6202014-03-19 10:47:20 -07001312 a = new AlphaAnimation(1, 1);
1313 }
1314 break;
1315 }
1316 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
Winson Chunga4ccb862014-08-22 15:26:27 -07001317 // Target app window during the scale down
1318 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1319 // Fade in the destination activity if we are animating from a wallpaper
1320 // activity.
1321 a = new AlphaAnimation(0, 1);
1322 } else {
1323 a = new AlphaAnimation(1, 1);
1324 }
Winson Chung399f6202014-03-19 10:47:20 -07001325 break;
1326 }
Winson Chung399f6202014-03-19 10:47:20 -07001327 default:
1328 throw new RuntimeException("Invalid thumbnail transition state");
1329 }
1330
Jorim Jaggi787e9dd2016-03-15 10:52:40 +01001331 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
1332 getAspectScaleDuration(), getAspectScaleInterpolator());
Winson Chung399f6202014-03-19 10:47:20 -07001333 }
1334
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001335 private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
1336 @Nullable Rect surfaceInsets, int taskId) {
1337 getNextAppTransitionStartRect(taskId, mTmpRect);
1338 return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
1339 true);
1340 }
1341
1342 private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
1343 @Nullable Rect surfaceInsets, int taskId) {
1344 getNextAppTransitionStartRect(taskId, mTmpRect);
1345 return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
1346 false);
1347 }
1348
1349 private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
1350 Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
1351 final float sourceWidth = sourceFrame.width();
1352 final float sourceHeight = sourceFrame.height();
1353 final float destWidth = destFrame.width();
1354 final float destHeight = destFrame.height();
1355 final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
1356 final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001357 AnimationSet set = new AnimationSet(true);
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001358 final int surfaceInsetsH = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001359 ? 0 : surfaceInsets.left + surfaceInsets.right;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001360 final int surfaceInsetsV = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001361 ? 0 : surfaceInsets.top + surfaceInsets.bottom;
1362 // We want the scaling to happen from the center of the surface. In order to achieve that,
1363 // we need to account for surface insets that will be used to enlarge the surface.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001364 final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
1365 final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
1366 final ScaleAnimation scale = enter ?
1367 new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
1368 : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
1369 final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
1370 final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
1371 final int destHCenter = destFrame.left + destFrame.width() / 2;
1372 final int destVCenter = destFrame.top + destFrame.height() / 2;
1373 final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
1374 final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
1375 final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
1376 : new TranslateAnimation(0, fromX, 0, fromY);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001377 set.addAnimation(scale);
1378 set.addAnimation(translation);
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001379
1380 final IRemoteCallback callback = mAnimationFinishedCallback;
1381 if (callback != null) {
1382 set.setAnimationListener(new Animation.AnimationListener() {
1383 @Override
1384 public void onAnimationStart(Animation animation) { }
1385
1386 @Override
1387 public void onAnimationEnd(Animation animation) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001388 mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001389 }
1390
1391 @Override
1392 public void onAnimationRepeat(Animation animation) { }
1393 });
1394 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -07001395 return set;
1396 }
1397
Winson Chung399f6202014-03-19 10:47:20 -07001398 /**
Winson Chunga4ccb862014-08-22 15:26:27 -07001399 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001400 * when a thumbnail is specified with the pending animation override.
Winson Chunga4ccb862014-08-22 15:26:27 -07001401 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001402 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
Winson Chungaa7fa012017-05-24 15:50:06 -07001403 GraphicBuffer thumbnailHeader) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001404 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001405 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001406 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chunga4ccb862014-08-22 15:26:27 -07001407 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001408 final int thumbHeightI = thumbnailHeader.getHeight();
Winson Chunga4ccb862014-08-22 15:26:27 -07001409 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1410
1411 if (mNextAppTransitionScaleUp) {
1412 // Animation for the thumbnail zooming from its initial size to the full screen
1413 float scaleW = appWidth / thumbWidth;
1414 float scaleH = appHeight / thumbHeight;
1415 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001416 computePivot(mTmpRect.left, 1 / scaleW),
1417 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001418 scale.setInterpolator(mDecelerateInterpolator);
1419
1420 Animation alpha = new AlphaAnimation(1, 0);
1421 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
1422
1423 // This AnimationSet uses the Interpolators assigned above.
1424 AnimationSet set = new AnimationSet(false);
1425 set.addAnimation(scale);
1426 set.addAnimation(alpha);
1427 a = set;
1428 } else {
1429 // Animation for the thumbnail zooming down from the full screen to its final size
1430 float scaleW = appWidth / thumbWidth;
1431 float scaleH = appHeight / thumbHeight;
1432 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001433 computePivot(mTmpRect.left, 1 / scaleW),
1434 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001435 }
1436
1437 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1438 }
1439
1440 /**
Winson Chung399f6202014-03-19 10:47:20 -07001441 * This animation is created when we are doing a thumbnail transition, for the activity that is
1442 * leaving, and the activity that is entering.
1443 */
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001444 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
1445 int transit, int taskId) {
1446 final int appWidth = containingFrame.width();
1447 final int appHeight = containingFrame.height();
Winson Chungaa7fa012017-05-24 15:50:06 -07001448 final GraphicBuffer thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
Winson Chung399f6202014-03-19 10:47:20 -07001449 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001450 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001451 final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
Winson Chung399f6202014-03-19 10:47:20 -07001452 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001453 final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
Winson Chung399f6202014-03-19 10:47:20 -07001454 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1455
1456 switch (thumbTransitState) {
1457 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
1458 // Entering app scales up with the thumbnail
1459 float scaleW = thumbWidth / appWidth;
1460 float scaleH = thumbHeight / appHeight;
1461 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001462 computePivot(mTmpRect.left, scaleW),
1463 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001464 break;
1465 }
1466 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
1467 // Exiting app while the thumbnail is scaling up should fade or stay in place
1468 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1469 // Fade out while bringing up selected activity. This keeps the
1470 // current activity from showing through a launching wallpaper
1471 // activity.
1472 a = new AlphaAnimation(1, 0);
1473 } else {
1474 // noop animation
1475 a = new AlphaAnimation(1, 1);
1476 }
1477 break;
1478 }
1479 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
1480 // Entering the other app, it should just be visible while we scale the thumbnail
1481 // down above it
1482 a = new AlphaAnimation(1, 1);
1483 break;
1484 }
1485 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1486 // Exiting the current app, the app should scale down with the thumbnail
1487 float scaleW = thumbWidth / appWidth;
1488 float scaleH = thumbHeight / appHeight;
1489 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001490 computePivot(mTmpRect.left, scaleW),
1491 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001492
1493 Animation alpha = new AlphaAnimation(1, 0);
1494
1495 AnimationSet set = new AnimationSet(true);
1496 set.addAnimation(scale);
1497 set.addAnimation(alpha);
1498 set.setZAdjustment(Animation.ZORDER_TOP);
1499 a = set;
1500 break;
1501 }
1502 default:
1503 throw new RuntimeException("Invalid thumbnail transition state");
1504 }
1505
1506 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1507 }
1508
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001509 private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) {
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001510 getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
1511 final int left = mTmpFromClipRect.left;
1512 final int top = mTmpFromClipRect.top;
1513 mTmpFromClipRect.offset(-left, -top);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001514 // TODO: Isn't that strange that we ignore exact position of the containingFrame?
1515 mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height());
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001516 AnimationSet set = new AnimationSet(true);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001517 float fromWidth = mTmpFromClipRect.width();
1518 float toWidth = mTmpToClipRect.width();
1519 float fromHeight = mTmpFromClipRect.height();
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001520 // While the window might span the whole display, the actual content will be cropped to the
1521 // system decoration frame, for example when the window is docked. We need to take into
1522 // account the visible height when constructing the animation.
1523 float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom;
1524 int translateAdjustment = 0;
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001525 if (fromWidth <= toWidth && fromHeight <= toHeight) {
1526 // The final window is larger in both dimensions than current window (e.g. we are
1527 // maximizing), so we can simply unclip the new window and there will be no disappearing
1528 // frame.
1529 set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
1530 } else {
1531 // The disappearing window has one larger dimension. We need to apply scaling, so the
1532 // first frame of the entry animation matches the old window.
1533 set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001534 // We might not be going exactly full screen, but instead be aligned under the status
1535 // bar using cropping. We still need to account for the cropped part, which will also
1536 // be scaled.
1537 translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001538 }
1539
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001540 // We animate the translation from the old position of the removed window, to the new
1541 // position of the added window. The latter might not be full screen, for example docked for
1542 // docked windows.
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001543 TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001544 0, top - containingFrame.top - translateAdjustment, 0);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001545 set.addAnimation(translate);
1546 set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
Filip Gruszczynskie95b0ae2015-09-30 10:55:33 -07001547 set.setZAdjustment(Animation.ZORDER_TOP);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001548 return set;
1549 }
1550
Jorim Jaggic554b772015-06-04 16:07:57 -07001551 /**
1552 * @return true if and only if the first frame of the transition can be skipped, i.e. the first
1553 * frame of the transition doesn't change the visuals on screen, so we can start
1554 * directly with the second one
1555 */
1556 boolean canSkipFirstFrame() {
1557 return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
1558 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
Jorim Jaggife762342016-10-13 14:33:27 +02001559 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
1560 && mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY;
Jorim Jaggic554b772015-06-04 16:07:57 -07001561 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08001562
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001563 RemoteAnimationController getRemoteAnimationController() {
1564 return mRemoteAnimationController;
1565 }
1566
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001567 /**
1568 *
1569 * @param frame These are the bounds of the window when it finishes the animation. This is where
1570 * the animation must usually finish in entrance animation, as the next frame will
1571 * display the window at these coordinates. In case of exit animation, this is
1572 * where the animation must start, as the frame before the animation is displaying
1573 * the window at these bounds.
1574 * @param insets Knowing where the window will be positioned is not enough. Some parts of the
1575 * window might be obscured, usually by the system windows (status bar and
1576 * navigation bar) and we use content insets to convey that information. This
1577 * usually affects the animation aspects vertically, as the system decoration is
1578 * at the top and the bottom. For example when we animate from full screen to
1579 * recents, we want to exclude the covered parts, because they won't match the
1580 * thumbnail after the last frame is executed.
1581 * @param surfaceInsets In rare situation the surface is larger than the content and we need to
1582 * know about this to make the animation frames match. We currently use
1583 * this for freeform windows, which have larger surfaces to display
1584 * shadows. When we animate them from recents, we want to match the content
1585 * to the recents thumbnail and hence need to account for the surface being
1586 * bigger.
1587 */
Winsonb2024762016-04-05 17:32:30 -07001588 Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int uiMode,
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -08001589 int orientation, Rect frame, Rect displayFrame, Rect insets,
Matthew Ng43db6d22017-06-27 15:29:39 -07001590 @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
1591 boolean freeform, int taskId) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001592 Animation a;
Jorim Jaggife762342016-10-13 14:33:27 +02001593 if (isKeyguardGoingAwayTransit(transit) && enter) {
1594 a = loadKeyguardExitAnimation(transit);
1595 } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) {
1596 a = null;
1597 } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) {
1598 a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit);
1599 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001600 || transit == TRANSIT_TASK_OPEN
1601 || transit == TRANSIT_TASK_TO_FRONT)) {
1602 a = loadAnimationRes(lp, enter
1603 ? com.android.internal.R.anim.voice_activity_open_enter
1604 : com.android.internal.R.anim.voice_activity_open_exit);
1605 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1606 "applyAnimation voice:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001607 + " anim=" + a + " transit=" + appTransitionToString(transit)
1608 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001609 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
1610 || transit == TRANSIT_TASK_CLOSE
1611 || transit == TRANSIT_TASK_TO_BACK)) {
1612 a = loadAnimationRes(lp, enter
1613 ? com.android.internal.R.anim.voice_activity_close_enter
1614 : com.android.internal.R.anim.voice_activity_close_exit);
1615 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1616 "applyAnimation voice:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001617 + " anim=" + a + " transit=" + appTransitionToString(transit)
1618 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001619 } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001620 a = createRelaunchAnimation(frame, insets);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001621 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1622 "applyAnimation:"
1623 + " anim=" + a + " nextAppTransition=" + mNextAppTransition
1624 + " transit=" + appTransitionToString(transit)
1625 + " Callers=" + Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001626 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
1627 a = loadAnimationRes(mNextAppTransitionPackage, enter ?
Craig Mautner164d4bb2012-11-26 13:51:23 -08001628 mNextAppTransitionEnter : mNextAppTransitionExit);
1629 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1630 "applyAnimation:"
1631 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001632 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001633 + " Callers=" + Debug.getCallers(3));
Winson Chung044d5292014-11-06 11:05:19 -08001634 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
1635 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
1636 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1637 "applyAnimation:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001638 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
1639 + " transit=" + appTransitionToString(transit)
1640 + " Callers=" + Debug.getCallers(3));
Chet Haase10e23ab2015-02-11 15:08:38 -08001641 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
Jorim Jaggi8fe7e0a2016-02-12 19:43:39 -08001642 a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
Chet Haase10e23ab2015-02-11 15:08:38 -08001643 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1644 "applyAnimation:"
1645 + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001646 + " transit=" + appTransitionToString(transit)
Chet Haase10e23ab2015-02-11 15:08:38 -08001647 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001648 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001649 a = createScaleUpAnimationLocked(transit, enter, frame);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001650 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1651 "applyAnimation:"
1652 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001653 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001654 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001655 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
1656 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001657 mNextAppTransitionScaleUp =
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001658 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
Winson Chunga4ccb862014-08-22 15:26:27 -07001659 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001660 frame, transit, taskId);
Winson Chunga4ccb862014-08-22 15:26:27 -07001661 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1662 String animName = mNextAppTransitionScaleUp ?
1663 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
1664 Slog.v(TAG, "applyAnimation:"
1665 + " anim=" + a + " nextAppTransition=" + animName
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001666 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Winson Chunga4ccb862014-08-22 15:26:27 -07001667 + " Callers=" + Debug.getCallers(3));
1668 }
1669 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
1670 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
1671 mNextAppTransitionScaleUp =
1672 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
1673 a = createAspectScaledThumbnailEnterExitAnimationLocked(
Winsonb2024762016-04-05 17:32:30 -07001674 getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
Matthew Ng43db6d22017-06-27 15:29:39 -07001675 insets, surfaceInsets, stableInsets, freeform, taskId);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001676 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1677 String animName = mNextAppTransitionScaleUp ?
Winson Chunga4ccb862014-08-22 15:26:27 -07001678 "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
Craig Mautner164d4bb2012-11-26 13:51:23 -08001679 Slog.v(TAG, "applyAnimation:"
1680 + " anim=" + a + " nextAppTransition=" + animName
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001681 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001682 + " Callers=" + Debug.getCallers(3));
1683 }
Tony Mak089c35e2017-12-18 20:34:14 +00001684 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS
1685 && (transit == TRANSIT_ACTIVITY_OPEN
1686 || transit == TRANSIT_TASK_OPEN
1687 || transit == TRANSIT_TASK_TO_FRONT)) {
Tony Mak64b8d562017-12-28 17:44:02 +00001688
Tony Mak089c35e2017-12-18 20:34:14 +00001689 a = loadAnimationRes("android", enter
Tony Mak64b8d562017-12-28 17:44:02 +00001690 ? com.android.internal.R.anim.task_open_enter_cross_profile_apps
1691 : com.android.internal.R.anim.task_open_exit);
Tony Mak089c35e2017-12-18 20:34:14 +00001692 Slog.v(TAG,
1693 "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:"
1694 + " anim=" + a + " transit=" + appTransitionToString(transit)
1695 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001696 } else {
1697 int animAttr = 0;
1698 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -08001699 case TRANSIT_ACTIVITY_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001700 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001701 ? WindowAnimation_activityOpenEnterAnimation
1702 : WindowAnimation_activityOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001703 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001704 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001705 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001706 ? WindowAnimation_activityCloseEnterAnimation
1707 : WindowAnimation_activityCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001708 break;
Jorim Jaggi192086e2016-03-11 17:17:03 +01001709 case TRANSIT_DOCK_TASK_FROM_RECENTS:
Craig Mautner4b71aa12012-12-27 17:20:01 -08001710 case TRANSIT_TASK_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001711 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001712 ? WindowAnimation_taskOpenEnterAnimation
1713 : WindowAnimation_taskOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001714 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001715 case TRANSIT_TASK_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001716 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001717 ? WindowAnimation_taskCloseEnterAnimation
1718 : WindowAnimation_taskCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001719 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001720 case TRANSIT_TASK_TO_FRONT:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001721 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001722 ? WindowAnimation_taskToFrontEnterAnimation
1723 : WindowAnimation_taskToFrontExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001724 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001725 case TRANSIT_TASK_TO_BACK:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001726 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001727 ? WindowAnimation_taskToBackEnterAnimation
1728 : WindowAnimation_taskToBackExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001729 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001730 case TRANSIT_WALLPAPER_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001731 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001732 ? WindowAnimation_wallpaperOpenEnterAnimation
1733 : WindowAnimation_wallpaperOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001734 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001735 case TRANSIT_WALLPAPER_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001736 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001737 ? WindowAnimation_wallpaperCloseEnterAnimation
1738 : WindowAnimation_wallpaperCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001739 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001740 case TRANSIT_WALLPAPER_INTRA_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001741 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001742 ? WindowAnimation_wallpaperIntraOpenEnterAnimation
1743 : WindowAnimation_wallpaperIntraOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001744 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001745 case TRANSIT_WALLPAPER_INTRA_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001746 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001747 ? WindowAnimation_wallpaperIntraCloseEnterAnimation
1748 : WindowAnimation_wallpaperIntraCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001749 break;
Craig Mautnerbb742462014-07-07 15:28:55 -07001750 case TRANSIT_TASK_OPEN_BEHIND:
1751 animAttr = enter
1752 ? WindowAnimation_launchTaskBehindSourceAnimation
Craig Mautner3b2cd1d2014-08-25 14:25:54 -07001753 : WindowAnimation_launchTaskBehindTargetAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001754 }
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001755 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001756 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1757 "applyAnimation:"
1758 + " anim=" + a
1759 + " animAttr=0x" + Integer.toHexString(animAttr)
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001760 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001761 + " Callers=" + Debug.getCallers(3));
1762 }
1763 return a;
1764 }
1765
Jorim Jaggife762342016-10-13 14:33:27 +02001766 private Animation loadKeyguardExitAnimation(int transit) {
1767 if ((mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) != 0) {
1768 return null;
1769 }
1770 final boolean toShade =
1771 (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0;
1772 return mService.mPolicy.createHiddenByKeyguardExit(
1773 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade);
1774 }
1775
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001776 int getAppStackClipMode() {
Matthew Ngbf1d9852017-03-14 12:23:09 -07001777 // When dismiss keyguard animation occurs, clip before the animation to prevent docked
1778 // app from showing beyond the divider
1779 if (mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY
1780 || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
1781 return STACK_CLIP_BEFORE_ANIM;
1782 }
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001783 return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
Jorim Jaggic69bd222016-03-15 14:38:37 +01001784 || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS
Jorim Jaggi1f458fb2016-03-25 17:36:37 -07001785 || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
Jorim Jaggi6a7c90a2016-03-11 15:04:59 +01001786 ? STACK_CLIP_NONE
1787 : STACK_CLIP_AFTER_ANIM;
1788 }
1789
Jorim Jaggife762342016-10-13 14:33:27 +02001790 public int getTransitFlags() {
1791 return mNextAppTransitionFlags;
1792 }
1793
Craig Mautner164d4bb2012-11-26 13:51:23 -08001794 void postAnimationCallback() {
1795 if (mNextAppTransitionCallback != null) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001796 mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
1797 mNextAppTransitionCallback));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001798 mNextAppTransitionCallback = null;
1799 }
1800 }
1801
1802 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001803 IRemoteCallback startedCallback) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001804 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001805 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001806 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001807 mNextAppTransitionPackage = packageName;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001808 mNextAppTransitionEnter = enterAnim;
1809 mNextAppTransitionExit = exitAnim;
1810 postAnimationCallback();
1811 mNextAppTransitionCallback = startedCallback;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001812 }
1813 }
1814
1815 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001816 int startHeight) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001817 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001818 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001819 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
Winson4c3fecd2016-07-13 12:29:48 -07001820 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001821 postAnimationCallback();
Craig Mautner164d4bb2012-11-26 13:51:23 -08001822 }
1823 }
1824
Chet Haase10e23ab2015-02-11 15:08:38 -08001825 void overridePendingAppTransitionClipReveal(int startX, int startY,
1826 int startWidth, int startHeight) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001827 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001828 clear();
Chet Haase10e23ab2015-02-11 15:08:38 -08001829 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001830 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
Chet Haase10e23ab2015-02-11 15:08:38 -08001831 postAnimationCallback();
Chet Haase10e23ab2015-02-11 15:08:38 -08001832 }
1833 }
1834
Winson Chungaa7fa012017-05-24 15:50:06 -07001835 void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX, int startY,
Craig Mautner164d4bb2012-11-26 13:51:23 -08001836 IRemoteCallback startedCallback, boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001837 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001838 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001839 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
1840 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001841 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001842 putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001843 postAnimationCallback();
1844 mNextAppTransitionCallback = startedCallback;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001845 }
1846 }
1847
Winson Chungaa7fa012017-05-24 15:50:06 -07001848 void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX, int startY,
Winson Chung2e7f3bd2014-09-05 13:17:22 +02001849 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001850 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001851 clear();
Winson Chunga4ccb862014-08-22 15:26:27 -07001852 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1853 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Winson Chunga4ccb862014-08-22 15:26:27 -07001854 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001855 putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight,
1856 srcThumb);
Winson Chunga4ccb862014-08-22 15:26:27 -07001857 postAnimationCallback();
1858 mNextAppTransitionCallback = startedCallback;
Winson Chunga4ccb862014-08-22 15:26:27 -07001859 }
1860 }
1861
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001862 void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001863 IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
1864 boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001865 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001866 clear();
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001867 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1868 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001869 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi43102412015-11-11 16:28:37 +01001870 if (specs != null) {
1871 for (int i = 0; i < specs.length; i++) {
1872 AppTransitionAnimationSpec spec = specs[i];
1873 if (spec != null) {
1874 mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec);
1875 if (i == 0) {
1876 // In full screen mode, the transition code depends on the default spec
1877 // to be set.
1878 Rect rect = spec.rect;
1879 putDefaultNextAppTransitionCoordinates(rect.left, rect.top,
Winson Chungaa7fa012017-05-24 15:50:06 -07001880 rect.width(), rect.height(), spec.buffer);
Jorim Jaggi43102412015-11-11 16:28:37 +01001881 }
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001882 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001883 }
1884 }
1885 postAnimationCallback();
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001886 mNextAppTransitionCallback = onAnimationStartedCallback;
1887 mAnimationFinishedCallback = onAnimationFinishedCallback;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001888 }
1889 }
1890
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001891 void overridePendingAppTransitionMultiThumbFuture(
1892 IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
1893 boolean scaleUp) {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001894 if (canOverridePendingAppTransition()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001895 clear();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001896 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1897 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001898 mNextAppTransitionAnimationsSpecsFuture = specsFuture;
1899 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +01001900 mNextAppTransitionFutureCallback = callback;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001901 }
1902 }
1903
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001904 void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter) {
Winson Chung044d5292014-11-06 11:05:19 -08001905 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001906 clear();
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001907 mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE;
1908 mRemoteAnimationController = new RemoteAnimationController(mService,
1909 remoteAnimationAdapter, mService.mH);
1910 }
1911 }
1912
1913 void overrideInPlaceAppTransition(String packageName, int anim) {
1914 if (canOverridePendingAppTransition()) {
1915 clear();
Winson Chung044d5292014-11-06 11:05:19 -08001916 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
1917 mNextAppTransitionPackage = packageName;
1918 mNextAppTransitionInPlace = anim;
Winson Chung044d5292014-11-06 11:05:19 -08001919 }
1920 }
1921
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001922 /**
Tony Mak089c35e2017-12-18 20:34:14 +00001923 * @see {@link #NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS}
1924 */
1925 void overridePendingAppTransitionStartCrossProfileApps() {
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001926 if (canOverridePendingAppTransition()) {
Tony Mak089c35e2017-12-18 20:34:14 +00001927 clear();
1928 mNextAppTransitionType = NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
1929 postAnimationCallback();
1930 }
1931 }
1932
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001933 private boolean canOverridePendingAppTransition() {
1934 // Remote animations always take precedence
1935 return isTransitionSet() && mNextAppTransitionType != NEXT_TRANSIT_TYPE_REMOTE;
1936 }
1937
Tony Mak089c35e2017-12-18 20:34:14 +00001938 /**
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001939 * If a future is set for the app transition specs, fetch it in another thread.
1940 */
1941 private void fetchAppTransitionSpecsFromFuture() {
1942 if (mNextAppTransitionAnimationsSpecsFuture != null) {
1943 mNextAppTransitionAnimationsSpecsPending = true;
1944 final IAppTransitionAnimationSpecsFuture future
1945 = mNextAppTransitionAnimationsSpecsFuture;
1946 mNextAppTransitionAnimationsSpecsFuture = null;
Jorim Jaggied410b62017-05-05 15:16:14 +02001947 mDefaultExecutor.execute(() -> {
1948 AppTransitionAnimationSpec[] specs = null;
1949 try {
1950 Binder.allowBlocking(future.asBinder());
1951 specs = future.get();
1952 } catch (RemoteException e) {
1953 Slog.w(TAG, "Failed to fetch app transition specs: " + e);
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001954 }
Jorim Jaggied410b62017-05-05 15:16:14 +02001955 synchronized (mService.mWindowMap) {
1956 mNextAppTransitionAnimationsSpecsPending = false;
1957 overridePendingAppTransitionMultiThumb(specs,
1958 mNextAppTransitionFutureCallback, null /* finishedCallback */,
1959 mNextAppTransitionScaleUp);
1960 mNextAppTransitionFutureCallback = null;
Jorim Jaggied410b62017-05-05 15:16:14 +02001961 }
1962 mService.requestTraversal();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001963 });
1964 }
1965 }
1966
Craig Mautner164d4bb2012-11-26 13:51:23 -08001967 @Override
1968 public String toString() {
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001969 return "mNextAppTransition=" + appTransitionToString(mNextAppTransition);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001970 }
1971
Craig Mautner4b71aa12012-12-27 17:20:01 -08001972 /**
1973 * Returns the human readable name of a window transition.
1974 *
1975 * @param transition The window transition.
1976 * @return The transition symbolic name.
1977 */
1978 public static String appTransitionToString(int transition) {
1979 switch (transition) {
1980 case TRANSIT_UNSET: {
1981 return "TRANSIT_UNSET";
1982 }
1983 case TRANSIT_NONE: {
1984 return "TRANSIT_NONE";
1985 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08001986 case TRANSIT_ACTIVITY_OPEN: {
1987 return "TRANSIT_ACTIVITY_OPEN";
1988 }
1989 case TRANSIT_ACTIVITY_CLOSE: {
1990 return "TRANSIT_ACTIVITY_CLOSE";
1991 }
1992 case TRANSIT_TASK_OPEN: {
1993 return "TRANSIT_TASK_OPEN";
1994 }
1995 case TRANSIT_TASK_CLOSE: {
1996 return "TRANSIT_TASK_CLOSE";
1997 }
1998 case TRANSIT_TASK_TO_FRONT: {
1999 return "TRANSIT_TASK_TO_FRONT";
2000 }
2001 case TRANSIT_TASK_TO_BACK: {
2002 return "TRANSIT_TASK_TO_BACK";
2003 }
2004 case TRANSIT_WALLPAPER_CLOSE: {
2005 return "TRANSIT_WALLPAPER_CLOSE";
2006 }
2007 case TRANSIT_WALLPAPER_OPEN: {
2008 return "TRANSIT_WALLPAPER_OPEN";
2009 }
2010 case TRANSIT_WALLPAPER_INTRA_OPEN: {
2011 return "TRANSIT_WALLPAPER_INTRA_OPEN";
2012 }
2013 case TRANSIT_WALLPAPER_INTRA_CLOSE: {
2014 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
2015 }
Craig Mautnerbb742462014-07-07 15:28:55 -07002016 case TRANSIT_TASK_OPEN_BEHIND: {
2017 return "TRANSIT_TASK_OPEN_BEHIND";
2018 }
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07002019 case TRANSIT_ACTIVITY_RELAUNCH: {
2020 return "TRANSIT_ACTIVITY_RELAUNCH";
2021 }
Jorim Jaggi192086e2016-03-11 17:17:03 +01002022 case TRANSIT_DOCK_TASK_FROM_RECENTS: {
2023 return "TRANSIT_DOCK_TASK_FROM_RECENTS";
2024 }
Jorim Jaggife762342016-10-13 14:33:27 +02002025 case TRANSIT_KEYGUARD_GOING_AWAY: {
2026 return "TRANSIT_KEYGUARD_GOING_AWAY";
2027 }
2028 case TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
2029 return "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
2030 }
2031 case TRANSIT_KEYGUARD_OCCLUDE: {
2032 return "TRANSIT_KEYGUARD_OCCLUDE";
2033 }
2034 case TRANSIT_KEYGUARD_UNOCCLUDE: {
2035 return "TRANSIT_KEYGUARD_UNOCCLUDE";
2036 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08002037 default: {
2038 return "<UNKNOWN>";
2039 }
2040 }
2041 }
2042
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002043 private String appStateToString() {
2044 switch (mAppTransitionState) {
2045 case APP_STATE_IDLE:
2046 return "APP_STATE_IDLE";
2047 case APP_STATE_READY:
2048 return "APP_STATE_READY";
2049 case APP_STATE_RUNNING:
2050 return "APP_STATE_RUNNING";
2051 case APP_STATE_TIMEOUT:
2052 return "APP_STATE_TIMEOUT";
2053 default:
2054 return "unknown state=" + mAppTransitionState;
2055 }
2056 }
2057
2058 private String transitTypeToString() {
2059 switch (mNextAppTransitionType) {
2060 case NEXT_TRANSIT_TYPE_NONE:
2061 return "NEXT_TRANSIT_TYPE_NONE";
2062 case NEXT_TRANSIT_TYPE_CUSTOM:
2063 return "NEXT_TRANSIT_TYPE_CUSTOM";
Winson Chung044d5292014-11-06 11:05:19 -08002064 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
2065 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002066 case NEXT_TRANSIT_TYPE_SCALE_UP:
2067 return "NEXT_TRANSIT_TYPE_SCALE_UP";
2068 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
2069 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
2070 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
2071 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
Winson Chunga4ccb862014-08-22 15:26:27 -07002072 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
2073 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
2074 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
2075 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
Tony Mak64b8d562017-12-28 17:44:02 +00002076 case NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:
2077 return "NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002078 default:
2079 return "unknown type=" + mNextAppTransitionType;
2080 }
2081 }
2082
Steven Timotiusaf03df62017-07-18 16:56:43 -07002083 void writeToProto(ProtoOutputStream proto, long fieldId) {
2084 final long token = proto.start(fieldId);
2085 proto.write(APP_TRANSITION_STATE, mAppTransitionState);
2086 proto.write(LAST_USED_APP_TRANSITION, mLastUsedAppTransition);
2087 proto.end(token);
2088 }
2089
Craig Mautner164d4bb2012-11-26 13:51:23 -08002090 @Override
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002091 public void dump(PrintWriter pw, String prefix) {
2092 pw.print(prefix); pw.println(this);
2093 pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002094 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002095 pw.print(prefix); pw.print("mNextAppTransitionType=");
2096 pw.println(transitTypeToString());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002097 }
2098 switch (mNextAppTransitionType) {
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002099 case NEXT_TRANSIT_TYPE_CUSTOM:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002100 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Craig Mautner164d4bb2012-11-26 13:51:23 -08002101 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002102 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
Craig Mautner164d4bb2012-11-26 13:51:23 -08002103 pw.print(Integer.toHexString(mNextAppTransitionEnter));
2104 pw.print(" mNextAppTransitionExit=0x");
2105 pw.println(Integer.toHexString(mNextAppTransitionExit));
2106 break;
Winson Chung044d5292014-11-06 11:05:19 -08002107 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002108 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Winson Chung044d5292014-11-06 11:05:19 -08002109 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002110 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
Winson Chung044d5292014-11-06 11:05:19 -08002111 pw.print(Integer.toHexString(mNextAppTransitionInPlace));
2112 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002113 case NEXT_TRANSIT_TYPE_SCALE_UP: {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002114 getDefaultNextAppTransitionStartRect(mTmpRect);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002115 pw.print(prefix); pw.print("mNextAppTransitionStartX=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002116 pw.print(mTmpRect.left);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002117 pw.print(" mNextAppTransitionStartY=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002118 pw.println(mTmpRect.top);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002119 pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002120 pw.print(mTmpRect.width());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002121 pw.print(" mNextAppTransitionStartHeight=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07002122 pw.println(mTmpRect.height());
Craig Mautner164d4bb2012-11-26 13:51:23 -08002123 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002124 }
Craig Mautner9a29a5d2012-12-27 19:03:40 -08002125 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
2126 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
Winson Chunga4ccb862014-08-22 15:26:27 -07002127 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002128 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
2129 pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
2130 pw.println(mDefaultNextAppTransitionAnimationSpec);
2131 pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
2132 pw.println(mNextAppTransitionAnimationsSpecs);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002133 pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
2134 pw.println(mNextAppTransitionScaleUp);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002135 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07002136 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002137 }
2138 if (mNextAppTransitionCallback != null) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08002139 pw.print(prefix); pw.print("mNextAppTransitionCallback=");
2140 pw.println(mNextAppTransitionCallback);
Craig Mautner164d4bb2012-11-26 13:51:23 -08002141 }
Chong Zhang60091a92016-07-27 17:52:45 -07002142 if (mLastUsedAppTransition != TRANSIT_NONE) {
2143 pw.print(prefix); pw.print("mLastUsedAppTransition=");
2144 pw.println(appTransitionToString(mLastUsedAppTransition));
2145 pw.print(prefix); pw.print("mLastOpeningApp=");
2146 pw.println(mLastOpeningApp);
2147 pw.print(prefix); pw.print("mLastClosingApp=");
2148 pw.println(mLastClosingApp);
2149 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002150 }
Amith Yamasani4befbec2013-07-10 16:18:01 -07002151
2152 public void setCurrentUser(int newUserId) {
2153 mCurrentUserId = newUserId;
2154 }
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002155
2156 /**
2157 * @return true if transition is not running and should not be skipped, false if transition is
2158 * already running
2159 */
Jorim Jaggife762342016-10-13 14:33:27 +02002160 boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent, int flags,
2161 boolean forceOverride) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002162 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
2163 + " transit=" + appTransitionToString(transit)
2164 + " " + this
2165 + " alwaysKeepCurrent=" + alwaysKeepCurrent
2166 + " Callers=" + Debug.getCallers(3));
Jorim Jaggife762342016-10-13 14:33:27 +02002167 if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
2168 || mNextAppTransition == TRANSIT_NONE) {
2169 setAppTransition(transit, flags);
Jorim Jaggia69243a2017-06-15 15:10:38 -04002170 }
2171 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
2172 // relies on the fact that we always execute a Keyguard transition after preparing one.
2173 else if (!alwaysKeepCurrent && !isKeyguardTransit(transit)) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002174 if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
2175 // Opening a new task always supersedes a close for the anim.
Jorim Jaggife762342016-10-13 14:33:27 +02002176 setAppTransition(transit, flags);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002177 } else if (transit == TRANSIT_ACTIVITY_OPEN
2178 && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
2179 // Opening a new activity always supersedes a close for the anim.
Jorim Jaggife762342016-10-13 14:33:27 +02002180 setAppTransition(transit, flags);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002181 }
2182 }
2183 boolean prepared = prepare();
2184 if (isTransitionSet()) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08002185 mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
2186 mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07002187 }
2188 return prepared;
2189 }
Winsonb2024762016-04-05 17:32:30 -07002190
2191 /**
Jorim Jaggife762342016-10-13 14:33:27 +02002192 * @return true if {@param transit} is representing a transition in which Keyguard is going
2193 * away, false otherwise
2194 */
2195 public static boolean isKeyguardGoingAwayTransit(int transit) {
2196 return transit == TRANSIT_KEYGUARD_GOING_AWAY
2197 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
2198 }
2199
2200 private static boolean isKeyguardTransit(int transit) {
2201 return isKeyguardGoingAwayTransit(transit) || transit == TRANSIT_KEYGUARD_OCCLUDE
2202 || transit == TRANSIT_KEYGUARD_UNOCCLUDE;
2203 }
2204
2205 /**
Manu Cornetd7376802017-01-13 13:44:07 -08002206 * @return whether the transition should show the thumbnail being scaled down.
2207 */
2208 private boolean shouldScaleDownThumbnailTransition(int uiMode, int orientation) {
Sid Soundararajan0e88d322017-03-07 15:37:30 -08002209 return mGridLayoutRecentsEnabled
Manu Cornetd7376802017-01-13 13:44:07 -08002210 || orientation == Configuration.ORIENTATION_PORTRAIT;
2211 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08002212}