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