1 /* 2 * Copyright (C) 2018 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.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; 20 21 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; 22 import static com.android.server.wm.AnimationAdapterProto.REMOTE; 23 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; 24 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 25 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 26 27 import android.annotation.ColorInt; 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.graphics.Point; 31 import android.graphics.Rect; 32 import android.os.Binder; 33 import android.os.Handler; 34 import android.os.IBinder.DeathRecipient; 35 import android.os.RemoteException; 36 import android.os.SystemClock; 37 import android.util.Slog; 38 import android.util.proto.ProtoOutputStream; 39 import android.view.IRemoteAnimationFinishedCallback; 40 import android.view.RemoteAnimationAdapter; 41 import android.view.RemoteAnimationTarget; 42 import android.view.SurfaceControl; 43 import android.view.SurfaceControl.Transaction; 44 import android.view.WindowManager; 45 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.internal.protolog.common.LogLevel; 48 import com.android.internal.protolog.common.ProtoLog; 49 import com.android.internal.util.FastPrintWriter; 50 import com.android.server.wm.SurfaceAnimator.AnimationType; 51 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; 52 53 import java.io.PrintWriter; 54 import java.io.StringWriter; 55 import java.util.ArrayList; 56 import java.util.function.Consumer; 57 58 /** 59 * Helper class to run app animations in a remote process. 60 */ 61 class RemoteAnimationController implements DeathRecipient { 62 private static final String TAG = TAG_WITH_CLASS_NAME 63 ? "RemoteAnimationController" : TAG_WM; 64 private static final long TIMEOUT_MS = 10000; 65 66 private final WindowManagerService mService; 67 private final DisplayContent mDisplayContent; 68 private final RemoteAnimationAdapter mRemoteAnimationAdapter; 69 private final ArrayList<RemoteAnimationRecord> mPendingAnimations = new ArrayList<>(); 70 private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations = 71 new ArrayList<>(); 72 @VisibleForTesting 73 final ArrayList<NonAppWindowAnimationAdapter> mPendingNonAppAnimations = new ArrayList<>(); 74 private final Handler mHandler; 75 private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable"); 76 private boolean mIsFinishing; 77 78 private FinishedCallback mFinishedCallback; 79 private final boolean mIsActivityEmbedding; 80 private boolean mCanceled; 81 private boolean mLinkedToDeathOfRunner; 82 @Nullable 83 private Runnable mOnRemoteAnimationReady; 84 RemoteAnimationController(WindowManagerService service, DisplayContent displayContent, RemoteAnimationAdapter remoteAnimationAdapter, Handler handler, boolean isActivityEmbedding)85 RemoteAnimationController(WindowManagerService service, DisplayContent displayContent, 86 RemoteAnimationAdapter remoteAnimationAdapter, Handler handler, 87 boolean isActivityEmbedding) { 88 mService = service; 89 mDisplayContent = displayContent; 90 mRemoteAnimationAdapter = remoteAnimationAdapter; 91 mHandler = handler; 92 mIsActivityEmbedding = isActivityEmbedding; 93 } 94 95 /** 96 * Creates an animation record for each individual {@link WindowContainer}. 97 * 98 * @param windowContainer The windows to animate. 99 * @param position The position app bounds relative to its parent. 100 * @param localBounds The bounds of the app relative to its parent. 101 * @param endBounds The end bounds after the transition, in screen coordinates. 102 * @param startBounds The start bounds before the transition, in screen coordinates. 103 * @param showBackdrop To show background behind a window during animation. 104 * @return The record representing animation(s) to run on the app. 105 */ createRemoteAnimationRecord(WindowContainer windowContainer, Point position, Rect localBounds, Rect endBounds, Rect startBounds, boolean showBackdrop)106 RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer, 107 Point position, Rect localBounds, Rect endBounds, Rect startBounds, 108 boolean showBackdrop) { 109 return createRemoteAnimationRecord(windowContainer, position, localBounds, endBounds, 110 startBounds, showBackdrop, startBounds != null /* shouldCreateSnapshot */); 111 } 112 113 /** 114 * Creates an animation record for each individual {@link WindowContainer}. 115 * 116 * @param windowContainer The windows to animate. 117 * @param position The position app bounds relative to its parent. 118 * @param localBounds The bounds of the app relative to its parent. 119 * @param endBounds The end bounds after the transition, in screen coordinates. 120 * @param startBounds The start bounds before the transition, in screen coordinates. 121 * @param showBackdrop To show background behind a window during animation. 122 * @param shouldCreateSnapshot Whether this target should create a snapshot animation. 123 * @return The record representing animation(s) to run on the app. 124 */ createRemoteAnimationRecord(WindowContainer windowContainer, Point position, Rect localBounds, Rect endBounds, Rect startBounds, boolean showBackdrop, boolean shouldCreateSnapshot)125 RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer, 126 Point position, Rect localBounds, Rect endBounds, Rect startBounds, 127 boolean showBackdrop, boolean shouldCreateSnapshot) { 128 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s", 129 windowContainer); 130 final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position, 131 localBounds, endBounds, startBounds, showBackdrop, shouldCreateSnapshot); 132 mPendingAnimations.add(adapters); 133 return adapters; 134 } 135 136 /** Sets callback to run before starting remote animation. */ setOnRemoteAnimationReady(@ullable Runnable onRemoteAnimationReady)137 void setOnRemoteAnimationReady(@Nullable Runnable onRemoteAnimationReady) { 138 mOnRemoteAnimationReady = onRemoteAnimationReady; 139 } 140 141 /** 142 * We use isFromActivityEmbedding() in the server process to tell if we're running an 143 * Activity Embedding type remote animation, where animations are driven by the client. 144 * This is currently supporting features like showBackdrop where we need to load App XML. 145 */ isFromActivityEmbedding()146 public boolean isFromActivityEmbedding() { 147 return mIsActivityEmbedding; 148 } 149 150 /** 151 * Called when the transition is ready to be started, and all leashes have been set up. 152 */ goodToGo(@indowManager.TransitionOldType int transit)153 void goodToGo(@WindowManager.TransitionOldType int transit) { 154 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo()"); 155 if (mCanceled) { 156 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, 157 "goodToGo(): Animation canceled already"); 158 onAnimationFinished(); 159 invokeAnimationCancelled("already_cancelled"); 160 return; 161 } 162 163 // Scale the timeout with the animator scale the controlling app is using. 164 mHandler.postDelayed(mTimeoutRunnable, 165 (long) (TIMEOUT_MS * mService.getCurrentAnimatorScale())); 166 mFinishedCallback = new FinishedCallback(this); 167 168 // Create the app targets 169 final RemoteAnimationTarget[] appTargets = createAppAnimations(); 170 if (appTargets.length == 0 && !AppTransition.isKeyguardOccludeTransitOld(transit)) { 171 // Keyguard occlude transition can be executed before the occluding activity becomes 172 // visible. Even in this case, KeyguardService expects to receive binder call, so we 173 // don't cancel remote animation. 174 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, 175 "goodToGo(): No apps to animate, mPendingAnimations=%d", 176 mPendingAnimations.size()); 177 onAnimationFinished(); 178 invokeAnimationCancelled("no_app_targets"); 179 return; 180 } 181 182 if (mOnRemoteAnimationReady != null) { 183 mOnRemoteAnimationReady.run(); 184 mOnRemoteAnimationReady = null; 185 } 186 187 // Create the remote wallpaper animation targets (if any) 188 final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations(); 189 190 // Create the remote non app animation targets (if any) 191 final RemoteAnimationTarget[] nonAppTargets = createNonAppWindowAnimations(transit); 192 193 mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { 194 try { 195 linkToDeathOfRunner(); 196 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): onAnimationStart," 197 + " transit=%s, apps=%d, wallpapers=%d, nonApps=%d", 198 AppTransition.appTransitionOldToString(transit), appTargets.length, 199 wallpaperTargets.length, nonAppTargets.length); 200 if (AppTransition.isKeyguardOccludeTransitOld(transit)) { 201 EventLogTags.writeWmSetKeyguardOccluded( 202 transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE ? 0 : 1, 203 1 /* animate */, 204 transit, 205 "onAnimationStart"); 206 } 207 mRemoteAnimationAdapter.getRunner().onAnimationStart(transit, appTargets, 208 wallpaperTargets, nonAppTargets, mFinishedCallback); 209 } catch (RemoteException e) { 210 Slog.e(TAG, "Failed to start remote animation", e); 211 onAnimationFinished(); 212 } 213 if (ProtoLog.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS, LogLevel.DEBUG)) { 214 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation(): Notify animation start:"); 215 writeStartDebugStatement(); 216 } 217 }); 218 setRunningRemoteAnimation(true); 219 } 220 cancelAnimation(String reason)221 void cancelAnimation(String reason) { 222 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason); 223 synchronized (mService.getWindowManagerLock()) { 224 if (mCanceled) { 225 return; 226 } 227 mCanceled = true; 228 } 229 onAnimationFinished(); 230 invokeAnimationCancelled(reason); 231 } 232 writeStartDebugStatement()233 private void writeStartDebugStatement() { 234 ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Starting remote animation"); 235 final StringWriter sw = new StringWriter(); 236 final FastPrintWriter pw = new FastPrintWriter(sw); 237 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 238 mPendingAnimations.get(i).mAdapter.dump(pw, ""); 239 } 240 pw.close(); 241 ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "%s", sw.toString()); 242 } 243 createAppAnimations()244 private RemoteAnimationTarget[] createAppAnimations() { 245 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAppAnimations()"); 246 final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>(); 247 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 248 final RemoteAnimationRecord wrappers = mPendingAnimations.get(i); 249 final RemoteAnimationTarget target = wrappers.createRemoteAnimationTarget(); 250 if (target != null) { 251 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tAdd container=%s", 252 wrappers.mWindowContainer); 253 targets.add(target); 254 } else { 255 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tRemove container=%s", 256 wrappers.mWindowContainer); 257 258 // We can't really start an animation but we still need to make sure to finish the 259 // pending animation that was started by SurfaceAnimator 260 if (wrappers.mAdapter != null 261 && wrappers.mAdapter.mCapturedFinishCallback != null) { 262 wrappers.mAdapter.mCapturedFinishCallback 263 .onAnimationFinished(wrappers.mAdapter.mAnimationType, 264 wrappers.mAdapter); 265 } 266 if (wrappers.mThumbnailAdapter != null 267 && wrappers.mThumbnailAdapter.mCapturedFinishCallback != null) { 268 wrappers.mThumbnailAdapter.mCapturedFinishCallback 269 .onAnimationFinished(wrappers.mThumbnailAdapter.mAnimationType, 270 wrappers.mThumbnailAdapter); 271 } 272 mPendingAnimations.remove(i); 273 } 274 } 275 return targets.toArray(new RemoteAnimationTarget[targets.size()]); 276 } 277 createWallpaperAnimations()278 private RemoteAnimationTarget[] createWallpaperAnimations() { 279 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createWallpaperAnimations()"); 280 return WallpaperAnimationAdapter.startWallpaperAnimations(mDisplayContent, 281 mRemoteAnimationAdapter.getDuration(), 282 mRemoteAnimationAdapter.getStatusBarTransitionDelay(), 283 adapter -> { 284 synchronized (mService.mGlobalLock) { 285 // If the wallpaper animation is canceled, continue with the app animation 286 mPendingWallpaperAnimations.remove(adapter); 287 } 288 }, mPendingWallpaperAnimations); 289 } 290 291 private RemoteAnimationTarget[] createNonAppWindowAnimations( 292 @WindowManager.TransitionOldType int transit) { 293 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createNonAppWindowAnimations()"); 294 return NonAppWindowAnimationAdapter.startNonAppWindowAnimations(mService, 295 mDisplayContent, 296 transit, 297 mRemoteAnimationAdapter.getDuration(), 298 mRemoteAnimationAdapter.getStatusBarTransitionDelay(), 299 mPendingNonAppAnimations); 300 } 301 302 private void onAnimationFinished() { 303 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationFinished(): mPendingAnimations=%d", 304 mPendingAnimations.size()); 305 mHandler.removeCallbacks(mTimeoutRunnable); 306 synchronized (mService.mGlobalLock) { 307 mIsFinishing = true; 308 unlinkToDeathOfRunner(); 309 releaseFinishedCallback(); 310 try { 311 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, 312 "onAnimationFinished(): Notify animation finished:"); 313 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 314 final RemoteAnimationRecord adapters = mPendingAnimations.get(i); 315 if (adapters.mAdapter != null) { 316 adapters.mAdapter.mCapturedFinishCallback 317 .onAnimationFinished(adapters.mAdapter.mAnimationType, 318 adapters.mAdapter); 319 } 320 if (adapters.mThumbnailAdapter != null) { 321 adapters.mThumbnailAdapter.mCapturedFinishCallback 322 .onAnimationFinished(adapters.mThumbnailAdapter.mAnimationType, 323 adapters.mThumbnailAdapter); 324 } 325 mPendingAnimations.remove(i); 326 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tcontainer=%s", 327 adapters.mWindowContainer); 328 } 329 330 for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) { 331 final WallpaperAnimationAdapter adapter = mPendingWallpaperAnimations.get(i); 332 adapter.getLeashFinishedCallback().onAnimationFinished( 333 adapter.getLastAnimationType(), adapter); 334 mPendingWallpaperAnimations.remove(i); 335 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\twallpaper=%s", adapter.getToken()); 336 } 337 338 for (int i = mPendingNonAppAnimations.size() - 1; i >= 0; i--) { 339 final NonAppWindowAnimationAdapter adapter = mPendingNonAppAnimations.get(i); 340 adapter.getLeashFinishedCallback().onAnimationFinished( 341 adapter.getLastAnimationType(), adapter); 342 mPendingNonAppAnimations.remove(i); 343 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tnonApp=%s", 344 adapter.getWindowContainer()); 345 } 346 } catch (Exception e) { 347 Slog.e(TAG, "Failed to finish remote animation", e); 348 throw e; 349 } finally { 350 mIsFinishing = false; 351 } 352 // Reset input for all activities when the remote animation is finished. 353 final Consumer<ActivityRecord> updateActivities = 354 activity -> activity.setDropInputForAnimation(false); 355 mDisplayContent.forAllActivities(updateActivities); 356 } 357 setRunningRemoteAnimation(false); 358 ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation"); 359 } 360 361 private void invokeAnimationCancelled(String reason) { 362 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason); 363 try { 364 mRemoteAnimationAdapter.getRunner().onAnimationCancelled(); 365 } catch (RemoteException e) { 366 Slog.e(TAG, "Failed to notify cancel", e); 367 } 368 mOnRemoteAnimationReady = null; 369 } 370 371 private void releaseFinishedCallback() { 372 if (mFinishedCallback != null) { 373 mFinishedCallback.release(); 374 mFinishedCallback = null; 375 } 376 } 377 378 private void setRunningRemoteAnimation(boolean running) { 379 final int pid = mRemoteAnimationAdapter.getCallingPid(); 380 final int uid = mRemoteAnimationAdapter.getCallingUid(); 381 382 if (pid == 0) { 383 throw new RuntimeException("Calling pid of remote animation was null"); 384 } 385 final WindowProcessController wpc = mService.mAtmService.getProcessController(pid, uid); 386 if (wpc == null) { 387 Slog.w(TAG, "Unable to find process with pid=" + pid + " uid=" + uid); 388 return; 389 } 390 wpc.setRunningRemoteAnimation(running); 391 } 392 393 private void linkToDeathOfRunner() throws RemoteException { 394 if (!mLinkedToDeathOfRunner) { 395 mRemoteAnimationAdapter.getRunner().asBinder().linkToDeath(this, 0); 396 mLinkedToDeathOfRunner = true; 397 } 398 } 399 400 private void unlinkToDeathOfRunner() { 401 if (mLinkedToDeathOfRunner) { 402 mRemoteAnimationAdapter.getRunner().asBinder().unlinkToDeath(this, 0); 403 mLinkedToDeathOfRunner = false; 404 } 405 } 406 407 @Override 408 public void binderDied() { 409 cancelAnimation("binderDied"); 410 } 411 412 private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub { 413 414 RemoteAnimationController mOuter; 415 416 FinishedCallback(RemoteAnimationController outer) { 417 mOuter = outer; 418 } 419 420 @Override 421 public void onAnimationFinished() throws RemoteException { 422 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-onAnimationFinished(): mOuter=%s", mOuter); 423 final long token = Binder.clearCallingIdentity(); 424 try { 425 if (mOuter != null) { 426 mOuter.onAnimationFinished(); 427 428 // In case the client holds on to the finish callback, make sure we don't leak 429 // RemoteAnimationController which in turn would leak the runner on the client. 430 mOuter = null; 431 } 432 } finally { 433 Binder.restoreCallingIdentity(token); 434 } 435 } 436 437 /** 438 * Marks this callback as not be used anymore by releasing the reference to the outer class 439 * to prevent memory leak. 440 */ 441 void release() { 442 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-release(): mOuter=%s", mOuter); 443 mOuter = null; 444 } 445 }; 446 447 /** 448 * Contains information about a remote-animation for one WindowContainer. This keeps track of, 449 * potentially, multiple animating surfaces (AdapterWrappers) associated with one 450 * Window/Transition. For example, a change transition has an adapter controller for the 451 * main window and an adapter controlling the start-state snapshot. 452 * <p> 453 * This can be thought of as a bridge between the information that the remote animator sees (via 454 * {@link RemoteAnimationTarget}) and what the server sees (the 455 * {@link RemoteAnimationAdapterWrapper}(s) interfacing with the moving surfaces). 456 */ 457 public class RemoteAnimationRecord { 458 RemoteAnimationAdapterWrapper mAdapter; 459 RemoteAnimationAdapterWrapper mThumbnailAdapter = null; 460 RemoteAnimationTarget mTarget; 461 final WindowContainer mWindowContainer; 462 final Rect mStartBounds; 463 final boolean mShowBackdrop; 464 @ColorInt int mBackdropColor = 0; 465 private @RemoteAnimationTarget.Mode int mMode = RemoteAnimationTarget.MODE_CHANGING; 466 467 RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds, 468 Rect endBounds, @Nullable Rect startBounds, boolean showBackdrop, 469 boolean shouldCreateSnapshot) { 470 mWindowContainer = windowContainer; 471 mShowBackdrop = showBackdrop; 472 if (startBounds != null) { 473 mStartBounds = new Rect(startBounds); 474 mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds, 475 mStartBounds, mShowBackdrop); 476 if (shouldCreateSnapshot && mRemoteAnimationAdapter.getChangeNeedsSnapshot()) { 477 final Rect thumbnailLocalBounds = new Rect(startBounds); 478 thumbnailLocalBounds.offsetTo(0, 0); 479 // Snapshot is located at (0,0) of the animation leash. It doesn't have size 480 // change, so the startBounds is its end bounds, and no start bounds for it. 481 mThumbnailAdapter = new RemoteAnimationAdapterWrapper(this, new Point(0, 0), 482 thumbnailLocalBounds, startBounds, new Rect(), mShowBackdrop); 483 } 484 } else { 485 mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds, 486 new Rect(), mShowBackdrop); 487 mStartBounds = null; 488 } 489 } 490 491 void setBackDropColor(@ColorInt int backdropColor) { 492 mBackdropColor = backdropColor; 493 } 494 495 RemoteAnimationTarget createRemoteAnimationTarget() { 496 if (mAdapter == null 497 || mAdapter.mCapturedFinishCallback == null 498 || mAdapter.mCapturedLeash == null) { 499 return null; 500 } 501 mTarget = mWindowContainer.createRemoteAnimationTarget(this); 502 return mTarget; 503 } 504 505 void setMode(@RemoteAnimationTarget.Mode int mode) { 506 mMode = mode; 507 } 508 509 int getMode() { 510 return mMode; 511 } 512 513 /** Whether its parent is also an animation target in the same transition. */ 514 boolean hasAnimatingParent() { 515 // mOpeningApps and mClosingApps are only activities, so only need to check 516 // mChangingContainers. 517 for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) { 518 if (mWindowContainer.isDescendantOf( 519 mDisplayContent.mChangingContainers.valueAt(i))) { 520 return true; 521 } 522 } 523 return false; 524 } 525 } 526 527 class RemoteAnimationAdapterWrapper implements AnimationAdapter { 528 private final RemoteAnimationRecord mRecord; 529 SurfaceControl mCapturedLeash; 530 private OnAnimationFinishedCallback mCapturedFinishCallback; 531 private @AnimationType int mAnimationType; 532 final Point mPosition = new Point(); 533 final Rect mLocalBounds; 534 final Rect mEndBounds = new Rect(); 535 final Rect mStartBounds = new Rect(); 536 final boolean mShowBackdrop; 537 538 RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position, 539 Rect localBounds, Rect endBounds, Rect startBounds, boolean showBackdrop) { 540 mRecord = record; 541 mPosition.set(position.x, position.y); 542 mLocalBounds = localBounds; 543 mEndBounds.set(endBounds); 544 mStartBounds.set(startBounds); 545 mShowBackdrop = showBackdrop; 546 } 547 548 @Override 549 @ColorInt 550 public int getBackgroundColor() { 551 return mRecord.mBackdropColor; 552 } 553 554 @Override 555 public boolean getShowBackground() { 556 return mShowBackdrop; 557 } 558 559 @Override 560 public boolean getShowWallpaper() { 561 return false; 562 } 563 564 @Override 565 public void startAnimation(SurfaceControl animationLeash, Transaction t, 566 @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) { 567 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); 568 569 if (mStartBounds.isEmpty()) { 570 // Restore position and stack crop until client has a chance to modify it. 571 t.setPosition(animationLeash, mPosition.x, mPosition.y); 572 t.setWindowCrop(animationLeash, mEndBounds.width(), mEndBounds.height()); 573 } else { 574 // Offset the change animation leash to the relative start position in parent. 575 // (mPosition) is the relative end position in parent container. 576 // (mStartBounds - mEndBounds) is the position difference between start and end. 577 // (mPosition + mStartBounds - mEndBounds) will be the relative start position. 578 t.setPosition(animationLeash, mPosition.x + mStartBounds.left - mEndBounds.left, 579 mPosition.y + mStartBounds.top - mEndBounds.top); 580 t.setWindowCrop(animationLeash, mStartBounds.width(), mStartBounds.height()); 581 } 582 mCapturedLeash = animationLeash; 583 mCapturedFinishCallback = finishCallback; 584 mAnimationType = type; 585 } 586 587 @Override 588 public void onAnimationCancelled(SurfaceControl animationLeash) { 589 if (mIsFinishing) { 590 return; 591 } 592 if (mRecord.mAdapter == this) { 593 mRecord.mAdapter = null; 594 } else { 595 mRecord.mThumbnailAdapter = null; 596 } 597 if (mRecord.mAdapter == null && mRecord.mThumbnailAdapter == null) { 598 mPendingAnimations.remove(mRecord); 599 } 600 if (mPendingAnimations.isEmpty()) { 601 cancelAnimation("allAppAnimationsCanceled"); 602 } 603 } 604 605 @Override 606 public long getDurationHint() { 607 return mRemoteAnimationAdapter.getDuration(); 608 } 609 610 @Override 611 public long getStatusBarTransitionsStartTime() { 612 return SystemClock.uptimeMillis() 613 + mRemoteAnimationAdapter.getStatusBarTransitionDelay(); 614 } 615 616 @Override 617 public void dump(PrintWriter pw, String prefix) { 618 pw.print(prefix); pw.print("container="); pw.println(mRecord.mWindowContainer); 619 if (mRecord.mTarget != null) { 620 pw.print(prefix); pw.println("Target:"); 621 mRecord.mTarget.dump(pw, prefix + " "); 622 } else { 623 pw.print(prefix); pw.println("Target: null"); 624 } 625 } 626 627 @Override 628 public void dumpDebug(ProtoOutputStream proto) { 629 final long token = proto.start(REMOTE); 630 if (mRecord.mTarget != null) { 631 mRecord.mTarget.dumpDebug(proto, TARGET); 632 } 633 proto.end(token); 634 } 635 } 636 } 637