AppTransition.java revision 2550f3f787a850dc2cd0f45aa78ba70fb5c8ec3e
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 static android.view.WindowManagerInternal.AppTransitionListener; 20import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation; 21import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; 22import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation; 23import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation; 24import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation; 25import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation; 26import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation; 27import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation; 28import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation; 29import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation; 30import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation; 31import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation; 32import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation; 33import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation; 34import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation; 35import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation; 36import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation; 37import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; 38import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation; 39import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; 40import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; 41import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; 42import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START; 43import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 44import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; 45import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 46import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 47import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; 48import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; 49 50import android.annotation.Nullable; 51import android.content.Context; 52import android.content.res.Configuration; 53import android.graphics.Bitmap; 54import android.graphics.Path; 55import android.graphics.Rect; 56import android.os.Debug; 57import android.os.IBinder; 58import android.os.IRemoteCallback; 59import android.os.RemoteException; 60import android.os.SystemProperties; 61import android.util.ArraySet; 62import android.util.Slog; 63import android.util.SparseArray; 64import android.view.AppTransitionAnimationSpec; 65import android.view.IAppTransitionAnimationSpecsFuture; 66import android.view.WindowManager; 67import android.view.animation.AlphaAnimation; 68import android.view.animation.Animation; 69import android.view.animation.AnimationSet; 70import android.view.animation.AnimationUtils; 71import android.view.animation.ClipRectAnimation; 72import android.view.animation.Interpolator; 73import android.view.animation.PathInterpolator; 74import android.view.animation.ScaleAnimation; 75import android.view.animation.TranslateAnimation; 76 77import com.android.internal.util.DumpUtils.Dump; 78import com.android.server.AttributeCache; 79import com.android.server.wm.WindowManagerService.H; 80import com.android.server.wm.animation.ClipRectLRAnimation; 81import com.android.server.wm.animation.ClipRectTBAnimation; 82import com.android.server.wm.animation.CurvedTranslateAnimation; 83 84import java.io.PrintWriter; 85import java.util.ArrayList; 86import java.util.concurrent.ExecutorService; 87import java.util.concurrent.Executors; 88 89// State management of app transitions. When we are preparing for a 90// transition, mNextAppTransition will be the kind of transition to 91// perform or TRANSIT_NONE if we are not waiting. If we are waiting, 92// mOpeningApps and mClosingApps are the lists of tokens that will be 93// made visible or hidden at the next transition. 94public class AppTransition implements Dump { 95 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM; 96 private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8; 97 98 /** Not set up for a transition. */ 99 public static final int TRANSIT_UNSET = -1; 100 /** No animation for transition. */ 101 public static final int TRANSIT_NONE = 0; 102 /** A window in a new activity is being opened on top of an existing one in the same task. */ 103 public static final int TRANSIT_ACTIVITY_OPEN = 6; 104 /** The window in the top-most activity is being closed to reveal the 105 * previous activity in the same task. */ 106 public static final int TRANSIT_ACTIVITY_CLOSE = 7; 107 /** A window in a new task is being opened on top of an existing one 108 * in another activity's task. */ 109 public static final int TRANSIT_TASK_OPEN = 8; 110 /** A window in the top-most activity is being closed to reveal the 111 * previous activity in a different task. */ 112 public static final int TRANSIT_TASK_CLOSE = 9; 113 /** A window in an existing task is being displayed on top of an existing one 114 * in another activity's task. */ 115 public static final int TRANSIT_TASK_TO_FRONT = 10; 116 /** A window in an existing task is being put below all other tasks. */ 117 public static final int TRANSIT_TASK_TO_BACK = 11; 118 /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that 119 * does, effectively closing the wallpaper. */ 120 public static final int TRANSIT_WALLPAPER_CLOSE = 12; 121 /** A window in a new activity that does have a wallpaper is being opened on one that didn't, 122 * effectively opening the wallpaper. */ 123 public static final int TRANSIT_WALLPAPER_OPEN = 13; 124 /** A window in a new activity is being opened on top of an existing one, and both are on top 125 * of the wallpaper. */ 126 public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14; 127 /** The window in the top-most activity is being closed to reveal the previous activity, and 128 * both are on top of the wallpaper. */ 129 public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15; 130 /** A window in a new task is being opened behind an existing one in another activity's task. 131 * The new window will show briefly and then be gone. */ 132 public static final int TRANSIT_TASK_OPEN_BEHIND = 16; 133 /** A window in a task is being animated in-place. */ 134 public static final int TRANSIT_TASK_IN_PLACE = 17; 135 /** An activity is being relaunched (e.g. due to configuration change). */ 136 public static final int TRANSIT_ACTIVITY_RELAUNCH = 18; 137 /** A task is being docked from recents. */ 138 public static final int TRANSIT_DOCK_TASK_FROM_RECENTS = 19; 139 /** Keyguard is going away */ 140 public static final int TRANSIT_KEYGUARD_GOING_AWAY = 20; 141 /** Keyguard is going away with showing an activity behind that requests wallpaper */ 142 public static final int TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21; 143 /** Keyguard is being occluded */ 144 public static final int TRANSIT_KEYGUARD_OCCLUDE = 22; 145 /** Keyguard is being unoccluded */ 146 public static final int TRANSIT_KEYGUARD_UNOCCLUDE = 23; 147 148 /** Transition flag: Keyguard is going away, but keeping the notification shade open */ 149 public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE = 0x1; 150 /** Transition flag: Keyguard is going away, but doesn't want an animation for it */ 151 public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION = 0x2; 152 /** Transition flag: Keyguard is going away while it was showing the system wallpaper. */ 153 public static final int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER = 0x4; 154 155 /** Fraction of animation at which the recents thumbnail stays completely transparent */ 156 private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f; 157 /** Fraction of animation at which the recents thumbnail becomes completely transparent */ 158 private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f; 159 160 static final int DEFAULT_APP_TRANSITION_DURATION = 336; 161 162 /** Interpolator to be used for animations that respond directly to a touch */ 163 static final Interpolator TOUCH_RESPONSE_INTERPOLATOR = 164 new PathInterpolator(0.3f, 0f, 0.1f, 1f); 165 166 private static final Interpolator THUMBNAIL_DOCK_INTERPOLATOR = 167 new PathInterpolator(0.85f, 0f, 1f, 1f); 168 169 /** 170 * Maximum duration for the clip reveal animation. This is used when there is a lot of movement 171 * involved, to make it more understandable. 172 */ 173 private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420; 174 private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336; 175 private static final long APP_TRANSITION_TIMEOUT_MS = 5000; 176 177 private final Context mContext; 178 private final WindowManagerService mService; 179 180 private int mNextAppTransition = TRANSIT_UNSET; 181 private int mNextAppTransitionFlags = 0; 182 private int mLastUsedAppTransition = TRANSIT_UNSET; 183 private String mLastOpeningApp; 184 private String mLastClosingApp; 185 186 private static final int NEXT_TRANSIT_TYPE_NONE = 0; 187 private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1; 188 private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2; 189 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3; 190 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4; 191 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5; 192 private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6; 193 private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7; 194 private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8; 195 private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; 196 197 // These are the possible states for the enter/exit activities during a thumbnail transition 198 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0; 199 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1; 200 private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2; 201 private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3; 202 203 private String mNextAppTransitionPackage; 204 // Used for thumbnail transitions. True if we're scaling up, false if scaling down 205 private boolean mNextAppTransitionScaleUp; 206 private IRemoteCallback mNextAppTransitionCallback; 207 private IRemoteCallback mNextAppTransitionFutureCallback; 208 private IRemoteCallback mAnimationFinishedCallback; 209 private int mNextAppTransitionEnter; 210 private int mNextAppTransitionExit; 211 private int mNextAppTransitionInPlace; 212 213 // Keyed by task id. 214 private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs 215 = new SparseArray<>(); 216 private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture; 217 private boolean mNextAppTransitionAnimationsSpecsPending; 218 private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec; 219 220 private Rect mNextAppTransitionInsets = new Rect(); 221 222 private Rect mTmpFromClipRect = new Rect(); 223 private Rect mTmpToClipRect = new Rect(); 224 225 private final Rect mTmpRect = new Rect(); 226 227 private final static int APP_STATE_IDLE = 0; 228 private final static int APP_STATE_READY = 1; 229 private final static int APP_STATE_RUNNING = 2; 230 private final static int APP_STATE_TIMEOUT = 3; 231 private int mAppTransitionState = APP_STATE_IDLE; 232 233 private final int mConfigShortAnimTime; 234 private final Interpolator mDecelerateInterpolator; 235 private final Interpolator mThumbnailFadeInInterpolator; 236 private final Interpolator mThumbnailFadeOutInterpolator; 237 private final Interpolator mLinearOutSlowInInterpolator; 238 private final Interpolator mFastOutLinearInInterpolator; 239 private final Interpolator mFastOutSlowInInterpolator; 240 private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f); 241 242 private final int mClipRevealTranslationY; 243 244 private int mCurrentUserId = 0; 245 private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION; 246 247 private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>(); 248 private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor(); 249 250 private int mLastClipRevealMaxTranslation; 251 private boolean mLastHadClipReveal; 252 private boolean mProlongedAnimationsEnded; 253 254 private final boolean mGridLayoutRecentsEnabled; 255 256 AppTransition(Context context, WindowManagerService service) { 257 mContext = context; 258 mService = service; 259 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, 260 com.android.internal.R.interpolator.linear_out_slow_in); 261 mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, 262 com.android.internal.R.interpolator.fast_out_linear_in); 263 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, 264 com.android.internal.R.interpolator.fast_out_slow_in); 265 mConfigShortAnimTime = context.getResources().getInteger( 266 com.android.internal.R.integer.config_shortAnimTime); 267 mDecelerateInterpolator = AnimationUtils.loadInterpolator(context, 268 com.android.internal.R.interpolator.decelerate_cubic); 269 mThumbnailFadeInInterpolator = new Interpolator() { 270 @Override 271 public float getInterpolation(float input) { 272 // Linear response for first fraction, then complete after that. 273 if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) { 274 return 0f; 275 } 276 float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) / 277 (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION); 278 return mFastOutLinearInInterpolator.getInterpolation(t); 279 } 280 }; 281 mThumbnailFadeOutInterpolator = new Interpolator() { 282 @Override 283 public float getInterpolation(float input) { 284 // Linear response for first fraction, then complete after that. 285 if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) { 286 float t = input / RECENTS_THUMBNAIL_FADEOUT_FRACTION; 287 return mLinearOutSlowInInterpolator.getInterpolation(t); 288 } 289 return 1f; 290 } 291 }; 292 mClipRevealTranslationY = (int) (CLIP_REVEAL_TRANSLATION_Y_DP 293 * mContext.getResources().getDisplayMetrics().density); 294 mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false); 295 } 296 297 boolean isTransitionSet() { 298 return mNextAppTransition != TRANSIT_UNSET; 299 } 300 301 boolean isTransitionEqual(int transit) { 302 return mNextAppTransition == transit; 303 } 304 305 int getAppTransition() { 306 return mNextAppTransition; 307 } 308 309 private void setAppTransition(int transit, int flags) { 310 mNextAppTransition = transit; 311 mNextAppTransitionFlags |= flags; 312 setLastAppTransition(TRANSIT_UNSET, null, null); 313 } 314 315 void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp) { 316 mLastUsedAppTransition = transit; 317 mLastOpeningApp = "" + openingApp; 318 mLastClosingApp = "" + closingApp; 319 } 320 321 boolean isReady() { 322 return mAppTransitionState == APP_STATE_READY 323 || mAppTransitionState == APP_STATE_TIMEOUT; 324 } 325 326 void setReady() { 327 mAppTransitionState = APP_STATE_READY; 328 fetchAppTransitionSpecsFromFuture(); 329 } 330 331 boolean isRunning() { 332 return mAppTransitionState == APP_STATE_RUNNING; 333 } 334 335 void setIdle() { 336 mAppTransitionState = APP_STATE_IDLE; 337 } 338 339 boolean isTimeout() { 340 return mAppTransitionState == APP_STATE_TIMEOUT; 341 } 342 343 void setTimeout() { 344 mAppTransitionState = APP_STATE_TIMEOUT; 345 } 346 347 Bitmap getAppTransitionThumbnailHeader(int taskId) { 348 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId); 349 if (spec == null) { 350 spec = mDefaultNextAppTransitionAnimationSpec; 351 } 352 return spec != null ? spec.bitmap : null; 353 } 354 355 /** Returns whether the next thumbnail transition is aspect scaled up. */ 356 boolean isNextThumbnailTransitionAspectScaled() { 357 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || 358 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 359 } 360 361 /** Returns whether the next thumbnail transition is scaling up. */ 362 boolean isNextThumbnailTransitionScaleUp() { 363 return mNextAppTransitionScaleUp; 364 } 365 366 boolean isNextAppTransitionThumbnailUp() { 367 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP || 368 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP; 369 } 370 371 boolean isNextAppTransitionThumbnailDown() { 372 return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN || 373 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 374 } 375 376 /** 377 * @return true if and only if we are currently fetching app transition specs from the future 378 * passed into {@link #overridePendingAppTransitionMultiThumbFuture} 379 */ 380 boolean isFetchingAppTransitionsSpecs() { 381 return mNextAppTransitionAnimationsSpecsPending; 382 } 383 384 private boolean prepare() { 385 if (!isRunning()) { 386 mAppTransitionState = APP_STATE_IDLE; 387 notifyAppTransitionPendingLocked(); 388 mLastHadClipReveal = false; 389 mLastClipRevealMaxTranslation = 0; 390 mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION; 391 return true; 392 } 393 return false; 394 } 395 396 /** 397 * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another 398 * layout pass needs to be done 399 */ 400 int goodToGo(int transit, AppWindowAnimator topOpeningAppAnimator, 401 AppWindowAnimator topClosingAppAnimator, ArraySet<AppWindowToken> openingApps, 402 ArraySet<AppWindowToken> closingApps) { 403 mNextAppTransition = TRANSIT_UNSET; 404 mNextAppTransitionFlags = 0; 405 mAppTransitionState = APP_STATE_RUNNING; 406 int redoLayout = notifyAppTransitionStartingLocked(transit, 407 topOpeningAppAnimator != null ? topOpeningAppAnimator.mAppToken.token : null, 408 topClosingAppAnimator != null ? topClosingAppAnimator.mAppToken.token : null, 409 topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null, 410 topClosingAppAnimator != null ? topClosingAppAnimator.animation : null); 411 mService.getDefaultDisplayContentLocked().getDockedDividerController() 412 .notifyAppTransitionStarting(openingApps, transit); 413 414 // Prolong the start for the transition when docking a task from recents, unless recents 415 // ended it already then we don't need to wait. 416 if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) { 417 for (int i = openingApps.size() - 1; i >= 0; i--) { 418 final AppWindowAnimator appAnimator = openingApps.valueAt(i).mAppAnimator; 419 appAnimator.startProlongAnimation(PROLONG_ANIMATION_AT_START); 420 } 421 } 422 return redoLayout; 423 } 424 425 /** 426 * Let the transitions manager know that the somebody wanted to end the prolonged animations. 427 */ 428 void notifyProlongedAnimationsEnded() { 429 mProlongedAnimationsEnded = true; 430 } 431 432 void clear() { 433 mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; 434 mNextAppTransitionPackage = null; 435 mNextAppTransitionAnimationsSpecs.clear(); 436 mNextAppTransitionAnimationsSpecsFuture = null; 437 mDefaultNextAppTransitionAnimationSpec = null; 438 mAnimationFinishedCallback = null; 439 mProlongedAnimationsEnded = false; 440 } 441 442 void freeze() { 443 final int transit = mNextAppTransition; 444 setAppTransition(AppTransition.TRANSIT_UNSET, 0 /* flags */); 445 clear(); 446 setReady(); 447 notifyAppTransitionCancelledLocked(transit); 448 } 449 450 void registerListenerLocked(AppTransitionListener listener) { 451 mListeners.add(listener); 452 } 453 454 public void notifyAppTransitionFinishedLocked(IBinder token) { 455 for (int i = 0; i < mListeners.size(); i++) { 456 mListeners.get(i).onAppTransitionFinishedLocked(token); 457 } 458 } 459 460 private void notifyAppTransitionPendingLocked() { 461 for (int i = 0; i < mListeners.size(); i++) { 462 mListeners.get(i).onAppTransitionPendingLocked(); 463 } 464 } 465 466 private void notifyAppTransitionCancelledLocked(int transit) { 467 for (int i = 0; i < mListeners.size(); i++) { 468 mListeners.get(i).onAppTransitionCancelledLocked(transit); 469 } 470 } 471 472 private int notifyAppTransitionStartingLocked(int transit, IBinder openToken, 473 IBinder closeToken, Animation openAnimation, Animation closeAnimation) { 474 int redoLayout = 0; 475 for (int i = 0; i < mListeners.size(); i++) { 476 redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, openToken, 477 closeToken, openAnimation, closeAnimation); 478 } 479 return redoLayout; 480 } 481 482 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) { 483 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg=" 484 + (lp != null ? lp.packageName : null) 485 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null)); 486 if (lp != null && lp.windowAnimations != 0) { 487 // If this is a system resource, don't try to load it from the 488 // application resources. It is nice to avoid loading application 489 // resources if we can. 490 String packageName = lp.packageName != null ? lp.packageName : "android"; 491 int resId = lp.windowAnimations; 492 if ((resId&0xFF000000) == 0x01000000) { 493 packageName = "android"; 494 } 495 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 496 + packageName); 497 return AttributeCache.instance().get(packageName, resId, 498 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 499 } 500 return null; 501 } 502 503 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) { 504 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package=" 505 + packageName + " resId=0x" + Integer.toHexString(resId)); 506 if (packageName != null) { 507 if ((resId&0xFF000000) == 0x01000000) { 508 packageName = "android"; 509 } 510 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 511 + packageName); 512 return AttributeCache.instance().get(packageName, resId, 513 com.android.internal.R.styleable.WindowAnimation, mCurrentUserId); 514 } 515 return null; 516 } 517 518 Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) { 519 int anim = 0; 520 Context context = mContext; 521 if (animAttr >= 0) { 522 AttributeCache.Entry ent = getCachedAnimations(lp); 523 if (ent != null) { 524 context = ent.context; 525 anim = ent.array.getResourceId(animAttr, 0); 526 } 527 } 528 if (anim != 0) { 529 return AnimationUtils.loadAnimation(context, anim); 530 } 531 return null; 532 } 533 534 Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) { 535 Context context = mContext; 536 if (resId >= 0) { 537 AttributeCache.Entry ent = getCachedAnimations(lp); 538 if (ent != null) { 539 context = ent.context; 540 } 541 return AnimationUtils.loadAnimation(context, resId); 542 } 543 return null; 544 } 545 546 private Animation loadAnimationRes(String packageName, int resId) { 547 int anim = 0; 548 Context context = mContext; 549 if (resId >= 0) { 550 AttributeCache.Entry ent = getCachedAnimations(packageName, resId); 551 if (ent != null) { 552 context = ent.context; 553 anim = resId; 554 } 555 } 556 if (anim != 0) { 557 return AnimationUtils.loadAnimation(context, anim); 558 } 559 return null; 560 } 561 562 /** 563 * Compute the pivot point for an animation that is scaling from a small 564 * rect on screen to a larger rect. The pivot point varies depending on 565 * the distance between the inner and outer edges on both sides. This 566 * function computes the pivot point for one dimension. 567 * @param startPos Offset from left/top edge of outer rectangle to 568 * left/top edge of inner rectangle. 569 * @param finalScale The scaling factor between the size of the outer 570 * and inner rectangles. 571 */ 572 private static float computePivot(int startPos, float finalScale) { 573 574 /* 575 Theorem of intercepting lines: 576 577 + + +-----------------------------------------------+ 578 | | | | 579 | | | | 580 | | | | 581 | | | | 582 x | y | | | 583 | | | | 584 | | | | 585 | | | | 586 | | | | 587 | + | +--------------------+ | 588 | | | | | 589 | | | | | 590 | | | | | 591 | | | | | 592 | | | | | 593 | | | | | 594 | | | | | 595 | | | | | 596 | | | | | 597 | | | | | 598 | | | | | 599 | | | | | 600 | | | | | 601 | | | | | 602 | | | | | 603 | | | | | 604 | | | | | 605 | | +--------------------+ | 606 | | | 607 | | | 608 | | | 609 | | | 610 | | | 611 | | | 612 | | | 613 | +-----------------------------------------------+ 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 + ++ 624 p ++ 625 626 scale = (x - y) / x 627 <=> x = -y / (scale - 1) 628 */ 629 final float denom = finalScale-1; 630 if (Math.abs(denom) < .0001f) { 631 return startPos; 632 } 633 return -startPos / denom; 634 } 635 636 private Animation createScaleUpAnimationLocked(int transit, boolean enter, 637 Rect containingFrame) { 638 Animation a; 639 getDefaultNextAppTransitionStartRect(mTmpRect); 640 final int appWidth = containingFrame.width(); 641 final int appHeight = containingFrame.height(); 642 if (enter) { 643 // Entering app zooms out from the center of the initial rect. 644 float scaleW = mTmpRect.width() / (float) appWidth; 645 float scaleH = mTmpRect.height() / (float) appHeight; 646 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, 647 computePivot(mTmpRect.left, scaleW), 648 computePivot(mTmpRect.top, scaleH)); 649 scale.setInterpolator(mDecelerateInterpolator); 650 651 Animation alpha = new AlphaAnimation(0, 1); 652 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 653 654 AnimationSet set = new AnimationSet(false); 655 set.addAnimation(scale); 656 set.addAnimation(alpha); 657 set.setDetachWallpaper(true); 658 a = set; 659 } else if (transit == TRANSIT_WALLPAPER_INTRA_OPEN || 660 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) { 661 // If we are on top of the wallpaper, we need an animation that 662 // correctly handles the wallpaper staying static behind all of 663 // the animated elements. To do this, will just have the existing 664 // element fade out. 665 a = new AlphaAnimation(1, 0); 666 a.setDetachWallpaper(true); 667 } else { 668 // For normal animations, the exiting element just holds in place. 669 a = new AlphaAnimation(1, 1); 670 } 671 672 // Pick the desired duration. If this is an inter-activity transition, 673 // it is the standard duration for that. Otherwise we use the longer 674 // task transition duration. 675 final long duration; 676 switch (transit) { 677 case TRANSIT_ACTIVITY_OPEN: 678 case TRANSIT_ACTIVITY_CLOSE: 679 duration = mConfigShortAnimTime; 680 break; 681 default: 682 duration = DEFAULT_APP_TRANSITION_DURATION; 683 break; 684 } 685 a.setDuration(duration); 686 a.setFillAfter(true); 687 a.setInterpolator(mDecelerateInterpolator); 688 a.initialize(appWidth, appHeight, appWidth, appHeight); 689 return a; 690 } 691 692 private void getDefaultNextAppTransitionStartRect(Rect rect) { 693 if (mDefaultNextAppTransitionAnimationSpec == null || 694 mDefaultNextAppTransitionAnimationSpec.rect == null) { 695 Slog.e(TAG, "Starting rect for app requested, but none available", new Throwable()); 696 rect.setEmpty(); 697 } else { 698 rect.set(mDefaultNextAppTransitionAnimationSpec.rect); 699 } 700 } 701 702 void getNextAppTransitionStartRect(int taskId, Rect rect) { 703 AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId); 704 if (spec == null) { 705 spec = mDefaultNextAppTransitionAnimationSpec; 706 } 707 if (spec == null || spec.rect == null) { 708 Slog.e(TAG, "Starting rect for task: " + taskId + " requested, but not available", 709 new Throwable()); 710 rect.setEmpty(); 711 } else { 712 rect.set(spec.rect); 713 } 714 } 715 716 private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height, 717 Bitmap bitmap) { 718 mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */, 719 bitmap, new Rect(left, top, left + width, top + height)); 720 } 721 722 /** 723 * @return the duration of the last clip reveal animation 724 */ 725 long getLastClipRevealTransitionDuration() { 726 return mLastClipRevealTransitionDuration; 727 } 728 729 /** 730 * @return the maximum distance the app surface is traveling of the last clip reveal animation 731 */ 732 int getLastClipRevealMaxTranslation() { 733 return mLastClipRevealMaxTranslation; 734 } 735 736 /** 737 * @return true if in the last app transition had a clip reveal animation, false otherwise 738 */ 739 boolean hadClipRevealAnimation() { 740 return mLastHadClipReveal; 741 } 742 743 /** 744 * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that 745 * the start rect is outside of the target rect, and there is a lot of movement going on. 746 * 747 * @param cutOff whether the start rect was not fully contained by the end rect 748 * @param translationX the total translation the surface moves in x direction 749 * @param translationY the total translation the surfaces moves in y direction 750 * @param displayFrame our display frame 751 * 752 * @return the duration of the clip reveal animation, in milliseconds 753 */ 754 private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX, 755 float translationY, Rect displayFrame) { 756 if (!cutOff) { 757 return DEFAULT_APP_TRANSITION_DURATION; 758 } 759 final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(), 760 Math.abs(translationY) / displayFrame.height()); 761 return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction * 762 (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION)); 763 } 764 765 private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame, 766 Rect displayFrame) { 767 final Animation anim; 768 if (enter) { 769 final int appWidth = appFrame.width(); 770 final int appHeight = appFrame.height(); 771 772 // mTmpRect will contain an area around the launcher icon that was pressed. We will 773 // clip reveal from that area in the final area of the app. 774 getDefaultNextAppTransitionStartRect(mTmpRect); 775 776 float t = 0f; 777 if (appHeight > 0) { 778 t = (float) mTmpRect.top / displayFrame.height(); 779 } 780 int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t); 781 int translationX = 0; 782 int translationYCorrection = translationY; 783 int centerX = mTmpRect.centerX(); 784 int centerY = mTmpRect.centerY(); 785 int halfWidth = mTmpRect.width() / 2; 786 int halfHeight = mTmpRect.height() / 2; 787 int clipStartX = centerX - halfWidth - appFrame.left; 788 int clipStartY = centerY - halfHeight - appFrame.top; 789 boolean cutOff = false; 790 791 // If the starting rectangle is fully or partially outside of the target rectangle, we 792 // need to start the clipping at the edge and then achieve the rest with translation 793 // and extending the clip rect from that edge. 794 if (appFrame.top > centerY - halfHeight) { 795 translationY = (centerY - halfHeight) - appFrame.top; 796 translationYCorrection = 0; 797 clipStartY = 0; 798 cutOff = true; 799 } 800 if (appFrame.left > centerX - halfWidth) { 801 translationX = (centerX - halfWidth) - appFrame.left; 802 clipStartX = 0; 803 cutOff = true; 804 } 805 if (appFrame.right < centerX + halfWidth) { 806 translationX = (centerX + halfWidth) - appFrame.right; 807 clipStartX = appWidth - mTmpRect.width(); 808 cutOff = true; 809 } 810 final long duration = calculateClipRevealTransitionDuration(cutOff, translationX, 811 translationY, displayFrame); 812 813 // Clip third of the from size of launch icon, expand to full width/height 814 Animation clipAnimLR = new ClipRectLRAnimation( 815 clipStartX, clipStartX + mTmpRect.width(), 0, appWidth); 816 clipAnimLR.setInterpolator(mClipHorizontalInterpolator); 817 clipAnimLR.setDuration((long) (duration / 2.5f)); 818 819 TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0); 820 translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR 821 : mLinearOutSlowInInterpolator); 822 translate.setDuration(duration); 823 824 Animation clipAnimTB = new ClipRectTBAnimation( 825 clipStartY, clipStartY + mTmpRect.height(), 826 0, appHeight, 827 translationYCorrection, 0, 828 mLinearOutSlowInInterpolator); 829 clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); 830 clipAnimTB.setDuration(duration); 831 832 // Quick fade-in from icon to app window 833 final long alphaDuration = duration / 4; 834 AlphaAnimation alpha = new AlphaAnimation(0.5f, 1); 835 alpha.setDuration(alphaDuration); 836 alpha.setInterpolator(mLinearOutSlowInInterpolator); 837 838 AnimationSet set = new AnimationSet(false); 839 set.addAnimation(clipAnimLR); 840 set.addAnimation(clipAnimTB); 841 set.addAnimation(translate); 842 set.addAnimation(alpha); 843 set.setZAdjustment(Animation.ZORDER_TOP); 844 set.initialize(appWidth, appHeight, appWidth, appHeight); 845 anim = set; 846 mLastHadClipReveal = true; 847 mLastClipRevealTransitionDuration = duration; 848 849 // If the start rect was full inside the target rect (cutOff == false), we don't need 850 // to store the translation, because it's only used if cutOff == true. 851 mLastClipRevealMaxTranslation = cutOff 852 ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0; 853 } else { 854 final long duration; 855 switch (transit) { 856 case TRANSIT_ACTIVITY_OPEN: 857 case TRANSIT_ACTIVITY_CLOSE: 858 duration = mConfigShortAnimTime; 859 break; 860 default: 861 duration = DEFAULT_APP_TRANSITION_DURATION; 862 break; 863 } 864 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN || 865 transit == TRANSIT_WALLPAPER_INTRA_CLOSE) { 866 // If we are on top of the wallpaper, we need an animation that 867 // correctly handles the wallpaper staying static behind all of 868 // the animated elements. To do this, will just have the existing 869 // element fade out. 870 anim = new AlphaAnimation(1, 0); 871 anim.setDetachWallpaper(true); 872 } else { 873 // For normal animations, the exiting element just holds in place. 874 anim = new AlphaAnimation(1, 1); 875 } 876 anim.setInterpolator(mDecelerateInterpolator); 877 anim.setDuration(duration); 878 anim.setFillAfter(true); 879 } 880 return anim; 881 } 882 883 /** 884 * Prepares the specified animation with a standard duration, interpolator, etc. 885 */ 886 Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight, 887 long duration, Interpolator interpolator) { 888 if (duration > 0) { 889 a.setDuration(duration); 890 } 891 a.setFillAfter(true); 892 if (interpolator != null) { 893 a.setInterpolator(interpolator); 894 } 895 a.initialize(appWidth, appHeight, appWidth, appHeight); 896 return a; 897 } 898 899 /** 900 * Prepares the specified animation with a standard duration, interpolator, etc. 901 */ 902 Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) { 903 // Pick the desired duration. If this is an inter-activity transition, 904 // it is the standard duration for that. Otherwise we use the longer 905 // task transition duration. 906 final int duration; 907 switch (transit) { 908 case TRANSIT_ACTIVITY_OPEN: 909 case TRANSIT_ACTIVITY_CLOSE: 910 duration = mConfigShortAnimTime; 911 break; 912 default: 913 duration = DEFAULT_APP_TRANSITION_DURATION; 914 break; 915 } 916 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration, 917 mDecelerateInterpolator); 918 } 919 920 /** 921 * Return the current thumbnail transition state. 922 */ 923 int getThumbnailTransitionState(boolean enter) { 924 if (enter) { 925 if (mNextAppTransitionScaleUp) { 926 return THUMBNAIL_TRANSITION_ENTER_SCALE_UP; 927 } else { 928 return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN; 929 } 930 } else { 931 if (mNextAppTransitionScaleUp) { 932 return THUMBNAIL_TRANSITION_EXIT_SCALE_UP; 933 } else { 934 return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN; 935 } 936 } 937 } 938 939 /** 940 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 941 * when a thumbnail is specified with the pending animation override. 942 */ 943 Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets, 944 Bitmap thumbnailHeader, final int taskId, int uiMode, int orientation) { 945 Animation a; 946 final int thumbWidthI = thumbnailHeader.getWidth(); 947 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 948 final int thumbHeightI = thumbnailHeader.getHeight(); 949 final int appWidth = appRect.width(); 950 951 float scaleW = appWidth / thumbWidth; 952 getNextAppTransitionStartRect(taskId, mTmpRect); 953 final float fromX; 954 float fromY; 955 final float toX; 956 float toY; 957 final float pivotX; 958 final float pivotY; 959 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) { 960 fromX = mTmpRect.left; 961 fromY = mTmpRect.top; 962 963 // For the curved translate animation to work, the pivot points needs to be at the 964 // same absolute position as the one from the real surface. 965 toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left; 966 toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top; 967 pivotX = mTmpRect.width() / 2; 968 pivotY = appRect.height() / 2 / scaleW; 969 if (mGridLayoutRecentsEnabled) { 970 // In the grid layout, the header is displayed above the thumbnail instead of 971 // overlapping it. 972 fromY -= thumbHeightI; 973 toY -= thumbHeightI * scaleW; 974 } 975 } else { 976 pivotX = 0; 977 pivotY = 0; 978 fromX = mTmpRect.left; 979 fromY = mTmpRect.top; 980 toX = appRect.left; 981 toY = appRect.top; 982 } 983 final long duration = getAspectScaleDuration(); 984 final Interpolator interpolator = getAspectScaleInterpolator(); 985 if (mNextAppTransitionScaleUp) { 986 // Animation up from the thumbnail to the full screen 987 Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY); 988 scale.setInterpolator(interpolator); 989 scale.setDuration(duration); 990 Animation alpha = new AlphaAnimation(1f, 0f); 991 alpha.setInterpolator(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS 992 ? THUMBNAIL_DOCK_INTERPOLATOR : mThumbnailFadeOutInterpolator); 993 alpha.setDuration(mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS 994 ? duration / 2 995 : duration); 996 Animation translate = createCurvedMotion(fromX, toX, fromY, toY); 997 translate.setInterpolator(interpolator); 998 translate.setDuration(duration); 999 1000 mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI); 1001 mTmpToClipRect.set(appRect); 1002 1003 // Containing frame is in screen space, but we need the clip rect in the 1004 // app space. 1005 mTmpToClipRect.offsetTo(0, 0); 1006 mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW); 1007 mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW); 1008 1009 if (contentInsets != null) { 1010 mTmpToClipRect.inset((int) (-contentInsets.left * scaleW), 1011 (int) (-contentInsets.top * scaleW), 1012 (int) (-contentInsets.right * scaleW), 1013 (int) (-contentInsets.bottom * scaleW)); 1014 } 1015 1016 Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); 1017 clipAnim.setInterpolator(interpolator); 1018 clipAnim.setDuration(duration); 1019 1020 // This AnimationSet uses the Interpolators assigned above. 1021 AnimationSet set = new AnimationSet(false); 1022 set.addAnimation(scale); 1023 if (!mGridLayoutRecentsEnabled) { 1024 // In the grid layout, the header should be shown for the whole animation. 1025 set.addAnimation(alpha); 1026 } 1027 set.addAnimation(translate); 1028 set.addAnimation(clipAnim); 1029 a = set; 1030 } else { 1031 // Animation down from the full screen to the thumbnail 1032 Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY); 1033 scale.setInterpolator(interpolator); 1034 scale.setDuration(duration); 1035 Animation alpha = new AlphaAnimation(0f, 1f); 1036 alpha.setInterpolator(mThumbnailFadeInInterpolator); 1037 alpha.setDuration(duration); 1038 Animation translate = createCurvedMotion(toX, fromX, toY, fromY); 1039 translate.setInterpolator(interpolator); 1040 translate.setDuration(duration); 1041 1042 // This AnimationSet uses the Interpolators assigned above. 1043 AnimationSet set = new AnimationSet(false); 1044 set.addAnimation(scale); 1045 if (!mGridLayoutRecentsEnabled) { 1046 // In the grid layout, the header should be shown for the whole animation. 1047 set.addAnimation(alpha); 1048 } 1049 set.addAnimation(translate); 1050 a = set; 1051 1052 } 1053 return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0, 1054 null); 1055 } 1056 1057 private Animation createCurvedMotion(float fromX, float toX, float fromY, float toY) { 1058 1059 // Almost no x-change - use linear animation 1060 if (Math.abs(toX - fromX) < 1f || mNextAppTransition != TRANSIT_DOCK_TASK_FROM_RECENTS) { 1061 return new TranslateAnimation(fromX, toX, fromY, toY); 1062 } else { 1063 final Path path = createCurvedPath(fromX, toX, fromY, toY); 1064 return new CurvedTranslateAnimation(path); 1065 } 1066 } 1067 1068 private Path createCurvedPath(float fromX, float toX, float fromY, float toY) { 1069 final Path path = new Path(); 1070 path.moveTo(fromX, fromY); 1071 1072 if (fromY > toY) { 1073 // If the object needs to go up, move it in horizontal direction first, then vertical. 1074 path.cubicTo(fromX, fromY, toX, 0.9f * fromY + 0.1f * toY, toX, toY); 1075 } else { 1076 // If the object needs to go down, move it in vertical direction first, then horizontal. 1077 path.cubicTo(fromX, fromY, fromX, 0.1f * fromY + 0.9f * toY, toX, toY); 1078 } 1079 return path; 1080 } 1081 1082 private long getAspectScaleDuration() { 1083 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) { 1084 return (long) (THUMBNAIL_APP_TRANSITION_DURATION * 1.35f); 1085 } else { 1086 return THUMBNAIL_APP_TRANSITION_DURATION; 1087 } 1088 } 1089 1090 private Interpolator getAspectScaleInterpolator() { 1091 if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) { 1092 return mFastOutSlowInInterpolator; 1093 } else { 1094 return TOUCH_RESPONSE_INTERPOLATOR; 1095 } 1096 } 1097 1098 /** 1099 * This alternate animation is created when we are doing a thumbnail transition, for the 1100 * activity that is leaving, and the activity that is entering. 1101 */ 1102 Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState, 1103 int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets, 1104 @Nullable Rect surfaceInsets, boolean freeform, int taskId) { 1105 Animation a; 1106 final int appWidth = containingFrame.width(); 1107 final int appHeight = containingFrame.height(); 1108 getDefaultNextAppTransitionStartRect(mTmpRect); 1109 final int thumbWidthI = mTmpRect.width(); 1110 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 1111 final int thumbHeightI = mTmpRect.height(); 1112 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 1113 final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left; 1114 final int thumbStartY = mTmpRect.top - containingFrame.top; 1115 1116 switch (thumbTransitState) { 1117 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: 1118 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 1119 final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP; 1120 if (freeform && scaleUp) { 1121 a = createAspectScaledThumbnailEnterFreeformAnimationLocked( 1122 containingFrame, surfaceInsets, taskId); 1123 } else if (freeform) { 1124 a = createAspectScaledThumbnailExitFreeformAnimationLocked( 1125 containingFrame, surfaceInsets, taskId); 1126 } else { 1127 AnimationSet set = new AnimationSet(true); 1128 1129 // In portrait, we scale to fit the width 1130 mTmpFromClipRect.set(containingFrame); 1131 mTmpToClipRect.set(containingFrame); 1132 1133 // Containing frame is in screen space, but we need the clip rect in the 1134 // app space. 1135 mTmpFromClipRect.offsetTo(0, 0); 1136 mTmpToClipRect.offsetTo(0, 0); 1137 1138 // Exclude insets region from the source clip. 1139 mTmpFromClipRect.inset(contentInsets); 1140 mNextAppTransitionInsets.set(contentInsets); 1141 1142 if (shouldScaleDownThumbnailTransition(uiMode, orientation)) { 1143 // We scale the width and clip to the top/left square 1144 float scale = thumbWidth / 1145 (appWidth - contentInsets.left - contentInsets.right); 1146 if (!mGridLayoutRecentsEnabled) { 1147 int unscaledThumbHeight = (int) (thumbHeight / scale); 1148 mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight; 1149 } 1150 1151 mNextAppTransitionInsets.set(contentInsets); 1152 1153 Animation scaleAnim = new ScaleAnimation( 1154 scaleUp ? scale : 1, scaleUp ? 1 : scale, 1155 scaleUp ? scale : 1, scaleUp ? 1 : scale, 1156 containingFrame.width() / 2f, 1157 containingFrame.height() / 2f + contentInsets.top); 1158 final float targetX = (mTmpRect.left - containingFrame.left); 1159 final float x = containingFrame.width() / 2f 1160 - containingFrame.width() / 2f * scale; 1161 final float targetY = (mTmpRect.top - containingFrame.top); 1162 final float y = containingFrame.height() / 2f 1163 - containingFrame.height() / 2f * scale; 1164 final float startX = targetX - x; 1165 final float startY = targetY - y; 1166 Animation clipAnim = scaleUp 1167 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect) 1168 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect); 1169 Animation translateAnim = scaleUp 1170 ? createCurvedMotion(startX, 0, startY - contentInsets.top, 0) 1171 : createCurvedMotion(0, startX, 0, startY - contentInsets.top); 1172 1173 set.addAnimation(clipAnim); 1174 set.addAnimation(scaleAnim); 1175 set.addAnimation(translateAnim); 1176 1177 } else { 1178 // In landscape, we don't scale at all and only crop 1179 mTmpFromClipRect.bottom = mTmpFromClipRect.top + thumbHeightI; 1180 mTmpFromClipRect.right = mTmpFromClipRect.left + thumbWidthI; 1181 1182 Animation clipAnim = scaleUp 1183 ? new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect) 1184 : new ClipRectAnimation(mTmpToClipRect, mTmpFromClipRect); 1185 Animation translateAnim = scaleUp 1186 ? createCurvedMotion(thumbStartX, 0, 1187 thumbStartY - contentInsets.top, 0) 1188 : createCurvedMotion(0, thumbStartX, 0, 1189 thumbStartY - contentInsets.top); 1190 1191 set.addAnimation(clipAnim); 1192 set.addAnimation(translateAnim); 1193 } 1194 a = set; 1195 a.setZAdjustment(Animation.ZORDER_TOP); 1196 } 1197 break; 1198 } 1199 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 1200 // Previous app window during the scale up 1201 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 1202 // Fade out the source activity if we are animating to a wallpaper 1203 // activity. 1204 a = new AlphaAnimation(1, 0); 1205 } else { 1206 a = new AlphaAnimation(1, 1); 1207 } 1208 break; 1209 } 1210 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 1211 // Target app window during the scale down 1212 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 1213 // Fade in the destination activity if we are animating from a wallpaper 1214 // activity. 1215 a = new AlphaAnimation(0, 1); 1216 } else { 1217 a = new AlphaAnimation(1, 1); 1218 } 1219 break; 1220 } 1221 default: 1222 throw new RuntimeException("Invalid thumbnail transition state"); 1223 } 1224 1225 return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, 1226 getAspectScaleDuration(), getAspectScaleInterpolator()); 1227 } 1228 1229 private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame, 1230 @Nullable Rect surfaceInsets, int taskId) { 1231 getNextAppTransitionStartRect(taskId, mTmpRect); 1232 return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets, 1233 true); 1234 } 1235 1236 private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame, 1237 @Nullable Rect surfaceInsets, int taskId) { 1238 getNextAppTransitionStartRect(taskId, mTmpRect); 1239 return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets, 1240 false); 1241 } 1242 1243 private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame, 1244 Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) { 1245 final float sourceWidth = sourceFrame.width(); 1246 final float sourceHeight = sourceFrame.height(); 1247 final float destWidth = destFrame.width(); 1248 final float destHeight = destFrame.height(); 1249 final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth; 1250 final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight; 1251 AnimationSet set = new AnimationSet(true); 1252 final int surfaceInsetsH = surfaceInsets == null 1253 ? 0 : surfaceInsets.left + surfaceInsets.right; 1254 final int surfaceInsetsV = surfaceInsets == null 1255 ? 0 : surfaceInsets.top + surfaceInsets.bottom; 1256 // We want the scaling to happen from the center of the surface. In order to achieve that, 1257 // we need to account for surface insets that will be used to enlarge the surface. 1258 final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2; 1259 final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2; 1260 final ScaleAnimation scale = enter ? 1261 new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter) 1262 : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter); 1263 final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2; 1264 final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2; 1265 final int destHCenter = destFrame.left + destFrame.width() / 2; 1266 final int destVCenter = destFrame.top + destFrame.height() / 2; 1267 final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter; 1268 final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter; 1269 final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0) 1270 : new TranslateAnimation(0, fromX, 0, fromY); 1271 set.addAnimation(scale); 1272 set.addAnimation(translation); 1273 1274 final IRemoteCallback callback = mAnimationFinishedCallback; 1275 if (callback != null) { 1276 set.setAnimationListener(new Animation.AnimationListener() { 1277 @Override 1278 public void onAnimationStart(Animation animation) { } 1279 1280 @Override 1281 public void onAnimationEnd(Animation animation) { 1282 mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget(); 1283 } 1284 1285 @Override 1286 public void onAnimationRepeat(Animation animation) { } 1287 }); 1288 } 1289 return set; 1290 } 1291 1292 /** 1293 * This animation runs for the thumbnail that gets cross faded with the enter/exit activity 1294 * when a thumbnail is specified with the pending animation override. 1295 */ 1296 Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit, 1297 Bitmap thumbnailHeader) { 1298 Animation a; 1299 getDefaultNextAppTransitionStartRect(mTmpRect); 1300 final int thumbWidthI = thumbnailHeader.getWidth(); 1301 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 1302 final int thumbHeightI = thumbnailHeader.getHeight(); 1303 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 1304 1305 if (mNextAppTransitionScaleUp) { 1306 // Animation for the thumbnail zooming from its initial size to the full screen 1307 float scaleW = appWidth / thumbWidth; 1308 float scaleH = appHeight / thumbHeight; 1309 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 1310 computePivot(mTmpRect.left, 1 / scaleW), 1311 computePivot(mTmpRect.top, 1 / scaleH)); 1312 scale.setInterpolator(mDecelerateInterpolator); 1313 1314 Animation alpha = new AlphaAnimation(1, 0); 1315 alpha.setInterpolator(mThumbnailFadeOutInterpolator); 1316 1317 // This AnimationSet uses the Interpolators assigned above. 1318 AnimationSet set = new AnimationSet(false); 1319 set.addAnimation(scale); 1320 set.addAnimation(alpha); 1321 a = set; 1322 } else { 1323 // Animation for the thumbnail zooming down from the full screen to its final size 1324 float scaleW = appWidth / thumbWidth; 1325 float scaleH = appHeight / thumbHeight; 1326 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 1327 computePivot(mTmpRect.left, 1 / scaleW), 1328 computePivot(mTmpRect.top, 1 / scaleH)); 1329 } 1330 1331 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 1332 } 1333 1334 /** 1335 * This animation is created when we are doing a thumbnail transition, for the activity that is 1336 * leaving, and the activity that is entering. 1337 */ 1338 Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame, 1339 int transit, int taskId) { 1340 final int appWidth = containingFrame.width(); 1341 final int appHeight = containingFrame.height(); 1342 Bitmap thumbnailHeader = getAppTransitionThumbnailHeader(taskId); 1343 Animation a; 1344 getDefaultNextAppTransitionStartRect(mTmpRect); 1345 final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth; 1346 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 1347 final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight; 1348 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 1349 1350 switch (thumbTransitState) { 1351 case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: { 1352 // Entering app scales up with the thumbnail 1353 float scaleW = thumbWidth / appWidth; 1354 float scaleH = thumbHeight / appHeight; 1355 a = new ScaleAnimation(scaleW, 1, scaleH, 1, 1356 computePivot(mTmpRect.left, scaleW), 1357 computePivot(mTmpRect.top, scaleH)); 1358 break; 1359 } 1360 case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: { 1361 // Exiting app while the thumbnail is scaling up should fade or stay in place 1362 if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) { 1363 // Fade out while bringing up selected activity. This keeps the 1364 // current activity from showing through a launching wallpaper 1365 // activity. 1366 a = new AlphaAnimation(1, 0); 1367 } else { 1368 // noop animation 1369 a = new AlphaAnimation(1, 1); 1370 } 1371 break; 1372 } 1373 case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: { 1374 // Entering the other app, it should just be visible while we scale the thumbnail 1375 // down above it 1376 a = new AlphaAnimation(1, 1); 1377 break; 1378 } 1379 case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { 1380 // Exiting the current app, the app should scale down with the thumbnail 1381 float scaleW = thumbWidth / appWidth; 1382 float scaleH = thumbHeight / appHeight; 1383 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 1384 computePivot(mTmpRect.left, scaleW), 1385 computePivot(mTmpRect.top, scaleH)); 1386 1387 Animation alpha = new AlphaAnimation(1, 0); 1388 1389 AnimationSet set = new AnimationSet(true); 1390 set.addAnimation(scale); 1391 set.addAnimation(alpha); 1392 set.setZAdjustment(Animation.ZORDER_TOP); 1393 a = set; 1394 break; 1395 } 1396 default: 1397 throw new RuntimeException("Invalid thumbnail transition state"); 1398 } 1399 1400 return prepareThumbnailAnimation(a, appWidth, appHeight, transit); 1401 } 1402 1403 private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) { 1404 getDefaultNextAppTransitionStartRect(mTmpFromClipRect); 1405 final int left = mTmpFromClipRect.left; 1406 final int top = mTmpFromClipRect.top; 1407 mTmpFromClipRect.offset(-left, -top); 1408 // TODO: Isn't that strange that we ignore exact position of the containingFrame? 1409 mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height()); 1410 AnimationSet set = new AnimationSet(true); 1411 float fromWidth = mTmpFromClipRect.width(); 1412 float toWidth = mTmpToClipRect.width(); 1413 float fromHeight = mTmpFromClipRect.height(); 1414 // While the window might span the whole display, the actual content will be cropped to the 1415 // system decoration frame, for example when the window is docked. We need to take into 1416 // account the visible height when constructing the animation. 1417 float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom; 1418 int translateAdjustment = 0; 1419 if (fromWidth <= toWidth && fromHeight <= toHeight) { 1420 // The final window is larger in both dimensions than current window (e.g. we are 1421 // maximizing), so we can simply unclip the new window and there will be no disappearing 1422 // frame. 1423 set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)); 1424 } else { 1425 // The disappearing window has one larger dimension. We need to apply scaling, so the 1426 // first frame of the entry animation matches the old window. 1427 set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1)); 1428 // We might not be going exactly full screen, but instead be aligned under the status 1429 // bar using cropping. We still need to account for the cropped part, which will also 1430 // be scaled. 1431 translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight); 1432 } 1433 1434 // We animate the translation from the old position of the removed window, to the new 1435 // position of the added window. The latter might not be full screen, for example docked for 1436 // docked windows. 1437 TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left, 1438 0, top - containingFrame.top - translateAdjustment, 0); 1439 set.addAnimation(translate); 1440 set.setDuration(DEFAULT_APP_TRANSITION_DURATION); 1441 set.setZAdjustment(Animation.ZORDER_TOP); 1442 return set; 1443 } 1444 1445 /** 1446 * @return true if and only if the first frame of the transition can be skipped, i.e. the first 1447 * frame of the transition doesn't change the visuals on screen, so we can start 1448 * directly with the second one 1449 */ 1450 boolean canSkipFirstFrame() { 1451 return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM 1452 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE 1453 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL 1454 && mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY; 1455 } 1456 1457 /** 1458 * 1459 * @param frame These are the bounds of the window when it finishes the animation. This is where 1460 * the animation must usually finish in entrance animation, as the next frame will 1461 * display the window at these coordinates. In case of exit animation, this is 1462 * where the animation must start, as the frame before the animation is displaying 1463 * the window at these bounds. 1464 * @param insets Knowing where the window will be positioned is not enough. Some parts of the 1465 * window might be obscured, usually by the system windows (status bar and 1466 * navigation bar) and we use content insets to convey that information. This 1467 * usually affects the animation aspects vertically, as the system decoration is 1468 * at the top and the bottom. For example when we animate from full screen to 1469 * recents, we want to exclude the covered parts, because they won't match the 1470 * thumbnail after the last frame is executed. 1471 * @param surfaceInsets In rare situation the surface is larger than the content and we need to 1472 * know about this to make the animation frames match. We currently use 1473 * this for freeform windows, which have larger surfaces to display 1474 * shadows. When we animate them from recents, we want to match the content 1475 * to the recents thumbnail and hence need to account for the surface being 1476 * bigger. 1477 */ 1478 Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int uiMode, 1479 int orientation, Rect frame, Rect displayFrame, Rect insets, 1480 @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform, 1481 int taskId) { 1482 Animation a; 1483 if (isKeyguardGoingAwayTransit(transit) && enter) { 1484 a = loadKeyguardExitAnimation(transit); 1485 } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) { 1486 a = null; 1487 } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) { 1488 a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit); 1489 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN 1490 || transit == TRANSIT_TASK_OPEN 1491 || transit == TRANSIT_TASK_TO_FRONT)) { 1492 a = loadAnimationRes(lp, enter 1493 ? com.android.internal.R.anim.voice_activity_open_enter 1494 : com.android.internal.R.anim.voice_activity_open_exit); 1495 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1496 "applyAnimation voice:" 1497 + " anim=" + a + " transit=" + appTransitionToString(transit) 1498 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); 1499 } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE 1500 || transit == TRANSIT_TASK_CLOSE 1501 || transit == TRANSIT_TASK_TO_BACK)) { 1502 a = loadAnimationRes(lp, enter 1503 ? com.android.internal.R.anim.voice_activity_close_enter 1504 : com.android.internal.R.anim.voice_activity_close_exit); 1505 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1506 "applyAnimation voice:" 1507 + " anim=" + a + " transit=" + appTransitionToString(transit) 1508 + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); 1509 } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) { 1510 a = createRelaunchAnimation(frame, insets); 1511 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1512 "applyAnimation:" 1513 + " anim=" + a + " nextAppTransition=" + mNextAppTransition 1514 + " transit=" + appTransitionToString(transit) 1515 + " Callers=" + Debug.getCallers(3)); 1516 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { 1517 a = loadAnimationRes(mNextAppTransitionPackage, enter ? 1518 mNextAppTransitionEnter : mNextAppTransitionExit); 1519 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1520 "applyAnimation:" 1521 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM" 1522 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1523 + " Callers=" + Debug.getCallers(3)); 1524 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) { 1525 a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace); 1526 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1527 "applyAnimation:" 1528 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE" 1529 + " transit=" + appTransitionToString(transit) 1530 + " Callers=" + Debug.getCallers(3)); 1531 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) { 1532 a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame); 1533 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1534 "applyAnimation:" 1535 + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL" 1536 + " transit=" + appTransitionToString(transit) 1537 + " Callers=" + Debug.getCallers(3)); 1538 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) { 1539 a = createScaleUpAnimationLocked(transit, enter, frame); 1540 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1541 "applyAnimation:" 1542 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" 1543 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1544 + " Callers=" + Debug.getCallers(3)); 1545 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP || 1546 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { 1547 mNextAppTransitionScaleUp = 1548 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); 1549 a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter), 1550 frame, transit, taskId); 1551 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 1552 String animName = mNextAppTransitionScaleUp ? 1553 "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; 1554 Slog.v(TAG, "applyAnimation:" 1555 + " anim=" + a + " nextAppTransition=" + animName 1556 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1557 + " Callers=" + Debug.getCallers(3)); 1558 } 1559 } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP || 1560 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) { 1561 mNextAppTransitionScaleUp = 1562 (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP); 1563 a = createAspectScaledThumbnailEnterExitAnimationLocked( 1564 getThumbnailTransitionState(enter), uiMode, orientation, transit, frame, 1565 insets, surfaceInsets, freeform, taskId); 1566 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 1567 String animName = mNextAppTransitionScaleUp ? 1568 "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN"; 1569 Slog.v(TAG, "applyAnimation:" 1570 + " anim=" + a + " nextAppTransition=" + animName 1571 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1572 + " Callers=" + Debug.getCallers(3)); 1573 } 1574 } else { 1575 int animAttr = 0; 1576 switch (transit) { 1577 case TRANSIT_ACTIVITY_OPEN: 1578 animAttr = enter 1579 ? WindowAnimation_activityOpenEnterAnimation 1580 : WindowAnimation_activityOpenExitAnimation; 1581 break; 1582 case TRANSIT_ACTIVITY_CLOSE: 1583 animAttr = enter 1584 ? WindowAnimation_activityCloseEnterAnimation 1585 : WindowAnimation_activityCloseExitAnimation; 1586 break; 1587 case TRANSIT_DOCK_TASK_FROM_RECENTS: 1588 case TRANSIT_TASK_OPEN: 1589 animAttr = enter 1590 ? WindowAnimation_taskOpenEnterAnimation 1591 : WindowAnimation_taskOpenExitAnimation; 1592 break; 1593 case TRANSIT_TASK_CLOSE: 1594 animAttr = enter 1595 ? WindowAnimation_taskCloseEnterAnimation 1596 : WindowAnimation_taskCloseExitAnimation; 1597 break; 1598 case TRANSIT_TASK_TO_FRONT: 1599 animAttr = enter 1600 ? WindowAnimation_taskToFrontEnterAnimation 1601 : WindowAnimation_taskToFrontExitAnimation; 1602 break; 1603 case TRANSIT_TASK_TO_BACK: 1604 animAttr = enter 1605 ? WindowAnimation_taskToBackEnterAnimation 1606 : WindowAnimation_taskToBackExitAnimation; 1607 break; 1608 case TRANSIT_WALLPAPER_OPEN: 1609 animAttr = enter 1610 ? WindowAnimation_wallpaperOpenEnterAnimation 1611 : WindowAnimation_wallpaperOpenExitAnimation; 1612 break; 1613 case TRANSIT_WALLPAPER_CLOSE: 1614 animAttr = enter 1615 ? WindowAnimation_wallpaperCloseEnterAnimation 1616 : WindowAnimation_wallpaperCloseExitAnimation; 1617 break; 1618 case TRANSIT_WALLPAPER_INTRA_OPEN: 1619 animAttr = enter 1620 ? WindowAnimation_wallpaperIntraOpenEnterAnimation 1621 : WindowAnimation_wallpaperIntraOpenExitAnimation; 1622 break; 1623 case TRANSIT_WALLPAPER_INTRA_CLOSE: 1624 animAttr = enter 1625 ? WindowAnimation_wallpaperIntraCloseEnterAnimation 1626 : WindowAnimation_wallpaperIntraCloseExitAnimation; 1627 break; 1628 case TRANSIT_TASK_OPEN_BEHIND: 1629 animAttr = enter 1630 ? WindowAnimation_launchTaskBehindSourceAnimation 1631 : WindowAnimation_launchTaskBehindTargetAnimation; 1632 } 1633 a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null; 1634 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 1635 "applyAnimation:" 1636 + " anim=" + a 1637 + " animAttr=0x" + Integer.toHexString(animAttr) 1638 + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter 1639 + " Callers=" + Debug.getCallers(3)); 1640 } 1641 return a; 1642 } 1643 1644 private Animation loadKeyguardExitAnimation(int transit) { 1645 if ((mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) != 0) { 1646 return null; 1647 } 1648 final boolean toShade = 1649 (mNextAppTransitionFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0; 1650 return mService.mPolicy.createHiddenByKeyguardExit( 1651 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, toShade); 1652 } 1653 1654 int getAppStackClipMode() { 1655 return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH 1656 || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS 1657 || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY 1658 || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER 1659 || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL 1660 ? STACK_CLIP_NONE 1661 : STACK_CLIP_AFTER_ANIM; 1662 } 1663 1664 public int getTransitFlags() { 1665 return mNextAppTransitionFlags; 1666 } 1667 1668 void postAnimationCallback() { 1669 if (mNextAppTransitionCallback != null) { 1670 mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, 1671 mNextAppTransitionCallback)); 1672 mNextAppTransitionCallback = null; 1673 } 1674 } 1675 1676 void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, 1677 IRemoteCallback startedCallback) { 1678 if (isTransitionSet()) { 1679 clear(); 1680 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM; 1681 mNextAppTransitionPackage = packageName; 1682 mNextAppTransitionEnter = enterAnim; 1683 mNextAppTransitionExit = exitAnim; 1684 postAnimationCallback(); 1685 mNextAppTransitionCallback = startedCallback; 1686 } else { 1687 postAnimationCallback(); 1688 } 1689 } 1690 1691 void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, 1692 int startHeight) { 1693 if (isTransitionSet()) { 1694 clear(); 1695 mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP; 1696 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null); 1697 postAnimationCallback(); 1698 } 1699 } 1700 1701 void overridePendingAppTransitionClipReveal(int startX, int startY, 1702 int startWidth, int startHeight) { 1703 if (isTransitionSet()) { 1704 clear(); 1705 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL; 1706 putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null); 1707 postAnimationCallback(); 1708 } 1709 } 1710 1711 void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY, 1712 IRemoteCallback startedCallback, boolean scaleUp) { 1713 if (isTransitionSet()) { 1714 clear(); 1715 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP 1716 : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN; 1717 mNextAppTransitionScaleUp = scaleUp; 1718 putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb); 1719 postAnimationCallback(); 1720 mNextAppTransitionCallback = startedCallback; 1721 } else { 1722 postAnimationCallback(); 1723 } 1724 } 1725 1726 void overridePendingAppTransitionAspectScaledThumb(Bitmap srcThumb, int startX, int startY, 1727 int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) { 1728 if (isTransitionSet()) { 1729 clear(); 1730 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP 1731 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 1732 mNextAppTransitionScaleUp = scaleUp; 1733 putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight, 1734 srcThumb); 1735 postAnimationCallback(); 1736 mNextAppTransitionCallback = startedCallback; 1737 } else { 1738 postAnimationCallback(); 1739 } 1740 } 1741 1742 public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs, 1743 IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback, 1744 boolean scaleUp) { 1745 if (isTransitionSet()) { 1746 clear(); 1747 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP 1748 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 1749 mNextAppTransitionScaleUp = scaleUp; 1750 if (specs != null) { 1751 for (int i = 0; i < specs.length; i++) { 1752 AppTransitionAnimationSpec spec = specs[i]; 1753 if (spec != null) { 1754 mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec); 1755 if (i == 0) { 1756 // In full screen mode, the transition code depends on the default spec 1757 // to be set. 1758 Rect rect = spec.rect; 1759 putDefaultNextAppTransitionCoordinates(rect.left, rect.top, 1760 rect.width(), rect.height(), spec.bitmap); 1761 } 1762 } 1763 } 1764 } 1765 postAnimationCallback(); 1766 mNextAppTransitionCallback = onAnimationStartedCallback; 1767 mAnimationFinishedCallback = onAnimationFinishedCallback; 1768 } else { 1769 postAnimationCallback(); 1770 } 1771 } 1772 1773 void overridePendingAppTransitionMultiThumbFuture( 1774 IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback, 1775 boolean scaleUp) { 1776 if (isTransitionSet()) { 1777 clear(); 1778 mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP 1779 : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; 1780 mNextAppTransitionAnimationsSpecsFuture = specsFuture; 1781 mNextAppTransitionScaleUp = scaleUp; 1782 mNextAppTransitionFutureCallback = callback; 1783 } 1784 } 1785 1786 void overrideInPlaceAppTransition(String packageName, int anim) { 1787 if (isTransitionSet()) { 1788 clear(); 1789 mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE; 1790 mNextAppTransitionPackage = packageName; 1791 mNextAppTransitionInPlace = anim; 1792 } else { 1793 postAnimationCallback(); 1794 } 1795 } 1796 1797 /** 1798 * If a future is set for the app transition specs, fetch it in another thread. 1799 */ 1800 private void fetchAppTransitionSpecsFromFuture() { 1801 if (mNextAppTransitionAnimationsSpecsFuture != null) { 1802 mNextAppTransitionAnimationsSpecsPending = true; 1803 final IAppTransitionAnimationSpecsFuture future 1804 = mNextAppTransitionAnimationsSpecsFuture; 1805 mNextAppTransitionAnimationsSpecsFuture = null; 1806 mDefaultExecutor.execute(new Runnable() { 1807 @Override 1808 public void run() { 1809 AppTransitionAnimationSpec[] specs = null; 1810 try { 1811 specs = future.get(); 1812 } catch (RemoteException e) { 1813 Slog.w(TAG, "Failed to fetch app transition specs: " + e); 1814 } 1815 synchronized (mService.mWindowMap) { 1816 mNextAppTransitionAnimationsSpecsPending = false; 1817 overridePendingAppTransitionMultiThumb(specs, 1818 mNextAppTransitionFutureCallback, null /* finishedCallback */, 1819 mNextAppTransitionScaleUp); 1820 mNextAppTransitionFutureCallback = null; 1821 if (specs != null) { 1822 mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp); 1823 } 1824 } 1825 mService.requestTraversal(); 1826 } 1827 }); 1828 } 1829 } 1830 1831 @Override 1832 public String toString() { 1833 return "mNextAppTransition=" + appTransitionToString(mNextAppTransition); 1834 } 1835 1836 /** 1837 * Returns the human readable name of a window transition. 1838 * 1839 * @param transition The window transition. 1840 * @return The transition symbolic name. 1841 */ 1842 public static String appTransitionToString(int transition) { 1843 switch (transition) { 1844 case TRANSIT_UNSET: { 1845 return "TRANSIT_UNSET"; 1846 } 1847 case TRANSIT_NONE: { 1848 return "TRANSIT_NONE"; 1849 } 1850 case TRANSIT_ACTIVITY_OPEN: { 1851 return "TRANSIT_ACTIVITY_OPEN"; 1852 } 1853 case TRANSIT_ACTIVITY_CLOSE: { 1854 return "TRANSIT_ACTIVITY_CLOSE"; 1855 } 1856 case TRANSIT_TASK_OPEN: { 1857 return "TRANSIT_TASK_OPEN"; 1858 } 1859 case TRANSIT_TASK_CLOSE: { 1860 return "TRANSIT_TASK_CLOSE"; 1861 } 1862 case TRANSIT_TASK_TO_FRONT: { 1863 return "TRANSIT_TASK_TO_FRONT"; 1864 } 1865 case TRANSIT_TASK_TO_BACK: { 1866 return "TRANSIT_TASK_TO_BACK"; 1867 } 1868 case TRANSIT_WALLPAPER_CLOSE: { 1869 return "TRANSIT_WALLPAPER_CLOSE"; 1870 } 1871 case TRANSIT_WALLPAPER_OPEN: { 1872 return "TRANSIT_WALLPAPER_OPEN"; 1873 } 1874 case TRANSIT_WALLPAPER_INTRA_OPEN: { 1875 return "TRANSIT_WALLPAPER_INTRA_OPEN"; 1876 } 1877 case TRANSIT_WALLPAPER_INTRA_CLOSE: { 1878 return "TRANSIT_WALLPAPER_INTRA_CLOSE"; 1879 } 1880 case TRANSIT_TASK_OPEN_BEHIND: { 1881 return "TRANSIT_TASK_OPEN_BEHIND"; 1882 } 1883 case TRANSIT_ACTIVITY_RELAUNCH: { 1884 return "TRANSIT_ACTIVITY_RELAUNCH"; 1885 } 1886 case TRANSIT_DOCK_TASK_FROM_RECENTS: { 1887 return "TRANSIT_DOCK_TASK_FROM_RECENTS"; 1888 } 1889 case TRANSIT_KEYGUARD_GOING_AWAY: { 1890 return "TRANSIT_KEYGUARD_GOING_AWAY"; 1891 } 1892 case TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER: { 1893 return "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER"; 1894 } 1895 case TRANSIT_KEYGUARD_OCCLUDE: { 1896 return "TRANSIT_KEYGUARD_OCCLUDE"; 1897 } 1898 case TRANSIT_KEYGUARD_UNOCCLUDE: { 1899 return "TRANSIT_KEYGUARD_UNOCCLUDE"; 1900 } 1901 default: { 1902 return "<UNKNOWN>"; 1903 } 1904 } 1905 } 1906 1907 private String appStateToString() { 1908 switch (mAppTransitionState) { 1909 case APP_STATE_IDLE: 1910 return "APP_STATE_IDLE"; 1911 case APP_STATE_READY: 1912 return "APP_STATE_READY"; 1913 case APP_STATE_RUNNING: 1914 return "APP_STATE_RUNNING"; 1915 case APP_STATE_TIMEOUT: 1916 return "APP_STATE_TIMEOUT"; 1917 default: 1918 return "unknown state=" + mAppTransitionState; 1919 } 1920 } 1921 1922 private String transitTypeToString() { 1923 switch (mNextAppTransitionType) { 1924 case NEXT_TRANSIT_TYPE_NONE: 1925 return "NEXT_TRANSIT_TYPE_NONE"; 1926 case NEXT_TRANSIT_TYPE_CUSTOM: 1927 return "NEXT_TRANSIT_TYPE_CUSTOM"; 1928 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1929 return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE"; 1930 case NEXT_TRANSIT_TYPE_SCALE_UP: 1931 return "NEXT_TRANSIT_TYPE_SCALE_UP"; 1932 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1933 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP"; 1934 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1935 return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN"; 1936 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1937 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP"; 1938 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: 1939 return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN"; 1940 default: 1941 return "unknown type=" + mNextAppTransitionType; 1942 } 1943 } 1944 1945 @Override 1946 public void dump(PrintWriter pw, String prefix) { 1947 pw.print(prefix); pw.println(this); 1948 pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString()); 1949 if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) { 1950 pw.print(prefix); pw.print("mNextAppTransitionType="); 1951 pw.println(transitTypeToString()); 1952 } 1953 switch (mNextAppTransitionType) { 1954 case NEXT_TRANSIT_TYPE_CUSTOM: 1955 pw.print(prefix); pw.print("mNextAppTransitionPackage="); 1956 pw.println(mNextAppTransitionPackage); 1957 pw.print(prefix); pw.print("mNextAppTransitionEnter=0x"); 1958 pw.print(Integer.toHexString(mNextAppTransitionEnter)); 1959 pw.print(" mNextAppTransitionExit=0x"); 1960 pw.println(Integer.toHexString(mNextAppTransitionExit)); 1961 break; 1962 case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: 1963 pw.print(prefix); pw.print("mNextAppTransitionPackage="); 1964 pw.println(mNextAppTransitionPackage); 1965 pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x"); 1966 pw.print(Integer.toHexString(mNextAppTransitionInPlace)); 1967 break; 1968 case NEXT_TRANSIT_TYPE_SCALE_UP: { 1969 getDefaultNextAppTransitionStartRect(mTmpRect); 1970 pw.print(prefix); pw.print("mNextAppTransitionStartX="); 1971 pw.print(mTmpRect.left); 1972 pw.print(" mNextAppTransitionStartY="); 1973 pw.println(mTmpRect.top); 1974 pw.print(prefix); pw.print("mNextAppTransitionStartWidth="); 1975 pw.print(mTmpRect.width()); 1976 pw.print(" mNextAppTransitionStartHeight="); 1977 pw.println(mTmpRect.height()); 1978 break; 1979 } 1980 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP: 1981 case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: 1982 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: 1983 case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: { 1984 pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec="); 1985 pw.println(mDefaultNextAppTransitionAnimationSpec); 1986 pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs="); 1987 pw.println(mNextAppTransitionAnimationsSpecs); 1988 pw.print(prefix); pw.print("mNextAppTransitionScaleUp="); 1989 pw.println(mNextAppTransitionScaleUp); 1990 break; 1991 } 1992 } 1993 if (mNextAppTransitionCallback != null) { 1994 pw.print(prefix); pw.print("mNextAppTransitionCallback="); 1995 pw.println(mNextAppTransitionCallback); 1996 } 1997 if (mLastUsedAppTransition != TRANSIT_NONE) { 1998 pw.print(prefix); pw.print("mLastUsedAppTransition="); 1999 pw.println(appTransitionToString(mLastUsedAppTransition)); 2000 pw.print(prefix); pw.print("mLastOpeningApp="); 2001 pw.println(mLastOpeningApp); 2002 pw.print(prefix); pw.print("mLastClosingApp="); 2003 pw.println(mLastClosingApp); 2004 } 2005 } 2006 2007 public void setCurrentUser(int newUserId) { 2008 mCurrentUserId = newUserId; 2009 } 2010 2011 /** 2012 * @return true if transition is not running and should not be skipped, false if transition is 2013 * already running 2014 */ 2015 boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent, int flags, 2016 boolean forceOverride) { 2017 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:" 2018 + " transit=" + appTransitionToString(transit) 2019 + " " + this 2020 + " alwaysKeepCurrent=" + alwaysKeepCurrent 2021 + " Callers=" + Debug.getCallers(3)); 2022 if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet() 2023 || mNextAppTransition == TRANSIT_NONE) { 2024 setAppTransition(transit, flags); 2025 } else if (!alwaysKeepCurrent) { 2026 if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) { 2027 // Opening a new task always supersedes a close for the anim. 2028 setAppTransition(transit, flags); 2029 } else if (transit == TRANSIT_ACTIVITY_OPEN 2030 && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) { 2031 // Opening a new activity always supersedes a close for the anim. 2032 setAppTransition(transit, flags); 2033 } 2034 } 2035 boolean prepared = prepare(); 2036 if (isTransitionSet()) { 2037 mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT); 2038 mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS); 2039 } 2040 return prepared; 2041 } 2042 2043 /** 2044 * @return true if {@param transit} is representing a transition in which Keyguard is going 2045 * away, false otherwise 2046 */ 2047 public static boolean isKeyguardGoingAwayTransit(int transit) { 2048 return transit == TRANSIT_KEYGUARD_GOING_AWAY 2049 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER; 2050 } 2051 2052 private static boolean isKeyguardTransit(int transit) { 2053 return isKeyguardGoingAwayTransit(transit) || transit == TRANSIT_KEYGUARD_OCCLUDE 2054 || transit == TRANSIT_KEYGUARD_UNOCCLUDE; 2055 } 2056 2057 /** 2058 * @return whether the transition should show the thumbnail being scaled down. 2059 */ 2060 private boolean shouldScaleDownThumbnailTransition(int uiMode, int orientation) { 2061 return mGridLayoutRecentsEnabled 2062 || orientation == Configuration.ORIENTATION_PORTRAIT; 2063 } 2064} 2065