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