1 /* 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 17 package com.android.server.wm; 18 19 import android.content.Context; 20 import android.content.res.Configuration; 21 import android.graphics.Bitmap; 22 import android.graphics.Rect; 23 import android.os.Debug; 24 import android.os.Handler; 25 import android.os.IRemoteCallback; 26 import android.util.Slog; 27 import android.view.WindowManager; 28 import android.view.animation.AlphaAnimation; 29 import android.view.animation.Animation; 30 import android.view.animation.AnimationSet; 31 import android.view.animation.AnimationUtils; 32 import android.view.animation.ClipRectAnimation; 33 import android.view.animation.Interpolator; 34 import android.view.animation.ScaleAnimation; 35 import android.view.animation.TranslateAnimation; 36 import com.android.internal.util.DumpUtils.Dump; 37 import com.android.server.AttributeCache; 38 import com.android.server.wm.WindowManagerService.H; 39 40 import java.io.PrintWriter; 41 42 import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation; 43 import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation; 44 import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation; 45 import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; 46 import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation; 47 import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation; 48 import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation; 49 import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation; 50 import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation; 51 import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation; 52 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation; 53 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation; 54 import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation; 55 import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation; 56 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; 57 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; 58 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation; 59 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation; 60 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation; 61 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; 62 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation; 63 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; 64 65 // State management of app transitions. When we are preparing for a 66 // transition, mNextAppTransition will be the kind of transition to 67 // perform or TRANSIT_NONE if we are not waiting. If we are waiting, 68 // mOpeningApps and mClosingApps are the lists of tokens that will be 69 // made visible or hidden at the next transition. 70 public class AppTransition implements Dump { 71 private static final String TAG = "AppTransition"; 72 private static final boolean DEBUG_APP_TRANSITIONS = 73 WindowManagerService.DEBUG_APP_TRANSITIONS; 74 private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM; 75 76 77 /** Not set up for a transition. */ 78 public static final int TRANSIT_UNSET = -1; 79 /** No animation for transition. */ 80 public static final int TRANSIT_NONE = 0; 81 /** A window in a new activity is being opened on top of an existing one in the same task. */ 82 public static final int TRANSIT_ACTIVITY_OPEN = 6; 83 /** The window in the top-most activity is being closed to reveal the 84 * previous activity in the same task. */ 85 public static final int TRANSIT_ACTIVITY_CLOSE = 7; 86 /** A window in a new task is being opened on top of an existing one 87 * in another activity's task. */ 88 public static final int TRANSIT_TASK_OPEN = 8; 89 /** A window in the top-most activity is being closed to reveal the 90 * previous activity in a different task. */ 91 public static final int TRANSIT_TASK_CLOSE = 9; 92 /** A window in an existing task is being displayed on top of an existing one 93 * in another activity's task. */ 94 public static final int TRANSIT_TASK_TO_FRONT = 10; 95 /** A window in an existing task is being put below all other tasks. */ 96 public static final int TRANSIT_TASK_TO_BACK = 11; 97 /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that 98 * does, effectively closing the wallpaper. */ 99 public static final int TRANSIT_WALLPAPER_CLOSE = 12; 100 /** A window in a new activity that does have a wallpaper is being opened on one that didn't, 101 * effectively opening the wallpaper. */ 102 public static final int TRANSIT_WALLPAPER_OPEN = 13; 103 /** A window in a new activity is being opened on top of an existing one, and both are on top 104 * of the wallpaper. */ 105 public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14; 106 /** The window in the top-most activity is being closed to reveal the previous activity, and 107 * both are on top of the wallpaper. */ 108 public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15; 109 /** A window in a new task is being opened behind an existing one in another activity's task. 110 * The new window will show briefly and then be gone. */ 111 public static final int TRANSIT_TASK_OPEN_BEHIND = 16; 112 /** A window in a task is being animated in-place. */ 113 public static final int TRANSIT_TASK_IN_PLACE = 17; 114 115 /** Fraction of animation at which the recents thumbnail stays completely transparent */ 116 private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.7f; 117 /** Fraction of animation at which the recents thumbnail becomes completely transparent */ 118 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.3f; 119 120 private static final int DEFAULT_APP_TRANSITION_DURATION = 250; 121 private static final int THUMBNAIL_APP_TRANSITION_DURATION = 325; 122 private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 325; 123 124 private final Context mContext; 125 private final Handler mH; 126 127 private int mNextAppTransition = TRANSIT_UNSET; 128 129 private static final int NEXT_TRANSIT_TYPE_NONE = 0; 130 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1; 131 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2; 132 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3; 133 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4; 134 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5; 135 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6; 136 private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7; 137 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; 138 139 // These are the possible states for the enter/exit activities during a thumbnail transition 140 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0; 141 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1; 142 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2; 143 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3; 144 145 private String mNextAppTransitionPackage; 146 private Bitmap mNextAppTransitionThumbnail; 147 // Used for thumbnail transitions. True if we're scaling up, false if scaling down 148 private boolean mNextAppTransitionScaleUp; 149 private IRemoteCallback mNextAppTransitionCallback; 150 private int mNextAppTransitionEnter; 151 private int mNextAppTransitionExit; 152 private int mNextAppTransitionInPlace; 153 private int mNextAppTransitionStartX; 154 private int mNextAppTransitionStartY; 155 private int mNextAppTransitionStartWidth; 156 private int mNextAppTransitionStartHeight; 157 private Rect mNextAppTransitionInsets = new Rect(); 158 159 private Rect mTmpFromClipRect = new Rect(); 160 private Rect mTmpToClipRect = new Rect(); 161 162 private final static int APP_STATE_IDLE = 0; 163 private final static int APP_STATE_READY = 1; 164 private final static int APP_STATE_RUNNING = 2; 165 private final static int APP_STATE_TIMEOUT = 3; 166 private int mAppTransitionState = APP_STATE_IDLE; 167 168 private final int mConfigShortAnimTime; 169 private final Interpolator mDecelerateInterpolator; 170 private final Interpolator mThumbnailFadeInInterpolator; 171 private final Interpolator mThumbnailFadeOutInterpolator; 172 private final Interpolator mThumbnailFastOutSlowInInterpolator; 173 174 private int mCurrentUserId = 0; 175 AppTransition(Context context, Handler h)176 AppTransition(Context context, Handler h) { 177 mContext = context; 178 mH = h; 179 mConfigShortAnimTime = context.getResources().getInteger( 180 com.android.internal.R.integer.config_shortAnimTime); 181 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context, 182 com.android.internal.R.interpolator.decelerate_cubic); 183 mThumbnailFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, 184 com.android.internal.R.interpolator.fast_out_slow_in); 185 mThumbnailFadeInInterpolator = new Interpolator() { 186 @Override 187 public float getInterpolation(float input) { 188 // Linear response for first fraction, then complete after that. 189 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) { 190 return 0f; 191 } 192 return (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) / 193 (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION); 194 } 195 }; 196 mThumbnailFadeOutInterpolator = new Interpolator() { 197 @Override 198 public float getInterpolation(float input) { 199 // Linear response for first fraction, then complete after that. 200 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) { 201 return input / RECENTS_THUMBNAIL_FADEOUT_FRACTION; 202 } 203 return 1f; 204 } 205 }; 206 } 207 isTransitionSet()208 boolean isTransitionSet() { 209 return mNextAppTransition != TRANSIT_UNSET; 210 } 211 isTransitionNone()212 boolean isTransitionNone() { 213 return mNextAppTransition == TRANSIT_NONE; 214 } 215 isTransitionEqual(int transit)216 boolean isTransitionEqual(int transit) { 217 return mNextAppTransition == transit; 218 } 219 getAppTransition()220 int getAppTransition() { 221 return mNextAppTransition; 222 } 223 setAppTransition(int transit)224 void setAppTransition(int transit) { 225 mNextAppTransition = transit; 226 } 227 isReady()228 boolean isReady() { 229 return mAppTransitionState == APP_STATE_READY 230 || mAppTransitionState == APP_STATE_TIMEOUT; 231 } 232 setReady()233 void setReady() { 234 mAppTransitionState = APP_STATE_READY; 235 } 236 isRunning()237 boolean isRunning() { 238 return mAppTransitionState == APP_STATE_RUNNING; 239 } 240 setIdle()241 void setIdle() { 242 mAppTransitionState = APP_STATE_IDLE; 243 } 244 isTimeout()245 boolean isTimeout() { 246 return mAppTransitionState == APP_STATE_TIMEOUT; 247 } 248 setTimeout()249 void setTimeout() { 250 mAppTransitionState = APP_STATE_TIMEOUT; 251 } 252 getNextAppTransitionThumbnail()253 Bitmap getNextAppTransitionThumbnail() { 254 return mNextAppTransitionThumbnail; 255 } 256 257 /** Returns whether the next thumbnail transition is aspect scaled up. */ isNextThumbnailTransitionAspectScaled()258 boolean isNextThumbnailTransitionAspectScaled() { 259 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || 260 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 261 } 262 263 /** Returns whether the next thumbnail transition is scaling up. */ isNextThumbnailTransitionScaleUp()264 boolean isNextThumbnailTransitionScaleUp() { 265 return mNextAppTransitionScaleUp; 266 } 267 getStartingX()268 int getStartingX() { 269 return mNextAppTransitionStartX; 270 } 271 getStartingY()272 int getStartingY() { 273 return mNextAppTransitionStartY; 274 } 275 prepare()276 void prepare() { 277 if (!isRunning()) { 278 mAppTransitionState = APP_STATE_IDLE; 279 } 280 } 281 goodToGo()282 void goodToGo() { 283 mNextAppTransition = TRANSIT_UNSET; 284 mAppTransitionState = APP_STATE_RUNNING; 285 } 286 clear()287 void clear() { 288 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; 289 mNextAppTransitionPackage = null; 290 mNextAppTransitionThumbnail = null; 291 } 292 freeze()293 void freeze() { 294 setAppTransition(AppTransition.TRANSIT_UNSET); 295 clear(); 296 setReady(); 297 } 298 getCachedAnimations(WindowManager.LayoutParams lp)299 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) { 300 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg=" 301 + (lp != null ? lp.packageName : null) 302 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null)); 303 if (lp != null && lp.windowAnimations != 0) { 304 // If this is a system resource, don't try to load it from the 305 // application resources. It is nice to avoid loading application 306 // resources if we can. 307 String packageName = lp.packageName != null ? lp.packageName : "android"; 308 int resId = lp.windowAnimations; 309 if ((resId&0xFF000000) == 0x01000000) { 310 packageName = "android"; 311 } 312 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 313 + packageName); 314 return AttributeCache.instance().get(packageName, resId, 315 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 316 } 317 return null; 318 } 319 getCachedAnimations(String packageName, int resId)320 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) { 321 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package=" 322 + packageName + " resId=0x" + Integer.toHexString(resId)); 323 if (packageName != null) { 324 if ((resId&0xFF000000) == 0x01000000) { 325 packageName = "android"; 326 } 327 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 328 + packageName); 329 return AttributeCache.instance().get(packageName, resId, 330 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 331 } 332 return null; 333 } 334 loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr)335 Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) { 336 int anim = 0; 337 Context context = mContext; 338 if (animAttr >= 0) { 339 AttributeCache.Entry ent = getCachedAnimations(lp); 340 if (ent != null) { 341 context = ent.context; 342 anim = ent.array.getResourceId(animAttr, 0); 343 } 344 } 345 if (anim != 0) { 346 return AnimationUtils.loadAnimation(context, anim); 347 } 348 return null; 349 } 350 loadAnimationRes(WindowManager.LayoutParams lp, int resId)351 Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) { 352 Context context = mContext; 353 if (resId >= 0) { 354 AttributeCache.Entry ent = getCachedAnimations(lp); 355 if (ent != null) { 356 context = ent.context; 357 } 358 return AnimationUtils.loadAnimation(context, resId); 359 } 360 return null; 361 } 362 loadAnimationRes(String packageName, int resId)363 private Animation loadAnimationRes(String packageName, int resId) { 364 int anim = 0; 365 Context context = mContext; 366 if (resId >= 0) { 367 AttributeCache.Entry ent = getCachedAnimations(packageName, resId); 368 if (ent != null) { 369 context = ent.context; 370 anim = resId; 371 } 372 } 373 if (anim != 0) { 374 return AnimationUtils.loadAnimation(context, anim); 375 } 376 return null; 377 } 378 379 /** 380 * Compute the pivot point for an animation that is scaling from a small 381 * rect on screen to a larger rect. The pivot point varies depending on 382 * the distance between the inner and outer edges on both sides. This 383 * function computes the pivot point for one dimension. 384 * @param startPos Offset from left/top edge of outer rectangle to 385 * left/top edge of inner rectangle. 386 * @param finalScale The scaling factor between the size of the outer 387 * and inner rectangles. 388 */ computePivot(int startPos, float finalScale)389 private static float computePivot(int startPos, float finalScale) { 390 final float denom = finalScale-1; 391 if (Math.abs(denom) < .0001f) { 392 return startPos; 393 } 394 return -startPos / denom; 395 } 396 createScaleUpAnimationLocked(int transit, boolean enter, int appWidth, int appHeight)397 private Animation createScaleUpAnimationLocked(int transit, boolean enter, 398 int appWidth, int appHeight) { 399 Animation a = null; 400 if (enter) { 401 // Entering app zooms out from the center of the initial rect. 402 float scaleW = mNextAppTransitionStartWidth / (float) appWidth; 403 float scaleH = mNextAppTransitionStartHeight / (float) appHeight; 404 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, 405 computePivot(mNextAppTransitionStartX, scaleW), 406 computePivot(mNextAppTransitionStartY, scaleH)); 407 scale.setInterpolator(mDecelerateInterpolator); 408 409 Animation alpha = new AlphaAnimation(0, 1); 410 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 411 412 AnimationSet set = new AnimationSet(false); 413 set.addAnimation(scale); 414 set.addAnimation(alpha); 415 set.setDetachWallpaper(true); 416 a = set; 417 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN || 418 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) { 419 // If we are on top of the wallpaper, we need an animation that 420 // correctly handles the wallpaper staying static behind all of 421 // the animated elements. To do this, will just have the existing 422 // element fade out. 423 a = new AlphaAnimation(1, 0); 424 a.setDetachWallpaper(true); 425 } else { 426 // For normal animations, the exiting element just holds in place. 427 a = new AlphaAnimation(1, 1); 428 } 429 430 // Pick the desired duration. If this is an inter-activity transition, 431 // it is the standard duration for that. Otherwise we use the longer 432 // task transition duration. 433 final long duration; 434 switch (transit) { 435 case TRANSIT_ACTIVITY_OPEN: 436 case TRANSIT_ACTIVITY_CLOSE: 437 duration = mConfigShortAnimTime; 438 break; 439 default: 440 duration = DEFAULT_APP_TRANSITION_DURATION; 441 break; 442 } 443 a.setDuration(duration); 444 a.setFillAfter(true); 445 a.setInterpolator(mDecelerateInterpolator); 446 a.initialize(appWidth, appHeight, appWidth, appHeight); 447 return a; 448 } 449 450 /** 451 * Prepares the specified animation with a standard duration, interpolator, etc. 452 */ prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight, int duration, Interpolator interpolator)453 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight, 454 int duration, Interpolator interpolator) { 455 if (duration > 0) { 456 a.setDuration(duration); 457 } 458 a.setFillAfter(true); 459 a.setInterpolator(interpolator); 460 a.initialize(appWidth, appHeight, appWidth, appHeight); 461 return a; 462 } 463 464 /** 465 * Prepares the specified animation with a standard duration, interpolator, etc. 466 */ prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit)467 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) { 468 // Pick the desired duration. If this is an inter-activity transition, 469 // it is the standard duration for that. Otherwise we use the longer 470 // task transition duration. 471 final int duration; 472 switch (transit) { 473 case TRANSIT_ACTIVITY_OPEN: 474 case TRANSIT_ACTIVITY_CLOSE: 475 duration = mConfigShortAnimTime; 476 break; 477 default: 478 duration = DEFAULT_APP_TRANSITION_DURATION; 479 break; 480 } 481 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, 482 mDecelerateInterpolator); 483 } 484 485 /** 486 * Return the current thumbnail transition state. 487 */ getThumbnailTransitionState(boolean enter)488 int getThumbnailTransitionState(boolean enter) { 489 if (enter) { 490 if (mNextAppTransitionScaleUp) { 491 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP; 492 } else { 493 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN; 494 } 495 } else { 496 if (mNextAppTransitionScaleUp) { 497 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP; 498 } else { 499 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN; 500 } 501 } 502 } 503 504 /** 505 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 506 * when a thumbnail is specified with the activity options. 507 */ createThumbnailAspectScaleAnimationLocked(int appWidth, int appHeight, int deviceWidth, int transit)508 Animation createThumbnailAspectScaleAnimationLocked(int appWidth, int appHeight, 509 int deviceWidth, int transit) { 510 Animation a; 511 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 512 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 513 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 514 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 515 516 float scaleW = deviceWidth / thumbWidth; 517 float unscaledWidth = deviceWidth; 518 float unscaledHeight = thumbHeight * scaleW; 519 float unscaledStartY = mNextAppTransitionStartY - (unscaledHeight - thumbHeight) / 2f; 520 if (mNextAppTransitionScaleUp) { 521 // Animation up from the thumbnail to the full screen 522 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, 523 mNextAppTransitionStartX + (thumbWidth / 2f), 524 mNextAppTransitionStartY + (thumbHeight / 2f)); 525 scale.setInterpolator(mThumbnailFastOutSlowInInterpolator); 526 scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 527 Animation alpha = new AlphaAnimation(1, 0); 528 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 529 alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION); 530 Animation translate = new TranslateAnimation(0, 0, 0, -unscaledStartY + 531 mNextAppTransitionInsets.top); 532 translate.setInterpolator(mThumbnailFastOutSlowInInterpolator); 533 translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 534 535 // This AnimationSet uses the Interpolators assigned above. 536 AnimationSet set = new AnimationSet(false); 537 set.addAnimation(scale); 538 set.addAnimation(alpha); 539 set.addAnimation(translate); 540 a = set; 541 } else { 542 // Animation down from the full screen to the thumbnail 543 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, 544 mNextAppTransitionStartX + (thumbWidth / 2f), 545 mNextAppTransitionStartY + (thumbHeight / 2f)); 546 scale.setInterpolator(mThumbnailFastOutSlowInInterpolator); 547 scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 548 Animation alpha = new AlphaAnimation(0f, 1f); 549 alpha.setInterpolator(mThumbnailFadeInInterpolator); 550 alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION); 551 Animation translate = new TranslateAnimation(0, 0, -unscaledStartY + 552 mNextAppTransitionInsets.top, 0); 553 translate.setInterpolator(mThumbnailFastOutSlowInInterpolator); 554 translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 555 556 // This AnimationSet uses the Interpolators assigned above. 557 AnimationSet set = new AnimationSet(false); 558 set.addAnimation(scale); 559 set.addAnimation(alpha); 560 set.addAnimation(translate); 561 a = set; 562 563 } 564 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, 0, 565 mThumbnailFastOutSlowInInterpolator); 566 } 567 568 /** 569 * This alternate animation is created when we are doing a thumbnail transition, for the 570 * activity that is leaving, and the activity that is entering. 571 */ createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth, int appHeight, int orientation, int transit, Rect containingFrame, Rect contentInsets, boolean isFullScreen)572 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState, 573 int appWidth, int appHeight, int orientation, int transit, Rect containingFrame, 574 Rect contentInsets, boolean isFullScreen) { 575 Animation a; 576 final int thumbWidthI = mNextAppTransitionStartWidth; 577 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 578 final int thumbHeightI = mNextAppTransitionStartHeight; 579 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 580 581 // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions 582 float scale = 1f; 583 int scaledTopDecor = 0; 584 585 switch (thumbTransitState) { 586 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: { 587 // App window scaling up to become full screen 588 if (orientation == Configuration.ORIENTATION_PORTRAIT) { 589 // In portrait, we scale the width and clip to the top/left square 590 scale = thumbWidth / appWidth; 591 scaledTopDecor = (int) (scale * contentInsets.top); 592 int unscaledThumbHeight = (int) (thumbHeight / scale); 593 mTmpFromClipRect.set(containingFrame); 594 if (isFullScreen) { 595 mTmpFromClipRect.top = contentInsets.top; 596 } 597 mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); 598 mTmpToClipRect.set(containingFrame); 599 } else { 600 // In landscape, we scale the height and clip to the top/left square 601 scale = thumbHeight / (appHeight - contentInsets.top); 602 scaledTopDecor = (int) (scale * contentInsets.top); 603 int unscaledThumbWidth = (int) (thumbWidth / scale); 604 int unscaledThumbHeight = (int) (thumbHeight / scale); 605 mTmpFromClipRect.set(containingFrame); 606 if (isFullScreen) { 607 mTmpFromClipRect.top = contentInsets.top; 608 mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); 609 } 610 mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth); 611 mTmpToClipRect.set(containingFrame); 612 } 613 mNextAppTransitionInsets.set(contentInsets); 614 615 Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1, 616 computePivot(mNextAppTransitionStartX, scale), 617 computePivot(mNextAppTransitionStartY, scale)); 618 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); 619 Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0); 620 621 AnimationSet set = new AnimationSet(true); 622 set.addAnimation(clipAnim); 623 set.addAnimation(scaleAnim); 624 set.addAnimation(translateAnim); 625 a = set; 626 break; 627 } 628 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 629 // Previous app window during the scale up 630 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 631 // Fade out the source activity if we are animating to a wallpaper 632 // activity. 633 a = new AlphaAnimation(1, 0); 634 } else { 635 a = new AlphaAnimation(1, 1); 636 } 637 break; 638 } 639 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 640 // Target app window during the scale down 641 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 642 // Fade in the destination activity if we are animating from a wallpaper 643 // activity. 644 a = new AlphaAnimation(0, 1); 645 } else { 646 a = new AlphaAnimation(1, 1); 647 } 648 break; 649 } 650 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 651 // App window scaling down from full screen 652 if (orientation == Configuration.ORIENTATION_PORTRAIT) { 653 // In portrait, we scale the width and clip to the top/left square 654 scale = thumbWidth / appWidth; 655 scaledTopDecor = (int) (scale * contentInsets.top); 656 int unscaledThumbHeight = (int) (thumbHeight / scale); 657 mTmpFromClipRect.set(containingFrame); 658 mTmpToClipRect.set(containingFrame); 659 if (isFullScreen) { 660 mTmpToClipRect.top = contentInsets.top; 661 } 662 mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); 663 } else { 664 // In landscape, we scale the height and clip to the top/left square 665 scale = thumbHeight / (appHeight - contentInsets.top); 666 scaledTopDecor = (int) (scale * contentInsets.top); 667 int unscaledThumbWidth = (int) (thumbWidth / scale); 668 int unscaledThumbHeight = (int) (thumbHeight / scale); 669 mTmpFromClipRect.set(containingFrame); 670 mTmpToClipRect.set(containingFrame); 671 if (isFullScreen) { 672 mTmpToClipRect.top = contentInsets.top; 673 mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); 674 } 675 mTmpToClipRect.right = (mTmpToClipRect.left + unscaledThumbWidth); 676 } 677 mNextAppTransitionInsets.set(contentInsets); 678 679 Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale, 680 computePivot(mNextAppTransitionStartX, scale), 681 computePivot(mNextAppTransitionStartY, scale)); 682 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); 683 Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor); 684 685 AnimationSet set = new AnimationSet(true); 686 set.addAnimation(clipAnim); 687 set.addAnimation(scaleAnim); 688 set.addAnimation(translateAnim); 689 690 a = set; 691 a.setZAdjustment(Animation.ZORDER_TOP); 692 break; 693 } 694 default: 695 throw new RuntimeException("Invalid thumbnail transition state"); 696 } 697 698 int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION, 699 THUMBNAIL_APP_TRANSITION_DURATION); 700 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, 701 mThumbnailFastOutSlowInInterpolator); 702 } 703 704 /** 705 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 706 * when a thumbnail is specified with the activity options. 707 */ createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit)708 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit) { 709 Animation a; 710 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 711 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 712 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 713 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 714 715 if (mNextAppTransitionScaleUp) { 716 // Animation for the thumbnail zooming from its initial size to the full screen 717 float scaleW = appWidth / thumbWidth; 718 float scaleH = appHeight / thumbHeight; 719 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 720 computePivot(mNextAppTransitionStartX, 1 / scaleW), 721 computePivot(mNextAppTransitionStartY, 1 / scaleH)); 722 scale.setInterpolator(mDecelerateInterpolator); 723 724 Animation alpha = new AlphaAnimation(1, 0); 725 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 726 727 // This AnimationSet uses the Interpolators assigned above. 728 AnimationSet set = new AnimationSet(false); 729 set.addAnimation(scale); 730 set.addAnimation(alpha); 731 a = set; 732 } else { 733 // Animation for the thumbnail zooming down from the full screen to its final size 734 float scaleW = appWidth / thumbWidth; 735 float scaleH = appHeight / thumbHeight; 736 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 737 computePivot(mNextAppTransitionStartX, 1 / scaleW), 738 computePivot(mNextAppTransitionStartY, 1 / scaleH)); 739 } 740 741 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 742 } 743 744 /** 745 * This animation is created when we are doing a thumbnail transition, for the activity that is 746 * leaving, and the activity that is entering. 747 */ createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth, int appHeight, int transit)748 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth, 749 int appHeight, int transit) { 750 Animation a; 751 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 752 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 753 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 754 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 755 756 switch (thumbTransitState) { 757 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: { 758 // Entering app scales up with the thumbnail 759 float scaleW = thumbWidth / appWidth; 760 float scaleH = thumbHeight / appHeight; 761 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 762 computePivot(mNextAppTransitionStartX, scaleW), 763 computePivot(mNextAppTransitionStartY, scaleH)); 764 break; 765 } 766 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 767 // Exiting app while the thumbnail is scaling up should fade or stay in place 768 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 769 // Fade out while bringing up selected activity. This keeps the 770 // current activity from showing through a launching wallpaper 771 // activity. 772 a = new AlphaAnimation(1, 0); 773 } else { 774 // noop animation 775 a = new AlphaAnimation(1, 1); 776 } 777 break; 778 } 779 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 780 // Entering the other app, it should just be visible while we scale the thumbnail 781 // down above it 782 a = new AlphaAnimation(1, 1); 783 break; 784 } 785 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 786 // Exiting the current app, the app should scale down with the thumbnail 787 float scaleW = thumbWidth / appWidth; 788 float scaleH = thumbHeight / appHeight; 789 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 790 computePivot(mNextAppTransitionStartX, scaleW), 791 computePivot(mNextAppTransitionStartY, scaleH)); 792 793 Animation alpha = new AlphaAnimation(1, 0); 794 795 AnimationSet set = new AnimationSet(true); 796 set.addAnimation(scale); 797 set.addAnimation(alpha); 798 set.setZAdjustment(Animation.ZORDER_TOP); 799 a = set; 800 break; 801 } 802 default: 803 throw new RuntimeException("Invalid thumbnail transition state"); 804 } 805 806 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 807 } 808 809 loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets, boolean isFullScreen, boolean isVoiceInteraction)810 Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, 811 int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets, 812 boolean isFullScreen, boolean isVoiceInteraction) { 813 Animation a; 814 if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN 815 || transit == TRANSIT_TASK_OPEN 816 || transit == TRANSIT_TASK_TO_FRONT)) { 817 a = loadAnimationRes(lp, enter 818 ? com.android.internal.R.anim.voice_activity_open_enter 819 : com.android.internal.R.anim.voice_activity_open_exit); 820 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 821 "applyAnimation voice:" 822 + " anim=" + a + " transit=" + transit + " isEntrance=" + enter 823 + " Callers=" + Debug.getCallers(3)); 824 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE 825 || transit == TRANSIT_TASK_CLOSE 826 || transit == TRANSIT_TASK_TO_BACK)) { 827 a = loadAnimationRes(lp, enter 828 ? com.android.internal.R.anim.voice_activity_close_enter 829 : com.android.internal.R.anim.voice_activity_close_exit); 830 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 831 "applyAnimation voice:" 832 + " anim=" + a + " transit=" + transit + " isEntrance=" + enter 833 + " Callers=" + Debug.getCallers(3)); 834 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { 835 a = loadAnimationRes(mNextAppTransitionPackage, enter ? 836 mNextAppTransitionEnter : mNextAppTransitionExit); 837 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 838 "applyAnimation:" 839 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM" 840 + " transit=" + transit + " isEntrance=" + enter 841 + " Callers=" + Debug.getCallers(3)); 842 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) { 843 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace); 844 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 845 "applyAnimation:" 846 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE" 847 + " transit=" + transit + " Callers=" + Debug.getCallers(3)); 848 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) { 849 a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight); 850 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 851 "applyAnimation:" 852 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" 853 + " transit=" + transit + " isEntrance=" + enter 854 + " Callers=" + Debug.getCallers(3)); 855 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP || 856 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { 857 mNextAppTransitionScaleUp = 858 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); 859 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter), 860 appWidth, appHeight, transit); 861 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 862 String animName = mNextAppTransitionScaleUp ? 863 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; 864 Slog.v(TAG, "applyAnimation:" 865 + " anim=" + a + " nextAppTransition=" + animName 866 + " transit=" + transit + " isEntrance=" + enter 867 + " Callers=" + Debug.getCallers(3)); 868 } 869 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || 870 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) { 871 mNextAppTransitionScaleUp = 872 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP); 873 a = createAspectScaledThumbnailEnterExitAnimationLocked( 874 getThumbnailTransitionState(enter), appWidth, appHeight, orientation, 875 transit, containingFrame, contentInsets, isFullScreen); 876 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 877 String animName = mNextAppTransitionScaleUp ? 878 "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN"; 879 Slog.v(TAG, "applyAnimation:" 880 + " anim=" + a + " nextAppTransition=" + animName 881 + " transit=" + transit + " isEntrance=" + enter 882 + " Callers=" + Debug.getCallers(3)); 883 } 884 } else { 885 int animAttr = 0; 886 switch (transit) { 887 case TRANSIT_ACTIVITY_OPEN: 888 animAttr = enter 889 ? WindowAnimation_activityOpenEnterAnimation 890 : WindowAnimation_activityOpenExitAnimation; 891 break; 892 case TRANSIT_ACTIVITY_CLOSE: 893 animAttr = enter 894 ? WindowAnimation_activityCloseEnterAnimation 895 : WindowAnimation_activityCloseExitAnimation; 896 break; 897 case TRANSIT_TASK_OPEN: 898 animAttr = enter 899 ? WindowAnimation_taskOpenEnterAnimation 900 : WindowAnimation_taskOpenExitAnimation; 901 break; 902 case TRANSIT_TASK_CLOSE: 903 animAttr = enter 904 ? WindowAnimation_taskCloseEnterAnimation 905 : WindowAnimation_taskCloseExitAnimation; 906 break; 907 case TRANSIT_TASK_TO_FRONT: 908 animAttr = enter 909 ? WindowAnimation_taskToFrontEnterAnimation 910 : WindowAnimation_taskToFrontExitAnimation; 911 break; 912 case TRANSIT_TASK_TO_BACK: 913 animAttr = enter 914 ? WindowAnimation_taskToBackEnterAnimation 915 : WindowAnimation_taskToBackExitAnimation; 916 break; 917 case TRANSIT_WALLPAPER_OPEN: 918 animAttr = enter 919 ? WindowAnimation_wallpaperOpenEnterAnimation 920 : WindowAnimation_wallpaperOpenExitAnimation; 921 break; 922 case TRANSIT_WALLPAPER_CLOSE: 923 animAttr = enter 924 ? WindowAnimation_wallpaperCloseEnterAnimation 925 : WindowAnimation_wallpaperCloseExitAnimation; 926 break; 927 case TRANSIT_WALLPAPER_INTRA_OPEN: 928 animAttr = enter 929 ? WindowAnimation_wallpaperIntraOpenEnterAnimation 930 : WindowAnimation_wallpaperIntraOpenExitAnimation; 931 break; 932 case TRANSIT_WALLPAPER_INTRA_CLOSE: 933 animAttr = enter 934 ? WindowAnimation_wallpaperIntraCloseEnterAnimation 935 : WindowAnimation_wallpaperIntraCloseExitAnimation; 936 break; 937 case TRANSIT_TASK_OPEN_BEHIND: 938 animAttr = enter 939 ? WindowAnimation_launchTaskBehindSourceAnimation 940 : WindowAnimation_launchTaskBehindTargetAnimation; 941 } 942 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null; 943 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 944 "applyAnimation:" 945 + " anim=" + a 946 + " animAttr=0x" + Integer.toHexString(animAttr) 947 + " transit=" + transit + " isEntrance=" + enter 948 + " Callers=" + Debug.getCallers(3)); 949 } 950 return a; 951 } 952 postAnimationCallback()953 void postAnimationCallback() { 954 if (mNextAppTransitionCallback != null) { 955 mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, mNextAppTransitionCallback)); 956 mNextAppTransitionCallback = null; 957 } 958 } 959 overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, IRemoteCallback startedCallback)960 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, 961 IRemoteCallback startedCallback) { 962 if (isTransitionSet()) { 963 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM; 964 mNextAppTransitionPackage = packageName; 965 mNextAppTransitionThumbnail = null; 966 mNextAppTransitionEnter = enterAnim; 967 mNextAppTransitionExit = exitAnim; 968 postAnimationCallback(); 969 mNextAppTransitionCallback = startedCallback; 970 } else { 971 postAnimationCallback(); 972 } 973 } 974 overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, int startHeight)975 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, 976 int startHeight) { 977 if (isTransitionSet()) { 978 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP; 979 mNextAppTransitionPackage = null; 980 mNextAppTransitionThumbnail = null; 981 mNextAppTransitionStartX = startX; 982 mNextAppTransitionStartY = startY; 983 mNextAppTransitionStartWidth = startWidth; 984 mNextAppTransitionStartHeight = startHeight; 985 postAnimationCallback(); 986 mNextAppTransitionCallback = null; 987 } 988 } 989 overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY, IRemoteCallback startedCallback, boolean scaleUp)990 void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY, 991 IRemoteCallback startedCallback, boolean scaleUp) { 992 if (isTransitionSet()) { 993 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP 994 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN; 995 mNextAppTransitionPackage = null; 996 mNextAppTransitionThumbnail = srcThumb; 997 mNextAppTransitionScaleUp = scaleUp; 998 mNextAppTransitionStartX = startX; 999 mNextAppTransitionStartY = startY; 1000 postAnimationCallback(); 1001 mNextAppTransitionCallback = startedCallback; 1002 } else { 1003 postAnimationCallback(); 1004 } 1005 } 1006 overridePendingAppTransitionAspectScaledThumb(Bitmap srcThumb, int startX, int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp)1007 void overridePendingAppTransitionAspectScaledThumb(Bitmap srcThumb, int startX, int startY, 1008 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) { 1009 if (isTransitionSet()) { 1010 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP 1011 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 1012 mNextAppTransitionPackage = null; 1013 mNextAppTransitionThumbnail = srcThumb; 1014 mNextAppTransitionScaleUp = scaleUp; 1015 mNextAppTransitionStartX = startX; 1016 mNextAppTransitionStartY = startY; 1017 mNextAppTransitionStartWidth = targetWidth; 1018 mNextAppTransitionStartHeight = targetHeight; 1019 postAnimationCallback(); 1020 mNextAppTransitionCallback = startedCallback; 1021 } else { 1022 postAnimationCallback(); 1023 } 1024 } 1025 overrideInPlaceAppTransition(String packageName, int anim)1026 void overrideInPlaceAppTransition(String packageName, int anim) { 1027 if (isTransitionSet()) { 1028 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE; 1029 mNextAppTransitionPackage = packageName; 1030 mNextAppTransitionInPlace = anim; 1031 } else { 1032 postAnimationCallback(); 1033 } 1034 } 1035 1036 @Override toString()1037 public String toString() { 1038 return "mNextAppTransition=0x" + Integer.toHexString(mNextAppTransition); 1039 } 1040 1041 /** 1042 * Returns the human readable name of a window transition. 1043 * 1044 * @param transition The window transition. 1045 * @return The transition symbolic name. 1046 */ appTransitionToString(int transition)1047 public static String appTransitionToString(int transition) { 1048 switch (transition) { 1049 case TRANSIT_UNSET: { 1050 return "TRANSIT_UNSET"; 1051 } 1052 case TRANSIT_NONE: { 1053 return "TRANSIT_NONE"; 1054 } 1055 case TRANSIT_ACTIVITY_OPEN: { 1056 return "TRANSIT_ACTIVITY_OPEN"; 1057 } 1058 case TRANSIT_ACTIVITY_CLOSE: { 1059 return "TRANSIT_ACTIVITY_CLOSE"; 1060 } 1061 case TRANSIT_TASK_OPEN: { 1062 return "TRANSIT_TASK_OPEN"; 1063 } 1064 case TRANSIT_TASK_CLOSE: { 1065 return "TRANSIT_TASK_CLOSE"; 1066 } 1067 case TRANSIT_TASK_TO_FRONT: { 1068 return "TRANSIT_TASK_TO_FRONT"; 1069 } 1070 case TRANSIT_TASK_TO_BACK: { 1071 return "TRANSIT_TASK_TO_BACK"; 1072 } 1073 case TRANSIT_WALLPAPER_CLOSE: { 1074 return "TRANSIT_WALLPAPER_CLOSE"; 1075 } 1076 case TRANSIT_WALLPAPER_OPEN: { 1077 return "TRANSIT_WALLPAPER_OPEN"; 1078 } 1079 case TRANSIT_WALLPAPER_INTRA_OPEN: { 1080 return "TRANSIT_WALLPAPER_INTRA_OPEN"; 1081 } 1082 case TRANSIT_WALLPAPER_INTRA_CLOSE: { 1083 return "TRANSIT_WALLPAPER_INTRA_CLOSE"; 1084 } 1085 case TRANSIT_TASK_OPEN_BEHIND: { 1086 return "TRANSIT_TASK_OPEN_BEHIND"; 1087 } 1088 default: { 1089 return "<UNKNOWN>"; 1090 } 1091 } 1092 } 1093 appStateToString()1094 private String appStateToString() { 1095 switch (mAppTransitionState) { 1096 case APP_STATE_IDLE: 1097 return "APP_STATE_IDLE"; 1098 case APP_STATE_READY: 1099 return "APP_STATE_READY"; 1100 case APP_STATE_RUNNING: 1101 return "APP_STATE_RUNNING"; 1102 case APP_STATE_TIMEOUT: 1103 return "APP_STATE_TIMEOUT"; 1104 default: 1105 return "unknown state=" + mAppTransitionState; 1106 } 1107 } 1108 transitTypeToString()1109 private String transitTypeToString() { 1110 switch (mNextAppTransitionType) { 1111 case NEXT_TRANSIT_TYPE_NONE: 1112 return "NEXT_TRANSIT_TYPE_NONE"; 1113 case NEXT_TRANSIT_TYPE_CUSTOM: 1114 return "NEXT_TRANSIT_TYPE_CUSTOM"; 1115 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1116 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE"; 1117 case NEXT_TRANSIT_TYPE_SCALE_UP: 1118 return "NEXT_TRANSIT_TYPE_SCALE_UP"; 1119 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1120 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP"; 1121 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1122 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN"; 1123 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1124 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP"; 1125 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: 1126 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN"; 1127 default: 1128 return "unknown type=" + mNextAppTransitionType; 1129 } 1130 } 1131 1132 @Override dump(PrintWriter pw)1133 public void dump(PrintWriter pw) { 1134 pw.print(" " + this); 1135 pw.print(" mAppTransitionState="); pw.println(appStateToString()); 1136 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) { 1137 pw.print(" mNextAppTransitionType="); pw.println(transitTypeToString()); 1138 } 1139 switch (mNextAppTransitionType) { 1140 case NEXT_TRANSIT_TYPE_CUSTOM: 1141 pw.print(" mNextAppTransitionPackage="); 1142 pw.println(mNextAppTransitionPackage); 1143 pw.print(" mNextAppTransitionEnter=0x"); 1144 pw.print(Integer.toHexString(mNextAppTransitionEnter)); 1145 pw.print(" mNextAppTransitionExit=0x"); 1146 pw.println(Integer.toHexString(mNextAppTransitionExit)); 1147 break; 1148 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1149 pw.print(" mNextAppTransitionPackage="); 1150 pw.println(mNextAppTransitionPackage); 1151 pw.print(" mNextAppTransitionInPlace=0x"); 1152 pw.print(Integer.toHexString(mNextAppTransitionInPlace)); 1153 break; 1154 case NEXT_TRANSIT_TYPE_SCALE_UP: 1155 pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX); 1156 pw.print(" mNextAppTransitionStartY="); 1157 pw.println(mNextAppTransitionStartY); 1158 pw.print(" mNextAppTransitionStartWidth="); 1159 pw.print(mNextAppTransitionStartWidth); 1160 pw.print(" mNextAppTransitionStartHeight="); 1161 pw.println(mNextAppTransitionStartHeight); 1162 break; 1163 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1164 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1165 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1166 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: 1167 pw.print(" mNextAppTransitionThumbnail="); 1168 pw.print(mNextAppTransitionThumbnail); 1169 pw.print(" mNextAppTransitionStartX="); 1170 pw.print(mNextAppTransitionStartX); 1171 pw.print(" mNextAppTransitionStartY="); 1172 pw.println(mNextAppTransitionStartY); 1173 pw.print(" mNextAppTransitionStartWidth="); 1174 pw.print(mNextAppTransitionStartWidth); 1175 pw.print(" mNextAppTransitionStartHeight="); 1176 pw.println(mNextAppTransitionStartHeight); 1177 pw.print(" mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp); 1178 break; 1179 } 1180 if (mNextAppTransitionCallback != null) { 1181 pw.print(" mNextAppTransitionCallback="); 1182 pw.println(mNextAppTransitionCallback); 1183 } 1184 } 1185 setCurrentUser(int newUserId)1186 public void setCurrentUser(int newUserId) { 1187 mCurrentUserId = newUserId; 1188 } 1189 } 1190