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