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