blob: 30019e77dc75f7649973f0a3f6e56ba7a4c75496 [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
Craig Mautner164d4bb2012-11-26 13:51:23 -080019import android.content.Context;
20import android.graphics.Bitmap;
21import android.graphics.Point;
22import android.os.Debug;
23import android.os.Handler;
24import android.os.IRemoteCallback;
25import android.util.Slog;
26import android.view.WindowManager;
Craig Mautner164d4bb2012-11-26 13:51:23 -080027import android.view.animation.AlphaAnimation;
28import android.view.animation.Animation;
29import android.view.animation.AnimationSet;
30import android.view.animation.AnimationUtils;
Craig Mautner164d4bb2012-11-26 13:51:23 -080031import android.view.animation.Interpolator;
32import android.view.animation.ScaleAnimation;
33
34import com.android.internal.util.DumpUtils.Dump;
35import com.android.server.AttributeCache;
36import com.android.server.wm.WindowManagerService.H;
37
38import java.io.PrintWriter;
39
Craig Mautner9a29a5d2012-12-27 19:03:40 -080040import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
41import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
42import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
43import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
44import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
45import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
46import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
47import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
48import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
49import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
50import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
51import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
52import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
53import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
54import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
55import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
56import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
57import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
58import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
59import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
60
Craig Mautner164d4bb2012-11-26 13:51:23 -080061// State management of app transitions. When we are preparing for a
62// transition, mNextAppTransition will be the kind of transition to
63// perform or TRANSIT_NONE if we are not waiting. If we are waiting,
64// mOpeningApps and mClosingApps are the lists of tokens that will be
65// made visible or hidden at the next transition.
66public class AppTransition implements Dump {
67 private static final String TAG = "AppTransition";
Craig Mautner321bdf52012-12-18 09:53:24 -080068 private static final boolean DEBUG_APP_TRANSITIONS =
69 WindowManagerService.DEBUG_APP_TRANSITIONS;
70 private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM;
71
Craig Mautner9a29a5d2012-12-27 19:03:40 -080072 /** Bit mask that is set for all enter transition. */
Craig Mautner4b71aa12012-12-27 17:20:01 -080073 public static final int TRANSIT_ENTER_MASK = 0x1000;
Craig Mautner9a29a5d2012-12-27 19:03:40 -080074
75 /** Bit mask that is set for all exit transitions. */
Craig Mautner4b71aa12012-12-27 17:20:01 -080076 public static final int TRANSIT_EXIT_MASK = 0x2000;
Craig Mautner9a29a5d2012-12-27 19:03:40 -080077
Craig Mautner4b71aa12012-12-27 17:20:01 -080078 /** Not set up for a transition. */
79 public static final int TRANSIT_UNSET = -1;
80 /** No animation for transition. */
81 public static final int TRANSIT_NONE = 0;
82 /** A window in a new activity is being opened on top of an existing one in the same task. */
83 public static final int TRANSIT_ACTIVITY_OPEN = 6 | TRANSIT_ENTER_MASK;
84 /** The window in the top-most activity is being closed to reveal the
85 * previous activity in the same task. */
86 public static final int TRANSIT_ACTIVITY_CLOSE = 7 | TRANSIT_EXIT_MASK;
87 /** A window in a new task is being opened on top of an existing one
88 * in another activity's task. */
89 public static final int TRANSIT_TASK_OPEN = 8 | TRANSIT_ENTER_MASK;
90 /** A window in the top-most activity is being closed to reveal the
91 * previous activity in a different task. */
92 public static final int TRANSIT_TASK_CLOSE = 9 | TRANSIT_EXIT_MASK;
93 /** A window in an existing task is being displayed on top of an existing one
94 * in another activity's task. */
95 public static final int TRANSIT_TASK_TO_FRONT = 10 | TRANSIT_ENTER_MASK;
96 /** A window in an existing task is being put below all other tasks. */
97 public static final int TRANSIT_TASK_TO_BACK = 11 | TRANSIT_EXIT_MASK;
Craig Mautner9a29a5d2012-12-27 19:03:40 -080098 /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that
99 * does, effectively closing the wallpaper. */
Craig Mautner4b71aa12012-12-27 17:20:01 -0800100 public static final int TRANSIT_WALLPAPER_CLOSE = 12 | TRANSIT_EXIT_MASK;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800101 /** A window in a new activity that does have a wallpaper is being opened on one that didn't,
102 * effectively opening the wallpaper. */
Craig Mautner4b71aa12012-12-27 17:20:01 -0800103 public static final int TRANSIT_WALLPAPER_OPEN = 13 | TRANSIT_ENTER_MASK;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800104 /** A window in a new activity is being opened on top of an existing one, and both are on top
105 * of the wallpaper. */
Craig Mautner4b71aa12012-12-27 17:20:01 -0800106 public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14 | TRANSIT_ENTER_MASK;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800107 /** The window in the top-most activity is being closed to reveal the previous activity, and
108 * both are on top of the wallpaper. */
Craig Mautner4b71aa12012-12-27 17:20:01 -0800109 public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15 | TRANSIT_EXIT_MASK;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800110
Craig Mautner321bdf52012-12-18 09:53:24 -0800111 /** Fraction of animation at which the recents thumbnail becomes completely transparent */
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800112 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.25f;
Craig Mautner321bdf52012-12-18 09:53:24 -0800113
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800114 private static final long DEFAULT_APP_TRANSITION_DURATION = 250;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800115
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800116 private final Context mContext;
117 private final Handler mH;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800118
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800119 private int mNextAppTransition = TRANSIT_UNSET;
120
121 private static final int NEXT_TRANSIT_TYPE_NONE = 0;
122 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
123 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
124 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
125 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
126 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
127
128 private String mNextAppTransitionPackage;
129 private Bitmap mNextAppTransitionThumbnail;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800130 // Used for thumbnail transitions. True if we're scaling up, false if scaling down
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800131 private boolean mNextAppTransitionScaleUp;
132 private IRemoteCallback mNextAppTransitionCallback;
133 private int mNextAppTransitionEnter;
134 private int mNextAppTransitionExit;
135 private int mNextAppTransitionStartX;
136 private int mNextAppTransitionStartY;
137 private int mNextAppTransitionStartWidth;
138 private int mNextAppTransitionStartHeight;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800139
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800140 private final static int APP_STATE_IDLE = 0;
141 private final static int APP_STATE_READY = 1;
142 private final static int APP_STATE_RUNNING = 2;
143 private final static int APP_STATE_TIMEOUT = 3;
144 private int mAppTransitionState = APP_STATE_IDLE;
145
146 private final int mConfigShortAnimTime;
Craig Mautner321bdf52012-12-18 09:53:24 -0800147 private final Interpolator mDecelerateInterpolator;
148 private final Interpolator mThumbnailFadeoutInterpolator;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800149
150 AppTransition(Context context, Handler h) {
151 mContext = context;
152 mH = h;
153 mConfigShortAnimTime = context.getResources().getInteger(
154 com.android.internal.R.integer.config_shortAnimTime);
Craig Mautner321bdf52012-12-18 09:53:24 -0800155 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
156 com.android.internal.R.interpolator.decelerate_cubic);
157 mThumbnailFadeoutInterpolator = new Interpolator() {
158 @Override
159 public float getInterpolation(float input) {
160 // Linear response for first fraction, then complete after that.
161 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) {
162 return input / RECENTS_THUMBNAIL_FADEOUT_FRACTION;
163 }
164 return 1.0f;
165 }
166 };
Craig Mautner164d4bb2012-11-26 13:51:23 -0800167 }
168
169 boolean isTransitionSet() {
170 return mNextAppTransition != TRANSIT_UNSET;
171 }
172
173 boolean isTransitionNone() {
174 return mNextAppTransition == TRANSIT_NONE;
175 }
176
177 boolean isTransitionEqual(int transit) {
178 return mNextAppTransition == transit;
179 }
180
181 int getAppTransition() {
Craig Mautner321bdf52012-12-18 09:53:24 -0800182 return mNextAppTransition;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800183 }
184
185 void setAppTransition(int transit) {
186 mNextAppTransition = transit;
187 }
188
189 boolean isReady() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800190 return mAppTransitionState == APP_STATE_READY
191 || mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800192 }
193
Craig Mautnerae446592012-12-06 19:05:05 -0800194 void setReady() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800195 mAppTransitionState = APP_STATE_READY;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800196 }
197
198 boolean isRunning() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800199 return mAppTransitionState == APP_STATE_RUNNING;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800200 }
201
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800202 void setIdle() {
203 mAppTransitionState = APP_STATE_IDLE;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800204 }
205
206 boolean isTimeout() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800207 return mAppTransitionState == APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800208 }
209
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800210 void setTimeout() {
211 mAppTransitionState = APP_STATE_TIMEOUT;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800212 }
213
214 Bitmap getNextAppTransitionThumbnail() {
215 return mNextAppTransitionThumbnail;
216 }
217
218 void getStartingPoint(Point outPoint) {
219 outPoint.x = mNextAppTransitionStartX;
220 outPoint.y = mNextAppTransitionStartY;
221 }
222
Craig Mautner164d4bb2012-11-26 13:51:23 -0800223 void prepare() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800224 if (!isRunning()) {
225 mAppTransitionState = APP_STATE_IDLE;
226 }
Craig Mautner164d4bb2012-11-26 13:51:23 -0800227 }
228
229 void goodToGo() {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800230 mNextAppTransition = TRANSIT_UNSET;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800231 mAppTransitionState = APP_STATE_RUNNING;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800232 }
233
234 void clear() {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800235 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800236 mNextAppTransitionPackage = null;
237 mNextAppTransitionThumbnail = null;
238 }
239
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800240 void freeze() {
241 setAppTransition(AppTransition.TRANSIT_UNSET);
242 clear();
243 setReady();
244 }
245
Craig Mautner164d4bb2012-11-26 13:51:23 -0800246 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
247 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
248 + (lp != null ? lp.packageName : null)
249 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
250 if (lp != null && lp.windowAnimations != 0) {
251 // If this is a system resource, don't try to load it from the
252 // application resources. It is nice to avoid loading application
253 // resources if we can.
254 String packageName = lp.packageName != null ? lp.packageName : "android";
255 int resId = lp.windowAnimations;
256 if ((resId&0xFF000000) == 0x01000000) {
257 packageName = "android";
258 }
259 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
260 + packageName);
261 return AttributeCache.instance().get(packageName, resId,
262 com.android.internal.R.styleable.WindowAnimation);
263 }
264 return null;
265 }
266
267 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
268 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
269 + packageName + " resId=0x" + Integer.toHexString(resId));
270 if (packageName != null) {
271 if ((resId&0xFF000000) == 0x01000000) {
272 packageName = "android";
273 }
274 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
275 + packageName);
276 return AttributeCache.instance().get(packageName, resId,
277 com.android.internal.R.styleable.WindowAnimation);
278 }
279 return null;
280 }
281
282 Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
283 int anim = 0;
284 Context context = mContext;
285 if (animAttr >= 0) {
286 AttributeCache.Entry ent = getCachedAnimations(lp);
287 if (ent != null) {
288 context = ent.context;
289 anim = ent.array.getResourceId(animAttr, 0);
290 }
291 }
292 if (anim != 0) {
293 return AnimationUtils.loadAnimation(context, anim);
294 }
295 return null;
296 }
297
298 private Animation loadAnimation(String packageName, int resId) {
299 int anim = 0;
300 Context context = mContext;
301 if (resId >= 0) {
302 AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
303 if (ent != null) {
304 context = ent.context;
305 anim = resId;
306 }
307 }
308 if (anim != 0) {
309 return AnimationUtils.loadAnimation(context, anim);
310 }
311 return null;
312 }
313
Craig Mautner164d4bb2012-11-26 13:51:23 -0800314 /**
315 * Compute the pivot point for an animation that is scaling from a small
316 * rect on screen to a larger rect. The pivot point varies depending on
317 * the distance between the inner and outer edges on both sides. This
318 * function computes the pivot point for one dimension.
319 * @param startPos Offset from left/top edge of outer rectangle to
320 * left/top edge of inner rectangle.
321 * @param finalScale The scaling factor between the size of the outer
322 * and inner rectangles.
323 */
324 private static float computePivot(int startPos, float finalScale) {
325 final float denom = finalScale-1;
326 if (Math.abs(denom) < .0001f) {
327 return startPos;
328 }
329 return -startPos / denom;
330 }
331
332 private Animation createScaleUpAnimationLocked(int transit, boolean enter,
333 int appWidth, int appHeight) {
334 Animation a = null;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800335 if (enter) {
336 // Entering app zooms out from the center of the initial rect.
337 float scaleW = mNextAppTransitionStartWidth / (float) appWidth;
338 float scaleH = mNextAppTransitionStartHeight / (float) appHeight;
339 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
340 computePivot(mNextAppTransitionStartX, scaleW),
341 computePivot(mNextAppTransitionStartY, scaleH));
Craig Mautner321bdf52012-12-18 09:53:24 -0800342 scale.setInterpolator(mDecelerateInterpolator);
343
Craig Mautner164d4bb2012-11-26 13:51:23 -0800344 Animation alpha = new AlphaAnimation(0, 1);
Craig Mautner321bdf52012-12-18 09:53:24 -0800345 alpha.setInterpolator(mThumbnailFadeoutInterpolator);
346
347 AnimationSet set = new AnimationSet(false);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800348 set.addAnimation(scale);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800349 set.addAnimation(alpha);
350 set.setDetachWallpaper(true);
351 a = set;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800352 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
353 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
Craig Mautner321bdf52012-12-18 09:53:24 -0800354 // If we are on top of the wallpaper, we need an animation that
355 // correctly handles the wallpaper staying static behind all of
356 // the animated elements. To do this, will just have the existing
357 // element fade out.
358 a = new AlphaAnimation(1, 0);
359 a.setDetachWallpaper(true);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800360 } else {
Craig Mautner321bdf52012-12-18 09:53:24 -0800361 // For normal animations, the exiting element just holds in place.
362 a = new AlphaAnimation(1, 1);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800363 }
Craig Mautner321bdf52012-12-18 09:53:24 -0800364
365 // Pick the desired duration. If this is an inter-activity transition,
366 // it is the standard duration for that. Otherwise we use the longer
367 // task transition duration.
368 final long duration;
369 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800370 case TRANSIT_ACTIVITY_OPEN:
371 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800372 duration = mConfigShortAnimTime;
373 break;
374 default:
375 duration = DEFAULT_APP_TRANSITION_DURATION;
376 break;
377 }
378 a.setDuration(duration);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800379 a.setFillAfter(true);
Craig Mautner321bdf52012-12-18 09:53:24 -0800380 a.setInterpolator(mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800381 a.initialize(appWidth, appHeight, appWidth, appHeight);
382 return a;
383 }
384
385 Animation createThumbnailAnimationLocked(int transit, boolean enter, boolean thumb,
386 int appWidth, int appHeight) {
387 Animation a;
388 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
389 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
390 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
391 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800392 if (thumb) {
393 // Animation for zooming thumbnail from its initial size to
394 // filling the screen.
395 if (mNextAppTransitionScaleUp) {
396 float scaleW = appWidth / thumbWidth;
397 float scaleH = appHeight / thumbHeight;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800398 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
399 computePivot(mNextAppTransitionStartX, 1 / scaleW),
400 computePivot(mNextAppTransitionStartY, 1 / scaleH));
Craig Mautner321bdf52012-12-18 09:53:24 -0800401 scale.setInterpolator(mDecelerateInterpolator);
402
Craig Mautner164d4bb2012-11-26 13:51:23 -0800403 Animation alpha = new AlphaAnimation(1, 0);
Craig Mautner321bdf52012-12-18 09:53:24 -0800404 alpha.setInterpolator(mThumbnailFadeoutInterpolator);
405
406 // This AnimationSet uses the Interpolators assigned above.
407 AnimationSet set = new AnimationSet(false);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800408 set.addAnimation(scale);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800409 set.addAnimation(alpha);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800410 a = set;
411 } else {
412 float scaleW = appWidth / thumbWidth;
413 float scaleH = appHeight / thumbHeight;
Craig Mautner321bdf52012-12-18 09:53:24 -0800414 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Craig Mautner164d4bb2012-11-26 13:51:23 -0800415 computePivot(mNextAppTransitionStartX, 1 / scaleW),
416 computePivot(mNextAppTransitionStartY, 1 / scaleH));
Craig Mautner164d4bb2012-11-26 13:51:23 -0800417 }
418 } else if (enter) {
419 // Entering app zooms out from the center of the thumbnail.
420 if (mNextAppTransitionScaleUp) {
421 float scaleW = thumbWidth / appWidth;
422 float scaleH = thumbHeight / appHeight;
Craig Mautner321bdf52012-12-18 09:53:24 -0800423 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
Craig Mautner164d4bb2012-11-26 13:51:23 -0800424 computePivot(mNextAppTransitionStartX, scaleW),
425 computePivot(mNextAppTransitionStartY, scaleH));
Craig Mautner164d4bb2012-11-26 13:51:23 -0800426 } else {
427 // noop animation
428 a = new AlphaAnimation(1, 1);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800429 }
430 } else {
431 // Exiting app
432 if (mNextAppTransitionScaleUp) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800433 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800434 // Fade out while bringing up selected activity. This keeps the
435 // current activity from showing through a launching wallpaper
436 // activity.
437 a = new AlphaAnimation(1, 0);
438 } else {
439 // noop animation
440 a = new AlphaAnimation(1, 1);
441 }
Craig Mautner164d4bb2012-11-26 13:51:23 -0800442 } else {
443 float scaleW = thumbWidth / appWidth;
444 float scaleH = thumbHeight / appHeight;
445 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
446 computePivot(mNextAppTransitionStartX, scaleW),
447 computePivot(mNextAppTransitionStartY, scaleH));
Craig Mautner321bdf52012-12-18 09:53:24 -0800448
Craig Mautner164d4bb2012-11-26 13:51:23 -0800449 Animation alpha = new AlphaAnimation(1, 0);
Craig Mautner321bdf52012-12-18 09:53:24 -0800450
451 AnimationSet set = new AnimationSet(true);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800452 set.addAnimation(scale);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800453 set.addAnimation(alpha);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800454 set.setZAdjustment(Animation.ZORDER_TOP);
455 a = set;
456 }
457 }
Craig Mautner321bdf52012-12-18 09:53:24 -0800458
459 // Pick the desired duration. If this is an inter-activity transition,
460 // it is the standard duration for that. Otherwise we use the longer
461 // task transition duration.
462 final long duration;
463 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800464 case TRANSIT_ACTIVITY_OPEN:
465 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner321bdf52012-12-18 09:53:24 -0800466 duration = mConfigShortAnimTime;
467 break;
468 default:
469 duration = DEFAULT_APP_TRANSITION_DURATION;
470 break;
471 }
472 a.setDuration(duration);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800473 a.setFillAfter(true);
Craig Mautner321bdf52012-12-18 09:53:24 -0800474 a.setInterpolator(mDecelerateInterpolator);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800475 a.initialize(appWidth, appHeight, appWidth, appHeight);
476 return a;
477 }
478
479
480 Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
481 int appWidth, int appHeight) {
482 Animation a;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800483 if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800484 a = loadAnimation(mNextAppTransitionPackage, enter ?
485 mNextAppTransitionEnter : mNextAppTransitionExit);
486 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
487 "applyAnimation:"
488 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
489 + " transit=" + transit + " isEntrance=" + enter
490 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800491 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800492 a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
493 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
494 "applyAnimation:"
495 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
496 + " transit=" + transit + " isEntrance=" + enter
497 + " Callers=" + Debug.getCallers(3));
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800498 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
499 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
Craig Mautner164d4bb2012-11-26 13:51:23 -0800500 mNextAppTransitionScaleUp =
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800501 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
Craig Mautner164d4bb2012-11-26 13:51:23 -0800502 a = createThumbnailAnimationLocked(transit, enter, false, appWidth, appHeight);
503 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
504 String animName = mNextAppTransitionScaleUp ?
505 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
506 Slog.v(TAG, "applyAnimation:"
507 + " anim=" + a + " nextAppTransition=" + animName
508 + " transit=" + transit + " isEntrance=" + enter
509 + " Callers=" + Debug.getCallers(3));
510 }
511 } else {
512 int animAttr = 0;
513 switch (transit) {
Craig Mautner4b71aa12012-12-27 17:20:01 -0800514 case TRANSIT_ACTIVITY_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800515 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800516 ? WindowAnimation_activityOpenEnterAnimation
517 : WindowAnimation_activityOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800518 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800519 case TRANSIT_ACTIVITY_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800520 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800521 ? WindowAnimation_activityCloseEnterAnimation
522 : WindowAnimation_activityCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800523 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800524 case TRANSIT_TASK_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800525 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800526 ? WindowAnimation_taskOpenEnterAnimation
527 : WindowAnimation_taskOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800528 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800529 case TRANSIT_TASK_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800530 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800531 ? WindowAnimation_taskCloseEnterAnimation
532 : WindowAnimation_taskCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800533 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800534 case TRANSIT_TASK_TO_FRONT:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800535 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800536 ? WindowAnimation_taskToFrontEnterAnimation
537 : WindowAnimation_taskToFrontExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800538 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800539 case TRANSIT_TASK_TO_BACK:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800540 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800541 ? WindowAnimation_taskToBackEnterAnimation
542 : WindowAnimation_taskToBackExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800543 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800544 case TRANSIT_WALLPAPER_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800545 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800546 ? WindowAnimation_wallpaperOpenEnterAnimation
547 : WindowAnimation_wallpaperOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800548 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800549 case TRANSIT_WALLPAPER_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800550 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800551 ? WindowAnimation_wallpaperCloseEnterAnimation
552 : WindowAnimation_wallpaperCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800553 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800554 case TRANSIT_WALLPAPER_INTRA_OPEN:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800555 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800556 ? WindowAnimation_wallpaperIntraOpenEnterAnimation
557 : WindowAnimation_wallpaperIntraOpenExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800558 break;
Craig Mautner4b71aa12012-12-27 17:20:01 -0800559 case TRANSIT_WALLPAPER_INTRA_CLOSE:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800560 animAttr = enter
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800561 ? WindowAnimation_wallpaperIntraCloseEnterAnimation
562 : WindowAnimation_wallpaperIntraCloseExitAnimation;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800563 break;
564 }
565 a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
566 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
567 "applyAnimation:"
568 + " anim=" + a
569 + " animAttr=0x" + Integer.toHexString(animAttr)
570 + " transit=" + transit + " isEntrance=" + enter
571 + " Callers=" + Debug.getCallers(3));
572 }
573 return a;
574 }
575
576 void postAnimationCallback() {
577 if (mNextAppTransitionCallback != null) {
578 mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, mNextAppTransitionCallback));
579 mNextAppTransitionCallback = null;
580 }
581 }
582
583 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
584 IRemoteCallback startedCallback) {
585 if (isTransitionSet()) {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800586 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800587 mNextAppTransitionPackage = packageName;
588 mNextAppTransitionThumbnail = null;
589 mNextAppTransitionEnter = enterAnim;
590 mNextAppTransitionExit = exitAnim;
591 postAnimationCallback();
592 mNextAppTransitionCallback = startedCallback;
593 } else {
594 postAnimationCallback();
595 }
596 }
597
598 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
599 int startHeight) {
600 if (isTransitionSet()) {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800601 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800602 mNextAppTransitionPackage = null;
603 mNextAppTransitionThumbnail = null;
604 mNextAppTransitionStartX = startX;
605 mNextAppTransitionStartY = startY;
606 mNextAppTransitionStartWidth = startWidth;
607 mNextAppTransitionStartHeight = startHeight;
608 postAnimationCallback();
609 mNextAppTransitionCallback = null;
610 }
611 }
612
613 void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
614 IRemoteCallback startedCallback, boolean scaleUp) {
615 if (isTransitionSet()) {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800616 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
617 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
Craig Mautner164d4bb2012-11-26 13:51:23 -0800618 mNextAppTransitionPackage = null;
619 mNextAppTransitionThumbnail = srcThumb;
620 mNextAppTransitionScaleUp = scaleUp;
621 mNextAppTransitionStartX = startX;
622 mNextAppTransitionStartY = startY;
623 postAnimationCallback();
624 mNextAppTransitionCallback = startedCallback;
625 } else {
626 postAnimationCallback();
627 }
628 }
629
630 @Override
631 public String toString() {
632 return "mNextAppTransition=0x" + Integer.toHexString(mNextAppTransition);
633 }
634
Craig Mautner4b71aa12012-12-27 17:20:01 -0800635 /**
636 * Returns the human readable name of a window transition.
637 *
638 * @param transition The window transition.
639 * @return The transition symbolic name.
640 */
641 public static String appTransitionToString(int transition) {
642 switch (transition) {
643 case TRANSIT_UNSET: {
644 return "TRANSIT_UNSET";
645 }
646 case TRANSIT_NONE: {
647 return "TRANSIT_NONE";
648 }
649 case TRANSIT_EXIT_MASK: {
650 return "TRANSIT_EXIT_MASK";
651 }
652 case TRANSIT_ACTIVITY_OPEN: {
653 return "TRANSIT_ACTIVITY_OPEN";
654 }
655 case TRANSIT_ACTIVITY_CLOSE: {
656 return "TRANSIT_ACTIVITY_CLOSE";
657 }
658 case TRANSIT_TASK_OPEN: {
659 return "TRANSIT_TASK_OPEN";
660 }
661 case TRANSIT_TASK_CLOSE: {
662 return "TRANSIT_TASK_CLOSE";
663 }
664 case TRANSIT_TASK_TO_FRONT: {
665 return "TRANSIT_TASK_TO_FRONT";
666 }
667 case TRANSIT_TASK_TO_BACK: {
668 return "TRANSIT_TASK_TO_BACK";
669 }
670 case TRANSIT_WALLPAPER_CLOSE: {
671 return "TRANSIT_WALLPAPER_CLOSE";
672 }
673 case TRANSIT_WALLPAPER_OPEN: {
674 return "TRANSIT_WALLPAPER_OPEN";
675 }
676 case TRANSIT_WALLPAPER_INTRA_OPEN: {
677 return "TRANSIT_WALLPAPER_INTRA_OPEN";
678 }
679 case TRANSIT_WALLPAPER_INTRA_CLOSE: {
680 return "TRANSIT_WALLPAPER_INTRA_CLOSE";
681 }
682 default: {
683 return "<UNKNOWN>";
684 }
685 }
686 }
687
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800688 private String appStateToString() {
689 switch (mAppTransitionState) {
690 case APP_STATE_IDLE:
691 return "APP_STATE_IDLE";
692 case APP_STATE_READY:
693 return "APP_STATE_READY";
694 case APP_STATE_RUNNING:
695 return "APP_STATE_RUNNING";
696 case APP_STATE_TIMEOUT:
697 return "APP_STATE_TIMEOUT";
698 default:
699 return "unknown state=" + mAppTransitionState;
700 }
701 }
702
703 private String transitTypeToString() {
704 switch (mNextAppTransitionType) {
705 case NEXT_TRANSIT_TYPE_NONE:
706 return "NEXT_TRANSIT_TYPE_NONE";
707 case NEXT_TRANSIT_TYPE_CUSTOM:
708 return "NEXT_TRANSIT_TYPE_CUSTOM";
709 case NEXT_TRANSIT_TYPE_SCALE_UP:
710 return "NEXT_TRANSIT_TYPE_SCALE_UP";
711 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
712 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
713 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
714 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
715 default:
716 return "unknown type=" + mNextAppTransitionType;
717 }
718 }
719
Craig Mautner164d4bb2012-11-26 13:51:23 -0800720 @Override
721 public void dump(PrintWriter pw) {
722 pw.print(" " + this);
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800723 pw.print(" mAppTransitionState="); pw.println(appStateToString());
724 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
725 pw.print(" mNextAppTransitionType="); pw.println(transitTypeToString());
Craig Mautner164d4bb2012-11-26 13:51:23 -0800726 }
727 switch (mNextAppTransitionType) {
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800728 case NEXT_TRANSIT_TYPE_CUSTOM:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800729 pw.print(" mNextAppTransitionPackage=");
730 pw.println(mNextAppTransitionPackage);
731 pw.print(" mNextAppTransitionEnter=0x");
732 pw.print(Integer.toHexString(mNextAppTransitionEnter));
733 pw.print(" mNextAppTransitionExit=0x");
734 pw.println(Integer.toHexString(mNextAppTransitionExit));
735 break;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800736 case NEXT_TRANSIT_TYPE_SCALE_UP:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800737 pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
738 pw.print(" mNextAppTransitionStartY=");
739 pw.println(mNextAppTransitionStartY);
740 pw.print(" mNextAppTransitionStartWidth=");
741 pw.print(mNextAppTransitionStartWidth);
742 pw.print(" mNextAppTransitionStartHeight=");
743 pw.println(mNextAppTransitionStartHeight);
744 break;
Craig Mautner9a29a5d2012-12-27 19:03:40 -0800745 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
746 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
Craig Mautner164d4bb2012-11-26 13:51:23 -0800747 pw.print(" mNextAppTransitionThumbnail=");
748 pw.print(mNextAppTransitionThumbnail);
749 pw.print(" mNextAppTransitionStartX=");
750 pw.print(mNextAppTransitionStartX);
751 pw.print(" mNextAppTransitionStartY=");
752 pw.println(mNextAppTransitionStartY);
753 pw.print(" mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
754 break;
755 }
756 if (mNextAppTransitionCallback != null) {
757 pw.print(" mNextAppTransitionCallback=");
758 pw.println(mNextAppTransitionCallback);
759 }
760 }
761}