1 /*
2  * Copyright (C) 2019 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.os.Trace.TRACE_TAG_WINDOW_MANAGER;
20 import static android.view.InsetsSource.ID_IME;
21 
22 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
23 import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
24 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
25 import static com.android.server.wm.ImeInsetsSourceProviderProto.IME_TARGET_FROM_IME;
26 import static com.android.server.wm.ImeInsetsSourceProviderProto.INSETS_SOURCE_PROVIDER;
27 import static com.android.server.wm.WindowManagerService.H.UPDATE_MULTI_WINDOW_STACKS;
28 
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.graphics.Rect;
32 import android.os.Trace;
33 import android.util.Slog;
34 import android.util.proto.ProtoOutputStream;
35 import android.view.InsetsSource;
36 import android.view.InsetsSourceConsumer;
37 import android.view.InsetsSourceControl;
38 import android.view.WindowInsets;
39 import android.view.inputmethod.Flags;
40 import android.view.inputmethod.ImeTracker;
41 
42 import com.android.internal.annotations.VisibleForTesting;
43 import com.android.internal.protolog.common.ProtoLog;
44 
45 import java.io.PrintWriter;
46 
47 /**
48  * Controller for IME inset source on the server. It's called provider as it provides the
49  * {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
50  */
51 final class ImeInsetsSourceProvider extends InsetsSourceProvider {
52 
53     private static final String TAG = ImeInsetsSourceProvider.class.getSimpleName();
54 
55     /** The token tracking the show IME request, non-null only while a show request is pending. */
56     @Nullable
57     private ImeTracker.Token mStatsToken;
58     /** The target that requested to show the IME, non-null only while a show request is pending. */
59     @Nullable
60     private InsetsControlTarget mImeRequester;
61     /** @see #isImeShowing() */
62     private boolean mImeShowing;
63     /** The latest received insets source. */
64     private final InsetsSource mLastSource = new InsetsSource(ID_IME, WindowInsets.Type.ime());
65 
66     /** @see #setFrozen(boolean) */
67     private boolean mFrozen;
68 
69     /**
70      * The server visibility of the source provider's window container. This is out of sync with
71      * {@link InsetsSourceProvider#mServerVisible} while {@link #mFrozen} is {@code true}.
72      *
73      * @see #setServerVisible
74      */
75     private boolean mServerVisible;
76 
77     /**
78      * When the IME is not ready, it has givenInsetsPending. However, this could happen again,
79      * after it became serverVisible. This flag indicates is used to determine if it is
80      * readyForDispatching
81      */
82     private boolean mGivenInsetsReady = false;
83 
ImeInsetsSourceProvider(@onNull InsetsSource source, @NonNull InsetsStateController stateController, @NonNull DisplayContent displayContent)84     ImeInsetsSourceProvider(@NonNull InsetsSource source,
85             @NonNull InsetsStateController stateController,
86             @NonNull DisplayContent displayContent) {
87         super(source, stateController, displayContent);
88     }
89 
90     @Override
onPostLayout()91     void onPostLayout() {
92         super.onPostLayout();
93 
94         if (android.view.inputmethod.Flags.refactorInsetsController()) {
95             final WindowState ws =
96                     mWindowContainer != null ? mWindowContainer.asWindowState() : null;
97             final boolean givenInsetsPending = ws != null && ws.mGivenInsetsPending;
98 
99             // isLeashReadyForDispatching (used to dispatch the leash of the control) is
100             // depending on mGivenInsetsReady. Therefore, triggering notifyControlChanged here
101             // again, so that the control with leash can be eventually dispatched
102             if (!mGivenInsetsReady && mServerVisible && !givenInsetsPending) {
103                 mGivenInsetsReady = true;
104                 mStateController.notifyControlChanged(mControlTarget);
105             }
106         }
107     }
108 
109     @Override
isLeashReadyForDispatching()110     protected boolean isLeashReadyForDispatching() {
111         if (android.view.inputmethod.Flags.refactorInsetsController()) {
112             final WindowState ws =
113                     mWindowContainer != null ? mWindowContainer.asWindowState() : null;
114             final boolean isDrawn = ws != null && ws.isDrawn();
115             return super.isLeashReadyForDispatching() && mServerVisible && isDrawn
116                     && mGivenInsetsReady;
117         } else {
118             return super.isLeashReadyForDispatching();
119         }
120     }
121 
122     @Nullable
123     @Override
getControl(InsetsControlTarget target)124     InsetsSourceControl getControl(InsetsControlTarget target) {
125         final InsetsSourceControl control = super.getControl(target);
126         if (control != null && target != null && target.getWindow() != null) {
127             final WindowState targetWin = target.getWindow();
128             final Task task = targetWin.getTask();
129             // If the control target changes during the app transition with the task snapshot
130             // starting window and the IME snapshot is visible, in case not have duplicated IME
131             // showing animation during transitioning, use a flag to inform IME source control to
132             // skip showing animation once.
133             StartingData startingData = null;
134             if (task != null) {
135                 startingData = targetWin.mActivityRecord.mStartingData;
136                 if (startingData == null) {
137                     final WindowState startingWin = task.topStartingWindow();
138                     if (startingWin != null) {
139                         startingData = startingWin.mStartingData;
140                     }
141                 }
142             }
143             control.setSkipAnimationOnce(startingData != null && startingData.hasImeSurface());
144         }
145         return control;
146     }
147 
148     @Override
setClientVisible(boolean clientVisible)149     void setClientVisible(boolean clientVisible) {
150         final boolean wasClientVisible = isClientVisible();
151         super.setClientVisible(clientVisible);
152         // The layer of ImePlaceholder needs to be updated on a higher z-order for
153         // non-activity window (For activity window, IME is already on top of it).
154         if (!wasClientVisible && isClientVisible()) {
155             final InsetsControlTarget imeControlTarget = getControlTarget();
156             if (imeControlTarget != null && imeControlTarget.getWindow() != null
157                     && imeControlTarget.getWindow().mActivityRecord == null) {
158                 mDisplayContent.assignWindowLayers(false /* setLayoutNeeded */);
159             }
160         }
161     }
162 
163     @Override
setServerVisible(boolean serverVisible)164     void setServerVisible(boolean serverVisible) {
165         if (mServerVisible != serverVisible) {
166             mServerVisible = serverVisible;
167             // reset the leash if the server visibility becomes hidden
168             if (android.view.inputmethod.Flags.refactorInsetsController()) {
169                 if (!serverVisible && !mFrozen) {
170                     mGivenInsetsReady = false;
171                     updateControlForTarget(mControlTarget, true /* force */);
172                 }
173             }
174         }
175         if (!mFrozen) {
176             super.setServerVisible(serverVisible);
177         }
178     }
179 
180     /**
181      * Freeze IME insets source state when required.
182      *
183      * <p>When setting {@param frozen} as {@code true}, the IME insets provider will freeze the
184      * current IME insets state and pending the IME insets state update until setting
185      * {@param frozen} as {@code false}.</p>
186      */
setFrozen(boolean frozen)187     void setFrozen(boolean frozen) {
188         if (mFrozen == frozen) {
189             return;
190         }
191         mFrozen = frozen;
192         if (!frozen) {
193             // Unfreeze and process the pending IME insets states.
194             super.setServerVisible(mServerVisible);
195         }
196     }
197 
198     @Override
updateSourceFrame(Rect frame)199     void updateSourceFrame(Rect frame) {
200         super.updateSourceFrame(frame);
201         onSourceChanged();
202     }
203 
204     @Override
updateVisibility()205     protected void updateVisibility() {
206         boolean oldVisibility = mSource.isVisible();
207         super.updateVisibility();
208         if (Flags.refactorInsetsController()) {
209             if (mSource.isVisible() && !oldVisibility && mImeRequester != null) {
210                 reportImeDrawnForOrganizerIfNeeded(mImeRequester);
211             }
212         }
213         onSourceChanged();
214     }
215 
216     @Override
updateControlForTarget(@ullable InsetsControlTarget target, boolean force)217     void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
218         if (target != null && target.getWindow() != null) {
219             // ime control target could be a different window.
220             // Refer WindowState#getImeControlTarget().
221             target = target.getWindow().getImeControlTarget();
222         }
223         super.updateControlForTarget(target, force);
224         if (Flags.refactorInsetsController()) {
225             if (target != null) {
226                 invokeOnImeRequestedChangedListener(target.getWindow());
227             }
228         }
229     }
230 
231     @Override
updateClientVisibility(InsetsControlTarget caller)232     protected boolean updateClientVisibility(InsetsControlTarget caller) {
233         InsetsControlTarget controlTarget = getControlTarget();
234         if (caller != controlTarget) {
235             if (Flags.refactorInsetsController()) {
236                 if (isImeInputTarget(caller)) {
237                     // In case of the multi window mode, update the requestedVisibleTypes from
238                     // the controlTarget (=RemoteInsetsControlTarget) via DisplayImeController.
239                     // Then, trigger onRequestedVisibleTypesChanged for the controlTarget with
240                     // its new requested visibility for the IME
241                     boolean imeVisible = caller.isRequestedVisible(WindowInsets.Type.ime());
242                     if (controlTarget != null) {
243                         controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
244                     } else {
245                         // In case of a virtual display that cannot show the IME, the
246                         // controlTarget will be null here, as no controlTarget was set yet. In
247                         // that case, proceed similar to the multi window mode (fallback =
248                         // RemoteInsetsControlTarget of the default display)
249                         controlTarget = mDisplayContent.getImeHostOrFallback(caller.getWindow());
250 
251                         if (controlTarget != caller) {
252                             controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
253                         }
254                     }
255 
256                     WindowState windowState = caller.getWindow();
257                     invokeOnImeRequestedChangedListener(windowState);
258                 }
259             }
260             return false;
261         }
262         boolean changed = super.updateClientVisibility(caller);
263         if (!Flags.refactorInsetsController()) {
264             if (changed && caller.isRequestedVisible(mSource.getType())) {
265                 reportImeDrawnForOrganizerIfNeeded(caller);
266             }
267         }
268         changed |= mDisplayContent.onImeInsetsClientVisibilityUpdate();
269         if (Flags.refactorInsetsController()) {
270             if (changed) {
271                 // RemoteInsetsControlTarget does not have a window. In this case, we use the
272                 // windowState from the imeInputTarget
273                 WindowState windowState = caller.getWindow() != null ? caller.getWindow()
274                         : ((mDisplayContent.getImeInputTarget() != null)
275                                 ? mDisplayContent.getImeInputTarget().getWindowState() : null);
276                 invokeOnImeRequestedChangedListener(windowState);
277             }
278         }
279         return changed;
280     }
281 
onInputTargetChanged(InputTarget target)282     void onInputTargetChanged(InputTarget target) {
283         if (Flags.refactorInsetsController() && target != null) {
284             WindowState targetWin = target.getWindowState();
285             InsetsControlTarget imeControlTarget = getControlTarget();
286             if (target != imeControlTarget && targetWin != null) {
287                 // If the targetWin is not the imeControlTarget (=RemoteInsetsControlTarget) let it
288                 // know about the new requestedVisibleTypes for the IME.
289                 if (imeControlTarget != null) {
290                     imeControlTarget.setImeInputTargetRequestedVisibility(
291                             (targetWin.getRequestedVisibleTypes()
292                                     & WindowInsets.Type.ime()) != 0);
293                 }
294             }
295         }
296     }
297 
invokeOnImeRequestedChangedListener(WindowState windowState)298     private void invokeOnImeRequestedChangedListener(WindowState windowState) {
299         final var imeListener = mDisplayContent.mWmService.mOnImeRequestedChangedListener;
300         if (imeListener != null) {
301             if (windowState != null) {
302                 mDisplayContent.mWmService.mH.post(() -> {
303                     imeListener.onImeRequestedChanged(windowState.mClient.asBinder(),
304                             windowState.isRequestedVisible(WindowInsets.Type.ime()));
305                 });
306             }
307         }
308     }
309 
reportImeDrawnForOrganizerIfNeeded(@onNull InsetsControlTarget caller)310     private void reportImeDrawnForOrganizerIfNeeded(@NonNull InsetsControlTarget caller) {
311         final WindowState callerWindow = caller.getWindow();
312         if (callerWindow == null) {
313             return;
314         }
315         WindowToken imeToken = mWindowContainer.asWindowState() != null
316                 ? mWindowContainer.asWindowState().mToken : null;
317         final var rotationController = mDisplayContent.getAsyncRotationController();
318         if ((rotationController != null && rotationController.isTargetToken(imeToken))
319                 || (imeToken != null && imeToken.isSelfAnimating(
320                         0 /* flags */, SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFORM))) {
321             // Skip reporting IME drawn state when the control target is in fixed
322             // rotation, AsyncRotationController will report after the animation finished.
323             return;
324         }
325         reportImeDrawnForOrganizer(caller);
326     }
327 
reportImeDrawnForOrganizer(@onNull InsetsControlTarget caller)328     private void reportImeDrawnForOrganizer(@NonNull InsetsControlTarget caller) {
329         final WindowState callerWindow = caller.getWindow();
330         if (callerWindow == null || callerWindow.getTask() == null) {
331             return;
332         }
333         if (callerWindow.getTask().isOrganized()) {
334             mWindowContainer.mWmService.mAtmService.mTaskOrganizerController
335                     .reportImeDrawnOnTask(caller.getWindow().getTask());
336         }
337     }
338 
339     /** Report the IME has drawn on the current IME control target for its task organizer */
reportImeDrawnForOrganizer()340     void reportImeDrawnForOrganizer() {
341         final InsetsControlTarget imeControlTarget = getControlTarget();
342         if (imeControlTarget != null) {
343             reportImeDrawnForOrganizer(imeControlTarget);
344         }
345     }
346 
onSourceChanged()347     private void onSourceChanged() {
348         if (mLastSource.equals(mSource)) {
349             return;
350         }
351         mLastSource.set(mSource);
352         mDisplayContent.mWmService.mH.obtainMessage(
353                 UPDATE_MULTI_WINDOW_STACKS, mDisplayContent).sendToTarget();
354     }
355 
356     /**
357      * Called from {@link WindowManagerInternal#showImePostLayout}
358      * when {@link android.inputmethodservice.InputMethodService} requests to show IME
359      * on the given control target.
360      *
361      * @param imeTarget  the control target on which the IME request is coming from.
362      * @param statsToken the token tracking the current IME request.
363      */
scheduleShowImePostLayout(@onNull InsetsControlTarget imeTarget, @NonNull ImeTracker.Token statsToken)364     void scheduleShowImePostLayout(@NonNull InsetsControlTarget imeTarget,
365             @NonNull ImeTracker.Token statsToken) {
366         if (mImeRequester == null) {
367             // Start tracing only on initial scheduled show IME request, to record end-to-end time.
368             Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
369         } else {
370             // We already have a scheduled show IME request, cancel the previous statsToken and
371             // continue with the new one.
372             logIsScheduledAndReadyToShowIme(false /* aborted */);
373             ImeTracker.forLogging().onCancelled(mStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
374         }
375         final boolean targetChanged = isTargetChangedWithinActivity(imeTarget);
376         mImeRequester = imeTarget;
377         mStatsToken = statsToken;
378         if (targetChanged) {
379             // target changed, check if new target can show IME.
380             ProtoLog.d(WM_DEBUG_IME, "IME target changed within ActivityRecord");
381             checkAndStartShowImePostLayout();
382             // if IME cannot be shown at this time, it is scheduled to be shown.
383             // once window that called IMM.showSoftInput() and DisplayContent's ImeTarget match,
384             // it will be shown.
385             return;
386         }
387 
388         ProtoLog.d(WM_DEBUG_IME, "Schedule IME show for %s", mImeRequester.getWindow() == null
389                 ? mImeRequester : mImeRequester.getWindow().getName());
390         mDisplayContent.mWmService.requestTraversal();
391     }
392 
393     /**
394      * Checks whether there is a previously scheduled show IME request and we are ready to show,
395      * in which case also start handling the request.
396      */
checkAndStartShowImePostLayout()397     void checkAndStartShowImePostLayout() {
398         if (!isScheduledAndReadyToShowIme()) {
399             // This can later become ready, so we don't want to cancel the pending request here.
400             return;
401         }
402         if (android.view.inputmethod.Flags.refactorInsetsController()) {
403             // Clear token here so we don't report an error in abortShowImePostLayout().
404             abortShowImePostLayout();
405             // The IME is drawn, so call into {@link WindowState#notifyInsetsControlChanged}
406             // if we have a leash
407             if (mControl != null && mControl.getLeash() != null
408                     && mControlTarget.getWindow() != null
409                     && !mControlTarget.getWindow().mGivenInsetsPending) {
410                 int displayId = mDisplayContent.getDisplayId();
411                 mControlTarget.notifyInsetsControlChanged(displayId);
412             }
413             return;
414         }
415 
416         ImeTracker.forLogging().onProgress(mStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
417         ProtoLog.d(WM_DEBUG_IME, "Run showImeRunner");
418 
419         final InsetsControlTarget target = getControlTarget();
420 
421         ProtoLog.i(WM_DEBUG_IME, "call showInsets(ime) on %s",
422                 target.getWindow() != null ? target.getWindow().getName() : "");
423         setImeShowing(true);
424         target.showInsets(WindowInsets.Type.ime(), true /* fromIme */, mStatsToken);
425         Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
426         if (target != mImeRequester) {
427             ProtoLog.w(WM_DEBUG_IME, "showInsets(ime) was requested by different window: %s ",
428                     (mImeRequester.getWindow() != null ? mImeRequester.getWindow().getName() : ""));
429         }
430         resetShowImePostLayout();
431     }
432 
433     /** Aborts the previously scheduled show IME request. */
abortShowImePostLayout()434     void abortShowImePostLayout() {
435         if (mImeRequester == null) {
436             return;
437         }
438         ProtoLog.d(WM_DEBUG_IME, "abortShowImePostLayout");
439         Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
440         logIsScheduledAndReadyToShowIme(true /* aborted */);
441         ImeTracker.forLogging().onFailed(
442                 mStatsToken, ImeTracker.PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT);
443         resetShowImePostLayout();
444     }
445 
446     /** Resets the state of the previously scheduled show IME request. */
resetShowImePostLayout()447     private void resetShowImePostLayout() {
448         mImeRequester = null;
449         mStatsToken = null;
450     }
451 
452     /** Checks whether there is a previously scheduled show IME request and we are ready to show. */
453     @VisibleForTesting
isScheduledAndReadyToShowIme()454     boolean isScheduledAndReadyToShowIme() {
455         // IMMS#mLastImeTargetWindow always considers focused window as
456         // IME target, however DisplayContent#computeImeTarget() can compute
457         // a different IME target.
458         // Refer to WindowManagerService#applyImeVisibility(token, false).
459         // If IMMS's imeTarget is child of DisplayContent's imeTarget and child window
460         // is above the parent, we will consider it as the same target for now.
461         // Also, if imeTarget is closing, it would be considered as outdated target.
462         // TODO(b/139861270): Remove the child & sublayer check once IMMS is aware of
463         //  actual IME target.
464         if (mImeRequester == null) {
465             // No show IME request previously scheduled.
466             return false;
467         }
468         if (!mServerVisible || mFrozen) {
469             // The window container is not available and considered visible.
470             // If frozen, the server visibility is not set until unfrozen.
471             return false;
472         }
473         if (mWindowContainer == null) {
474             // No window container set.
475             return false;
476         }
477         final WindowState windowState = mWindowContainer.asWindowState();
478         if (windowState == null) {
479             throw new IllegalArgumentException("IME insets must be provided by a window.");
480         }
481         if (!windowState.isDrawn() || windowState.mGivenInsetsPending) {
482             // The window is not drawn, or it has pending insets.
483             return false;
484         }
485         final InsetsControlTarget dcTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING);
486         if (dcTarget == null) {
487             // No IME layering target.
488             return false;
489         }
490         final InsetsControlTarget controlTarget = getControlTarget();
491         if (controlTarget == null) {
492             // No IME control target.
493             return false;
494         }
495         if (controlTarget != mDisplayContent.getImeTarget(IME_TARGET_CONTROL)) {
496             // The control target does not match the one in DisplayContent.
497             return false;
498         }
499         if (mStateController.hasPendingControls(controlTarget)) {
500             // The control target has pending controls.
501             return false;
502         }
503         if (getLeash(controlTarget) == null) {
504             // The control target has no source control leash (or it is not ready for dispatching).
505             return false;
506         }
507 
508         ProtoLog.d(WM_DEBUG_IME, "dcTarget: %s mImeRequester: %s",
509                 dcTarget.getWindow().getName(), mImeRequester.getWindow() == null
510                         ? mImeRequester : mImeRequester.getWindow().getName());
511 
512         return isImeLayeringTarget(mImeRequester, dcTarget)
513                 || isAboveImeLayeringTarget(mImeRequester, dcTarget)
514                 || isImeFallbackTarget(mImeRequester)
515                 || isImeInputTarget(mImeRequester)
516                 || sameAsImeControlTarget(mImeRequester);
517     }
518 
519     /**
520      * Logs the current state that can be checked by {@link #isScheduledAndReadyToShowIme}.
521      *
522      * @param aborted whether the scheduled show IME request was aborted or cancelled.
523      */
logIsScheduledAndReadyToShowIme(boolean aborted)524     private void logIsScheduledAndReadyToShowIme(boolean aborted) {
525         final var windowState = mWindowContainer != null ? mWindowContainer.asWindowState() : null;
526         final var dcTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING);
527         final var controlTarget = getControlTarget();
528         final var sb = new StringBuilder();
529         sb.append("showImePostLayout ").append(aborted ? "aborted" : "cancelled");
530         sb.append(", isScheduledAndReadyToShowIme: ").append(isScheduledAndReadyToShowIme());
531         sb.append(", mImeRequester: ").append(mImeRequester);
532         sb.append(", serverVisible: ").append(mServerVisible);
533         sb.append(", frozen: ").append(mFrozen);
534         sb.append(", mWindowContainer is: ").append(mWindowContainer != null ? "non-null" : "null");
535         sb.append(", windowState: ").append(windowState);
536         if (windowState != null) {
537             sb.append(", isDrawn: ").append(windowState.isDrawn());
538             sb.append(", mGivenInsetsPending: ").append(windowState.mGivenInsetsPending);
539         }
540         sb.append(", dcTarget: ").append(dcTarget);
541         sb.append(", controlTarget: ").append(controlTarget);
542         if (mImeRequester != null && dcTarget != null && controlTarget != null) {
543             sb.append("\n");
544             sb.append("controlTarget == DisplayContent.controlTarget: ");
545             sb.append(controlTarget == mDisplayContent.getImeTarget(IME_TARGET_CONTROL));
546             sb.append(", hasPendingControls: ");
547             sb.append(mStateController.hasPendingControls(controlTarget));
548             final boolean hasLeash = getLeash(controlTarget) != null;
549             sb.append(", leash is: ").append(hasLeash ? "non-null" : "null");
550             if (!hasLeash) {
551                 sb.append(", control is: ").append(mControl != null ? "non-null" : "null");
552                 sb.append(", mIsLeashReadyForDispatching: ").append(mIsLeashReadyForDispatching);
553             }
554             sb.append(", isImeLayeringTarget: ");
555             sb.append(isImeLayeringTarget(mImeRequester, dcTarget));
556             sb.append(", isAboveImeLayeringTarget: ");
557             sb.append(isAboveImeLayeringTarget(mImeRequester, dcTarget));
558             sb.append(", isImeFallbackTarget: ");
559             sb.append(isImeFallbackTarget(mImeRequester));
560             sb.append(", isImeInputTarget: ");
561             sb.append(isImeInputTarget(mImeRequester));
562             sb.append(", sameAsImeControlTarget: ");
563             sb.append(sameAsImeControlTarget(mImeRequester));
564         }
565         Slog.d(TAG, sb.toString());
566     }
567 
568     // ---------------------------------------------------------------------------------------
569     // Methods for checking IME insets target changing state.
570     //
isImeLayeringTarget(@onNull InsetsControlTarget target, @NonNull InsetsControlTarget dcTarget)571     private static boolean isImeLayeringTarget(@NonNull InsetsControlTarget target,
572             @NonNull InsetsControlTarget dcTarget) {
573         return !isImeTargetWindowClosing(dcTarget.getWindow()) && target == dcTarget;
574     }
575 
isAboveImeLayeringTarget(@onNull InsetsControlTarget target, @NonNull InsetsControlTarget dcTarget)576     private static boolean isAboveImeLayeringTarget(@NonNull InsetsControlTarget target,
577             @NonNull InsetsControlTarget dcTarget) {
578         return target.getWindow() != null
579                 && dcTarget.getWindow().getParentWindow() == target
580                 && dcTarget.getWindow().mSubLayer > target.getWindow().mSubLayer;
581     }
582 
isImeFallbackTarget(@onNull InsetsControlTarget target)583     private boolean isImeFallbackTarget(@NonNull InsetsControlTarget target) {
584         return target == mDisplayContent.getImeFallback();
585     }
586 
isImeInputTarget(@onNull InsetsControlTarget target)587     private boolean isImeInputTarget(@NonNull InsetsControlTarget target) {
588         return target == mDisplayContent.getImeInputTarget();
589     }
590 
sameAsImeControlTarget(@onNull InsetsControlTarget target)591     private boolean sameAsImeControlTarget(@NonNull InsetsControlTarget target) {
592         final InsetsControlTarget controlTarget = getControlTarget();
593         return controlTarget == target
594                 && (target.getWindow() == null || !isImeTargetWindowClosing(target.getWindow()));
595     }
596 
isImeTargetWindowClosing(@onNull WindowState win)597     private static boolean isImeTargetWindowClosing(@NonNull WindowState win) {
598         return win.mAnimatingExit || win.mActivityRecord != null
599                 && (win.mActivityRecord.isInTransition()
600                     && !win.mActivityRecord.isVisibleRequested()
601                     || win.mActivityRecord.willCloseOrEnterPip());
602     }
603 
isTargetChangedWithinActivity(@onNull InsetsControlTarget target)604     private boolean isTargetChangedWithinActivity(@NonNull InsetsControlTarget target) {
605         // We don't consider the target out of the activity.
606         if (target.getWindow() == null) {
607             return false;
608         }
609         return mImeRequester != target
610                 && mImeRequester != null
611                 && mImeRequester.getWindow() != null
612                 && mImeRequester.getWindow().mActivityRecord == target.getWindow().mActivityRecord;
613     }
614     // ---------------------------------------------------------------------------------------
615 
616     @Override
dump(PrintWriter pw, String prefix)617     public void dump(PrintWriter pw, String prefix) {
618         super.dump(pw, prefix);
619         prefix = prefix + "  ";
620         pw.print(prefix);
621         pw.print("mImeShowing=");
622         pw.print(mImeShowing);
623         if (mImeRequester != null) {
624             pw.print(prefix);
625             pw.print("showImePostLayout pending for mImeRequester=");
626             pw.print(mImeRequester);
627             pw.println();
628         } else {
629             pw.print(prefix);
630             pw.print("showImePostLayout not scheduled, mImeRequester=null");
631             pw.println();
632         }
633         pw.println();
634     }
635 
636     @Override
dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)637     void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) {
638         final long token = proto.start(fieldId);
639         super.dumpDebug(proto, INSETS_SOURCE_PROVIDER, logLevel);
640         final WindowState imeRequesterWindow =
641                 mImeRequester != null ? mImeRequester.getWindow() : null;
642         if (imeRequesterWindow != null) {
643             imeRequesterWindow.dumpDebug(proto, IME_TARGET_FROM_IME, logLevel);
644         }
645         proto.end(token);
646     }
647 
648     /**
649      * Sets whether the IME is currently supposed to be showing according to
650      * InputMethodManagerService.
651      */
setImeShowing(boolean imeShowing)652     public void setImeShowing(boolean imeShowing) {
653         mImeShowing = imeShowing;
654     }
655 
656     /**
657      * Returns whether the IME is currently supposed to be showing according to
658      * InputMethodManagerService.
659      */
isImeShowing()660     public boolean isImeShowing() {
661         return mImeShowing;
662     }
663 }
664