blob: d3941258de5ab8f114795b1951c6f15e5a85aa06 [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 android.view.WindowManagerInternal.AppTransitionListener;
20import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
21import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
22import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
23import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
24import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
25import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
26import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
27import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
28import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
29import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
30import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
31import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
32import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
33import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
34import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
35import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
36import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
37import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
38import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
39import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
40import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
41import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
42
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -070043import android.annotation.Nullable;
Craig Mautner164d4bb2012-11-26 13:51:23 -080044import android.content.Context;
Winson Chung2820c452014-04-15 15:34:44 -070045import android.content.res.Configuration;
Craig Mautner164d4bb2012-11-26 13:51:23 -080046import android.graphics.Bitmap;
Winson Chung399f6202014-03-19 10:47:20 -070047import android.graphics.Rect;
Craig Mautner164d4bb2012-11-26 13:51:23 -080048import android.os.Debug;
49import android.os.Handler;
Jorim Jaggi77ba4802015-02-18 13:57:50 +010050import android.os.IBinder;
Craig Mautner164d4bb2012-11-26 13:51:23 -080051import android.os.IRemoteCallback;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +010052import android.os.RemoteException;
Craig Mautner164d4bb2012-11-26 13:51:23 -080053import android.util.Slog;
Filip Gruszczynski170192a2015-08-16 17:46:34 -070054import android.util.SparseArray;
55import android.view.AppTransitionAnimationSpec;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +010056import android.view.IAppTransitionAnimationSpecsFuture;
Craig Mautner164d4bb2012-11-26 13:51:23 -080057import android.view.WindowManager;
Craig Mautner164d4bb2012-11-26 13:51:23 -080058import android.view.animation.AlphaAnimation;
59import android.view.animation.Animation;
60import android.view.animation.AnimationSet;
61import android.view.animation.AnimationUtils;
Winson Chung399f6202014-03-19 10:47:20 -070062import android.view.animation.ClipRectAnimation;
Chet Haase10e23ab2015-02-11 15:08:38 -080063import android.view.animation.ClipRectLRAnimation;
64import android.view.animation.ClipRectTBAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -080065import android.view.animation.Interpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -070066import android.view.animation.PathInterpolator;
Craig Mautner164d4bb2012-11-26 13:51:23 -080067import android.view.animation.ScaleAnimation;
Winson Chung399f6202014-03-19 10:47:20 -070068import android.view.animation.TranslateAnimation;
Jorim Jaggi1d763a62015-06-02 17:07:39 -070069
Craig Mautner164d4bb2012-11-26 13:51:23 -080070import com.android.internal.util.DumpUtils.Dump;
71import com.android.server.AttributeCache;
72import com.android.server.wm.WindowManagerService.H;
73
74import java.io.PrintWriter;
Jorim Jaggi77ba4802015-02-18 13:57:50 +010075import java.util.ArrayList;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +010076import java.util.concurrent.ExecutorService;
77import java.util.concurrent.Executors;
Craig Mautner164d4bb2012-11-26 13:51:23 -080078
Craig Mautner164d4bb2012-11-26 13:51:23 -080079// State management of app transitions. When we are preparing for a
80// transition, mNextAppTransition will be the kind of transition to
81// perform or TRANSIT_NONE if we are not waiting. If we are waiting,
82// mOpeningApps and mClosingApps are the lists of tokens that will be
83// made visible or hidden at the next transition.
84public class AppTransition implements Dump {
85 private static final String TAG = "AppTransition";
Craig Mautner321bdf52012-12-18 09:53:24 -080086 private static final boolean DEBUG_APP_TRANSITIONS =
87 WindowManagerService.DEBUG_APP_TRANSITIONS;
88 private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM;
Jorim Jaggi1d763a62015-06-02 17:07:39 -070089 private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8;
Craig Mautner9a29a5d2012-12-27 19:03:40 -080090
Craig Mautner4b71aa12012-12-27 17:20:01 -080091 /** Not set up for a transition. */
92 public static final int TRANSIT_UNSET = -1;
93 /** No animation for transition. */
94 public static final int TRANSIT_NONE = 0;
95 /** 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 -070096 public static final int TRANSIT_ACTIVITY_OPEN = 6;
Craig Mautner4b71aa12012-12-27 17:20:01 -080097 /** The window in the top-most activity is being closed to reveal the
98 * previous activity in the same task. */
Craig Mautnerbb742462014-07-07 15:28:55 -070099 public static final int TRANSIT_ACTIVITY_CLOSE = 7;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800100 /** A window in a new task is being opened on top of an existing one
101 * in another activity's task. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700102 public static final int TRANSIT_TASK_OPEN = 8;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800103 /** A window in the top-most activity is being closed to reveal the
104 * previous activity in a different task. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700105 public static final int TRANSIT_TASK_CLOSE = 9;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800106 /** A window in an existing task is being displayed on top of an existing one
107 * in another activity's task. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700108 public static final int TRANSIT_TASK_TO_FRONT = 10;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800109 /** A window in an existing task is being put below all other tasks. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700110 public static final int TRANSIT_TASK_TO_BACK = 11;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800111 /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that
112 * does, effectively closing the wallpaper. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700113 public static final int TRANSIT_WALLPAPER_CLOSE = 12;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800114 /** A window in a new activity that does have a wallpaper is being opened on one that didn't,
115 * effectively opening the wallpaper. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700116 public static final int TRANSIT_WALLPAPER_OPEN = 13;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800117 /** A window in a new activity is being opened on top of an existing one, and both are on top
118 * of the wallpaper. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700119 public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800120 /** The window in the top-most activity is being closed to reveal the previous activity, and
121 * both are on top of the wallpaper. */
Craig Mautnerbb742462014-07-07 15:28:55 -0700122 public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15;
123 /** A window in a new task is being opened behind an existing one in another activity's task.
124 * The new window will show briefly and then be gone. */
125 public static final int TRANSIT_TASK_OPEN_BEHIND = 16;
Winson Chung044d5292014-11-06 11:05:19 -0800126 /** A window in a task is being animated in-place. */
127 public static final int TRANSIT_TASK_IN_PLACE = 17;
Filip Gruszczynski55a309f2015-09-04 17:15:01 -0700128 /** An activity is being relaunched (e.g. due to configuration change). */
129 public static final int TRANSIT_ACTIVITY_RELAUNCH = 18;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800130
Winson Chunga4ccb862014-08-22 15:26:27 -0700131 /** Fraction of animation at which the recents thumbnail stays completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700132 private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800133 /** Fraction of animation at which the recents thumbnail becomes completely transparent */
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700134 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800135
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700136 private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
137 private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
138 private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700139 private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800140
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800141 private final Context mContext;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800142 private final WindowManagerService mService;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800143
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800144 private int mNextAppTransition = TRANSIT_UNSET;
145
146 private static final int NEXT_TRANSIT_TYPE_NONE = 0;
147 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
148 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
149 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
150 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
Winson Chunga4ccb862014-08-22 15:26:27 -0700151 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
152 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
Winson Chung044d5292014-11-06 11:05:19 -0800153 private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
Chet Haase10e23ab2015-02-11 15:08:38 -0800154 private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800155 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
156
Winson Chung399f6202014-03-19 10:47:20 -0700157 // These are the possible states for the enter/exit activities during a thumbnail transition
158 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
159 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
160 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
161 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
162
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800163 private String mNextAppTransitionPackage;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800164 // Used for thumbnail transitions. True if we're scaling up, false if scaling down
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800165 private boolean mNextAppTransitionScaleUp;
166 private IRemoteCallback mNextAppTransitionCallback;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +0100167 private IRemoteCallback mNextAppTransitionFutureCallback;
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -0700168 private IRemoteCallback mAnimationFinishedCallback;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800169 private int mNextAppTransitionEnter;
170 private int mNextAppTransitionExit;
Winson Chung044d5292014-11-06 11:05:19 -0800171 private int mNextAppTransitionInPlace;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700172
173 // Keyed by task id.
174 private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
175 = new SparseArray<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100176 private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
177 private boolean mNextAppTransitionAnimationsSpecsPending;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700178 private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
179
Winson Chunga4ccb862014-08-22 15:26:27 -0700180 private Rect mNextAppTransitionInsets = new Rect();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800181
Winson Chung2820c452014-04-15 15:34:44 -0700182 private Rect mTmpFromClipRect = new Rect();
183 private Rect mTmpToClipRect = new Rect();
184
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700185 private final Rect mTmpRect = new Rect();
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700186
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800187 private final static int APP_STATE_IDLE = 0;
188 private final static int APP_STATE_READY = 1;
189 private final static int APP_STATE_RUNNING = 2;
190 private final static int APP_STATE_TIMEOUT = 3;
191 private int mAppTransitionState = APP_STATE_IDLE;
192
193 private final int mConfigShortAnimTime;
Craig Mautner321bdf52012-12-18 09:53:24 -0800194 private final Interpolator mDecelerateInterpolator;
Winson Chunga4ccb862014-08-22 15:26:27 -0700195 private final Interpolator mThumbnailFadeInInterpolator;
196 private final Interpolator mThumbnailFadeOutInterpolator;
Chet Haase10e23ab2015-02-11 15:08:38 -0800197 private final Interpolator mLinearOutSlowInInterpolator;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700198 private final Interpolator mFastOutLinearInInterpolator;
199 private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
200
201 /** Interpolator to be used for animations that respond directly to a touch */
202 private final Interpolator mTouchResponseInterpolator =
203 new PathInterpolator(0.3f, 0f, 0.1f, 1f);
204
205 private final int mClipRevealTranslationY;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800206
Amith Yamasani4befbec2013-07-10 16:18:01 -0700207 private int mCurrentUserId = 0;
208
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100209 private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100210 private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100211
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800212 AppTransition(Context context, WindowManagerService service) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800213 mContext = context;
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800214 mService = service;
Chet Haase10e23ab2015-02-11 15:08:38 -0800215 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
216 com.android.internal.R.interpolator.linear_out_slow_in);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700217 mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
218 com.android.internal.R.interpolator.fast_out_linear_in);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800219 mConfigShortAnimTime = context.getResources().getInteger(
220 com.android.internal.R.integer.config_shortAnimTime);
Craig Mautner321bdf52012-12-18 09:53:24 -0800221 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
222 com.android.internal.R.interpolator.decelerate_cubic);
Winson Chunga4ccb862014-08-22 15:26:27 -0700223 mThumbnailFadeInInterpolator = new Interpolator() {
224 @Override
225 public float getInterpolation(float input) {
226 // Linear response for first fraction, then complete after that.
227 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) {
228 return 0f;
229 }
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700230 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) /
Winson Chunga4ccb862014-08-22 15:26:27 -0700231 (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700232 return mFastOutLinearInInterpolator.getInterpolation(t);
Winson Chunga4ccb862014-08-22 15:26:27 -0700233 }
234 };
235 mThumbnailFadeOutInterpolator = new Interpolator() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800236 @Override
237 public float getInterpolation(float input) {
238 // Linear response for first fraction, then complete after that.
239 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700240 float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
241 return mLinearOutSlowInInterpolator.getInterpolation(t);
Craig Mautner321bdf52012-12-18 09:53:24 -0800242 }
Winson Chunga4ccb862014-08-22 15:26:27 -0700243 return 1f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800244 }
245 };
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700246 mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP
247 * mContext.getResources().getDisplayMetrics().density);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800248 }
249
250 boolean isTransitionSet() {
251 return mNextAppTransition != TRANSIT_UNSET;
252 }
253
Craig Mautner164d4bb2012-11-26 13:51:23 -0800254 boolean isTransitionEqual(int transit) {
255 return mNextAppTransition == transit;
256 }
257
258 int getAppTransition() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800259 return mNextAppTransition;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800260 }
261
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700262 private void setAppTransition(int transit) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800263 mNextAppTransition = transit;
264 }
265
266 boolean isReady() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800267 return mAppTransitionState == APP_STATE_READY
268 || mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800269 }
270
Craig Mautnerae446592012-12-06 19:05:05 -0800271 void setReady() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800272 mAppTransitionState = APP_STATE_READY;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100273 fetchAppTransitionSpecsFromFuture();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800274 }
275
276 boolean isRunning() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800277 return mAppTransitionState == APP_STATE_RUNNING;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800278 }
279
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800280 void setIdle() {
281 mAppTransitionState = APP_STATE_IDLE;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800282 }
283
284 boolean isTimeout() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800285 return mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800286 }
287
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800288 void setTimeout() {
289 mAppTransitionState = APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800290 }
291
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700292 Bitmap getAppTransitionThumbnailHeader(int taskId) {
293 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800294 if (spec == null) {
295 spec = mDefaultNextAppTransitionAnimationSpec;
296 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700297 return spec != null ? spec.bitmap : null;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800298 }
299
Winson Chunga4ccb862014-08-22 15:26:27 -0700300 /** Returns whether the next thumbnail transition is aspect scaled up. */
301 boolean isNextThumbnailTransitionAspectScaled() {
302 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
303 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
304 }
305
306 /** Returns whether the next thumbnail transition is scaling up. */
307 boolean isNextThumbnailTransitionScaleUp() {
308 return mNextAppTransitionScaleUp;
309 }
310
Jorim Jaggi2f7d2922015-10-29 13:08:29 +0100311 /**
312 * @return true if and only if we are currently fetching app transition specs from the future
313 * passed into {@link #overridePendingAppTransitionMultiThumbFuture}
314 */
315 boolean isFetchingAppTransitionsSpecs() {
316 return mNextAppTransitionAnimationsSpecsPending;
317 }
318
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700319 private boolean prepare() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800320 if (!isRunning()) {
321 mAppTransitionState = APP_STATE_IDLE;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100322 notifyAppTransitionPendingLocked();
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700323 return true;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800324 }
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -0700325 return false;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800326 }
327
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100328 void goodToGo(AppWindowAnimator openingAppAnimator, AppWindowAnimator closingAppAnimator) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800329 mNextAppTransition = TRANSIT_UNSET;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800330 mAppTransitionState = APP_STATE_RUNNING;
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100331 notifyAppTransitionStartingLocked(
332 openingAppAnimator != null ? openingAppAnimator.mAppToken.token : null,
333 closingAppAnimator != null ? closingAppAnimator.mAppToken.token : null,
334 openingAppAnimator != null ? openingAppAnimator.animation : null,
335 closingAppAnimator != null ? closingAppAnimator.animation : null);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800336 }
337
338 void clear() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800339 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800340 mNextAppTransitionPackage = null;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700341 mNextAppTransitionAnimationsSpecs.clear();
Jorim Jaggi65193992015-11-23 16:49:59 -0800342 mNextAppTransitionAnimationsSpecsFuture = null;
343 mDefaultNextAppTransitionAnimationSpec = null;
344 mAnimationFinishedCallback = null;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800345 }
346
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800347 void freeze() {
348 setAppTransition(AppTransition.TRANSIT_UNSET);
349 clear();
350 setReady();
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100351 notifyAppTransitionCancelledLocked();
352 }
353
354 void registerListenerLocked(AppTransitionListener listener) {
355 mListeners.add(listener);
356 }
357
Wale Ogunwalea48eadb2015-05-14 17:43:12 -0700358 public void notifyAppTransitionFinishedLocked(IBinder token) {
Jorim Jaggi77ba4802015-02-18 13:57:50 +0100359 for (int i = 0; i < mListeners.size(); i++) {
360 mListeners.get(i).onAppTransitionFinishedLocked(token);
361 }
362 }
363
364 private void notifyAppTransitionPendingLocked() {
365 for (int i = 0; i < mListeners.size(); i++) {
366 mListeners.get(i).onAppTransitionPendingLocked();
367 }
368 }
369
370 private void notifyAppTransitionCancelledLocked() {
371 for (int i = 0; i < mListeners.size(); i++) {
372 mListeners.get(i).onAppTransitionCancelledLocked();
373 }
374 }
375
376 private void notifyAppTransitionStartingLocked(IBinder openToken,
377 IBinder closeToken, Animation openAnimation, Animation closeAnimation) {
378 for (int i = 0; i < mListeners.size(); i++) {
379 mListeners.get(i).onAppTransitionStartingLocked(openToken, closeToken, openAnimation,
380 closeAnimation);
381 }
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800382 }
383
Craig Mautner164d4bb2012-11-26 13:51:23 -0800384 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
385 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
386 + (lp != null ? lp.packageName : null)
387 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
388 if (lp != null && lp.windowAnimations != 0) {
389 // If this is a system resource, don't try to load it from the
390 // application resources. It is nice to avoid loading application
391 // resources if we can.
392 String packageName = lp.packageName != null ? lp.packageName : "android";
393 int resId = lp.windowAnimations;
394 if ((resId&0xFF000000) == 0x01000000) {
395 packageName = "android";
396 }
397 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
398 + packageName);
399 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700400 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800401 }
402 return null;
403 }
404
405 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
406 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
407 + packageName + " resId=0x" + Integer.toHexString(resId));
408 if (packageName != null) {
409 if ((resId&0xFF000000) == 0x01000000) {
410 packageName = "android";
411 }
412 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
413 + packageName);
414 return AttributeCache.instance().get(packageName, resId,
Amith Yamasani4befbec2013-07-10 16:18:01 -0700415 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800416 }
417 return null;
418 }
419
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700420 Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800421 int anim = 0;
422 Context context = mContext;
423 if (animAttr >= 0) {
424 AttributeCache.Entry ent = getCachedAnimations(lp);
425 if (ent != null) {
426 context = ent.context;
427 anim = ent.array.getResourceId(animAttr, 0);
428 }
429 }
430 if (anim != 0) {
431 return AnimationUtils.loadAnimation(context, anim);
432 }
433 return null;
434 }
435
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700436 Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) {
437 Context context = mContext;
438 if (resId >= 0) {
439 AttributeCache.Entry ent = getCachedAnimations(lp);
440 if (ent != null) {
441 context = ent.context;
442 }
443 return AnimationUtils.loadAnimation(context, resId);
444 }
445 return null;
446 }
447
448 private Animation loadAnimationRes(String packageName, int resId) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800449 int anim = 0;
450 Context context = mContext;
451 if (resId >= 0) {
452 AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
453 if (ent != null) {
454 context = ent.context;
455 anim = resId;
456 }
457 }
458 if (anim != 0) {
459 return AnimationUtils.loadAnimation(context, anim);
460 }
461 return null;
462 }
463
Craig Mautner164d4bb2012-11-26 13:51:23 -0800464 /**
465 * Compute the pivot point for an animation that is scaling from a small
466 * rect on screen to a larger rect. The pivot point varies depending on
467 * the distance between the inner and outer edges on both sides. This
468 * function computes the pivot point for one dimension.
469 * @param startPos Offset from left/top edge of outer rectangle to
470 * left/top edge of inner rectangle.
471 * @param finalScale The scaling factor between the size of the outer
472 * and inner rectangles.
473 */
474 private static float computePivot(int startPos, float finalScale) {
475 final float denom = finalScale-1;
476 if (Math.abs(denom) < .0001f) {
477 return startPos;
478 }
479 return -startPos / denom;
480 }
481
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700482 private Animation createScaleUpAnimationLocked(int transit, boolean enter,
483 Rect containingFrame) {
484 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700485 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700486 final int appWidth = containingFrame.width();
487 final int appHeight = containingFrame.height();
Craig Mautner164d4bb2012-11-26 13:51:23 -0800488 if (enter) {
489 // Entering app zooms out from the center of the initial rect.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700490 float scaleW = mTmpRect.width() / (float) appWidth;
491 float scaleH = mTmpRect.height() / (float) appHeight;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800492 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700493 computePivot(mTmpRect.left, scaleW),
494 computePivot(mTmpRect.right, scaleH));
Craig Mautner321bdf52012-12-18 09:53:24 -0800495 scale.setInterpolator(mDecelerateInterpolator);
496
Craig Mautner164d4bb2012-11-26 13:51:23 -0800497 Animation alpha = new AlphaAnimation(0, 1);
Winson Chunga4ccb862014-08-22 15:26:27 -0700498 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
Craig Mautner321bdf52012-12-18 09:53:24 -0800499
500 AnimationSet set = new AnimationSet(false);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800501 set.addAnimation(scale);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800502 set.addAnimation(alpha);
503 set.setDetachWallpaper(true);
504 a = set;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800505 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
506 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800507 // If we are on top of the wallpaper, we need an animation that
508 // correctly handles the wallpaper staying static behind all of
509 // the animated elements. To do this, will just have the existing
510 // element fade out.
511 a = new AlphaAnimation(1, 0);
512 a.setDetachWallpaper(true);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800513 } else {
Craig Mautner321bdf52012-12-18 09:53:24 -0800514 // For normal animations, the exiting element just holds in place.
515 a = new AlphaAnimation(1, 1);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800516 }
Craig Mautner321bdf52012-12-18 09:53:24 -0800517
518 // Pick the desired duration. If this is an inter-activity transition,
519 // it is the standard duration for that. Otherwise we use the longer
520 // task transition duration.
521 final long duration;
522 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800523 case TRANSIT_ACTIVITY_OPEN:
524 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800525 duration = mConfigShortAnimTime;
526 break;
527 default:
528 duration = DEFAULT_APP_TRANSITION_DURATION;
529 break;
530 }
531 a.setDuration(duration);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800532 a.setFillAfter(true);
Craig Mautner321bdf52012-12-18 09:53:24 -0800533 a.setInterpolator(mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800534 a.initialize(appWidth, appHeight, appWidth, appHeight);
535 return a;
536 }
537
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700538 private void getDefaultNextAppTransitionStartRect(Rect rect) {
539 if (mDefaultNextAppTransitionAnimationSpec == null ||
540 mDefaultNextAppTransitionAnimationSpec.rect == null) {
541 Slog.wtf(TAG, "Starting rect for app requested, but none available", new Throwable());
542 rect.setEmpty();
543 } else {
544 rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
545 }
546 }
547
548 void getNextAppTransitionStartRect(int taskId, Rect rect) {
549 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800550 if (spec == null) {
551 spec = mDefaultNextAppTransitionAnimationSpec;
552 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700553 if (spec == null || spec.rect == null) {
554 Slog.wtf(TAG, "Starting rect for task: " + taskId + " requested, but not available",
555 new Throwable());
556 rect.setEmpty();
557 } else {
558 rect.set(spec.rect);
559 }
560 }
561
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800562 private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height,
563 Bitmap bitmap) {
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700564 mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
Filip Gruszczynski7248c562015-11-09 13:05:40 -0800565 bitmap, new Rect(left, top, left + width, top + height));
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700566 }
567
Craig Mautner80b1f642015-04-22 10:59:09 -0700568 private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame) {
Chet Haase10e23ab2015-02-11 15:08:38 -0800569 final Animation anim;
570 if (enter) {
571 // Reveal will expand and move faster in horizontal direction
572
Craig Mautner80b1f642015-04-22 10:59:09 -0700573 final int appWidth = appFrame.width();
574 final int appHeight = appFrame.height();
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700575 // mTmpRect will contain an area around the launcher icon that was pressed. We will
Filip Gruszczynski82861362015-10-16 14:21:09 -0700576 // clip reveal from that area in the final area of the app.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700577 getDefaultNextAppTransitionStartRect(mTmpRect);
Craig Mautner80b1f642015-04-22 10:59:09 -0700578
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700579 float t = 0f;
580 if (appHeight > 0) {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700581 t = (float) mTmpRect.left / appHeight;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700582 }
Filip Gruszczynski82861362015-10-16 14:21:09 -0700583 int translationY = mClipRevealTranslationY + (int)(appHeight / 7f * t);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700584
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700585 int centerX = mTmpRect.centerX();
586 int centerY = mTmpRect.centerY();
587 int halfWidth = mTmpRect.width() / 2;
588 int halfHeight = mTmpRect.height() / 2;
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700589
590 // Clip third of the from size of launch icon, expand to full width/height
Chet Haase10e23ab2015-02-11 15:08:38 -0800591 Animation clipAnimLR = new ClipRectLRAnimation(
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700592 centerX - halfWidth, centerX + halfWidth, 0, appWidth);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700593 clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
594 clipAnimLR.setDuration((long) (DEFAULT_APP_TRANSITION_DURATION / 2.5f));
Filip Gruszczynski82861362015-10-16 14:21:09 -0700595
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700596 Animation clipAnimTB = new ClipRectTBAnimation(centerY - halfHeight - translationY,
597 centerY + halfHeight/ 2 - translationY, 0, appHeight);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700598 clipAnimTB.setInterpolator(mTouchResponseInterpolator);
Chet Haase10e23ab2015-02-11 15:08:38 -0800599 clipAnimTB.setDuration(DEFAULT_APP_TRANSITION_DURATION);
600
Filip Gruszczynski82861362015-10-16 14:21:09 -0700601 // We might be animating entrance of a docked task, so we need the translate to account
602 // for the app frame in which the window will reside. Every other calculation here
603 // is performed as if the window started at 0,0.
604 translationY -= appFrame.top;
605 TranslateAnimation translate = new TranslateAnimation(-appFrame.left, 0, translationY,
606 0);
607 translate.setInterpolator(mLinearOutSlowInInterpolator);
608 translate.setDuration(DEFAULT_APP_TRANSITION_DURATION);
Chet Haase10e23ab2015-02-11 15:08:38 -0800609
610 // Quick fade-in from icon to app window
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700611 final int alphaDuration = DEFAULT_APP_TRANSITION_DURATION / 4;
612 AlphaAnimation alpha = new AlphaAnimation(0.5f, 1);
Chet Haase10e23ab2015-02-11 15:08:38 -0800613 alpha.setDuration(alphaDuration);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700614 alpha.setInterpolator(mLinearOutSlowInInterpolator);
Chet Haase10e23ab2015-02-11 15:08:38 -0800615
616 AnimationSet set = new AnimationSet(false);
617 set.addAnimation(clipAnimLR);
618 set.addAnimation(clipAnimTB);
Filip Gruszczynski82861362015-10-16 14:21:09 -0700619 set.addAnimation(translate);
Chet Haase10e23ab2015-02-11 15:08:38 -0800620 set.addAnimation(alpha);
Filip Gruszczynski9e2cf5b2015-07-31 12:20:40 -0700621 set.setZAdjustment(Animation.ZORDER_TOP);
Chet Haase10e23ab2015-02-11 15:08:38 -0800622 set.initialize(appWidth, appHeight, appWidth, appHeight);
623 anim = set;
624 } else {
625 final long duration;
626 switch (transit) {
627 case TRANSIT_ACTIVITY_OPEN:
628 case TRANSIT_ACTIVITY_CLOSE:
629 duration = mConfigShortAnimTime;
630 break;
631 default:
632 duration = DEFAULT_APP_TRANSITION_DURATION;
633 break;
634 }
635 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
636 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
637 // If we are on top of the wallpaper, we need an animation that
638 // correctly handles the wallpaper staying static behind all of
639 // the animated elements. To do this, will just have the existing
640 // element fade out.
641 anim = new AlphaAnimation(1, 0);
642 anim.setDetachWallpaper(true);
643 } else {
644 // For normal animations, the exiting element just holds in place.
645 anim = new AlphaAnimation(1, 1);
646 }
647 anim.setInterpolator(mDecelerateInterpolator);
648 anim.setDuration(duration);
649 anim.setFillAfter(true);
650 }
651 return anim;
652 }
653
Winson Chung399f6202014-03-19 10:47:20 -0700654 /**
655 * Prepares the specified animation with a standard duration, interpolator, etc.
656 */
Winson Chung5393dff2014-05-08 14:25:43 -0700657 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
658 int duration, Interpolator interpolator) {
Winson Chunga4ccb862014-08-22 15:26:27 -0700659 if (duration > 0) {
660 a.setDuration(duration);
661 }
Winson Chung5393dff2014-05-08 14:25:43 -0700662 a.setFillAfter(true);
663 a.setInterpolator(interpolator);
664 a.initialize(appWidth, appHeight, appWidth, appHeight);
665 return a;
666 }
667
668 /**
669 * Prepares the specified animation with a standard duration, interpolator, etc.
670 */
Winson Chung399f6202014-03-19 10:47:20 -0700671 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800672 // Pick the desired duration. If this is an inter-activity transition,
673 // it is the standard duration for that. Otherwise we use the longer
674 // task transition duration.
Winson Chung5393dff2014-05-08 14:25:43 -0700675 final int duration;
Craig Mautner321bdf52012-12-18 09:53:24 -0800676 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800677 case TRANSIT_ACTIVITY_OPEN:
678 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800679 duration = mConfigShortAnimTime;
680 break;
681 default:
682 duration = DEFAULT_APP_TRANSITION_DURATION;
683 break;
684 }
Winson Chung5393dff2014-05-08 14:25:43 -0700685 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
686 mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800687 }
688
Winson Chung399f6202014-03-19 10:47:20 -0700689 /**
690 * Return the current thumbnail transition state.
691 */
692 int getThumbnailTransitionState(boolean enter) {
693 if (enter) {
694 if (mNextAppTransitionScaleUp) {
695 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
696 } else {
697 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
698 }
699 } else {
700 if (mNextAppTransitionScaleUp) {
701 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
702 } else {
703 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
704 }
705 }
706 }
707
708 /**
709 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700710 * when a thumbnail is specified with the pending animation override.
Winson Chung399f6202014-03-19 10:47:20 -0700711 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700712 Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, Bitmap thumbnailHeader,
713 final int taskId) {
Winson Chung399f6202014-03-19 10:47:20 -0700714 Animation a;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700715 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chung399f6202014-03-19 10:47:20 -0700716 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700717 final int thumbHeightI = thumbnailHeader.getHeight();
Winson Chung399f6202014-03-19 10:47:20 -0700718 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -0700719 final int appWidth = appRect.width();
Winson Chung399f6202014-03-19 10:47:20 -0700720
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -0700721 float scaleW = appWidth / thumbWidth;
Winson Chunga4ccb862014-08-22 15:26:27 -0700722 float unscaledHeight = thumbHeight * scaleW;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700723 getNextAppTransitionStartRect(taskId, mTmpRect);
724 float unscaledStartY = mTmpRect.top - (unscaledHeight - thumbHeight) / 2f;
Winson Chung399f6202014-03-19 10:47:20 -0700725 if (mNextAppTransitionScaleUp) {
Winson Chunga4ccb862014-08-22 15:26:27 -0700726 // Animation up from the thumbnail to the full screen
727 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700728 mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700729 scale.setInterpolator(mTouchResponseInterpolator);
Winson Chunga4ccb862014-08-22 15:26:27 -0700730 scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Winson Chung399f6202014-03-19 10:47:20 -0700731 Animation alpha = new AlphaAnimation(1, 0);
Winson Chunga4ccb862014-08-22 15:26:27 -0700732 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
733 alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -0700734 final float toX = appRect.left + appRect.width() / 2 -
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700735 (mTmpRect.left + thumbWidth / 2);
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -0700736 final float toY = appRect.top + mNextAppTransitionInsets.top + -unscaledStartY;
737 Animation translate = new TranslateAnimation(0, toX, 0, toY);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700738 translate.setInterpolator(mTouchResponseInterpolator);
Winson Chunga4ccb862014-08-22 15:26:27 -0700739 translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Winson Chung399f6202014-03-19 10:47:20 -0700740
741 // This AnimationSet uses the Interpolators assigned above.
742 AnimationSet set = new AnimationSet(false);
743 set.addAnimation(scale);
744 set.addAnimation(alpha);
Winson Chunga4ccb862014-08-22 15:26:27 -0700745 set.addAnimation(translate);
Winson Chung399f6202014-03-19 10:47:20 -0700746 a = set;
747 } else {
Winson Chunga4ccb862014-08-22 15:26:27 -0700748 // Animation down from the full screen to the thumbnail
749 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700750 mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700751 scale.setInterpolator(mTouchResponseInterpolator);
Winson Chunga4ccb862014-08-22 15:26:27 -0700752 scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
753 Animation alpha = new AlphaAnimation(0f, 1f);
754 alpha.setInterpolator(mThumbnailFadeInInterpolator);
755 alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
756 Animation translate = new TranslateAnimation(0, 0, -unscaledStartY +
757 mNextAppTransitionInsets.top, 0);
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700758 translate.setInterpolator(mTouchResponseInterpolator);
Winson Chunga4ccb862014-08-22 15:26:27 -0700759 translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Winson Chung399f6202014-03-19 10:47:20 -0700760
Winson Chunga4ccb862014-08-22 15:26:27 -0700761 // This AnimationSet uses the Interpolators assigned above.
762 AnimationSet set = new AnimationSet(false);
763 set.addAnimation(scale);
764 set.addAnimation(alpha);
765 set.addAnimation(translate);
766 a = set;
767
768 }
Filip Gruszczynskidfb25d32015-08-14 11:06:18 -0700769 return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700770 mTouchResponseInterpolator);
Winson Chung399f6202014-03-19 10:47:20 -0700771 }
772
773 /**
774 * This alternate animation is created when we are doing a thumbnail transition, for the
775 * activity that is leaving, and the activity that is entering.
776 */
Winson Chunga4ccb862014-08-22 15:26:27 -0700777 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700778 int orientation, int transit, Rect containingFrame, Rect contentInsets,
779 @Nullable Rect surfaceInsets, boolean freeform, int taskId) {
Winson Chung399f6202014-03-19 10:47:20 -0700780 Animation a;
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700781 final int appWidth = containingFrame.width();
782 final int appHeight = containingFrame.height();
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700783 getDefaultNextAppTransitionStartRect(mTmpRect);
784 final int thumbWidthI = mTmpRect.width();
Winson Chung399f6202014-03-19 10:47:20 -0700785 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700786 final int thumbHeightI = mTmpRect.height();
Winson Chung399f6202014-03-19 10:47:20 -0700787 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
788
Winson Chung2820c452014-04-15 15:34:44 -0700789 // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
790 float scale = 1f;
791 int scaledTopDecor = 0;
792
Winson Chung399f6202014-03-19 10:47:20 -0700793 switch (thumbTransitState) {
794 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -0700795 if (freeform) {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700796 a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700797 containingFrame, surfaceInsets, taskId);
Winson Chung2820c452014-04-15 15:34:44 -0700798 } else {
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -0700799 mTmpFromClipRect.set(containingFrame);
800 // exclude top screen decor (status bar) region from the source clip.
801 mTmpFromClipRect.top = contentInsets.top;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700802 // App window scaling up to become full screen
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -0700803 mTmpToClipRect.set(containingFrame);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700804 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
805 // In portrait, we scale the width and clip to the top/left square
806 scale = thumbWidth / appWidth;
807 scaledTopDecor = (int) (scale * contentInsets.top);
808 int unscaledThumbHeight = (int) (thumbHeight / scale);
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -0700809 mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700810 } else {
Filip Gruszczynskidd2ff842015-10-25 13:11:04 -0700811 // In landscape, we scale the height and clip to the top/left square. We
812 // only scale the part that is not covered by status bar and the nav bar.
813 scale = thumbHeight / (appHeight - contentInsets.top
814 - contentInsets.bottom);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700815 scaledTopDecor = (int) (scale * contentInsets.top);
816 int unscaledThumbWidth = (int) (thumbWidth / scale);
Filip Gruszczynskiefd3d1b2015-10-14 13:57:55 -0700817 mTmpFromClipRect.right = mTmpFromClipRect.left + unscaledThumbWidth;
Filip Gruszczynskidd2ff842015-10-25 13:11:04 -0700818 // This removes the navigation bar from the first frame, so it better
819 // matches the thumbnail. We need to do this explicitly in landscape,
820 // because in portrait we already crop vertically.
821 mTmpFromClipRect.bottom = mTmpFromClipRect.bottom - contentInsets.bottom;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700822 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700823
824 mNextAppTransitionInsets.set(contentInsets);
825
826 Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700827 computePivot(mTmpRect.left, scale),
828 computePivot(mTmpRect.top, scale));
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700829 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
830 Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
831
832 AnimationSet set = new AnimationSet(true);
833 set.addAnimation(clipAnim);
834 set.addAnimation(scaleAnim);
835 set.addAnimation(translateAnim);
836 a = set;
Winson Chung2820c452014-04-15 15:34:44 -0700837 }
Winson Chung399f6202014-03-19 10:47:20 -0700838 break;
839 }
840 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
Winson Chunga4ccb862014-08-22 15:26:27 -0700841 // Previous app window during the scale up
Winson Chung399f6202014-03-19 10:47:20 -0700842 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
Winson Chunga4ccb862014-08-22 15:26:27 -0700843 // Fade out the source activity if we are animating to a wallpaper
Winson Chung399f6202014-03-19 10:47:20 -0700844 // activity.
845 a = new AlphaAnimation(1, 0);
846 } else {
Winson Chung399f6202014-03-19 10:47:20 -0700847 a = new AlphaAnimation(1, 1);
848 }
849 break;
850 }
851 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
Winson Chunga4ccb862014-08-22 15:26:27 -0700852 // Target app window during the scale down
853 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
854 // Fade in the destination activity if we are animating from a wallpaper
855 // activity.
856 a = new AlphaAnimation(0, 1);
857 } else {
858 a = new AlphaAnimation(1, 1);
859 }
Winson Chung399f6202014-03-19 10:47:20 -0700860 break;
861 }
862 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
Winson Chunga4ccb862014-08-22 15:26:27 -0700863 // App window scaling down from full screen
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700864 if (freeform) {
865 a = createAspectScaledThumbnailExitFreeformAnimationLocked(
866 containingFrame, surfaceInsets, taskId);
Winson Chung2820c452014-04-15 15:34:44 -0700867 } else {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700868 mTmpFromClipRect.set(containingFrame);
869 mTmpToClipRect.set(containingFrame);
870 // exclude top screen decor (status bar) region from the destination clip.
871 mTmpToClipRect.top = contentInsets.top;
872 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
873 // In portrait, we scale the width and clip to the top/left square
874 scale = thumbWidth / appWidth;
875 scaledTopDecor = (int) (scale * contentInsets.top);
876 int unscaledThumbHeight = (int) (thumbHeight / scale);
877 mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
878 } else {
879 // In landscape, we scale the height and clip to the top/left square. We only
880 // scale the part that is not covered by status bar and the nav bar.
881 scale = thumbHeight / (appHeight - contentInsets.top - contentInsets.bottom);
882 scaledTopDecor = (int) (scale * contentInsets.top);
883 int unscaledThumbWidth = (int) (thumbWidth / scale);
884 mTmpToClipRect.right = mTmpToClipRect.left + unscaledThumbWidth;
885 // This removes the navigation bar from the last frame, so it better matches the
886 // thumbnail. We need to do this explicitly in landscape, because in portrait we
887 // already crop vertically.
888 mTmpToClipRect.bottom = mTmpToClipRect.bottom - contentInsets.bottom;
889 }
890
891 mNextAppTransitionInsets.set(contentInsets);
892
893 Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
894 computePivot(mTmpRect.left, scale),
895 computePivot(mTmpRect.top, scale));
896 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
897 Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
898
899 AnimationSet set = new AnimationSet(true);
900 set.addAnimation(clipAnim);
901 set.addAnimation(scaleAnim);
902 set.addAnimation(translateAnim);
903
904 a = set;
905 a.setZAdjustment(Animation.ZORDER_TOP);
Winson Chung2820c452014-04-15 15:34:44 -0700906 }
Winson Chung399f6202014-03-19 10:47:20 -0700907 break;
908 }
909 default:
910 throw new RuntimeException("Invalid thumbnail transition state");
911 }
912
Winson Chungab79fce2014-11-04 16:15:22 -0800913 int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
914 THUMBNAIL_APP_TRANSITION_DURATION);
915 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
Jorim Jaggi1d763a62015-06-02 17:07:39 -0700916 mTouchResponseInterpolator);
Winson Chung399f6202014-03-19 10:47:20 -0700917 }
918
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700919 private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
920 @Nullable Rect surfaceInsets, int taskId) {
921 getNextAppTransitionStartRect(taskId, mTmpRect);
922 return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
923 true);
924 }
925
926 private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
927 @Nullable Rect surfaceInsets, int taskId) {
928 getNextAppTransitionStartRect(taskId, mTmpRect);
929 return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
930 false);
931 }
932
933 private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
934 Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
935 final float sourceWidth = sourceFrame.width();
936 final float sourceHeight = sourceFrame.height();
937 final float destWidth = destFrame.width();
938 final float destHeight = destFrame.height();
939 final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
940 final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700941 AnimationSet set = new AnimationSet(true);
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700942 final int surfaceInsetsH = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700943 ? 0 : surfaceInsets.left + surfaceInsets.right;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700944 final int surfaceInsetsV = surfaceInsets == null
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700945 ? 0 : surfaceInsets.top + surfaceInsets.bottom;
946 // We want the scaling to happen from the center of the surface. In order to achieve that,
947 // we need to account for surface insets that will be used to enlarge the surface.
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700948 final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
949 final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
950 final ScaleAnimation scale = enter ?
951 new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
952 : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
953 final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
954 final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
955 final int destHCenter = destFrame.left + destFrame.width() / 2;
956 final int destVCenter = destFrame.top + destFrame.height() / 2;
957 final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
958 final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
959 final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
960 : new TranslateAnimation(0, fromX, 0, fromY);
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700961 set.addAnimation(scale);
962 set.addAnimation(translation);
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -0700963
964 final IRemoteCallback callback = mAnimationFinishedCallback;
965 if (callback != null) {
966 set.setAnimationListener(new Animation.AnimationListener() {
967 @Override
968 public void onAnimationStart(Animation animation) { }
969
970 @Override
971 public void onAnimationEnd(Animation animation) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -0800972 mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -0700973 }
974
975 @Override
976 public void onAnimationRepeat(Animation animation) { }
977 });
978 }
Filip Gruszczynski71b0d2d2015-08-12 18:52:26 -0700979 return set;
980 }
981
Winson Chung399f6202014-03-19 10:47:20 -0700982 /**
Winson Chunga4ccb862014-08-22 15:26:27 -0700983 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700984 * when a thumbnail is specified with the pending animation override.
Winson Chunga4ccb862014-08-22 15:26:27 -0700985 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700986 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
987 Bitmap thumbnailHeader) {
Winson Chunga4ccb862014-08-22 15:26:27 -0700988 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -0700989 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700990 final int thumbWidthI = thumbnailHeader.getWidth();
Winson Chunga4ccb862014-08-22 15:26:27 -0700991 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700992 final int thumbHeightI = thumbnailHeader.getHeight();
Winson Chunga4ccb862014-08-22 15:26:27 -0700993 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
994
995 if (mNextAppTransitionScaleUp) {
996 // Animation for the thumbnail zooming from its initial size to the full screen
997 float scaleW = appWidth / thumbWidth;
998 float scaleH = appHeight / thumbHeight;
999 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001000 computePivot(mTmpRect.left, 1 / scaleW),
1001 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001002 scale.setInterpolator(mDecelerateInterpolator);
1003
1004 Animation alpha = new AlphaAnimation(1, 0);
1005 alpha.setInterpolator(mThumbnailFadeOutInterpolator);
1006
1007 // This AnimationSet uses the Interpolators assigned above.
1008 AnimationSet set = new AnimationSet(false);
1009 set.addAnimation(scale);
1010 set.addAnimation(alpha);
1011 a = set;
1012 } else {
1013 // Animation for the thumbnail zooming down from the full screen to its final size
1014 float scaleW = appWidth / thumbWidth;
1015 float scaleH = appHeight / thumbHeight;
1016 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001017 computePivot(mTmpRect.left, 1 / scaleW),
1018 computePivot(mTmpRect.top, 1 / scaleH));
Winson Chunga4ccb862014-08-22 15:26:27 -07001019 }
1020
1021 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1022 }
1023
1024 /**
Winson Chung399f6202014-03-19 10:47:20 -07001025 * This animation is created when we are doing a thumbnail transition, for the activity that is
1026 * leaving, and the activity that is entering.
1027 */
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001028 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
1029 int transit, int taskId) {
1030 final int appWidth = containingFrame.width();
1031 final int appHeight = containingFrame.height();
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001032 Bitmap thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
Winson Chung399f6202014-03-19 10:47:20 -07001033 Animation a;
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001034 getDefaultNextAppTransitionStartRect(mTmpRect);
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001035 final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
Winson Chung399f6202014-03-19 10:47:20 -07001036 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001037 final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
Winson Chung399f6202014-03-19 10:47:20 -07001038 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
1039
1040 switch (thumbTransitState) {
1041 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
1042 // Entering app scales up with the thumbnail
1043 float scaleW = thumbWidth / appWidth;
1044 float scaleH = thumbHeight / appHeight;
1045 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001046 computePivot(mTmpRect.left, scaleW),
1047 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001048 break;
1049 }
1050 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
1051 // Exiting app while the thumbnail is scaling up should fade or stay in place
1052 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
1053 // Fade out while bringing up selected activity. This keeps the
1054 // current activity from showing through a launching wallpaper
1055 // activity.
1056 a = new AlphaAnimation(1, 0);
1057 } else {
1058 // noop animation
1059 a = new AlphaAnimation(1, 1);
1060 }
1061 break;
1062 }
1063 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
1064 // Entering the other app, it should just be visible while we scale the thumbnail
1065 // down above it
1066 a = new AlphaAnimation(1, 1);
1067 break;
1068 }
1069 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
1070 // Exiting the current app, the app should scale down with the thumbnail
1071 float scaleW = thumbWidth / appWidth;
1072 float scaleH = thumbHeight / appHeight;
1073 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001074 computePivot(mTmpRect.left, scaleW),
1075 computePivot(mTmpRect.top, scaleH));
Winson Chung399f6202014-03-19 10:47:20 -07001076
1077 Animation alpha = new AlphaAnimation(1, 0);
1078
1079 AnimationSet set = new AnimationSet(true);
1080 set.addAnimation(scale);
1081 set.addAnimation(alpha);
1082 set.setZAdjustment(Animation.ZORDER_TOP);
1083 a = set;
1084 break;
1085 }
1086 default:
1087 throw new RuntimeException("Invalid thumbnail transition state");
1088 }
1089
1090 return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
1091 }
1092
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001093 private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) {
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001094 getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
1095 final int left = mTmpFromClipRect.left;
1096 final int top = mTmpFromClipRect.top;
1097 mTmpFromClipRect.offset(-left, -top);
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001098 // TODO: Isn't that strange that we ignore exact position of the containingFrame?
1099 mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height());
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001100 AnimationSet set = new AnimationSet(true);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001101 float fromWidth = mTmpFromClipRect.width();
1102 float toWidth = mTmpToClipRect.width();
1103 float fromHeight = mTmpFromClipRect.height();
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001104 // While the window might span the whole display, the actual content will be cropped to the
1105 // system decoration frame, for example when the window is docked. We need to take into
1106 // account the visible height when constructing the animation.
1107 float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom;
1108 int translateAdjustment = 0;
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001109 if (fromWidth <= toWidth && fromHeight <= toHeight) {
1110 // The final window is larger in both dimensions than current window (e.g. we are
1111 // maximizing), so we can simply unclip the new window and there will be no disappearing
1112 // frame.
1113 set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
1114 } else {
1115 // The disappearing window has one larger dimension. We need to apply scaling, so the
1116 // first frame of the entry animation matches the old window.
1117 set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001118 // We might not be going exactly full screen, but instead be aligned under the status
1119 // bar using cropping. We still need to account for the cropped part, which will also
1120 // be scaled.
1121 translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001122 }
1123
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001124 // We animate the translation from the old position of the removed window, to the new
1125 // position of the added window. The latter might not be full screen, for example docked for
1126 // docked windows.
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001127 TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
Filip Gruszczynski2dfcf842015-10-25 13:40:47 -07001128 0, top - containingFrame.top - translateAdjustment, 0);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001129 set.addAnimation(translate);
1130 set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
Filip Gruszczynskie95b0ae2015-09-30 10:55:33 -07001131 set.setZAdjustment(Animation.ZORDER_TOP);
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001132 return set;
1133 }
1134
Jorim Jaggic554b772015-06-04 16:07:57 -07001135 /**
1136 * @return true if and only if the first frame of the transition can be skipped, i.e. the first
1137 * frame of the transition doesn't change the visuals on screen, so we can start
1138 * directly with the second one
1139 */
1140 boolean canSkipFirstFrame() {
1141 return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
1142 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
1143 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL;
1144 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08001145
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001146 /**
1147 *
1148 * @param frame These are the bounds of the window when it finishes the animation. This is where
1149 * the animation must usually finish in entrance animation, as the next frame will
1150 * display the window at these coordinates. In case of exit animation, this is
1151 * where the animation must start, as the frame before the animation is displaying
1152 * the window at these bounds.
1153 * @param insets Knowing where the window will be positioned is not enough. Some parts of the
1154 * window might be obscured, usually by the system windows (status bar and
1155 * navigation bar) and we use content insets to convey that information. This
1156 * usually affects the animation aspects vertically, as the system decoration is
1157 * at the top and the bottom. For example when we animate from full screen to
1158 * recents, we want to exclude the covered parts, because they won't match the
1159 * thumbnail after the last frame is executed.
1160 * @param surfaceInsets In rare situation the surface is larger than the content and we need to
1161 * know about this to make the animation frames match. We currently use
1162 * this for freeform windows, which have larger surfaces to display
1163 * shadows. When we animate them from recents, we want to match the content
1164 * to the recents thumbnail and hence need to account for the surface being
1165 * bigger.
1166 */
Craig Mautner164d4bb2012-11-26 13:51:23 -08001167 Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001168 int orientation, Rect frame, Rect insets, @Nullable Rect surfaceInsets,
1169 boolean isVoiceInteraction, boolean freeform, int taskId) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001170 Animation a;
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001171 if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
1172 || transit == TRANSIT_TASK_OPEN
1173 || transit == TRANSIT_TASK_TO_FRONT)) {
1174 a = loadAnimationRes(lp, enter
1175 ? com.android.internal.R.anim.voice_activity_open_enter
1176 : com.android.internal.R.anim.voice_activity_open_exit);
1177 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1178 "applyAnimation voice:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001179 + " anim=" + a + " transit=" + appTransitionToString(transit)
1180 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001181 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
1182 || transit == TRANSIT_TASK_CLOSE
1183 || transit == TRANSIT_TASK_TO_BACK)) {
1184 a = loadAnimationRes(lp, enter
1185 ? com.android.internal.R.anim.voice_activity_close_enter
1186 : com.android.internal.R.anim.voice_activity_close_exit);
1187 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1188 "applyAnimation voice:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001189 + " anim=" + a + " transit=" + appTransitionToString(transit)
1190 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001191 } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001192 a = createRelaunchAnimation(frame, insets);
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001193 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1194 "applyAnimation:"
1195 + " anim=" + a + " nextAppTransition=" + mNextAppTransition
1196 + " transit=" + appTransitionToString(transit)
1197 + " Callers=" + Debug.getCallers(3));
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001198 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
1199 a = loadAnimationRes(mNextAppTransitionPackage, enter ?
Craig Mautner164d4bb2012-11-26 13:51:23 -08001200 mNextAppTransitionEnter : mNextAppTransitionExit);
1201 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1202 "applyAnimation:"
1203 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001204 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001205 + " Callers=" + Debug.getCallers(3));
Winson Chung044d5292014-11-06 11:05:19 -08001206 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
1207 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
1208 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1209 "applyAnimation:"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001210 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
1211 + " transit=" + appTransitionToString(transit)
1212 + " Callers=" + Debug.getCallers(3));
Chet Haase10e23ab2015-02-11 15:08:38 -08001213 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001214 a = createClipRevealAnimationLocked(transit, enter, frame);
Chet Haase10e23ab2015-02-11 15:08:38 -08001215 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1216 "applyAnimation:"
1217 + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
Filip Gruszczynski49b80af2015-09-24 09:04:26 -07001218 + " transit=" + appTransitionToString(transit)
Chet Haase10e23ab2015-02-11 15:08:38 -08001219 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001220 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001221 a = createScaleUpAnimationLocked(transit, enter, frame);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001222 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1223 "applyAnimation:"
1224 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001225 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001226 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001227 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
1228 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001229 mNextAppTransitionScaleUp =
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001230 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
Winson Chunga4ccb862014-08-22 15:26:27 -07001231 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001232 frame, transit, taskId);
Winson Chunga4ccb862014-08-22 15:26:27 -07001233 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1234 String animName = mNextAppTransitionScaleUp ?
1235 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
1236 Slog.v(TAG, "applyAnimation:"
1237 + " anim=" + a + " nextAppTransition=" + animName
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001238 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Winson Chunga4ccb862014-08-22 15:26:27 -07001239 + " Callers=" + Debug.getCallers(3));
1240 }
1241 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
1242 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
1243 mNextAppTransitionScaleUp =
1244 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
1245 a = createAspectScaledThumbnailEnterExitAnimationLocked(
Filip Gruszczynski541f92c2015-10-25 17:15:06 -07001246 getThumbnailTransitionState(enter), orientation, transit, frame,
1247 insets, surfaceInsets, freeform, taskId);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001248 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
1249 String animName = mNextAppTransitionScaleUp ?
Winson Chunga4ccb862014-08-22 15:26:27 -07001250 "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
Craig Mautner164d4bb2012-11-26 13:51:23 -08001251 Slog.v(TAG, "applyAnimation:"
1252 + " anim=" + a + " nextAppTransition=" + animName
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001253 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001254 + " Callers=" + Debug.getCallers(3));
1255 }
1256 } else {
1257 int animAttr = 0;
1258 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -08001259 case TRANSIT_ACTIVITY_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001260 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001261 ? WindowAnimation_activityOpenEnterAnimation
1262 : WindowAnimation_activityOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001263 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001264 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001265 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001266 ? WindowAnimation_activityCloseEnterAnimation
1267 : WindowAnimation_activityCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001268 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001269 case TRANSIT_TASK_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001270 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001271 ? WindowAnimation_taskOpenEnterAnimation
1272 : WindowAnimation_taskOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001273 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001274 case TRANSIT_TASK_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001275 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001276 ? WindowAnimation_taskCloseEnterAnimation
1277 : WindowAnimation_taskCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001278 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001279 case TRANSIT_TASK_TO_FRONT:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001280 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001281 ? WindowAnimation_taskToFrontEnterAnimation
1282 : WindowAnimation_taskToFrontExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001283 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001284 case TRANSIT_TASK_TO_BACK:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001285 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001286 ? WindowAnimation_taskToBackEnterAnimation
1287 : WindowAnimation_taskToBackExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001288 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001289 case TRANSIT_WALLPAPER_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001290 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001291 ? WindowAnimation_wallpaperOpenEnterAnimation
1292 : WindowAnimation_wallpaperOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001293 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001294 case TRANSIT_WALLPAPER_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001295 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001296 ? WindowAnimation_wallpaperCloseEnterAnimation
1297 : WindowAnimation_wallpaperCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001298 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001299 case TRANSIT_WALLPAPER_INTRA_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001300 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001301 ? WindowAnimation_wallpaperIntraOpenEnterAnimation
1302 : WindowAnimation_wallpaperIntraOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001303 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -08001304 case TRANSIT_WALLPAPER_INTRA_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -08001305 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001306 ? WindowAnimation_wallpaperIntraCloseEnterAnimation
1307 : WindowAnimation_wallpaperIntraCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001308 break;
Craig Mautnerbb742462014-07-07 15:28:55 -07001309 case TRANSIT_TASK_OPEN_BEHIND:
1310 animAttr = enter
1311 ? WindowAnimation_launchTaskBehindSourceAnimation
Craig Mautner3b2cd1d2014-08-25 14:25:54 -07001312 : WindowAnimation_launchTaskBehindTargetAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001313 }
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001314 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001315 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
1316 "applyAnimation:"
1317 + " anim=" + a
1318 + " animAttr=0x" + Integer.toHexString(animAttr)
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001319 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
Craig Mautner164d4bb2012-11-26 13:51:23 -08001320 + " Callers=" + Debug.getCallers(3));
1321 }
1322 return a;
1323 }
1324
1325 void postAnimationCallback() {
1326 if (mNextAppTransitionCallback != null) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001327 mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
1328 mNextAppTransitionCallback));
Craig Mautner164d4bb2012-11-26 13:51:23 -08001329 mNextAppTransitionCallback = null;
1330 }
1331 }
1332
1333 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001334 IRemoteCallback startedCallback) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001335 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001336 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001337 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001338 mNextAppTransitionPackage = packageName;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001339 mNextAppTransitionEnter = enterAnim;
1340 mNextAppTransitionExit = exitAnim;
1341 postAnimationCallback();
1342 mNextAppTransitionCallback = startedCallback;
1343 } else {
1344 postAnimationCallback();
1345 }
1346 }
1347
1348 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001349 int startHeight) {
Craig Mautner164d4bb2012-11-26 13:51:23 -08001350 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001351 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001352 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001353 putDefaultNextAppTransitionCoordinates(startX, startY, startX + startWidth,
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001354 startY + startHeight, null);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001355 postAnimationCallback();
Craig Mautner164d4bb2012-11-26 13:51:23 -08001356 }
1357 }
1358
Chet Haase10e23ab2015-02-11 15:08:38 -08001359 void overridePendingAppTransitionClipReveal(int startX, int startY,
1360 int startWidth, int startHeight) {
1361 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001362 clear();
Chet Haase10e23ab2015-02-11 15:08:38 -08001363 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001364 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
Chet Haase10e23ab2015-02-11 15:08:38 -08001365 postAnimationCallback();
Chet Haase10e23ab2015-02-11 15:08:38 -08001366 }
1367 }
1368
Craig Mautner164d4bb2012-11-26 13:51:23 -08001369 void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
1370 IRemoteCallback startedCallback, boolean scaleUp) {
1371 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001372 clear();
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001373 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
1374 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
Craig Mautner164d4bb2012-11-26 13:51:23 -08001375 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001376 putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001377 postAnimationCallback();
1378 mNextAppTransitionCallback = startedCallback;
1379 } else {
1380 postAnimationCallback();
1381 }
1382 }
1383
Winson Chunga4ccb862014-08-22 15:26:27 -07001384 void overridePendingAppTransitionAspectScaledThumb(Bitmap srcThumb, int startX, int startY,
Winson Chung2e7f3bd2014-09-05 13:17:22 +02001385 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) {
Winson Chunga4ccb862014-08-22 15:26:27 -07001386 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001387 clear();
Winson Chunga4ccb862014-08-22 15:26:27 -07001388 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1389 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Winson Chunga4ccb862014-08-22 15:26:27 -07001390 mNextAppTransitionScaleUp = scaleUp;
Filip Gruszczynski7248c562015-11-09 13:05:40 -08001391 putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight,
1392 srcThumb);
Winson Chunga4ccb862014-08-22 15:26:27 -07001393 postAnimationCallback();
1394 mNextAppTransitionCallback = startedCallback;
1395 } else {
1396 postAnimationCallback();
1397 }
1398 }
1399
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001400 public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001401 IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
1402 boolean scaleUp) {
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001403 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001404 clear();
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001405 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1406 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001407 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi43102412015-11-11 16:28:37 +01001408 if (specs != null) {
1409 for (int i = 0; i < specs.length; i++) {
1410 AppTransitionAnimationSpec spec = specs[i];
1411 if (spec != null) {
1412 mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec);
1413 if (i == 0) {
1414 // In full screen mode, the transition code depends on the default spec
1415 // to be set.
1416 Rect rect = spec.rect;
1417 putDefaultNextAppTransitionCoordinates(rect.left, rect.top,
Filip Gruszczynskie3264d82015-11-20 17:10:04 -08001418 rect.width(), rect.height(), spec.bitmap);
Jorim Jaggi43102412015-11-11 16:28:37 +01001419 }
Filip Gruszczynskid1431422015-09-08 11:18:54 -07001420 }
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001421 }
1422 }
1423 postAnimationCallback();
Filip Gruszczynski1a5203d2015-10-29 17:43:49 -07001424 mNextAppTransitionCallback = onAnimationStartedCallback;
1425 mAnimationFinishedCallback = onAnimationFinishedCallback;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001426 } else {
1427 postAnimationCallback();
1428 }
1429 }
1430
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001431 void overridePendingAppTransitionMultiThumbFuture(
1432 IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
1433 boolean scaleUp) {
1434 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001435 clear();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001436 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
1437 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001438 mNextAppTransitionAnimationsSpecsFuture = specsFuture;
1439 mNextAppTransitionScaleUp = scaleUp;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +01001440 mNextAppTransitionFutureCallback = callback;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001441 }
1442 }
1443
Winson Chung044d5292014-11-06 11:05:19 -08001444 void overrideInPlaceAppTransition(String packageName, int anim) {
1445 if (isTransitionSet()) {
Jorim Jaggi65193992015-11-23 16:49:59 -08001446 clear();
Winson Chung044d5292014-11-06 11:05:19 -08001447 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
1448 mNextAppTransitionPackage = packageName;
1449 mNextAppTransitionInPlace = anim;
1450 } else {
1451 postAnimationCallback();
1452 }
1453 }
1454
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001455 /**
1456 * If a future is set for the app transition specs, fetch it in another thread.
1457 */
1458 private void fetchAppTransitionSpecsFromFuture() {
1459 if (mNextAppTransitionAnimationsSpecsFuture != null) {
1460 mNextAppTransitionAnimationsSpecsPending = true;
1461 final IAppTransitionAnimationSpecsFuture future
1462 = mNextAppTransitionAnimationsSpecsFuture;
1463 mNextAppTransitionAnimationsSpecsFuture = null;
1464 mDefaultExecutor.execute(new Runnable() {
1465 @Override
1466 public void run() {
1467 AppTransitionAnimationSpec[] specs = null;
1468 try {
1469 specs = future.get();
1470 } catch (RemoteException e) {
1471 Slog.w(TAG, "Failed to fetch app transition specs: " + e);
1472 }
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001473 synchronized (mService.mWindowMap) {
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001474 mNextAppTransitionAnimationsSpecsPending = false;
Jorim Jaggi7cc7b082015-11-10 16:06:54 +01001475 overridePendingAppTransitionMultiThumb(specs,
1476 mNextAppTransitionFutureCallback, null /* finishedCallback */,
1477 mNextAppTransitionScaleUp);
1478 mNextAppTransitionFutureCallback = null;
Filip Gruszczynski96daf322015-11-18 18:01:27 -08001479 if (specs != null) {
1480 mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
1481 }
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001482 }
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001483 mService.requestTraversal();
Jorim Jaggi2f7d2922015-10-29 13:08:29 +01001484 }
1485 });
1486 }
1487 }
1488
Craig Mautner164d4bb2012-11-26 13:51:23 -08001489 @Override
1490 public String toString() {
Wale Ogunwale8ebc82a2015-05-13 15:27:12 -07001491 return "mNextAppTransition=" + appTransitionToString(mNextAppTransition);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001492 }
1493
Craig Mautner4b71aa12012-12-27 17:20:01 -08001494 /**
1495 * Returns the human readable name of a window transition.
1496 *
1497 * @param transition The window transition.
1498 * @return The transition symbolic name.
1499 */
1500 public static String appTransitionToString(int transition) {
1501 switch (transition) {
1502 case TRANSIT_UNSET: {
1503 return "TRANSIT_UNSET";
1504 }
1505 case TRANSIT_NONE: {
1506 return "TRANSIT_NONE";
1507 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08001508 case TRANSIT_ACTIVITY_OPEN: {
1509 return "TRANSIT_ACTIVITY_OPEN";
1510 }
1511 case TRANSIT_ACTIVITY_CLOSE: {
1512 return "TRANSIT_ACTIVITY_CLOSE";
1513 }
1514 case TRANSIT_TASK_OPEN: {
1515 return "TRANSIT_TASK_OPEN";
1516 }
1517 case TRANSIT_TASK_CLOSE: {
1518 return "TRANSIT_TASK_CLOSE";
1519 }
1520 case TRANSIT_TASK_TO_FRONT: {
1521 return "TRANSIT_TASK_TO_FRONT";
1522 }
1523 case TRANSIT_TASK_TO_BACK: {
1524 return "TRANSIT_TASK_TO_BACK";
1525 }
1526 case TRANSIT_WALLPAPER_CLOSE: {
1527 return "TRANSIT_WALLPAPER_CLOSE";
1528 }
1529 case TRANSIT_WALLPAPER_OPEN: {
1530 return "TRANSIT_WALLPAPER_OPEN";
1531 }
1532 case TRANSIT_WALLPAPER_INTRA_OPEN: {
1533 return "TRANSIT_WALLPAPER_INTRA_OPEN";
1534 }
1535 case TRANSIT_WALLPAPER_INTRA_CLOSE: {
1536 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
1537 }
Craig Mautnerbb742462014-07-07 15:28:55 -07001538 case TRANSIT_TASK_OPEN_BEHIND: {
1539 return "TRANSIT_TASK_OPEN_BEHIND";
1540 }
Filip Gruszczynski55a309f2015-09-04 17:15:01 -07001541 case TRANSIT_ACTIVITY_RELAUNCH: {
1542 return "TRANSIT_ACTIVITY_RELAUNCH";
1543 }
Craig Mautner4b71aa12012-12-27 17:20:01 -08001544 default: {
1545 return "<UNKNOWN>";
1546 }
1547 }
1548 }
1549
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001550 private String appStateToString() {
1551 switch (mAppTransitionState) {
1552 case APP_STATE_IDLE:
1553 return "APP_STATE_IDLE";
1554 case APP_STATE_READY:
1555 return "APP_STATE_READY";
1556 case APP_STATE_RUNNING:
1557 return "APP_STATE_RUNNING";
1558 case APP_STATE_TIMEOUT:
1559 return "APP_STATE_TIMEOUT";
1560 default:
1561 return "unknown state=" + mAppTransitionState;
1562 }
1563 }
1564
1565 private String transitTypeToString() {
1566 switch (mNextAppTransitionType) {
1567 case NEXT_TRANSIT_TYPE_NONE:
1568 return "NEXT_TRANSIT_TYPE_NONE";
1569 case NEXT_TRANSIT_TYPE_CUSTOM:
1570 return "NEXT_TRANSIT_TYPE_CUSTOM";
Winson Chung044d5292014-11-06 11:05:19 -08001571 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
1572 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001573 case NEXT_TRANSIT_TYPE_SCALE_UP:
1574 return "NEXT_TRANSIT_TYPE_SCALE_UP";
1575 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
1576 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
1577 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
1578 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
Winson Chunga4ccb862014-08-22 15:26:27 -07001579 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
1580 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
1581 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
1582 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001583 default:
1584 return "unknown type=" + mNextAppTransitionType;
1585 }
1586 }
1587
Craig Mautner164d4bb2012-11-26 13:51:23 -08001588 @Override
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001589 public void dump(PrintWriter pw, String prefix) {
1590 pw.print(prefix); pw.println(this);
1591 pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001592 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001593 pw.print(prefix); pw.print("mNextAppTransitionType=");
1594 pw.println(transitTypeToString());
Craig Mautner164d4bb2012-11-26 13:51:23 -08001595 }
1596 switch (mNextAppTransitionType) {
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001597 case NEXT_TRANSIT_TYPE_CUSTOM:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001598 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Craig Mautner164d4bb2012-11-26 13:51:23 -08001599 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001600 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
Craig Mautner164d4bb2012-11-26 13:51:23 -08001601 pw.print(Integer.toHexString(mNextAppTransitionEnter));
1602 pw.print(" mNextAppTransitionExit=0x");
1603 pw.println(Integer.toHexString(mNextAppTransitionExit));
1604 break;
Winson Chung044d5292014-11-06 11:05:19 -08001605 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001606 pw.print(prefix); pw.print("mNextAppTransitionPackage=");
Winson Chung044d5292014-11-06 11:05:19 -08001607 pw.println(mNextAppTransitionPackage);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001608 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
Winson Chung044d5292014-11-06 11:05:19 -08001609 pw.print(Integer.toHexString(mNextAppTransitionInPlace));
1610 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001611 case NEXT_TRANSIT_TYPE_SCALE_UP: {
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001612 getDefaultNextAppTransitionStartRect(mTmpRect);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001613 pw.print(prefix); pw.print("mNextAppTransitionStartX=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001614 pw.print(mTmpRect.left);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001615 pw.print(" mNextAppTransitionStartY=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001616 pw.println(mTmpRect.top);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001617 pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001618 pw.print(mTmpRect.width());
Craig Mautner164d4bb2012-11-26 13:51:23 -08001619 pw.print(" mNextAppTransitionStartHeight=");
Filip Gruszczynskid64ef3e2015-10-27 17:58:02 -07001620 pw.println(mTmpRect.height());
Craig Mautner164d4bb2012-11-26 13:51:23 -08001621 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001622 }
Craig Mautner9a29a5d2012-12-27 19:03:40 -08001623 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
1624 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
Winson Chunga4ccb862014-08-22 15:26:27 -07001625 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001626 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
1627 pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
1628 pw.println(mDefaultNextAppTransitionAnimationSpec);
1629 pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
1630 pw.println(mNextAppTransitionAnimationsSpecs);
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001631 pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
1632 pw.println(mNextAppTransitionScaleUp);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001633 break;
Filip Gruszczynski170192a2015-08-16 17:46:34 -07001634 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08001635 }
1636 if (mNextAppTransitionCallback != null) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001637 pw.print(prefix); pw.print("mNextAppTransitionCallback=");
1638 pw.println(mNextAppTransitionCallback);
Craig Mautner164d4bb2012-11-26 13:51:23 -08001639 }
1640 }
Amith Yamasani4befbec2013-07-10 16:18:01 -07001641
1642 public void setCurrentUser(int newUserId) {
1643 mCurrentUserId = newUserId;
1644 }
Filip Gruszczynski24966d42015-09-05 15:00:00 -07001645
1646 /**
1647 * @return true if transition is not running and should not be skipped, false if transition is
1648 * already running
1649 */
1650 boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent) {
1651 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
1652 + " transit=" + appTransitionToString(transit)
1653 + " " + this
1654 + " alwaysKeepCurrent=" + alwaysKeepCurrent
1655 + " Callers=" + Debug.getCallers(3));
1656 if (!isTransitionSet() || mNextAppTransition == TRANSIT_NONE) {
1657 setAppTransition(transit);
1658 } else if (!alwaysKeepCurrent) {
1659 if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
1660 // Opening a new task always supersedes a close for the anim.
1661 setAppTransition(transit);
1662 } else if (transit == TRANSIT_ACTIVITY_OPEN
1663 && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
1664 // Opening a new activity always supersedes a close for the anim.
1665 setAppTransition(transit);
1666 }
1667 }
1668 boolean prepared = prepare();
1669 if (isTransitionSet()) {
Filip Gruszczynski1a4dfe52015-11-15 10:58:57 -08001670 mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
1671 mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
Filip Gruszczynski24966d42015-09-05 15:00:00 -07001672 }
1673 return prepared;
1674 }
Craig Mautner164d4bb2012-11-26 13:51:23 -08001675}