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.InsetsState.ITYPE_CLIMATE_BAR;
20 import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
21 import static android.view.InsetsState.ITYPE_IME;
22 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
23 import static android.view.InsetsState.ITYPE_STATUS_BAR;
24 
25 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
26 import static com.android.server.wm.InsetsSourceProviderProto.CAPTURED_LEASH;
27 import static com.android.server.wm.InsetsSourceProviderProto.CLIENT_VISIBLE;
28 import static com.android.server.wm.InsetsSourceProviderProto.CONTROL;
29 import static com.android.server.wm.InsetsSourceProviderProto.CONTROLLABLE;
30 import static com.android.server.wm.InsetsSourceProviderProto.CONTROL_TARGET;
31 import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL;
32 import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET;
33 import static com.android.server.wm.InsetsSourceProviderProto.FRAME;
34 import static com.android.server.wm.InsetsSourceProviderProto.IME_OVERRIDDEN_FRAME;
35 import static com.android.server.wm.InsetsSourceProviderProto.IS_LEASH_READY_FOR_DISPATCHING;
36 import static com.android.server.wm.InsetsSourceProviderProto.PENDING_CONTROL_TARGET;
37 import static com.android.server.wm.InsetsSourceProviderProto.SEAMLESS_ROTATING;
38 import static com.android.server.wm.InsetsSourceProviderProto.SERVER_VISIBLE;
39 import static com.android.server.wm.InsetsSourceProviderProto.SOURCE;
40 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL;
41 import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED;
42 
43 import android.annotation.NonNull;
44 import android.annotation.Nullable;
45 import android.graphics.Insets;
46 import android.graphics.Point;
47 import android.graphics.Rect;
48 import android.util.proto.ProtoOutputStream;
49 import android.view.InsetsSource;
50 import android.view.InsetsSourceControl;
51 import android.view.InsetsState;
52 import android.view.SurfaceControl;
53 import android.view.SurfaceControl.Transaction;
54 
55 import com.android.internal.annotations.VisibleForTesting;
56 import com.android.internal.protolog.common.ProtoLog;
57 import com.android.internal.util.function.TriConsumer;
58 import com.android.server.wm.SurfaceAnimator.AnimationType;
59 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
60 
61 import java.io.PrintWriter;
62 import java.util.function.Consumer;
63 
64 /**
65  * Controller for a specific inset source on the server. It's called provider as it provides the
66  * {@link InsetsSource} to the client that uses it in {@link android.view.InsetsSourceConsumer}.
67  */
68 class InsetsSourceProvider {
69 
70     protected final DisplayContent mDisplayContent;
71     protected final @NonNull InsetsSource mSource;
72     protected WindowState mWin;
73 
74     private final Rect mTmpRect = new Rect();
75     private final InsetsStateController mStateController;
76     private final InsetsSourceControl mFakeControl;
77     private @Nullable InsetsSourceControl mControl;
78     private @Nullable InsetsControlTarget mControlTarget;
79     private @Nullable InsetsControlTarget mPendingControlTarget;
80     private @Nullable InsetsControlTarget mFakeControlTarget;
81 
82     private @Nullable ControlAdapter mAdapter;
83     private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider;
84     private TriConsumer<DisplayFrames, WindowState, Rect> mImeFrameProvider;
85     private final Rect mImeOverrideFrame = new Rect();
86     private boolean mIsLeashReadyForDispatching;
87     private final Rect mLastSourceFrame = new Rect();
88 
89     private final Consumer<Transaction> mSetLeashPositionConsumer = t -> {
90         if (mControl != null) {
91             final SurfaceControl leash = mControl.getLeash();
92             if (leash != null) {
93                 final Point position = mControl.getSurfacePosition();
94                 t.setPosition(leash, position.x, position.y);
95             }
96         }
97     };
98 
99     /** The visibility override from the current controlling window. */
100     private boolean mClientVisible;
101 
102     /**
103      * Whether the window is available and considered visible as in {@link WindowState#isVisible}.
104      */
105     private boolean mServerVisible;
106 
107     private boolean mSeamlessRotating;
108 
109     private final boolean mControllable;
110 
111     /**
112      * Whether to forced the dimensions of the source window to the inset frame and crop out any
113      * overflow.
114      * Used to crop the taskbar inset source when a task animation is occurring to hide the taskbar
115      * rounded corners overlays.
116      *
117      * TODO: Remove when we enable shell transitions (b/202383002)
118      */
119     private boolean mCropToProvidingInsets = false;
120 
InsetsSourceProvider(InsetsSource source, InsetsStateController stateController, DisplayContent displayContent)121     InsetsSourceProvider(InsetsSource source, InsetsStateController stateController,
122             DisplayContent displayContent) {
123         mClientVisible = InsetsState.getDefaultVisibility(source.getType());
124         mSource = source;
125         mDisplayContent = displayContent;
126         mStateController = stateController;
127         mFakeControl = new InsetsSourceControl(
128                 source.getType(), null /* leash */, new Point(), Insets.NONE);
129 
130         switch (source.getType()) {
131             case ITYPE_STATUS_BAR:
132             case ITYPE_NAVIGATION_BAR:
133             case ITYPE_IME:
134             case ITYPE_CLIMATE_BAR:
135             case ITYPE_EXTRA_NAVIGATION_BAR:
136                 mControllable = true;
137                 break;
138             default:
139                 mControllable = false;
140         }
141     }
142 
getSource()143     InsetsSource getSource() {
144         return mSource;
145     }
146 
147     /**
148      * @return Whether the current flag configuration allows to control this source.
149      */
isControllable()150     boolean isControllable() {
151         return mControllable;
152     }
153 
154     /**
155      * Updates the window that currently backs this source.
156      *
157      * @param win The window that links to this source.
158      * @param frameProvider Based on display frame state and the window, calculates the resulting
159      *                      frame that should be reported to clients.
160      * @param imeFrameProvider Based on display frame state and the window, calculates the resulting
161      *                         frame that should be reported to IME.
162      */
setWindow(@ullable WindowState win, @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider, @Nullable TriConsumer<DisplayFrames, WindowState, Rect> imeFrameProvider)163     void setWindow(@Nullable WindowState win,
164             @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider,
165             @Nullable TriConsumer<DisplayFrames, WindowState, Rect> imeFrameProvider) {
166         if (mWin != null) {
167             if (mControllable) {
168                 mWin.setControllableInsetProvider(null);
169             }
170             // The window may be animating such that we can hand out the leash to the control
171             // target. Revoke the leash by cancelling the animation to correct the state.
172             // TODO: Ideally, we should wait for the animation to finish so previous window can
173             // animate-out as new one animates-in.
174             mWin.cancelAnimation();
175             mWin.mProvidedInsetsSources.remove(mSource.getType());
176             mSeamlessRotating = false;
177         }
178         ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "InsetsSource setWin %s for type %s", win,
179                 InsetsState.typeToString(mSource.getType()));
180         mWin = win;
181         mFrameProvider = frameProvider;
182         mImeFrameProvider = imeFrameProvider;
183         if (win == null) {
184             setServerVisible(false);
185             mSource.setFrame(new Rect());
186             mSource.setVisibleFrame(null);
187         } else {
188             mWin.mProvidedInsetsSources.put(mSource.getType(), mSource);
189             if (mControllable) {
190                 mWin.setControllableInsetProvider(this);
191                 if (mPendingControlTarget != null) {
192                     updateControlForTarget(mPendingControlTarget, true /* force */);
193                     mPendingControlTarget = null;
194                 }
195             }
196         }
197     }
198 
199     /**
200      * @return Whether there is a window which backs this source.
201      */
hasWindow()202     boolean hasWindow() {
203         return mWin != null;
204     }
205 
206     /**
207      * The source frame can affect the layout of other windows, so this should be called once the
208      * window gets laid out.
209      */
updateSourceFrame()210     void updateSourceFrame() {
211         if (mWin == null || mWin.mGivenInsetsPending) {
212             // If the given insets are pending, they are not reliable for now. The source frame
213             // should be updated after the new given insets are sent to window manager.
214             return;
215         }
216 
217         // Make sure we set the valid source frame only when server visible is true, because the
218         // frame may not yet determined that server side doesn't think the window is ready to
219         // visible. (i.e. No surface, pending insets that were given during layout, etc..)
220         if (mServerVisible) {
221             mTmpRect.set(mWin.getFrame());
222             if (mFrameProvider != null) {
223                 mFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, mTmpRect);
224             } else {
225                 mTmpRect.inset(mWin.mGivenContentInsets);
226             }
227         } else {
228             mTmpRect.setEmpty();
229         }
230         mSource.setFrame(mTmpRect);
231 
232         if (mImeFrameProvider != null) {
233             mImeOverrideFrame.set(mWin.getFrame());
234             mImeFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin,
235                     mImeOverrideFrame);
236         }
237 
238         if (mWin.mGivenVisibleInsets.left != 0 || mWin.mGivenVisibleInsets.top != 0
239                 || mWin.mGivenVisibleInsets.right != 0 || mWin.mGivenVisibleInsets.bottom != 0) {
240             mTmpRect.set(mWin.getFrame());
241             mTmpRect.inset(mWin.mGivenVisibleInsets);
242             mSource.setVisibleFrame(mTmpRect);
243         } else {
244             mSource.setVisibleFrame(null);
245         }
246     }
247 
248     /** @return A new source computed by the specified window frame in the given display frames. */
createSimulatedSource(DisplayFrames displayFrames, WindowFrames windowFrames)249     InsetsSource createSimulatedSource(DisplayFrames displayFrames, WindowFrames windowFrames) {
250         // Don't copy visible frame because it might not be calculated in the provided display
251         // frames and it is not significant for this usage.
252         final InsetsSource source = new InsetsSource(mSource.getType());
253         source.setVisible(mSource.isVisible());
254         mTmpRect.set(windowFrames.mFrame);
255         if (mFrameProvider != null) {
256             mFrameProvider.accept(displayFrames, mWin, mTmpRect);
257         }
258         source.setFrame(mTmpRect);
259         return source;
260     }
261 
262     /**
263      * Called when a layout pass has occurred.
264      */
onPostLayout()265     void onPostLayout() {
266         if (mWin == null) {
267             return;
268         }
269 
270         setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy());
271         updateSourceFrame();
272         if (mControl != null) {
273             boolean changed = false;
274             final Point position = getWindowFrameSurfacePosition();
275             if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) {
276                 changed = true;
277                 if (mWin.getWindowFrames().didFrameSizeChange() && mWin.mWinAnimator.getShown()
278                         && mWin.okToDisplay()) {
279                     mWin.applyWithNextDraw(mSetLeashPositionConsumer);
280                 } else {
281                     mSetLeashPositionConsumer.accept(mWin.getSyncTransaction());
282                 }
283             }
284             if (mServerVisible && !mLastSourceFrame.equals(mSource.getFrame())) {
285                 final Insets insetsHint = mSource.calculateInsets(
286                         mWin.getBounds(), true /* ignoreVisibility */);
287                 if (!insetsHint.equals(mControl.getInsetsHint())) {
288                     changed = true;
289                     mControl.setInsetsHint(insetsHint);
290                 }
291                 mLastSourceFrame.set(mSource.getFrame());
292             }
293             if (changed) {
294                 mStateController.notifyControlChanged(mControlTarget);
295             }
296         }
297     }
298 
getWindowFrameSurfacePosition()299     private Point getWindowFrameSurfacePosition() {
300         final Rect frame = mWin.getFrame();
301         final Point position = new Point();
302         mWin.transformFrameToSurfacePosition(frame.left, frame.top, position);
303         return position;
304     }
305 
306     /**
307      * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
308      */
updateControlForFakeTarget(@ullable InsetsControlTarget fakeTarget)309     void updateControlForFakeTarget(@Nullable InsetsControlTarget fakeTarget) {
310         if (fakeTarget == mFakeControlTarget) {
311             return;
312         }
313         mFakeControlTarget = fakeTarget;
314     }
315 
316     /**
317      * Ensures that the inset source window is cropped so that anything that doesn't fit within the
318      * inset frame is cropped out until removeCropToProvidingInsetsBounds is called.
319      *
320      * The inset source surface will get cropped to the be of the size of the insets it's providing.
321      *
322      * For example, for the taskbar window which serves as the ITYPE_EXTRA_NAVIGATION_BAR inset
323      * source, the window is larger than the insets because of the rounded corners overlay, but
324      * during task animations we want to make sure that the overlay is cropped out of the window so
325      * that they don't hide the window animations.
326      *
327      * @param t The transaction to use to apply immediate overflow cropping operations.
328      *
329      * NOTE: The relies on the inset source window to have a leash (usually this would be a leash
330      * for the ANIMATION_TYPE_INSETS_CONTROL animation if the inset is controlled by the client)
331      *
332      * TODO: Remove when we migrate over to shell transitions (b/202383002)
333      */
setCropToProvidingInsetsBounds(Transaction t)334     void setCropToProvidingInsetsBounds(Transaction t) {
335         mCropToProvidingInsets = true;
336 
337         if (mWin != null && mWin.mSurfaceAnimator.hasLeash()) {
338             // apply to existing leash
339             t.setWindowCrop(mWin.mSurfaceAnimator.mLeash, getProvidingInsetsBoundsCropRect());
340         }
341     }
342 
343     /**
344      * Removes any overflow cropping and future cropping to the inset source window's leash that may
345      * have been set with a call to setCropToProvidingInsetsBounds().
346      * @param t The transaction to use to apply immediate removal of overflow cropping.
347      *
348      * TODO: Remove when we migrate over to shell transitions (b/202383002)
349      */
removeCropToProvidingInsetsBounds(Transaction t)350     void removeCropToProvidingInsetsBounds(Transaction t) {
351         mCropToProvidingInsets = false;
352 
353         // apply to existing leash
354         if (mWin != null && mWin.mSurfaceAnimator.hasLeash()) {
355             t.setWindowCrop(mWin.mSurfaceAnimator.mLeash, null);
356         }
357     }
358 
getProvidingInsetsBoundsCropRect()359     private Rect getProvidingInsetsBoundsCropRect() {
360         Rect sourceWindowFrame = mWin.getFrame();
361         Rect insetFrame = getSource().getFrame();
362 
363         // The rectangle in buffer space we want to crop to
364         return new Rect(
365                 insetFrame.left - sourceWindowFrame.left,
366                 insetFrame.top - sourceWindowFrame.top,
367                 insetFrame.right - sourceWindowFrame.left,
368                 insetFrame.bottom - sourceWindowFrame.top
369         );
370     }
371 
updateControlForTarget(@ullable InsetsControlTarget target, boolean force)372     void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
373         if (mSeamlessRotating) {
374             // We are un-rotating the window against the display rotation. We don't want the target
375             // to control the window for now.
376             return;
377         }
378 
379         if (mWin != null && mWin.getSurfaceControl() == null) {
380             // if window doesn't have a surface, set it null and return.
381             setWindow(null, null, null);
382         }
383         if (mWin == null) {
384             mPendingControlTarget = target;
385             return;
386         }
387         if (target == mControlTarget && !force) {
388             return;
389         }
390         if (target == null) {
391             // Cancelling the animation will invoke onAnimationCancelled, resetting all the fields.
392             mWin.cancelAnimation();
393             setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
394             return;
395         }
396         final Point surfacePosition = getWindowFrameSurfacePosition();
397         mAdapter = new ControlAdapter(surfacePosition);
398         if (getSource().getType() == ITYPE_IME) {
399             setClientVisible(target.getRequestedVisibility(mSource.getType()));
400         }
401         final Transaction t = mDisplayContent.getSyncTransaction();
402         mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */,
403                 ANIMATION_TYPE_INSETS_CONTROL);
404 
405         // The leash was just created. We cannot dispatch it until its surface transaction is
406         // applied. Otherwise, the client's operation to the leash might be overwritten by us.
407         mIsLeashReadyForDispatching = false;
408 
409         final SurfaceControl leash = mAdapter.mCapturedLeash;
410         mControlTarget = target;
411         updateVisibility();
412         mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition,
413                 mSource.calculateInsets(mWin.getBounds(), true /* ignoreVisibility */));
414         ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
415                 "InsetsSource Control %s for target %s", mControl, mControlTarget);
416     }
417 
startSeamlessRotation()418     void startSeamlessRotation() {
419       if (!mSeamlessRotating) {
420           mSeamlessRotating = true;
421           mWin.cancelAnimation();
422       }
423     }
424 
finishSeamlessRotation()425     void finishSeamlessRotation() {
426         mSeamlessRotating = false;
427     }
428 
updateClientVisibility(InsetsControlTarget caller)429     boolean updateClientVisibility(InsetsControlTarget caller) {
430         final boolean requestedVisible = caller.getRequestedVisibility(mSource.getType());
431         if (caller != mControlTarget || requestedVisible == mClientVisible) {
432             return false;
433         }
434         setClientVisible(requestedVisible);
435         return true;
436     }
437 
onSurfaceTransactionApplied()438     void onSurfaceTransactionApplied() {
439         mIsLeashReadyForDispatching = true;
440     }
441 
setClientVisible(boolean clientVisible)442     void setClientVisible(boolean clientVisible) {
443         if (mClientVisible == clientVisible) {
444             return;
445         }
446         mClientVisible = clientVisible;
447         if (!mDisplayContent.mLayoutAndAssignWindowLayersScheduled) {
448             mDisplayContent.mLayoutAndAssignWindowLayersScheduled = true;
449             mDisplayContent.mWmService.mH.obtainMessage(
450                     LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED, mDisplayContent).sendToTarget();
451         }
452         updateVisibility();
453     }
454 
455     @VisibleForTesting
setServerVisible(boolean serverVisible)456     void setServerVisible(boolean serverVisible) {
457         mServerVisible = serverVisible;
458         updateVisibility();
459     }
460 
updateVisibility()461     protected void updateVisibility() {
462         mSource.setVisible(mServerVisible && (isMirroredSource() || mClientVisible));
463         ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
464                 "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
465                 InsetsState.typeToString(mSource.getType()),
466                 mServerVisible, mClientVisible);
467     }
468 
isMirroredSource()469     private boolean isMirroredSource() {
470         if (mWin == null) {
471             return false;
472         }
473         final int[] provides = mWin.mAttrs.providesInsetsTypes;
474         if (provides == null) {
475             return false;
476         }
477         for (int i = 0; i < provides.length; i++) {
478             if (provides[i] == ITYPE_IME) {
479                 return true;
480             }
481         }
482         return false;
483     }
484 
getControl(InsetsControlTarget target)485     InsetsSourceControl getControl(InsetsControlTarget target) {
486         if (target == mControlTarget) {
487             if (!mIsLeashReadyForDispatching && mControl != null) {
488                 // The surface transaction of preparing leash is not applied yet. We don't send it
489                 // to the client in case that the client applies its transaction sooner than ours
490                 // that we could unexpectedly overwrite the surface state.
491                 return new InsetsSourceControl(mControl.getType(), null /* leash */,
492                         mControl.getSurfacePosition(), mControl.getInsetsHint());
493             }
494             return mControl;
495         }
496         if (target == mFakeControlTarget) {
497             return mFakeControl;
498         }
499         return null;
500     }
501 
getControlTarget()502     InsetsControlTarget getControlTarget() {
503         return mControlTarget;
504     }
505 
isClientVisible()506     boolean isClientVisible() {
507         return mClientVisible;
508     }
509 
510     /**
511      * @return Whether this provider uses a different frame to dispatch to the IME.
512      */
overridesImeFrame()513     boolean overridesImeFrame() {
514         return mImeFrameProvider != null;
515     }
516 
517     /**
518      * @return Rect to dispatch to the IME as frame. Only valid if {@link #overridesImeFrame()}
519      *         returns {@code true}.
520      */
getImeOverrideFrame()521     Rect getImeOverrideFrame() {
522         return mImeOverrideFrame;
523     }
524 
dump(PrintWriter pw, String prefix)525     public void dump(PrintWriter pw, String prefix) {
526         pw.println(prefix + getClass().getSimpleName());
527         prefix = prefix + "  ";
528         pw.print(prefix + "mSource="); mSource.dump("", pw);
529         if (mControl != null) {
530             pw.print(prefix + "mControl=");
531             mControl.dump("", pw);
532         }
533         pw.print(prefix);
534         pw.print("mIsLeashReadyForDispatching="); pw.print(mIsLeashReadyForDispatching);
535         pw.print(" mImeOverrideFrame="); pw.print(mImeOverrideFrame.toShortString());
536         pw.println();
537         if (mWin != null) {
538             pw.print(prefix + "mWin=");
539             pw.println(mWin);
540         }
541         if (mAdapter != null) {
542             pw.print(prefix + "mAdapter=");
543             mAdapter.dump(pw, "");
544         }
545         if (mControlTarget != null) {
546             pw.print(prefix + "mControlTarget=");
547             pw.println(mControlTarget.getWindow());
548         }
549         if (mPendingControlTarget != null) {
550             pw.print(prefix + "mPendingControlTarget=");
551             pw.println(mPendingControlTarget.getWindow());
552         }
553         if (mFakeControlTarget != null) {
554             pw.print(prefix + "mFakeControlTarget=");
555             pw.println(mFakeControlTarget.getWindow());
556         }
557     }
558 
dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)559     void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) {
560         final long token = proto.start(fieldId);
561         mSource.dumpDebug(proto, SOURCE);
562         mTmpRect.dumpDebug(proto, FRAME);
563         mFakeControl.dumpDebug(proto, FAKE_CONTROL);
564         if (mControl != null) {
565             mControl.dumpDebug(proto, CONTROL);
566         }
567         if (mControlTarget != null && mControlTarget.getWindow() != null) {
568             mControlTarget.getWindow().dumpDebug(proto, CONTROL_TARGET, logLevel);
569         }
570         if (mPendingControlTarget != null && mPendingControlTarget.getWindow() != null) {
571             mPendingControlTarget.getWindow().dumpDebug(proto, PENDING_CONTROL_TARGET, logLevel);
572         }
573         if (mFakeControlTarget != null && mFakeControlTarget.getWindow() != null) {
574             mFakeControlTarget.getWindow().dumpDebug(proto, FAKE_CONTROL_TARGET, logLevel);
575         }
576         if (mAdapter != null && mAdapter.mCapturedLeash != null) {
577             mAdapter.mCapturedLeash.dumpDebug(proto, CAPTURED_LEASH);
578         }
579         mImeOverrideFrame.dumpDebug(proto, IME_OVERRIDDEN_FRAME);
580         proto.write(IS_LEASH_READY_FOR_DISPATCHING, mIsLeashReadyForDispatching);
581         proto.write(CLIENT_VISIBLE, mClientVisible);
582         proto.write(SERVER_VISIBLE, mServerVisible);
583         proto.write(SEAMLESS_ROTATING, mSeamlessRotating);
584         proto.write(CONTROLLABLE, mControllable);
585         proto.end(token);
586     }
587 
588     private class ControlAdapter implements AnimationAdapter {
589 
590         private final Point mSurfacePosition;
591         private SurfaceControl mCapturedLeash;
592 
ControlAdapter(Point surfacePosition)593         ControlAdapter(Point surfacePosition) {
594             mSurfacePosition = surfacePosition;
595         }
596 
597         @Override
getShowWallpaper()598         public boolean getShowWallpaper() {
599             return false;
600         }
601 
602         @Override
startAnimation(SurfaceControl animationLeash, Transaction t, @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback)603         public void startAnimation(SurfaceControl animationLeash, Transaction t,
604                 @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) {
605             // TODO(b/166736352): Check if we still need to control the IME visibility here.
606             if (mSource.getType() == ITYPE_IME) {
607                 // TODO: use 0 alpha and remove t.hide() once b/138459974 is fixed.
608                 t.setAlpha(animationLeash, 1 /* alpha */);
609                 t.hide(animationLeash);
610             }
611             ProtoLog.i(WM_DEBUG_WINDOW_INSETS,
612                     "ControlAdapter startAnimation mSource: %s controlTarget: %s", mSource,
613                     mControlTarget);
614 
615             mCapturedLeash = animationLeash;
616             t.setPosition(mCapturedLeash, mSurfacePosition.x, mSurfacePosition.y);
617 
618             if (mCropToProvidingInsets) {
619                 // Apply crop to hide overflow
620                 t.setWindowCrop(mCapturedLeash, getProvidingInsetsBoundsCropRect());
621             }
622         }
623 
624         @Override
onAnimationCancelled(SurfaceControl animationLeash)625         public void onAnimationCancelled(SurfaceControl animationLeash) {
626             if (mAdapter == this) {
627                 mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this);
628                 mControl = null;
629                 mControlTarget = null;
630                 mAdapter = null;
631                 setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
632                 ProtoLog.i(WM_DEBUG_WINDOW_INSETS,
633                         "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
634                         mSource, mControlTarget);
635             }
636         }
637 
638         @Override
getDurationHint()639         public long getDurationHint() {
640             return 0;
641         }
642 
643         @Override
getStatusBarTransitionsStartTime()644         public long getStatusBarTransitionsStartTime() {
645             return 0;
646         }
647 
648         @Override
dump(PrintWriter pw, String prefix)649         public void dump(PrintWriter pw, String prefix) {
650             pw.print(prefix + "ControlAdapter mCapturedLeash=");
651             pw.print(mCapturedLeash);
652             pw.println();
653         }
654 
655         @Override
dumpDebug(ProtoOutputStream proto)656         public void dumpDebug(ProtoOutputStream proto) {
657         }
658     }
659 }
660