• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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