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