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