AppTransition.java revision 1d763a6d60c09e59b1aeba6a2cb009511323c08c
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 17package com.android.server.wm; 18 19import android.content.Context; 20import android.content.res.Configuration; 21import android.graphics.Bitmap; 22import android.graphics.Rect; 23import android.os.Debug; 24import android.os.Handler; 25import android.os.IBinder; 26import android.os.IRemoteCallback; 27import android.util.Slog; 28import android.view.WindowManager; 29import android.view.animation.AlphaAnimation; 30import android.view.animation.Animation; 31import android.view.animation.AnimationSet; 32import android.view.animation.AnimationUtils; 33import android.view.animation.ClipRectAnimation; 34import android.view.animation.ClipRectLRAnimation; 35import android.view.animation.ClipRectTBAnimation; 36import android.view.animation.Interpolator; 37import android.view.animation.PathInterpolator; 38import android.view.animation.ScaleAnimation; 39import android.view.animation.TranslateAnimation; 40import android.view.animation.TranslateYAnimation; 41 42import com.android.internal.util.DumpUtils.Dump; 43import com.android.server.AttributeCache; 44import com.android.server.wm.WindowManagerService.H; 45 46import java.io.PrintWriter; 47import java.util.ArrayList; 48 49import static android.view.WindowManagerInternal.AppTransitionListener; 50import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation; 51import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; 52import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation; 53import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation; 54import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation; 55import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation; 56import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation; 57import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation; 58import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation; 59import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation; 60import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation; 61import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation; 62import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation; 63import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation; 64import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation; 65import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation; 66import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation; 67import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; 68import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation; 69import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; 70import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; 71import 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. 78public 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 / 3, 535 centerX + mNextAppTransitionStartWidth / 3, 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 / 3 - translationY, 541 centerY + mNextAppTransitionStartHeight / 3 - 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.initialize(appWidth, appHeight, appWidth, appHeight); 563 anim = set; 564 } else { 565 final long duration; 566 switch (transit) { 567 case TRANSIT_ACTIVITY_OPEN: 568 case TRANSIT_ACTIVITY_CLOSE: 569 duration = mConfigShortAnimTime; 570 break; 571 default: 572 duration = DEFAULT_APP_TRANSITION_DURATION; 573 break; 574 } 575 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN || 576 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) { 577 // If we are on top of the wallpaper, we need an animation that 578 // correctly handles the wallpaper staying static behind all of 579 // the animated elements. To do this, will just have the existing 580 // element fade out. 581 anim = new AlphaAnimation(1, 0); 582 anim.setDetachWallpaper(true); 583 } else { 584 // For normal animations, the exiting element just holds in place. 585 anim = new AlphaAnimation(1, 1); 586 } 587 anim.setInterpolator(mDecelerateInterpolator); 588 anim.setDuration(duration); 589 anim.setFillAfter(true); 590 } 591 return anim; 592 } 593 594 /** 595 * Prepares the specified animation with a standard duration, interpolator, etc. 596 */ 597 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight, 598 int duration, Interpolator interpolator) { 599 if (duration > 0) { 600 a.setDuration(duration); 601 } 602 a.setFillAfter(true); 603 a.setInterpolator(interpolator); 604 a.initialize(appWidth, appHeight, appWidth, appHeight); 605 return a; 606 } 607 608 /** 609 * Prepares the specified animation with a standard duration, interpolator, etc. 610 */ 611 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) { 612 // Pick the desired duration. If this is an inter-activity transition, 613 // it is the standard duration for that. Otherwise we use the longer 614 // task transition duration. 615 final int duration; 616 switch (transit) { 617 case TRANSIT_ACTIVITY_OPEN: 618 case TRANSIT_ACTIVITY_CLOSE: 619 duration = mConfigShortAnimTime; 620 break; 621 default: 622 duration = DEFAULT_APP_TRANSITION_DURATION; 623 break; 624 } 625 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, 626 mDecelerateInterpolator); 627 } 628 629 /** 630 * Return the current thumbnail transition state. 631 */ 632 int getThumbnailTransitionState(boolean enter) { 633 if (enter) { 634 if (mNextAppTransitionScaleUp) { 635 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP; 636 } else { 637 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN; 638 } 639 } else { 640 if (mNextAppTransitionScaleUp) { 641 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP; 642 } else { 643 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN; 644 } 645 } 646 } 647 648 /** 649 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 650 * when a thumbnail is specified with the activity options. 651 */ 652 Animation createThumbnailAspectScaleAnimationLocked(int appWidth, int appHeight, 653 int deviceWidth, int transit) { 654 Animation a; 655 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 656 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 657 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 658 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 659 660 float scaleW = deviceWidth / thumbWidth; 661 float unscaledWidth = deviceWidth; 662 float unscaledHeight = thumbHeight * scaleW; 663 float unscaledStartY = mNextAppTransitionStartY - (unscaledHeight - thumbHeight) / 2f; 664 if (mNextAppTransitionScaleUp) { 665 // Animation up from the thumbnail to the full screen 666 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, 667 mNextAppTransitionStartX + (thumbWidth / 2f), 668 mNextAppTransitionStartY + (thumbHeight / 2f)); 669 scale.setInterpolator(mTouchResponseInterpolator); 670 scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 671 Animation alpha = new AlphaAnimation(1, 0); 672 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 673 alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION); 674 Animation translate = new TranslateAnimation(0, 0, 0, -unscaledStartY + 675 mNextAppTransitionInsets.top); 676 translate.setInterpolator(mTouchResponseInterpolator); 677 translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 678 679 // This AnimationSet uses the Interpolators assigned above. 680 AnimationSet set = new AnimationSet(false); 681 set.addAnimation(scale); 682 set.addAnimation(alpha); 683 set.addAnimation(translate); 684 a = set; 685 } else { 686 // Animation down from the full screen to the thumbnail 687 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, 688 mNextAppTransitionStartX + (thumbWidth / 2f), 689 mNextAppTransitionStartY + (thumbHeight / 2f)); 690 scale.setInterpolator(mTouchResponseInterpolator); 691 scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 692 Animation alpha = new AlphaAnimation(0f, 1f); 693 alpha.setInterpolator(mThumbnailFadeInInterpolator); 694 alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION); 695 Animation translate = new TranslateAnimation(0, 0, -unscaledStartY + 696 mNextAppTransitionInsets.top, 0); 697 translate.setInterpolator(mTouchResponseInterpolator); 698 translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); 699 700 // This AnimationSet uses the Interpolators assigned above. 701 AnimationSet set = new AnimationSet(false); 702 set.addAnimation(scale); 703 set.addAnimation(alpha); 704 set.addAnimation(translate); 705 a = set; 706 707 } 708 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, 0, 709 mTouchResponseInterpolator); 710 } 711 712 /** 713 * This alternate animation is created when we are doing a thumbnail transition, for the 714 * activity that is leaving, and the activity that is entering. 715 */ 716 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState, 717 int appWidth, int appHeight, int orientation, int transit, Rect containingFrame, 718 Rect contentInsets, boolean isFullScreen) { 719 Animation a; 720 final int thumbWidthI = mNextAppTransitionStartWidth; 721 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 722 final int thumbHeightI = mNextAppTransitionStartHeight; 723 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 724 725 // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions 726 float scale = 1f; 727 int scaledTopDecor = 0; 728 729 switch (thumbTransitState) { 730 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: { 731 // App window scaling up to become full screen 732 if (orientation == Configuration.ORIENTATION_PORTRAIT) { 733 // In portrait, we scale the width and clip to the top/left square 734 scale = thumbWidth / appWidth; 735 scaledTopDecor = (int) (scale * contentInsets.top); 736 int unscaledThumbHeight = (int) (thumbHeight / scale); 737 mTmpFromClipRect.set(containingFrame); 738 if (isFullScreen) { 739 mTmpFromClipRect.top = contentInsets.top; 740 } 741 mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); 742 mTmpToClipRect.set(containingFrame); 743 } else { 744 // In landscape, we scale the height and clip to the top/left square 745 scale = thumbHeight / (appHeight - contentInsets.top); 746 scaledTopDecor = (int) (scale * contentInsets.top); 747 int unscaledThumbWidth = (int) (thumbWidth / scale); 748 int unscaledThumbHeight = (int) (thumbHeight / scale); 749 mTmpFromClipRect.set(containingFrame); 750 if (isFullScreen) { 751 mTmpFromClipRect.top = contentInsets.top; 752 mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); 753 } 754 mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth); 755 mTmpToClipRect.set(containingFrame); 756 } 757 mNextAppTransitionInsets.set(contentInsets); 758 759 Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1, 760 computePivot(mNextAppTransitionStartX, scale), 761 computePivot(mNextAppTransitionStartY, scale)); 762 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); 763 Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0); 764 765 AnimationSet set = new AnimationSet(true); 766 set.addAnimation(clipAnim); 767 set.addAnimation(scaleAnim); 768 set.addAnimation(translateAnim); 769 a = set; 770 break; 771 } 772 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 773 // Previous app window during the scale up 774 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 775 // Fade out the source activity if we are animating to a wallpaper 776 // activity. 777 a = new AlphaAnimation(1, 0); 778 } else { 779 a = new AlphaAnimation(1, 1); 780 } 781 break; 782 } 783 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 784 // Target app window during the scale down 785 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 786 // Fade in the destination activity if we are animating from a wallpaper 787 // activity. 788 a = new AlphaAnimation(0, 1); 789 } else { 790 a = new AlphaAnimation(1, 1); 791 } 792 break; 793 } 794 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 795 // App window scaling down from full screen 796 if (orientation == Configuration.ORIENTATION_PORTRAIT) { 797 // In portrait, we scale the width and clip to the top/left square 798 scale = thumbWidth / appWidth; 799 scaledTopDecor = (int) (scale * contentInsets.top); 800 int unscaledThumbHeight = (int) (thumbHeight / scale); 801 mTmpFromClipRect.set(containingFrame); 802 mTmpToClipRect.set(containingFrame); 803 if (isFullScreen) { 804 mTmpToClipRect.top = contentInsets.top; 805 } 806 mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); 807 } else { 808 // In landscape, we scale the height and clip to the top/left square 809 scale = thumbHeight / (appHeight - contentInsets.top); 810 scaledTopDecor = (int) (scale * contentInsets.top); 811 int unscaledThumbWidth = (int) (thumbWidth / scale); 812 int unscaledThumbHeight = (int) (thumbHeight / scale); 813 mTmpFromClipRect.set(containingFrame); 814 mTmpToClipRect.set(containingFrame); 815 if (isFullScreen) { 816 mTmpToClipRect.top = contentInsets.top; 817 mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); 818 } 819 mTmpToClipRect.right = (mTmpToClipRect.left + unscaledThumbWidth); 820 } 821 mNextAppTransitionInsets.set(contentInsets); 822 823 Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale, 824 computePivot(mNextAppTransitionStartX, scale), 825 computePivot(mNextAppTransitionStartY, scale)); 826 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); 827 Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor); 828 829 AnimationSet set = new AnimationSet(true); 830 set.addAnimation(clipAnim); 831 set.addAnimation(scaleAnim); 832 set.addAnimation(translateAnim); 833 834 a = set; 835 a.setZAdjustment(Animation.ZORDER_TOP); 836 break; 837 } 838 default: 839 throw new RuntimeException("Invalid thumbnail transition state"); 840 } 841 842 int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION, 843 THUMBNAIL_APP_TRANSITION_DURATION); 844 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, 845 mTouchResponseInterpolator); 846 } 847 848 /** 849 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 850 * when a thumbnail is specified with the activity options. 851 */ 852 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit) { 853 Animation a; 854 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 855 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 856 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 857 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 858 859 if (mNextAppTransitionScaleUp) { 860 // Animation for the thumbnail zooming from its initial size to the full screen 861 float scaleW = appWidth / thumbWidth; 862 float scaleH = appHeight / thumbHeight; 863 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 864 computePivot(mNextAppTransitionStartX, 1 / scaleW), 865 computePivot(mNextAppTransitionStartY, 1 / scaleH)); 866 scale.setInterpolator(mDecelerateInterpolator); 867 868 Animation alpha = new AlphaAnimation(1, 0); 869 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 870 871 // This AnimationSet uses the Interpolators assigned above. 872 AnimationSet set = new AnimationSet(false); 873 set.addAnimation(scale); 874 set.addAnimation(alpha); 875 a = set; 876 } else { 877 // Animation for the thumbnail zooming down from the full screen to its final size 878 float scaleW = appWidth / thumbWidth; 879 float scaleH = appHeight / thumbHeight; 880 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 881 computePivot(mNextAppTransitionStartX, 1 / scaleW), 882 computePivot(mNextAppTransitionStartY, 1 / scaleH)); 883 } 884 885 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 886 } 887 888 /** 889 * This animation is created when we are doing a thumbnail transition, for the activity that is 890 * leaving, and the activity that is entering. 891 */ 892 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth, 893 int appHeight, int transit) { 894 Animation a; 895 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 896 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 897 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 898 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 899 900 switch (thumbTransitState) { 901 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: { 902 // Entering app scales up with the thumbnail 903 float scaleW = thumbWidth / appWidth; 904 float scaleH = thumbHeight / appHeight; 905 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 906 computePivot(mNextAppTransitionStartX, scaleW), 907 computePivot(mNextAppTransitionStartY, scaleH)); 908 break; 909 } 910 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 911 // Exiting app while the thumbnail is scaling up should fade or stay in place 912 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 913 // Fade out while bringing up selected activity. This keeps the 914 // current activity from showing through a launching wallpaper 915 // activity. 916 a = new AlphaAnimation(1, 0); 917 } else { 918 // noop animation 919 a = new AlphaAnimation(1, 1); 920 } 921 break; 922 } 923 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 924 // Entering the other app, it should just be visible while we scale the thumbnail 925 // down above it 926 a = new AlphaAnimation(1, 1); 927 break; 928 } 929 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 930 // Exiting the current app, the app should scale down with the thumbnail 931 float scaleW = thumbWidth / appWidth; 932 float scaleH = thumbHeight / appHeight; 933 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 934 computePivot(mNextAppTransitionStartX, scaleW), 935 computePivot(mNextAppTransitionStartY, scaleH)); 936 937 Animation alpha = new AlphaAnimation(1, 0); 938 939 AnimationSet set = new AnimationSet(true); 940 set.addAnimation(scale); 941 set.addAnimation(alpha); 942 set.setZAdjustment(Animation.ZORDER_TOP); 943 a = set; 944 break; 945 } 946 default: 947 throw new RuntimeException("Invalid thumbnail transition state"); 948 } 949 950 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 951 } 952 953 954 Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, 955 int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets, 956 Rect appFrame, boolean isFullScreen, boolean isVoiceInteraction) { 957 Animation a; 958 if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN 959 || transit == TRANSIT_TASK_OPEN 960 || transit == TRANSIT_TASK_TO_FRONT)) { 961 a = loadAnimationRes(lp, enter 962 ? com.android.internal.R.anim.voice_activity_open_enter 963 : com.android.internal.R.anim.voice_activity_open_exit); 964 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 965 "applyAnimation voice:" 966 + " anim=" + a + " transit=" + appTransitionToString(transit) 967 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); 968 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE 969 || transit == TRANSIT_TASK_CLOSE 970 || transit == TRANSIT_TASK_TO_BACK)) { 971 a = loadAnimationRes(lp, enter 972 ? com.android.internal.R.anim.voice_activity_close_enter 973 : com.android.internal.R.anim.voice_activity_close_exit); 974 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 975 "applyAnimation voice:" 976 + " anim=" + a + " transit=" + appTransitionToString(transit) 977 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); 978 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { 979 a = loadAnimationRes(mNextAppTransitionPackage, enter ? 980 mNextAppTransitionEnter : mNextAppTransitionExit); 981 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 982 "applyAnimation:" 983 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM" 984 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 985 + " Callers=" + Debug.getCallers(3)); 986 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) { 987 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace); 988 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 989 "applyAnimation:" 990 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE" 991 + " transit=" + appTransitionToString(transit) 992 + " Callers=" + Debug.getCallers(3)); 993 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) { 994 a = createClipRevealAnimationLocked(transit, enter, appFrame); 995 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 996 "applyAnimation:" 997 + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL" 998 + " Callers=" + Debug.getCallers(3)); 999 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) { 1000 a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight); 1001 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1002 "applyAnimation:" 1003 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" 1004 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1005 + " Callers=" + Debug.getCallers(3)); 1006 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP || 1007 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { 1008 mNextAppTransitionScaleUp = 1009 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); 1010 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter), 1011 appWidth, appHeight, transit); 1012 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 1013 String animName = mNextAppTransitionScaleUp ? 1014 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; 1015 Slog.v(TAG, "applyAnimation:" 1016 + " anim=" + a + " nextAppTransition=" + animName 1017 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1018 + " Callers=" + Debug.getCallers(3)); 1019 } 1020 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || 1021 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) { 1022 mNextAppTransitionScaleUp = 1023 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP); 1024 a = createAspectScaledThumbnailEnterExitAnimationLocked( 1025 getThumbnailTransitionState(enter), appWidth, appHeight, orientation, 1026 transit, containingFrame, contentInsets, isFullScreen); 1027 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 1028 String animName = mNextAppTransitionScaleUp ? 1029 "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN"; 1030 Slog.v(TAG, "applyAnimation:" 1031 + " anim=" + a + " nextAppTransition=" + animName 1032 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1033 + " Callers=" + Debug.getCallers(3)); 1034 } 1035 } else { 1036 int animAttr = 0; 1037 switch (transit) { 1038 case TRANSIT_ACTIVITY_OPEN: 1039 animAttr = enter 1040 ? WindowAnimation_activityOpenEnterAnimation 1041 : WindowAnimation_activityOpenExitAnimation; 1042 break; 1043 case TRANSIT_ACTIVITY_CLOSE: 1044 animAttr = enter 1045 ? WindowAnimation_activityCloseEnterAnimation 1046 : WindowAnimation_activityCloseExitAnimation; 1047 break; 1048 case TRANSIT_TASK_OPEN: 1049 animAttr = enter 1050 ? WindowAnimation_taskOpenEnterAnimation 1051 : WindowAnimation_taskOpenExitAnimation; 1052 break; 1053 case TRANSIT_TASK_CLOSE: 1054 animAttr = enter 1055 ? WindowAnimation_taskCloseEnterAnimation 1056 : WindowAnimation_taskCloseExitAnimation; 1057 break; 1058 case TRANSIT_TASK_TO_FRONT: 1059 animAttr = enter 1060 ? WindowAnimation_taskToFrontEnterAnimation 1061 : WindowAnimation_taskToFrontExitAnimation; 1062 break; 1063 case TRANSIT_TASK_TO_BACK: 1064 animAttr = enter 1065 ? WindowAnimation_taskToBackEnterAnimation 1066 : WindowAnimation_taskToBackExitAnimation; 1067 break; 1068 case TRANSIT_WALLPAPER_OPEN: 1069 animAttr = enter 1070 ? WindowAnimation_wallpaperOpenEnterAnimation 1071 : WindowAnimation_wallpaperOpenExitAnimation; 1072 break; 1073 case TRANSIT_WALLPAPER_CLOSE: 1074 animAttr = enter 1075 ? WindowAnimation_wallpaperCloseEnterAnimation 1076 : WindowAnimation_wallpaperCloseExitAnimation; 1077 break; 1078 case TRANSIT_WALLPAPER_INTRA_OPEN: 1079 animAttr = enter 1080 ? WindowAnimation_wallpaperIntraOpenEnterAnimation 1081 : WindowAnimation_wallpaperIntraOpenExitAnimation; 1082 break; 1083 case TRANSIT_WALLPAPER_INTRA_CLOSE: 1084 animAttr = enter 1085 ? WindowAnimation_wallpaperIntraCloseEnterAnimation 1086 : WindowAnimation_wallpaperIntraCloseExitAnimation; 1087 break; 1088 case TRANSIT_TASK_OPEN_BEHIND: 1089 animAttr = enter 1090 ? WindowAnimation_launchTaskBehindSourceAnimation 1091 : WindowAnimation_launchTaskBehindTargetAnimation; 1092 } 1093 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null; 1094 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1095 "applyAnimation:" 1096 + " anim=" + a 1097 + " animAttr=0x" + Integer.toHexString(animAttr) 1098 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1099 + " Callers=" + Debug.getCallers(3)); 1100 } 1101 return a; 1102 } 1103 1104 void postAnimationCallback() { 1105 if (mNextAppTransitionCallback != null) { 1106 mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, mNextAppTransitionCallback)); 1107 mNextAppTransitionCallback = null; 1108 } 1109 } 1110 1111 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, 1112 IRemoteCallback startedCallback) { 1113 if (isTransitionSet()) { 1114 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM; 1115 mNextAppTransitionPackage = packageName; 1116 mNextAppTransitionThumbnail = null; 1117 mNextAppTransitionEnter = enterAnim; 1118 mNextAppTransitionExit = exitAnim; 1119 postAnimationCallback(); 1120 mNextAppTransitionCallback = startedCallback; 1121 } else { 1122 postAnimationCallback(); 1123 } 1124 } 1125 1126 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, 1127 int startHeight) { 1128 if (isTransitionSet()) { 1129 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP; 1130 mNextAppTransitionPackage = null; 1131 mNextAppTransitionThumbnail = null; 1132 mNextAppTransitionStartX = startX; 1133 mNextAppTransitionStartY = startY; 1134 mNextAppTransitionStartWidth = startWidth; 1135 mNextAppTransitionStartHeight = startHeight; 1136 postAnimationCallback(); 1137 mNextAppTransitionCallback = null; 1138 } 1139 } 1140 1141 void overridePendingAppTransitionClipReveal(int startX, int startY, 1142 int startWidth, int startHeight) { 1143 if (isTransitionSet()) { 1144 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL; 1145 mNextAppTransitionStartX = startX; 1146 mNextAppTransitionStartY = startY; 1147 mNextAppTransitionStartWidth = startWidth; 1148 mNextAppTransitionStartHeight = startHeight; 1149 postAnimationCallback(); 1150 mNextAppTransitionCallback = null; 1151 } 1152 } 1153 1154 void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY, 1155 IRemoteCallback startedCallback, boolean scaleUp) { 1156 if (isTransitionSet()) { 1157 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP 1158 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN; 1159 mNextAppTransitionPackage = null; 1160 mNextAppTransitionThumbnail = srcThumb; 1161 mNextAppTransitionScaleUp = scaleUp; 1162 mNextAppTransitionStartX = startX; 1163 mNextAppTransitionStartY = startY; 1164 postAnimationCallback(); 1165 mNextAppTransitionCallback = startedCallback; 1166 } else { 1167 postAnimationCallback(); 1168 } 1169 } 1170 1171 void overridePendingAppTransitionAspectScaledThumb(Bitmap srcThumb, int startX, int startY, 1172 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) { 1173 if (isTransitionSet()) { 1174 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP 1175 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 1176 mNextAppTransitionPackage = null; 1177 mNextAppTransitionThumbnail = srcThumb; 1178 mNextAppTransitionScaleUp = scaleUp; 1179 mNextAppTransitionStartX = startX; 1180 mNextAppTransitionStartY = startY; 1181 mNextAppTransitionStartWidth = targetWidth; 1182 mNextAppTransitionStartHeight = targetHeight; 1183 postAnimationCallback(); 1184 mNextAppTransitionCallback = startedCallback; 1185 } else { 1186 postAnimationCallback(); 1187 } 1188 } 1189 1190 void overrideInPlaceAppTransition(String packageName, int anim) { 1191 if (isTransitionSet()) { 1192 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE; 1193 mNextAppTransitionPackage = packageName; 1194 mNextAppTransitionInPlace = anim; 1195 } else { 1196 postAnimationCallback(); 1197 } 1198 } 1199 1200 @Override 1201 public String toString() { 1202 return "mNextAppTransition=" + appTransitionToString(mNextAppTransition); 1203 } 1204 1205 /** 1206 * Returns the human readable name of a window transition. 1207 * 1208 * @param transition The window transition. 1209 * @return The transition symbolic name. 1210 */ 1211 public static String appTransitionToString(int transition) { 1212 switch (transition) { 1213 case TRANSIT_UNSET: { 1214 return "TRANSIT_UNSET"; 1215 } 1216 case TRANSIT_NONE: { 1217 return "TRANSIT_NONE"; 1218 } 1219 case TRANSIT_ACTIVITY_OPEN: { 1220 return "TRANSIT_ACTIVITY_OPEN"; 1221 } 1222 case TRANSIT_ACTIVITY_CLOSE: { 1223 return "TRANSIT_ACTIVITY_CLOSE"; 1224 } 1225 case TRANSIT_TASK_OPEN: { 1226 return "TRANSIT_TASK_OPEN"; 1227 } 1228 case TRANSIT_TASK_CLOSE: { 1229 return "TRANSIT_TASK_CLOSE"; 1230 } 1231 case TRANSIT_TASK_TO_FRONT: { 1232 return "TRANSIT_TASK_TO_FRONT"; 1233 } 1234 case TRANSIT_TASK_TO_BACK: { 1235 return "TRANSIT_TASK_TO_BACK"; 1236 } 1237 case TRANSIT_WALLPAPER_CLOSE: { 1238 return "TRANSIT_WALLPAPER_CLOSE"; 1239 } 1240 case TRANSIT_WALLPAPER_OPEN: { 1241 return "TRANSIT_WALLPAPER_OPEN"; 1242 } 1243 case TRANSIT_WALLPAPER_INTRA_OPEN: { 1244 return "TRANSIT_WALLPAPER_INTRA_OPEN"; 1245 } 1246 case TRANSIT_WALLPAPER_INTRA_CLOSE: { 1247 return "TRANSIT_WALLPAPER_INTRA_CLOSE"; 1248 } 1249 case TRANSIT_TASK_OPEN_BEHIND: { 1250 return "TRANSIT_TASK_OPEN_BEHIND"; 1251 } 1252 default: { 1253 return "<UNKNOWN>"; 1254 } 1255 } 1256 } 1257 1258 private String appStateToString() { 1259 switch (mAppTransitionState) { 1260 case APP_STATE_IDLE: 1261 return "APP_STATE_IDLE"; 1262 case APP_STATE_READY: 1263 return "APP_STATE_READY"; 1264 case APP_STATE_RUNNING: 1265 return "APP_STATE_RUNNING"; 1266 case APP_STATE_TIMEOUT: 1267 return "APP_STATE_TIMEOUT"; 1268 default: 1269 return "unknown state=" + mAppTransitionState; 1270 } 1271 } 1272 1273 private String transitTypeToString() { 1274 switch (mNextAppTransitionType) { 1275 case NEXT_TRANSIT_TYPE_NONE: 1276 return "NEXT_TRANSIT_TYPE_NONE"; 1277 case NEXT_TRANSIT_TYPE_CUSTOM: 1278 return "NEXT_TRANSIT_TYPE_CUSTOM"; 1279 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1280 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE"; 1281 case NEXT_TRANSIT_TYPE_SCALE_UP: 1282 return "NEXT_TRANSIT_TYPE_SCALE_UP"; 1283 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1284 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP"; 1285 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1286 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN"; 1287 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1288 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP"; 1289 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: 1290 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN"; 1291 default: 1292 return "unknown type=" + mNextAppTransitionType; 1293 } 1294 } 1295 1296 @Override 1297 public void dump(PrintWriter pw, String prefix) { 1298 pw.print(prefix); pw.println(this); 1299 pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString()); 1300 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) { 1301 pw.print(prefix); pw.print("mNextAppTransitionType="); 1302 pw.println(transitTypeToString()); 1303 } 1304 switch (mNextAppTransitionType) { 1305 case NEXT_TRANSIT_TYPE_CUSTOM: 1306 pw.print(prefix); pw.print("mNextAppTransitionPackage="); 1307 pw.println(mNextAppTransitionPackage); 1308 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x"); 1309 pw.print(Integer.toHexString(mNextAppTransitionEnter)); 1310 pw.print(" mNextAppTransitionExit=0x"); 1311 pw.println(Integer.toHexString(mNextAppTransitionExit)); 1312 break; 1313 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1314 pw.print(prefix); pw.print("mNextAppTransitionPackage="); 1315 pw.println(mNextAppTransitionPackage); 1316 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x"); 1317 pw.print(Integer.toHexString(mNextAppTransitionInPlace)); 1318 break; 1319 case NEXT_TRANSIT_TYPE_SCALE_UP: 1320 pw.print(prefix); pw.print("mNextAppTransitionStartX="); 1321 pw.print(mNextAppTransitionStartX); 1322 pw.print(" mNextAppTransitionStartY="); 1323 pw.println(mNextAppTransitionStartY); 1324 pw.print(prefix); pw.print("mNextAppTransitionStartWidth="); 1325 pw.print(mNextAppTransitionStartWidth); 1326 pw.print(" mNextAppTransitionStartHeight="); 1327 pw.println(mNextAppTransitionStartHeight); 1328 break; 1329 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1330 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1331 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1332 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: 1333 pw.print(prefix); pw.print("mNextAppTransitionThumbnail="); 1334 pw.print(mNextAppTransitionThumbnail); 1335 pw.print(" mNextAppTransitionStartX="); 1336 pw.print(mNextAppTransitionStartX); 1337 pw.print(" mNextAppTransitionStartY="); 1338 pw.println(mNextAppTransitionStartY); 1339 pw.print(prefix); pw.print("mNextAppTransitionStartWidth="); 1340 pw.print(mNextAppTransitionStartWidth); 1341 pw.print(" mNextAppTransitionStartHeight="); 1342 pw.println(mNextAppTransitionStartHeight); 1343 pw.print(prefix); pw.print("mNextAppTransitionScaleUp="); 1344 pw.println(mNextAppTransitionScaleUp); 1345 break; 1346 } 1347 if (mNextAppTransitionCallback != null) { 1348 pw.print(prefix); pw.print("mNextAppTransitionCallback="); 1349 pw.println(mNextAppTransitionCallback); 1350 } 1351 } 1352 1353 public void setCurrentUser(int newUserId) { 1354 mCurrentUserId = newUserId; 1355 } 1356} 1357