blob: 7491376cd1527688636f5470471ae696d5c817c9 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wm;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
import android.view.InsetsSource;
import android.view.WindowInsets;
import com.android.server.protolog.common.ProtoLog;
/**
* Controller for IME inset source on the server. It's called provider as it provides the
* {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
*/
class ImeInsetsSourceProvider extends InsetsSourceProvider {
private WindowState mImeTargetFromIme;
private Runnable mShowImeRunner;
private boolean mIsImeLayoutDrawn;
ImeInsetsSourceProvider(InsetsSource source,
InsetsStateController stateController, DisplayContent displayContent) {
super(source, stateController, displayContent);
}
/**
* Called from {@link WindowManagerInternal#showImePostLayout} when {@link InputMethodService}
* requests to show IME on {@param imeTarget}.
*
* @param imeTarget imeTarget on which IME request is coming from.
*/
void scheduleShowImePostLayout(WindowState imeTarget) {
boolean targetChanged = mImeTargetFromIme != imeTarget
&& mImeTargetFromIme != null && imeTarget != null && mShowImeRunner != null
&& mImeTargetFromIme.mActivityRecord == imeTarget.mActivityRecord;
mImeTargetFromIme = imeTarget;
if (targetChanged) {
// target changed, check if new target can show IME.
ProtoLog.d(WM_DEBUG_IME, "IME target changed within ActivityRecord");
checkShowImePostLayout();
// if IME cannot be shown at this time, it is scheduled to be shown.
// once window that called IMM.showSoftInput() and DisplayContent's ImeTarget match,
// it will be shown.
return;
}
ProtoLog.d(WM_DEBUG_IME, "Schedule IME show for %s", mImeTargetFromIme.getName());
mShowImeRunner = () -> {
ProtoLog.d(WM_DEBUG_IME, "Run showImeRunner");
// Target should still be the same.
if (isImeTargetFromDisplayContentAndImeSame()) {
final InsetsControlTarget target = mDisplayContent.mInputMethodControlTarget;
ProtoLog.d(WM_DEBUG_IME, "call showInsets(ime) on %s",
target.getWindow() != null ? target.getWindow().getName() : "");
target.showInsets(WindowInsets.Type.ime(), true /* fromIme */);
}
abortShowImePostLayout();
};
mDisplayContent.mWmService.requestTraversal();
}
void checkShowImePostLayout() {
// check if IME is drawn
if (mIsImeLayoutDrawn
|| (mImeTargetFromIme != null
&& isImeTargetFromDisplayContentAndImeSame()
&& mWin != null
&& mWin.isDrawnLw()
&& !mWin.mGivenInsetsPending)) {
mIsImeLayoutDrawn = true;
// show IME if InputMethodService requested it to be shown.
if (mShowImeRunner != null) {
mShowImeRunner.run();
}
}
}
/**
* Abort any pending request to show IME post layout.
*/
void abortShowImePostLayout() {
ProtoLog.d(WM_DEBUG_IME, "abortShowImePostLayout");
mImeTargetFromIme = null;
mIsImeLayoutDrawn = false;
mShowImeRunner = null;
}
private boolean isImeTargetFromDisplayContentAndImeSame() {
// IMMS#mLastImeTargetWindow always considers focused window as
// IME target, however DisplayContent#computeImeTarget() can compute
// a different IME target.
// Refer to WindowManagerService#applyImeVisibility(token, false).
// If IMMS's imeTarget is child of DisplayContent's imeTarget and child window
// is above the parent, we will consider it as the same target for now.
// Also, if imeTarget is closing, it would be considered as outdated target.
// TODO(b/139861270): Remove the child & sublayer check once IMMS is aware of
// actual IME target.
final WindowState dcTarget = mDisplayContent.mInputMethodTarget;
if (dcTarget == null || mImeTargetFromIme == null) {
return false;
}
ProtoLog.d(WM_DEBUG_IME, "dcTarget: %s mImeTargetFromIme: %s",
dcTarget.getName(), mImeTargetFromIme.getName());
return (!dcTarget.isClosing() && mImeTargetFromIme == dcTarget)
|| (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme
&& dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer)
|| mImeTargetFromIme == mDisplayContent.getImeFallback();
}
}