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 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 (ProtoLogImpl.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) { 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 mService.openSurfaceTransaction(); 311 try { 312 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, 313 "onAnimationFinished(): Notify animation finished:"); 314 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 315 final RemoteAnimationRecord adapters = mPendingAnimations.get(i); 316 if (adapters.mAdapter != null) { 317 adapters.mAdapter.mCapturedFinishCallback 318 .onAnimationFinished(adapters.mAdapter.mAnimationType, 319 adapters.mAdapter); 320 } 321 if (adapters.mThumbnailAdapter != null) { 322 adapters.mThumbnailAdapter.mCapturedFinishCallback 323 .onAnimationFinished(adapters.mThumbnailAdapter.mAnimationType, 324 adapters.mThumbnailAdapter); 325 } 326 mPendingAnimations.remove(i); 327 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tcontainer=%s", 328 adapters.mWindowContainer); 329 } 330 331 for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) { 332 final WallpaperAnimationAdapter adapter = mPendingWallpaperAnimations.get(i); 333 adapter.getLeashFinishedCallback().onAnimationFinished( 334 adapter.getLastAnimationType(), adapter); 335 mPendingWallpaperAnimations.remove(i); 336 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\twallpaper=%s", adapter.getToken()); 337 } 338 339 for (int i = mPendingNonAppAnimations.size() - 1; i >= 0; i--) { 340 final NonAppWindowAnimationAdapter adapter = mPendingNonAppAnimations.get(i); 341 adapter.getLeashFinishedCallback().onAnimationFinished( 342 adapter.getLastAnimationType(), adapter); 343 mPendingNonAppAnimations.remove(i); 344 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tnonApp=%s", 345 adapter.getWindowContainer()); 346 } 347 } catch (Exception e) { 348 Slog.e(TAG, "Failed to finish remote animation", e); 349 throw e; 350 } finally { 351 mService.closeSurfaceTransaction("RemoteAnimationController#finished"); 352 mIsFinishing = false; 353 } 354 // Reset input for all activities when the remote animation is finished. 355 final Consumer<ActivityRecord> updateActivities = 356 activity -> activity.setDropInputForAnimation(false); 357 mDisplayContent.forAllActivities(updateActivities); 358 } 359 setRunningRemoteAnimation(false); 360 ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation"); 361 } 362 363 private void invokeAnimationCancelled(String reason) { 364 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason); 365 try { 366 mRemoteAnimationAdapter.getRunner().onAnimationCancelled(); 367 } catch (RemoteException e) { 368 Slog.e(TAG, "Failed to notify cancel", e); 369 } 370 mOnRemoteAnimationReady = null; 371 } 372 373 private void releaseFinishedCallback() { 374 if (mFinishedCallback != null) { 375 mFinishedCallback.release(); 376 mFinishedCallback = null; 377 } 378 } 379 380 private void setRunningRemoteAnimation(boolean running) { 381 final int pid = mRemoteAnimationAdapter.getCallingPid(); 382 final int uid = mRemoteAnimationAdapter.getCallingUid(); 383 384 if (pid == 0) { 385 throw new RuntimeException("Calling pid of remote animation was null"); 386 } 387 final WindowProcessController wpc = mService.mAtmService.getProcessController(pid, uid); 388 if (wpc == null) { 389 Slog.w(TAG, "Unable to find process with pid=" + pid + " uid=" + uid); 390 return; 391 } 392 wpc.setRunningRemoteAnimation(running); 393 } 394 395 private void linkToDeathOfRunner() throws RemoteException { 396 if (!mLinkedToDeathOfRunner) { 397 mRemoteAnimationAdapter.getRunner().asBinder().linkToDeath(this, 0); 398 mLinkedToDeathOfRunner = true; 399 } 400 } 401 402 private void unlinkToDeathOfRunner() { 403 if (mLinkedToDeathOfRunner) { 404 mRemoteAnimationAdapter.getRunner().asBinder().unlinkToDeath(this, 0); 405 mLinkedToDeathOfRunner = false; 406 } 407 } 408 409 @Override 410 public void binderDied() { 411 cancelAnimation("binderDied"); 412 } 413 414 private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub { 415 416 RemoteAnimationController mOuter; 417 418 FinishedCallback(RemoteAnimationController outer) { 419 mOuter = outer; 420 } 421 422 @Override 423 public void onAnimationFinished() throws RemoteException { 424 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-onAnimationFinished(): mOuter=%s", mOuter); 425 final long token = Binder.clearCallingIdentity(); 426 try { 427 if (mOuter != null) { 428 mOuter.onAnimationFinished(); 429 430 // In case the client holds on to the finish callback, make sure we don't leak 431 // RemoteAnimationController which in turn would leak the runner on the client. 432 mOuter = null; 433 } 434 } finally { 435 Binder.restoreCallingIdentity(token); 436 } 437 } 438 439 /** 440 * Marks this callback as not be used anymore by releasing the reference to the outer class 441 * to prevent memory leak. 442 */ 443 void release() { 444 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-release(): mOuter=%s", mOuter); 445 mOuter = null; 446 } 447 }; 448 449 /** 450 * Contains information about a remote-animation for one WindowContainer. This keeps track of, 451 * potentially, multiple animating surfaces (AdapterWrappers) associated with one 452 * Window/Transition. For example, a change transition has an adapter controller for the 453 * main window and an adapter controlling the start-state snapshot. 454 * <p> 455 * This can be thought of as a bridge between the information that the remote animator sees (via 456 * {@link RemoteAnimationTarget}) and what the server sees (the 457 * {@link RemoteAnimationAdapterWrapper}(s) interfacing with the moving surfaces). 458 */ 459 public class RemoteAnimationRecord { 460 RemoteAnimationAdapterWrapper mAdapter; 461 RemoteAnimationAdapterWrapper mThumbnailAdapter = null; 462 RemoteAnimationTarget mTarget; 463 final WindowContainer mWindowContainer; 464 final Rect mStartBounds; 465 final boolean mShowBackdrop; 466 @ColorInt int mBackdropColor = 0; 467 private @RemoteAnimationTarget.Mode int mMode = RemoteAnimationTarget.MODE_CHANGING; 468 469 RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds, 470 Rect endBounds, @Nullable Rect startBounds, boolean showBackdrop, 471 boolean shouldCreateSnapshot) { 472 mWindowContainer = windowContainer; 473 mShowBackdrop = showBackdrop; 474 if (startBounds != null) { 475 mStartBounds = new Rect(startBounds); 476 mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds, 477 mStartBounds, mShowBackdrop); 478 if (shouldCreateSnapshot && mRemoteAnimationAdapter.getChangeNeedsSnapshot()) { 479 final Rect thumbnailLocalBounds = new Rect(startBounds); 480 thumbnailLocalBounds.offsetTo(0, 0); 481 // Snapshot is located at (0,0) of the animation leash. It doesn't have size 482 // change, so the startBounds is its end bounds, and no start bounds for it. 483 mThumbnailAdapter = new RemoteAnimationAdapterWrapper(this, new Point(0, 0), 484 thumbnailLocalBounds, startBounds, new Rect(), mShowBackdrop); 485 } 486 } else { 487 mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds, 488 new Rect(), mShowBackdrop); 489 mStartBounds = null; 490 } 491 } 492 493 void setBackDropColor(@ColorInt int backdropColor) { 494 mBackdropColor = backdropColor; 495 } 496 497 RemoteAnimationTarget createRemoteAnimationTarget() { 498 if (mAdapter == null 499 || mAdapter.mCapturedFinishCallback == null 500 || mAdapter.mCapturedLeash == null) { 501 return null; 502 } 503 mTarget = mWindowContainer.createRemoteAnimationTarget(this); 504 return mTarget; 505 } 506 507 void setMode(@RemoteAnimationTarget.Mode int mode) { 508 mMode = mode; 509 } 510 511 int getMode() { 512 return mMode; 513 } 514 515 /** Whether its parent is also an animation target in the same transition. */ 516 boolean hasAnimatingParent() { 517 // mOpeningApps and mClosingApps are only activities, so only need to check 518 // mChangingContainers. 519 for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) { 520 if (mWindowContainer.isDescendantOf( 521 mDisplayContent.mChangingContainers.valueAt(i))) { 522 return true; 523 } 524 } 525 return false; 526 } 527 } 528 529 class RemoteAnimationAdapterWrapper implements AnimationAdapter { 530 private final RemoteAnimationRecord mRecord; 531 SurfaceControl mCapturedLeash; 532 private OnAnimationFinishedCallback mCapturedFinishCallback; 533 private @AnimationType int mAnimationType; 534 final Point mPosition = new Point(); 535 final Rect mLocalBounds; 536 final Rect mEndBounds = new Rect(); 537 final Rect mStartBounds = new Rect(); 538 final boolean mShowBackdrop; 539 540 RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position, 541 Rect localBounds, Rect endBounds, Rect startBounds, boolean showBackdrop) { 542 mRecord = record; 543 mPosition.set(position.x, position.y); 544 mLocalBounds = localBounds; 545 mEndBounds.set(endBounds); 546 mStartBounds.set(startBounds); 547 mShowBackdrop = showBackdrop; 548 } 549 550 @Override 551 @ColorInt 552 public int getBackgroundColor() { 553 return mRecord.mBackdropColor; 554 } 555 556 @Override 557 public boolean getShowBackground() { 558 return mShowBackdrop; 559 } 560 561 @Override 562 public boolean getShowWallpaper() { 563 return false; 564 } 565 566 @Override 567 public void startAnimation(SurfaceControl animationLeash, Transaction t, 568 @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) { 569 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); 570 571 if (mStartBounds.isEmpty()) { 572 // Restore position and stack crop until client has a chance to modify it. 573 t.setPosition(animationLeash, mPosition.x, mPosition.y); 574 t.setWindowCrop(animationLeash, mEndBounds.width(), mEndBounds.height()); 575 } else { 576 // Offset the change animation leash to the relative start position in parent. 577 // (mPosition) is the relative end position in parent container. 578 // (mStartBounds - mEndBounds) is the position difference between start and end. 579 // (mPosition + mStartBounds - mEndBounds) will be the relative start position. 580 t.setPosition(animationLeash, mPosition.x + mStartBounds.left - mEndBounds.left, 581 mPosition.y + mStartBounds.top - mEndBounds.top); 582 t.setWindowCrop(animationLeash, mStartBounds.width(), mStartBounds.height()); 583 } 584 mCapturedLeash = animationLeash; 585 mCapturedFinishCallback = finishCallback; 586 mAnimationType = type; 587 } 588 589 @Override 590 public void onAnimationCancelled(SurfaceControl animationLeash) { 591 if (mIsFinishing) { 592 return; 593 } 594 if (mRecord.mAdapter == this) { 595 mRecord.mAdapter = null; 596 } else { 597 mRecord.mThumbnailAdapter = null; 598 } 599 if (mRecord.mAdapter == null && mRecord.mThumbnailAdapter == null) { 600 mPendingAnimations.remove(mRecord); 601 } 602 if (mPendingAnimations.isEmpty()) { 603 cancelAnimation("allAppAnimationsCanceled"); 604 } 605 } 606 607 @Override 608 public long getDurationHint() { 609 return mRemoteAnimationAdapter.getDuration(); 610 } 611 612 @Override 613 public long getStatusBarTransitionsStartTime() { 614 return SystemClock.uptimeMillis() 615 + mRemoteAnimationAdapter.getStatusBarTransitionDelay(); 616 } 617 618 @Override 619 public void dump(PrintWriter pw, String prefix) { 620 pw.print(prefix); pw.print("container="); pw.println(mRecord.mWindowContainer); 621 if (mRecord.mTarget != null) { 622 pw.print(prefix); pw.println("Target:"); 623 mRecord.mTarget.dump(pw, prefix + " "); 624 } else { 625 pw.print(prefix); pw.println("Target: null"); 626 } 627 } 628 629 @Override 630 public void dumpDebug(ProtoOutputStream proto) { 631 final long token = proto.start(REMOTE); 632 if (mRecord.mTarget != null) { 633 mRecord.mTarget.dumpDebug(proto, TARGET); 634 } 635 proto.end(token); 636 } 637 } 638 } 639