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