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.graphics.Bitmap; 21 import android.graphics.Point; 22 import android.os.Debug; 23 import android.os.Handler; 24 import android.os.IRemoteCallback; 25 import android.util.Slog; 26 import android.view.WindowManager; 27 import android.view.animation.AlphaAnimation; 28 import android.view.animation.Animation; 29 import android.view.animation.AnimationSet; 30 import android.view.animation.AnimationUtils; 31 import android.view.animation.Interpolator; 32 import android.view.animation.ScaleAnimation; 33 34 import com.android.internal.util.DumpUtils.Dump; 35 import com.android.server.AttributeCache; 36 import com.android.server.wm.WindowManagerService.H; 37 38 import java.io.PrintWriter; 39 40 import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation; 41 import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation; 42 import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation; 43 import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; 44 import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation; 45 import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation; 46 import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation; 47 import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation; 48 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation; 49 import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation; 50 import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation; 51 import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation; 52 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; 53 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; 54 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation; 55 import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation; 56 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation; 57 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; 58 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation; 59 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; 60 61 // 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. 66 public class AppTransition implements Dump { 67 private static final String TAG = "AppTransition"; 68 private static final boolean DEBUG_APP_TRANSITIONS = 69 WindowManagerService.DEBUG_APP_TRANSITIONS; 70 private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM; 71 72 /** Bit mask that is set for all enter transition. */ 73 public static final int TRANSIT_ENTER_MASK = 0x1000; 74 75 /** Bit mask that is set for all exit transitions. */ 76 public static final int TRANSIT_EXIT_MASK = 0x2000; 77 78 /** 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; 98 /** 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. */ 100 public static final int TRANSIT_WALLPAPER_CLOSE = 12 | TRANSIT_EXIT_MASK; 101 /** A window in a new activity that does have a wallpaper is being opened on one that didn't, 102 * effectively opening the wallpaper. */ 103 public static final int TRANSIT_WALLPAPER_OPEN = 13 | TRANSIT_ENTER_MASK; 104 /** A window in a new activity is being opened on top of an existing one, and both are on top 105 * of the wallpaper. */ 106 public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14 | TRANSIT_ENTER_MASK; 107 /** The window in the top-most activity is being closed to reveal the previous activity, and 108 * both are on top of the wallpaper. */ 109 public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15 | TRANSIT_EXIT_MASK; 110 111 /** Fraction of animation at which the recents thumbnail becomes completely transparent */ 112 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.25f; 113 114 private static final long DEFAULT_APP_TRANSITION_DURATION = 250; 115 116 private final Context mContext; 117 private final Handler mH; 118 119 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; 130 // Used for thumbnail transitions. True if we're scaling up, false if scaling down 131 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; 139 140 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; 147 private final Interpolator mDecelerateInterpolator; 148 private final Interpolator mThumbnailFadeoutInterpolator; 149 150 private int mCurrentUserId = 0; 151 152 AppTransition(Context context, Handler h) { 153 mContext = context; 154 mH = h; 155 mConfigShortAnimTime = context.getResources().getInteger( 156 com.android.internal.R.integer.config_shortAnimTime); 157 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context, 158 com.android.internal.R.interpolator.decelerate_cubic); 159 mThumbnailFadeoutInterpolator = new Interpolator() { 160 @Override 161 public float getInterpolation(float input) { 162 // Linear response for first fraction, then complete after that. 163 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) { 164 return input / RECENTS_THUMBNAIL_FADEOUT_FRACTION; 165 } 166 return 1.0f; 167 } 168 }; 169 } 170 171 boolean isTransitionSet() { 172 return mNextAppTransition != TRANSIT_UNSET; 173 } 174 175 boolean isTransitionNone() { 176 return mNextAppTransition == TRANSIT_NONE; 177 } 178 179 boolean isTransitionEqual(int transit) { 180 return mNextAppTransition == transit; 181 } 182 183 int getAppTransition() { 184 return mNextAppTransition; 185 } 186 187 void setAppTransition(int transit) { 188 mNextAppTransition = transit; 189 } 190 191 boolean isReady() { 192 return mAppTransitionState == APP_STATE_READY 193 || mAppTransitionState == APP_STATE_TIMEOUT; 194 } 195 196 void setReady() { 197 mAppTransitionState = APP_STATE_READY; 198 } 199 200 boolean isRunning() { 201 return mAppTransitionState == APP_STATE_RUNNING; 202 } 203 204 void setIdle() { 205 mAppTransitionState = APP_STATE_IDLE; 206 } 207 208 boolean isTimeout() { 209 return mAppTransitionState == APP_STATE_TIMEOUT; 210 } 211 212 void setTimeout() { 213 mAppTransitionState = APP_STATE_TIMEOUT; 214 } 215 216 Bitmap getNextAppTransitionThumbnail() { 217 return mNextAppTransitionThumbnail; 218 } 219 220 void getStartingPoint(Point outPoint) { 221 outPoint.x = mNextAppTransitionStartX; 222 outPoint.y = mNextAppTransitionStartY; 223 } 224 225 void prepare() { 226 if (!isRunning()) { 227 mAppTransitionState = APP_STATE_IDLE; 228 } 229 } 230 231 void goodToGo() { 232 mNextAppTransition = TRANSIT_UNSET; 233 mAppTransitionState = APP_STATE_RUNNING; 234 } 235 236 void clear() { 237 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; 238 mNextAppTransitionPackage = null; 239 mNextAppTransitionThumbnail = null; 240 } 241 242 void freeze() { 243 setAppTransition(AppTransition.TRANSIT_UNSET); 244 clear(); 245 setReady(); 246 } 247 248 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) { 249 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg=" 250 + (lp != null ? lp.packageName : null) 251 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null)); 252 if (lp != null && lp.windowAnimations != 0) { 253 // If this is a system resource, don't try to load it from the 254 // application resources. It is nice to avoid loading application 255 // resources if we can. 256 String packageName = lp.packageName != null ? lp.packageName : "android"; 257 int resId = lp.windowAnimations; 258 if ((resId&0xFF000000) == 0x01000000) { 259 packageName = "android"; 260 } 261 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 262 + packageName); 263 return AttributeCache.instance().get(packageName, resId, 264 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 265 } 266 return null; 267 } 268 269 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) { 270 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package=" 271 + packageName + " resId=0x" + Integer.toHexString(resId)); 272 if (packageName != null) { 273 if ((resId&0xFF000000) == 0x01000000) { 274 packageName = "android"; 275 } 276 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 277 + packageName); 278 return AttributeCache.instance().get(packageName, resId, 279 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 280 } 281 return null; 282 } 283 284 Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) { 285 int anim = 0; 286 Context context = mContext; 287 if (animAttr >= 0) { 288 AttributeCache.Entry ent = getCachedAnimations(lp); 289 if (ent != null) { 290 context = ent.context; 291 anim = ent.array.getResourceId(animAttr, 0); 292 } 293 } 294 if (anim != 0) { 295 return AnimationUtils.loadAnimation(context, anim); 296 } 297 return null; 298 } 299 300 private Animation loadAnimation(String packageName, int resId) { 301 int anim = 0; 302 Context context = mContext; 303 if (resId >= 0) { 304 AttributeCache.Entry ent = getCachedAnimations(packageName, resId); 305 if (ent != null) { 306 context = ent.context; 307 anim = resId; 308 } 309 } 310 if (anim != 0) { 311 return AnimationUtils.loadAnimation(context, anim); 312 } 313 return null; 314 } 315 316 /** 317 * Compute the pivot point for an animation that is scaling from a small 318 * rect on screen to a larger rect. The pivot point varies depending on 319 * the distance between the inner and outer edges on both sides. This 320 * function computes the pivot point for one dimension. 321 * @param startPos Offset from left/top edge of outer rectangle to 322 * left/top edge of inner rectangle. 323 * @param finalScale The scaling factor between the size of the outer 324 * and inner rectangles. 325 */ 326 private static float computePivot(int startPos, float finalScale) { 327 final float denom = finalScale-1; 328 if (Math.abs(denom) < .0001f) { 329 return startPos; 330 } 331 return -startPos / denom; 332 } 333 334 private Animation createScaleUpAnimationLocked(int transit, boolean enter, 335 int appWidth, int appHeight) { 336 Animation a = null; 337 if (enter) { 338 // Entering app zooms out from the center of the initial rect. 339 float scaleW = mNextAppTransitionStartWidth / (float) appWidth; 340 float scaleH = mNextAppTransitionStartHeight / (float) appHeight; 341 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, 342 computePivot(mNextAppTransitionStartX, scaleW), 343 computePivot(mNextAppTransitionStartY, scaleH)); 344 scale.setInterpolator(mDecelerateInterpolator); 345 346 Animation alpha = new AlphaAnimation(0, 1); 347 alpha.setInterpolator(mThumbnailFadeoutInterpolator); 348 349 AnimationSet set = new AnimationSet(false); 350 set.addAnimation(scale); 351 set.addAnimation(alpha); 352 set.setDetachWallpaper(true); 353 a = set; 354 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN || 355 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) { 356 // If we are on top of the wallpaper, we need an animation that 357 // correctly handles the wallpaper staying static behind all of 358 // the animated elements. To do this, will just have the existing 359 // element fade out. 360 a = new AlphaAnimation(1, 0); 361 a.setDetachWallpaper(true); 362 } else { 363 // For normal animations, the exiting element just holds in place. 364 a = new AlphaAnimation(1, 1); 365 } 366 367 // Pick the desired duration. If this is an inter-activity transition, 368 // it is the standard duration for that. Otherwise we use the longer 369 // task transition duration. 370 final long duration; 371 switch (transit) { 372 case TRANSIT_ACTIVITY_OPEN: 373 case TRANSIT_ACTIVITY_CLOSE: 374 duration = mConfigShortAnimTime; 375 break; 376 default: 377 duration = DEFAULT_APP_TRANSITION_DURATION; 378 break; 379 } 380 a.setDuration(duration); 381 a.setFillAfter(true); 382 a.setInterpolator(mDecelerateInterpolator); 383 a.initialize(appWidth, appHeight, appWidth, appHeight); 384 return a; 385 } 386 387 Animation createThumbnailAnimationLocked(int transit, boolean enter, boolean thumb, 388 int appWidth, int appHeight) { 389 Animation a; 390 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 391 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 392 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 393 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 394 if (thumb) { 395 // Animation for zooming thumbnail from its initial size to 396 // filling the screen. 397 if (mNextAppTransitionScaleUp) { 398 float scaleW = appWidth / thumbWidth; 399 float scaleH = appHeight / thumbHeight; 400 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 401 computePivot(mNextAppTransitionStartX, 1 / scaleW), 402 computePivot(mNextAppTransitionStartY, 1 / scaleH)); 403 scale.setInterpolator(mDecelerateInterpolator); 404 405 Animation alpha = new AlphaAnimation(1, 0); 406 alpha.setInterpolator(mThumbnailFadeoutInterpolator); 407 408 // This AnimationSet uses the Interpolators assigned above. 409 AnimationSet set = new AnimationSet(false); 410 set.addAnimation(scale); 411 set.addAnimation(alpha); 412 a = set; 413 } else { 414 float scaleW = appWidth / thumbWidth; 415 float scaleH = appHeight / thumbHeight; 416 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 417 computePivot(mNextAppTransitionStartX, 1 / scaleW), 418 computePivot(mNextAppTransitionStartY, 1 / scaleH)); 419 } 420 } else if (enter) { 421 // Entering app zooms out from the center of the thumbnail. 422 if (mNextAppTransitionScaleUp) { 423 float scaleW = thumbWidth / appWidth; 424 float scaleH = thumbHeight / appHeight; 425 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 426 computePivot(mNextAppTransitionStartX, scaleW), 427 computePivot(mNextAppTransitionStartY, scaleH)); 428 } else { 429 // noop animation 430 a = new AlphaAnimation(1, 1); 431 } 432 } else { 433 // Exiting app 434 if (mNextAppTransitionScaleUp) { 435 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 436 // Fade out while bringing up selected activity. This keeps the 437 // current activity from showing through a launching wallpaper 438 // activity. 439 a = new AlphaAnimation(1, 0); 440 } else { 441 // noop animation 442 a = new AlphaAnimation(1, 1); 443 } 444 } else { 445 float scaleW = thumbWidth / appWidth; 446 float scaleH = thumbHeight / appHeight; 447 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 448 computePivot(mNextAppTransitionStartX, scaleW), 449 computePivot(mNextAppTransitionStartY, scaleH)); 450 451 Animation alpha = new AlphaAnimation(1, 0); 452 453 AnimationSet set = new AnimationSet(true); 454 set.addAnimation(scale); 455 set.addAnimation(alpha); 456 set.setZAdjustment(Animation.ZORDER_TOP); 457 a = set; 458 } 459 } 460 461 // Pick the desired duration. If this is an inter-activity transition, 462 // it is the standard duration for that. Otherwise we use the longer 463 // task transition duration. 464 final long duration; 465 switch (transit) { 466 case TRANSIT_ACTIVITY_OPEN: 467 case TRANSIT_ACTIVITY_CLOSE: 468 duration = mConfigShortAnimTime; 469 break; 470 default: 471 duration = DEFAULT_APP_TRANSITION_DURATION; 472 break; 473 } 474 a.setDuration(duration); 475 a.setFillAfter(true); 476 a.setInterpolator(mDecelerateInterpolator); 477 a.initialize(appWidth, appHeight, appWidth, appHeight); 478 return a; 479 } 480 481 482 Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, 483 int appWidth, int appHeight) { 484 Animation a; 485 if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { 486 a = loadAnimation(mNextAppTransitionPackage, enter ? 487 mNextAppTransitionEnter : mNextAppTransitionExit); 488 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 489 "applyAnimation:" 490 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM" 491 + " transit=" + transit + " isEntrance=" + enter 492 + " Callers=" + Debug.getCallers(3)); 493 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) { 494 a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight); 495 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 496 "applyAnimation:" 497 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" 498 + " transit=" + transit + " isEntrance=" + enter 499 + " Callers=" + Debug.getCallers(3)); 500 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP || 501 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { 502 mNextAppTransitionScaleUp = 503 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); 504 a = createThumbnailAnimationLocked(transit, enter, false, appWidth, appHeight); 505 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 506 String animName = mNextAppTransitionScaleUp ? 507 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; 508 Slog.v(TAG, "applyAnimation:" 509 + " anim=" + a + " nextAppTransition=" + animName 510 + " transit=" + transit + " isEntrance=" + enter 511 + " Callers=" + Debug.getCallers(3)); 512 } 513 } else { 514 int animAttr = 0; 515 switch (transit) { 516 case TRANSIT_ACTIVITY_OPEN: 517 animAttr = enter 518 ? WindowAnimation_activityOpenEnterAnimation 519 : WindowAnimation_activityOpenExitAnimation; 520 break; 521 case TRANSIT_ACTIVITY_CLOSE: 522 animAttr = enter 523 ? WindowAnimation_activityCloseEnterAnimation 524 : WindowAnimation_activityCloseExitAnimation; 525 break; 526 case TRANSIT_TASK_OPEN: 527 animAttr = enter 528 ? WindowAnimation_taskOpenEnterAnimation 529 : WindowAnimation_taskOpenExitAnimation; 530 break; 531 case TRANSIT_TASK_CLOSE: 532 animAttr = enter 533 ? WindowAnimation_taskCloseEnterAnimation 534 : WindowAnimation_taskCloseExitAnimation; 535 break; 536 case TRANSIT_TASK_TO_FRONT: 537 animAttr = enter 538 ? WindowAnimation_taskToFrontEnterAnimation 539 : WindowAnimation_taskToFrontExitAnimation; 540 break; 541 case TRANSIT_TASK_TO_BACK: 542 animAttr = enter 543 ? WindowAnimation_taskToBackEnterAnimation 544 : WindowAnimation_taskToBackExitAnimation; 545 break; 546 case TRANSIT_WALLPAPER_OPEN: 547 animAttr = enter 548 ? WindowAnimation_wallpaperOpenEnterAnimation 549 : WindowAnimation_wallpaperOpenExitAnimation; 550 break; 551 case TRANSIT_WALLPAPER_CLOSE: 552 animAttr = enter 553 ? WindowAnimation_wallpaperCloseEnterAnimation 554 : WindowAnimation_wallpaperCloseExitAnimation; 555 break; 556 case TRANSIT_WALLPAPER_INTRA_OPEN: 557 animAttr = enter 558 ? WindowAnimation_wallpaperIntraOpenEnterAnimation 559 : WindowAnimation_wallpaperIntraOpenExitAnimation; 560 break; 561 case TRANSIT_WALLPAPER_INTRA_CLOSE: 562 animAttr = enter 563 ? WindowAnimation_wallpaperIntraCloseEnterAnimation 564 : WindowAnimation_wallpaperIntraCloseExitAnimation; 565 break; 566 } 567 a = animAttr != 0 ? loadAnimation(lp, animAttr) : null; 568 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 569 "applyAnimation:" 570 + " anim=" + a 571 + " animAttr=0x" + Integer.toHexString(animAttr) 572 + " transit=" + transit + " isEntrance=" + enter 573 + " Callers=" + Debug.getCallers(3)); 574 } 575 return a; 576 } 577 578 void postAnimationCallback() { 579 if (mNextAppTransitionCallback != null) { 580 mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, mNextAppTransitionCallback)); 581 mNextAppTransitionCallback = null; 582 } 583 } 584 585 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, 586 IRemoteCallback startedCallback) { 587 if (isTransitionSet()) { 588 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM; 589 mNextAppTransitionPackage = packageName; 590 mNextAppTransitionThumbnail = null; 591 mNextAppTransitionEnter = enterAnim; 592 mNextAppTransitionExit = exitAnim; 593 postAnimationCallback(); 594 mNextAppTransitionCallback = startedCallback; 595 } else { 596 postAnimationCallback(); 597 } 598 } 599 600 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, 601 int startHeight) { 602 if (isTransitionSet()) { 603 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP; 604 mNextAppTransitionPackage = null; 605 mNextAppTransitionThumbnail = null; 606 mNextAppTransitionStartX = startX; 607 mNextAppTransitionStartY = startY; 608 mNextAppTransitionStartWidth = startWidth; 609 mNextAppTransitionStartHeight = startHeight; 610 postAnimationCallback(); 611 mNextAppTransitionCallback = null; 612 } 613 } 614 615 void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY, 616 IRemoteCallback startedCallback, boolean scaleUp) { 617 if (isTransitionSet()) { 618 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP 619 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN; 620 mNextAppTransitionPackage = null; 621 mNextAppTransitionThumbnail = srcThumb; 622 mNextAppTransitionScaleUp = scaleUp; 623 mNextAppTransitionStartX = startX; 624 mNextAppTransitionStartY = startY; 625 postAnimationCallback(); 626 mNextAppTransitionCallback = startedCallback; 627 } else { 628 postAnimationCallback(); 629 } 630 } 631 632 @Override 633 public String toString() { 634 return "mNextAppTransition=0x" + Integer.toHexString(mNextAppTransition); 635 } 636 637 /** 638 * Returns the human readable name of a window transition. 639 * 640 * @param transition The window transition. 641 * @return The transition symbolic name. 642 */ 643 public static String appTransitionToString(int transition) { 644 switch (transition) { 645 case TRANSIT_UNSET: { 646 return "TRANSIT_UNSET"; 647 } 648 case TRANSIT_NONE: { 649 return "TRANSIT_NONE"; 650 } 651 case TRANSIT_EXIT_MASK: { 652 return "TRANSIT_EXIT_MASK"; 653 } 654 case TRANSIT_ACTIVITY_OPEN: { 655 return "TRANSIT_ACTIVITY_OPEN"; 656 } 657 case TRANSIT_ACTIVITY_CLOSE: { 658 return "TRANSIT_ACTIVITY_CLOSE"; 659 } 660 case TRANSIT_TASK_OPEN: { 661 return "TRANSIT_TASK_OPEN"; 662 } 663 case TRANSIT_TASK_CLOSE: { 664 return "TRANSIT_TASK_CLOSE"; 665 } 666 case TRANSIT_TASK_TO_FRONT: { 667 return "TRANSIT_TASK_TO_FRONT"; 668 } 669 case TRANSIT_TASK_TO_BACK: { 670 return "TRANSIT_TASK_TO_BACK"; 671 } 672 case TRANSIT_WALLPAPER_CLOSE: { 673 return "TRANSIT_WALLPAPER_CLOSE"; 674 } 675 case TRANSIT_WALLPAPER_OPEN: { 676 return "TRANSIT_WALLPAPER_OPEN"; 677 } 678 case TRANSIT_WALLPAPER_INTRA_OPEN: { 679 return "TRANSIT_WALLPAPER_INTRA_OPEN"; 680 } 681 case TRANSIT_WALLPAPER_INTRA_CLOSE: { 682 return "TRANSIT_WALLPAPER_INTRA_CLOSE"; 683 } 684 default: { 685 return "<UNKNOWN>"; 686 } 687 } 688 } 689 690 private String appStateToString() { 691 switch (mAppTransitionState) { 692 case APP_STATE_IDLE: 693 return "APP_STATE_IDLE"; 694 case APP_STATE_READY: 695 return "APP_STATE_READY"; 696 case APP_STATE_RUNNING: 697 return "APP_STATE_RUNNING"; 698 case APP_STATE_TIMEOUT: 699 return "APP_STATE_TIMEOUT"; 700 default: 701 return "unknown state=" + mAppTransitionState; 702 } 703 } 704 705 private String transitTypeToString() { 706 switch (mNextAppTransitionType) { 707 case NEXT_TRANSIT_TYPE_NONE: 708 return "NEXT_TRANSIT_TYPE_NONE"; 709 case NEXT_TRANSIT_TYPE_CUSTOM: 710 return "NEXT_TRANSIT_TYPE_CUSTOM"; 711 case NEXT_TRANSIT_TYPE_SCALE_UP: 712 return "NEXT_TRANSIT_TYPE_SCALE_UP"; 713 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 714 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP"; 715 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 716 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN"; 717 default: 718 return "unknown type=" + mNextAppTransitionType; 719 } 720 } 721 722 @Override 723 public void dump(PrintWriter pw) { 724 pw.print(" " + this); 725 pw.print(" mAppTransitionState="); pw.println(appStateToString()); 726 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) { 727 pw.print(" mNextAppTransitionType="); pw.println(transitTypeToString()); 728 } 729 switch (mNextAppTransitionType) { 730 case NEXT_TRANSIT_TYPE_CUSTOM: 731 pw.print(" mNextAppTransitionPackage="); 732 pw.println(mNextAppTransitionPackage); 733 pw.print(" mNextAppTransitionEnter=0x"); 734 pw.print(Integer.toHexString(mNextAppTransitionEnter)); 735 pw.print(" mNextAppTransitionExit=0x"); 736 pw.println(Integer.toHexString(mNextAppTransitionExit)); 737 break; 738 case NEXT_TRANSIT_TYPE_SCALE_UP: 739 pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX); 740 pw.print(" mNextAppTransitionStartY="); 741 pw.println(mNextAppTransitionStartY); 742 pw.print(" mNextAppTransitionStartWidth="); 743 pw.print(mNextAppTransitionStartWidth); 744 pw.print(" mNextAppTransitionStartHeight="); 745 pw.println(mNextAppTransitionStartHeight); 746 break; 747 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 748 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 749 pw.print(" mNextAppTransitionThumbnail="); 750 pw.print(mNextAppTransitionThumbnail); 751 pw.print(" mNextAppTransitionStartX="); 752 pw.print(mNextAppTransitionStartX); 753 pw.print(" mNextAppTransitionStartY="); 754 pw.println(mNextAppTransitionStartY); 755 pw.print(" mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp); 756 break; 757 } 758 if (mNextAppTransitionCallback != null) { 759 pw.print(" mNextAppTransitionCallback="); 760 pw.println(mNextAppTransitionCallback); 761 } 762 } 763 764 public void setCurrentUser(int newUserId) { 765 mCurrentUserId = newUserId; 766 } 767 } 768