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