Merge changes I6adbf430,I6e137a6e,I9e15358a,I2aea907b,I12d99c15, ...
* changes: Migrate IMMS#shouldRestoreImeVisibility to ImeVisibilityStateComputer Migrate applyImeVsibility to ImeVisibilityApplier Migrate computeImeDisplayIdForTarget to ImeVisibilityStateComputer Migrate to IME visibility settings Introduce ImeVisibilityApplier Introduce ImeVisibilityStateComputer
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.inputmethod;
|
||||
|
||||
import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
|
||||
|
||||
import static com.android.server.EventLogTags.IMF_HIDE_IME;
|
||||
import static com.android.server.EventLogTags.IMF_SHOW_IME;
|
||||
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
|
||||
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.ResultReceiver;
|
||||
import android.util.EventLog;
|
||||
import android.util.Slog;
|
||||
import android.view.inputmethod.ImeTracker;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.inputmethod.InputMethodDebug;
|
||||
import com.android.internal.inputmethod.SoftInputShowHideReason;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.wm.WindowManagerInternal;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link ImeVisibilityApplier} used in
|
||||
* {@link InputMethodManagerService}.
|
||||
*/
|
||||
final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
|
||||
|
||||
private static final String TAG = "DefaultImeVisibilityApplier";
|
||||
|
||||
private static final boolean DEBUG = InputMethodManagerService.DEBUG;
|
||||
|
||||
private InputMethodManagerService mService;
|
||||
|
||||
private final WindowManagerInternal mWindowManagerInternal;
|
||||
|
||||
|
||||
DefaultImeVisibilityApplier(InputMethodManagerService service) {
|
||||
mService = service;
|
||||
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
|
||||
}
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
@Override
|
||||
public void performShowIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
|
||||
int showFlags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
|
||||
final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
|
||||
if (curMethod != null) {
|
||||
// create a placeholder token for IMS so that IMS cannot inject windows into client app.
|
||||
final IBinder showInputToken = new Binder();
|
||||
mService.setRequestImeTokenToWindow(windowToken, showInputToken);
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Calling " + curMethod + ".showSoftInput(" + showInputToken
|
||||
+ ", " + showFlags + ", " + resultReceiver + ") for reason: "
|
||||
+ InputMethodDebug.softInputDisplayReasonToString(reason));
|
||||
}
|
||||
// TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
|
||||
if (curMethod.showSoftInput(showInputToken, statsToken, showFlags, resultReceiver)) {
|
||||
if (DEBUG_IME_VISIBILITY) {
|
||||
EventLog.writeEvent(IMF_SHOW_IME, statsToken.getTag(),
|
||||
Objects.toString(mService.mCurFocusedWindow),
|
||||
InputMethodDebug.softInputDisplayReasonToString(reason),
|
||||
InputMethodDebug.softInputModeToString(
|
||||
mService.mCurFocusedWindowSoftInputMode));
|
||||
}
|
||||
mService.onShowHideSoftInputRequested(true /* show */, windowToken, reason,
|
||||
statsToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
@Override
|
||||
public void performHideIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
|
||||
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
|
||||
final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
|
||||
if (curMethod != null) {
|
||||
final Binder hideInputToken = new Binder();
|
||||
mService.setRequestImeTokenToWindow(windowToken, hideInputToken);
|
||||
// The IME will report its visible state again after the following message finally
|
||||
// delivered to the IME process as an IPC. Hence the inconsistency between
|
||||
// IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
|
||||
// the final state.
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Calling " + curMethod + ".hideSoftInput(0, " + hideInputToken
|
||||
+ ", " + resultReceiver + ") for reason: "
|
||||
+ InputMethodDebug.softInputDisplayReasonToString(reason));
|
||||
}
|
||||
// TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
|
||||
if (curMethod.hideSoftInput(hideInputToken, statsToken, 0, resultReceiver)) {
|
||||
if (DEBUG_IME_VISIBILITY) {
|
||||
EventLog.writeEvent(IMF_HIDE_IME, statsToken.getTag(),
|
||||
Objects.toString(mService.mCurFocusedWindow),
|
||||
InputMethodDebug.softInputDisplayReasonToString(reason),
|
||||
InputMethodDebug.softInputModeToString(
|
||||
mService.mCurFocusedWindowSoftInputMode));
|
||||
}
|
||||
mService.onShowHideSoftInputRequested(false /* show */, windowToken, reason,
|
||||
statsToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
@Override
|
||||
public void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
|
||||
@ImeVisibilityStateComputer.VisibilityState int state) {
|
||||
switch (state) {
|
||||
case STATE_SHOW_IME:
|
||||
ImeTracker.get().onProgress(statsToken,
|
||||
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
|
||||
// Send to window manager to show IME after IME layout finishes.
|
||||
mWindowManagerInternal.showImePostLayout(windowToken, statsToken);
|
||||
break;
|
||||
case STATE_HIDE_IME:
|
||||
if (mService.mCurFocusedWindowClient != null) {
|
||||
ImeTracker.get().onProgress(statsToken,
|
||||
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
|
||||
// IMMS only knows of focused window, not the actual IME target.
|
||||
// e.g. it isn't aware of any window that has both
|
||||
// NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target.
|
||||
// Send it to window manager to hide IME from IME target window.
|
||||
// TODO(b/139861270): send to mCurClient.client once IMMS is aware of
|
||||
// actual IME target.
|
||||
mWindowManagerInternal.hideIme(windowToken,
|
||||
mService.mCurFocusedWindowClient.mSelfReportedDisplayId, statsToken);
|
||||
} else {
|
||||
ImeTracker.get().onFailed(statsToken,
|
||||
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid IME visibility state: " + state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.inputmethod;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.IBinder;
|
||||
import android.os.ResultReceiver;
|
||||
import android.view.inputmethod.ImeTracker;
|
||||
|
||||
import com.android.internal.inputmethod.SoftInputShowHideReason;
|
||||
|
||||
/**
|
||||
* Interface for IME visibility operations like show/hide and update Z-ordering relative to the IME
|
||||
* targeted window.
|
||||
*/
|
||||
interface ImeVisibilityApplier {
|
||||
/**
|
||||
* Performs showing IME on top of the given window.
|
||||
*
|
||||
* @param windowToken The token of a window that currently has focus.
|
||||
* @param statsToken A token that tracks the progress of an IME request.
|
||||
* @param showFlags Provides additional operating flags to show IME.
|
||||
* @param resultReceiver If non-null, this will be called back to the caller when
|
||||
* it has processed request to tell what it has done.
|
||||
* @param reason The reason for requesting to show IME.
|
||||
*/
|
||||
default void performShowIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
|
||||
int showFlags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}
|
||||
|
||||
/**
|
||||
* Performs hiding IME to the given window
|
||||
*
|
||||
* @param windowToken The token of a window that currently has focus.
|
||||
* @param statsToken A token that tracks the progress of an IME request.
|
||||
* @param resultReceiver If non-null, this will be called back to the caller when
|
||||
* it has processed request to tell what it has done.
|
||||
* @param reason The reason for requesting to hide IME.
|
||||
*/
|
||||
default void performHideIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
|
||||
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}
|
||||
|
||||
/**
|
||||
* Applies the IME visibility from {@link android.inputmethodservice.InputMethodService} with
|
||||
* according to the given visibility state.
|
||||
*
|
||||
* @param windowToken The token of a window for applying the IME visibility
|
||||
* @param statsToken A token that tracks the progress of an IME request.
|
||||
* @param state The new IME visibility state for the applier to handle
|
||||
*/
|
||||
default void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
|
||||
@ImeVisibilityStateComputer.VisibilityState int state) {}
|
||||
|
||||
/**
|
||||
* Updates the IME Z-ordering relative to the given window.
|
||||
*
|
||||
* This used to adjust the IME relative layer of the window during
|
||||
* {@link InputMethodManagerService} is in switching IME clients.
|
||||
*
|
||||
* @param windowToken The token of a window to update the Z-ordering relative to the IME.
|
||||
*/
|
||||
default void updateImeLayeringByTarget(IBinder windowToken) {
|
||||
// TODO: add a method in WindowManagerInternal to call DC#updateImeInputAndControlTarget
|
||||
// here to end up updating IME layering after IMMS#attachNewInputLocked called.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.inputmethod;
|
||||
|
||||
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_EXPLICITLY_REQUESTED;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_FORCED;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
|
||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
|
||||
import static android.view.WindowManager.LayoutParams.SoftInputModeFlags;
|
||||
|
||||
import static com.android.internal.inputmethod.InputMethodDebug.softInputModeToString;
|
||||
import static com.android.server.inputmethod.InputMethodManagerService.computeImeDisplayIdForTarget;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.IBinder;
|
||||
import android.util.PrintWriterPrinter;
|
||||
import android.util.Printer;
|
||||
import android.util.Slog;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.ImeTracker;
|
||||
import android.view.inputmethod.InputMethod;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.wm.WindowManagerInternal;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* A computer used by {@link InputMethodManagerService} that computes the IME visibility state
|
||||
* according the given {@link ImeTargetWindowState} from the focused window or the app requested IME
|
||||
* visibility from {@link InputMethodManager}.
|
||||
*/
|
||||
public final class ImeVisibilityStateComputer {
|
||||
|
||||
private static final String TAG = "ImeVisibilityStateComputer";
|
||||
|
||||
private static final boolean DEBUG = InputMethodManagerService.DEBUG;
|
||||
|
||||
private final InputMethodManagerService mService;
|
||||
private final WindowManagerInternal mWindowManagerInternal;
|
||||
|
||||
final InputMethodManagerService.ImeDisplayValidator mImeDisplayValidator;
|
||||
|
||||
/**
|
||||
* A map used to track the requested IME target window and its state. The key represents the
|
||||
* token of the window and the value is the corresponding IME window state.
|
||||
*/
|
||||
private final WeakHashMap<IBinder, ImeTargetWindowState> mRequestWindowStateMap =
|
||||
new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Set if IME was explicitly told to show the input method.
|
||||
*
|
||||
* @see InputMethodManager#SHOW_IMPLICIT that we set the value is {@code false}.
|
||||
* @see InputMethodManager#HIDE_IMPLICIT_ONLY that system will not hide IME when the value is
|
||||
* {@code true}.
|
||||
*/
|
||||
boolean mRequestedShowExplicitly;
|
||||
|
||||
/**
|
||||
* Set if we were forced to be shown.
|
||||
*
|
||||
* @see InputMethodManager#SHOW_FORCED
|
||||
* @see InputMethodManager#HIDE_NOT_ALWAYS
|
||||
*/
|
||||
boolean mShowForced;
|
||||
|
||||
/** Represent the invalid IME visibility state */
|
||||
public static final int STATE_INVALID = -1;
|
||||
|
||||
/** State to handle hiding the IME window requested by the app. */
|
||||
public static final int STATE_HIDE_IME = 0;
|
||||
|
||||
/** State to handle showing the IME window requested by the app. */
|
||||
public static final int STATE_SHOW_IME = 1;
|
||||
|
||||
/** State to handle showing the IME window with making the overlay window above it. */
|
||||
public static final int STATE_SHOW_IME_ABOVE_OVERLAY = 2;
|
||||
|
||||
/** State to handle showing the IME window with making the overlay window behind it. */
|
||||
public static final int STATE_SHOW_IME_BEHIND_OVERLAY = 3;
|
||||
|
||||
/** State to handle showing an IME preview surface during the app was loosing the IME focus */
|
||||
public static final int STATE_SHOW_IME_SNAPSHOT = 4;
|
||||
@IntDef({
|
||||
STATE_INVALID,
|
||||
STATE_HIDE_IME,
|
||||
STATE_SHOW_IME,
|
||||
STATE_SHOW_IME_ABOVE_OVERLAY,
|
||||
STATE_SHOW_IME_BEHIND_OVERLAY,
|
||||
STATE_SHOW_IME_SNAPSHOT,
|
||||
})
|
||||
@interface VisibilityState {}
|
||||
|
||||
/**
|
||||
* The policy to configure the IME visibility.
|
||||
*/
|
||||
private final ImeVisibilityPolicy mPolicy;
|
||||
|
||||
public ImeVisibilityStateComputer(InputMethodManagerService service) {
|
||||
mService = service;
|
||||
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
|
||||
mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
|
||||
mPolicy = new ImeVisibilityPolicy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when {@link InputMethodManagerService} is processing the show IME request.
|
||||
* @param statsToken The token for tracking this show request
|
||||
* @param showFlags The additional operation flags to indicate whether this show request mode is
|
||||
* implicit or explicit.
|
||||
* @return {@code true} when the computer has proceed this show request operation.
|
||||
*/
|
||||
boolean onImeShowFlags(@NonNull ImeTracker.Token statsToken, int showFlags) {
|
||||
if (mPolicy.mA11yRequestingNoSoftKeyboard || mPolicy.mImeHiddenByDisplayPolicy) {
|
||||
ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
|
||||
return false;
|
||||
}
|
||||
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
|
||||
if ((showFlags & InputMethodManager.SHOW_FORCED) != 0) {
|
||||
mRequestedShowExplicitly = true;
|
||||
mShowForced = true;
|
||||
} else if ((showFlags & InputMethodManager.SHOW_IMPLICIT) == 0) {
|
||||
mRequestedShowExplicitly = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when {@link InputMethodManagerService} is processing the hide IME request.
|
||||
* @param statsToken The token for tracking this hide request
|
||||
* @param hideFlags The additional operation flags to indicate whether this hide request mode is
|
||||
* implicit or explicit.
|
||||
* @return {@code true} when the computer has proceed this hide request operations.
|
||||
*/
|
||||
boolean canHideIme(@NonNull ImeTracker.Token statsToken, int hideFlags) {
|
||||
if ((hideFlags & InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
|
||||
&& (mRequestedShowExplicitly || mShowForced)) {
|
||||
if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
|
||||
ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
|
||||
return false;
|
||||
}
|
||||
if (mShowForced && (hideFlags & InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
|
||||
if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
|
||||
ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
|
||||
return false;
|
||||
}
|
||||
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
|
||||
return true;
|
||||
}
|
||||
|
||||
int getImeShowFlags() {
|
||||
int flags = 0;
|
||||
if (mShowForced) {
|
||||
flags |= InputMethod.SHOW_FORCED | InputMethod.SHOW_EXPLICIT;
|
||||
} else if (mRequestedShowExplicitly) {
|
||||
flags |= InputMethod.SHOW_EXPLICIT;
|
||||
} else {
|
||||
flags |= InputMethodManager.SHOW_IMPLICIT;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
void clearImeShowFlags() {
|
||||
mRequestedShowExplicitly = false;
|
||||
mShowForced = false;
|
||||
}
|
||||
|
||||
int computeImeDisplayId(@NonNull ImeTargetWindowState state, int displayId) {
|
||||
final int displayToShowIme = computeImeDisplayIdForTarget(displayId, mImeDisplayValidator);
|
||||
state.setImeDisplayId(displayToShowIme);
|
||||
final boolean imeHiddenByPolicy = displayToShowIme == INVALID_DISPLAY;
|
||||
mPolicy.setImeHiddenByDisplayPolicy(imeHiddenByPolicy);
|
||||
return displayToShowIme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to show/hide IME from the given window.
|
||||
*
|
||||
* @param windowToken The window which requests to show/hide IME.
|
||||
* @param showIme {@code true} means to show IME, {@code false} otherwise.
|
||||
* Note that in the computer will take this option to compute the
|
||||
* visibility state, it could be {@link #STATE_SHOW_IME} or
|
||||
* {@link #STATE_HIDE_IME}.
|
||||
*/
|
||||
void requestImeVisibility(IBinder windowToken, boolean showIme) {
|
||||
final ImeTargetWindowState state = getOrCreateWindowState(windowToken);
|
||||
state.setRequestedImeVisible(showIme);
|
||||
setWindowState(windowToken, state);
|
||||
}
|
||||
|
||||
ImeTargetWindowState getOrCreateWindowState(IBinder windowToken) {
|
||||
ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
|
||||
if (state == null) {
|
||||
state = new ImeTargetWindowState(SOFT_INPUT_STATE_UNSPECIFIED, false, false);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
ImeTargetWindowState getWindowStateOrNull(IBinder windowToken) {
|
||||
ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
|
||||
return state;
|
||||
}
|
||||
|
||||
void setRequestImeTokenToWindow(IBinder windowToken, IBinder token) {
|
||||
ImeTargetWindowState state = getWindowStateOrNull(windowToken);
|
||||
if (state != null) {
|
||||
state.setRequestImeToken(token);
|
||||
setWindowState(windowToken, state);
|
||||
}
|
||||
}
|
||||
|
||||
void setWindowState(IBinder windowToken, ImeTargetWindowState newState) {
|
||||
if (DEBUG) Slog.d(TAG, "setWindowState, windowToken=" + windowToken
|
||||
+ ", state=" + newState);
|
||||
mRequestWindowStateMap.put(windowToken, newState);
|
||||
}
|
||||
|
||||
IBinder getWindowTokenFrom(IBinder requestImeToken) {
|
||||
for (IBinder windowToken : mRequestWindowStateMap.keySet()) {
|
||||
final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
|
||||
if (state.getRequestImeToken() == requestImeToken) {
|
||||
return windowToken;
|
||||
}
|
||||
}
|
||||
// Fallback to the focused window for some edge cases (e.g. relaunching the activity)
|
||||
return mService.mCurFocusedWindow;
|
||||
}
|
||||
|
||||
IBinder getWindowTokenFrom(ImeTargetWindowState windowState) {
|
||||
for (IBinder windowToken : mRequestWindowStateMap.keySet()) {
|
||||
final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
|
||||
if (state == windowState) {
|
||||
return windowToken;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean shouldRestoreImeVisibility(@NonNull ImeTargetWindowState state) {
|
||||
final int softInputMode = state.getSoftInputModeState();
|
||||
switch (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
|
||||
case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
|
||||
return false;
|
||||
case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
|
||||
if ((softInputMode & SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return mWindowManagerInternal.shouldRestoreImeVisibility(getWindowTokenFrom(state));
|
||||
}
|
||||
|
||||
void dumpDebug(ProtoOutputStream proto, long fieldId) {
|
||||
proto.write(SHOW_EXPLICITLY_REQUESTED, mRequestedShowExplicitly);
|
||||
proto.write(SHOW_FORCED, mShowForced);
|
||||
proto.write(ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD,
|
||||
mPolicy.isA11yRequestNoSoftKeyboard());
|
||||
}
|
||||
|
||||
void dump(PrintWriter pw) {
|
||||
final Printer p = new PrintWriterPrinter(pw);
|
||||
p.println(" mRequestedShowExplicitly=" + mRequestedShowExplicitly
|
||||
+ " mShowForced=" + mShowForced);
|
||||
p.println(" mImeHiddenByDisplayPolicy=" + mPolicy.isImeHiddenByDisplayPolicy());
|
||||
}
|
||||
|
||||
/**
|
||||
* A settings class to manage all IME related visibility policies or settings.
|
||||
*
|
||||
* This is used for the visibility computer to manage and tell
|
||||
* {@link InputMethodManagerService} if the requested IME visibility is valid from
|
||||
* application call or the focus window.
|
||||
*/
|
||||
static class ImeVisibilityPolicy {
|
||||
/**
|
||||
* {@code true} if the Ime policy has been set to
|
||||
* {@link WindowManager#DISPLAY_IME_POLICY_HIDE}.
|
||||
*
|
||||
* This prevents the IME from showing when it otherwise may have shown.
|
||||
*/
|
||||
private boolean mImeHiddenByDisplayPolicy;
|
||||
|
||||
/**
|
||||
* Set when the accessibility service requests to hide IME by
|
||||
* {@link AccessibilityService.SoftKeyboardController#setShowMode}
|
||||
*/
|
||||
private boolean mA11yRequestingNoSoftKeyboard;
|
||||
|
||||
void setImeHiddenByDisplayPolicy(boolean hideIme) {
|
||||
mImeHiddenByDisplayPolicy = hideIme;
|
||||
}
|
||||
|
||||
boolean isImeHiddenByDisplayPolicy() {
|
||||
return mImeHiddenByDisplayPolicy;
|
||||
}
|
||||
|
||||
void setA11yRequestNoSoftKeyboard(int keyboardShowMode) {
|
||||
mA11yRequestingNoSoftKeyboard =
|
||||
(keyboardShowMode & AccessibilityService.SHOW_MODE_MASK) == SHOW_MODE_HIDDEN;
|
||||
}
|
||||
|
||||
boolean isA11yRequestNoSoftKeyboard() {
|
||||
return mA11yRequestingNoSoftKeyboard;
|
||||
}
|
||||
}
|
||||
|
||||
ImeVisibilityPolicy getImePolicy() {
|
||||
return mPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that represents the current state of the IME target window.
|
||||
*/
|
||||
static class ImeTargetWindowState {
|
||||
ImeTargetWindowState(@SoftInputModeFlags int softInputModeState, boolean imeFocusChanged,
|
||||
boolean hasFocusedEditor) {
|
||||
mSoftInputModeState = softInputModeState;
|
||||
mImeFocusChanged = imeFocusChanged;
|
||||
mHasFocusedEditor = hasFocusedEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visibility state for this window. By default no state has been specified.
|
||||
*/
|
||||
private final @SoftInputModeFlags int mSoftInputModeState;
|
||||
|
||||
/**
|
||||
* {@code true} means the IME focus changed from the previous window, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
private final boolean mImeFocusChanged;
|
||||
|
||||
/**
|
||||
* {@code true} when the window has focused an editor, {@code false} otherwise.
|
||||
*/
|
||||
private final boolean mHasFocusedEditor;
|
||||
|
||||
/**
|
||||
* Set if the client has asked for the input method to be shown.
|
||||
*/
|
||||
private boolean mRequestedImeVisible;
|
||||
|
||||
/**
|
||||
* A identifier for knowing the requester of {@link InputMethodManager#showSoftInput} or
|
||||
* {@link InputMethodManager#hideSoftInputFromWindow}.
|
||||
*/
|
||||
private IBinder mRequestImeToken;
|
||||
|
||||
/**
|
||||
* The IME target display id for which the latest startInput was called.
|
||||
*/
|
||||
private int mImeDisplayId = DEFAULT_DISPLAY;
|
||||
|
||||
boolean hasImeFocusChanged() {
|
||||
return mImeFocusChanged;
|
||||
}
|
||||
|
||||
boolean hasEdiorFocused() {
|
||||
return mHasFocusedEditor;
|
||||
}
|
||||
|
||||
int getSoftInputModeState() {
|
||||
return mSoftInputModeState;
|
||||
}
|
||||
|
||||
private void setImeDisplayId(int imeDisplayId) {
|
||||
mImeDisplayId = imeDisplayId;
|
||||
}
|
||||
|
||||
int getImeDisplayId() {
|
||||
return mImeDisplayId;
|
||||
}
|
||||
|
||||
private void setRequestedImeVisible(boolean requestedImeVisible) {
|
||||
mRequestedImeVisible = requestedImeVisible;
|
||||
}
|
||||
|
||||
boolean isRequestedImeVisible() {
|
||||
return mRequestedImeVisible;
|
||||
}
|
||||
|
||||
void setRequestImeToken(IBinder token) {
|
||||
mRequestImeToken = token;
|
||||
}
|
||||
|
||||
IBinder getRequestImeToken() {
|
||||
return mRequestImeToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ImeTargetWindowState{ imeToken " + mRequestImeToken
|
||||
+ " imeFocusChanged " + mImeFocusChanged
|
||||
+ " hasEditorFocused " + mHasFocusedEditor
|
||||
+ " requestedImeVisible " + mRequestedImeVisible
|
||||
+ " imeDisplayId " + mImeDisplayId
|
||||
+ " softInputModeState " + softInputModeToString(mSoftInputModeState)
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
|
||||
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
|
||||
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
|
||||
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.BACK_DISPOSITION;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.BOUND_TO_METHOD;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_ATTRIBUTE;
|
||||
@@ -39,8 +38,6 @@ import static android.server.inputmethod.InputMethodManagerServiceProto.IN_FULLS
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.IS_INTERACTIVE;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_IME_TARGET_WINDOW_NAME;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_SWITCH_USER_ID;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_EXPLICITLY_REQUESTED;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_FORCED;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_IME_WITH_HARD_KEYBOARD;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_REQUESTED;
|
||||
import static android.server.inputmethod.InputMethodManagerServiceProto.SYSTEM_READY;
|
||||
@@ -48,17 +45,14 @@ import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE;
|
||||
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
|
||||
import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
|
||||
|
||||
import static com.android.server.EventLogTags.IMF_HIDE_IME;
|
||||
import static com.android.server.EventLogTags.IMF_SHOW_IME;
|
||||
import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState;
|
||||
import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT;
|
||||
import static com.android.server.inputmethod.InputMethodUtils.isSoftInputModeStateVisibleAllowed;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.Manifest;
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.BinderThread;
|
||||
import android.annotation.DrawableRes;
|
||||
@@ -126,7 +120,6 @@ import android.view.DisplayInfo;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputDevice;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManager.DisplayImePolicy;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
@@ -299,6 +292,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
@NonNull private final InputMethodBindingController mBindingController;
|
||||
@NonNull private final AutofillSuggestionsController mAutofillController;
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
@NonNull private final ImeVisibilityStateComputer mVisibilityStateComputer;
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
@NonNull private final DefaultImeVisibilityApplier mVisibilityApplier;
|
||||
|
||||
/**
|
||||
* Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
|
||||
*
|
||||
@@ -529,13 +528,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
mBindingController.advanceSequenceNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code true} if the Ime policy has been set to {@link WindowManager#DISPLAY_IME_POLICY_HIDE}.
|
||||
*
|
||||
* This prevents the IME from showing when it otherwise may have shown.
|
||||
*/
|
||||
boolean mImeHiddenByDisplayPolicy;
|
||||
|
||||
/**
|
||||
* The client that is currently bound to an input method.
|
||||
*/
|
||||
@@ -637,16 +629,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
*/
|
||||
private boolean mShowRequested;
|
||||
|
||||
/**
|
||||
* Set if we were explicitly told to show the input method.
|
||||
*/
|
||||
boolean mShowExplicitlyRequested;
|
||||
|
||||
/**
|
||||
* Set if we were forced to be shown.
|
||||
*/
|
||||
boolean mShowForced;
|
||||
|
||||
/**
|
||||
* Set if we last told the input method to show itself.
|
||||
*/
|
||||
@@ -709,8 +691,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
*/
|
||||
private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY;
|
||||
|
||||
final ImeDisplayValidator mImeDisplayValidator;
|
||||
|
||||
/**
|
||||
* If non-null, this is the input method service we are currently connected
|
||||
* to.
|
||||
@@ -786,7 +766,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
int mImeWindowVis;
|
||||
|
||||
private LocaleList mLastSystemLocales;
|
||||
private boolean mAccessibilityRequestingNoSoftKeyboard;
|
||||
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
|
||||
private final String mSlotIme;
|
||||
|
||||
@@ -973,22 +952,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of generated token to windowToken that is requesting
|
||||
* {@link InputMethodManager#showSoftInput(View, int)}.
|
||||
* This map tracks origin of showSoftInput requests.
|
||||
*/
|
||||
@GuardedBy("ImfLock.class")
|
||||
private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Map of generated token to windowToken that is requesting
|
||||
* {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}.
|
||||
* This map tracks origin of hideSoftInput requests.
|
||||
*/
|
||||
@GuardedBy("ImfLock.class")
|
||||
private final WeakHashMap<IBinder, IBinder> mHideRequestWindowMap = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* A ring buffer to store the history of {@link StartInputInfo}.
|
||||
*/
|
||||
@@ -1207,11 +1170,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
} else if (accessibilityRequestingNoImeUri.equals(uri)) {
|
||||
final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0 /* def */, mUserId);
|
||||
mAccessibilityRequestingNoSoftKeyboard =
|
||||
(accessibilitySoftKeyboardSetting & AccessibilityService.SHOW_MODE_MASK)
|
||||
== AccessibilityService.SHOW_MODE_HIDDEN;
|
||||
if (mAccessibilityRequestingNoSoftKeyboard) {
|
||||
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
|
||||
mVisibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard(
|
||||
accessibilitySoftKeyboardSetting);
|
||||
if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
|
||||
final boolean showRequested = mShowRequested;
|
||||
hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
|
||||
0 /* flags */, null /* resultReceiver */,
|
||||
@@ -1722,7 +1684,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
|
||||
mImePlatformCompatUtils = new ImePlatformCompatUtils();
|
||||
mInputMethodDeviceConfigs = new InputMethodDeviceConfigs();
|
||||
mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
|
||||
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
|
||||
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
|
||||
|
||||
@@ -1747,6 +1708,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
? bindingControllerForTesting
|
||||
: new InputMethodBindingController(this);
|
||||
mAutofillController = new AutofillSuggestionsController(this);
|
||||
|
||||
mVisibilityStateComputer = new ImeVisibilityStateComputer(this);
|
||||
mVisibilityApplier = new DefaultImeVisibilityApplier(this);
|
||||
|
||||
mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
|
||||
com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
|
||||
mNonPreemptibleInputMethods = mRes.getStringArray(
|
||||
@@ -2339,29 +2304,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
mInputShown = false;
|
||||
}
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
private int getImeShowFlagsLocked() {
|
||||
int flags = 0;
|
||||
if (mShowForced) {
|
||||
flags |= InputMethod.SHOW_FORCED
|
||||
| InputMethod.SHOW_EXPLICIT;
|
||||
} else if (mShowExplicitlyRequested) {
|
||||
flags |= InputMethod.SHOW_EXPLICIT;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
private int getAppShowFlagsLocked() {
|
||||
int flags = 0;
|
||||
if (mShowForced) {
|
||||
flags |= InputMethodManager.SHOW_FORCED;
|
||||
} else if (!mShowExplicitlyRequested) {
|
||||
flags |= InputMethodManager.SHOW_IMPLICIT;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
@NonNull
|
||||
InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
|
||||
@@ -2403,7 +2345,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
// Re-use current statsToken, if it exists.
|
||||
final ImeTracker.Token statsToken = mCurStatsToken;
|
||||
mCurStatsToken = null;
|
||||
showCurrentInputLocked(mCurFocusedWindow, statsToken, getAppShowFlagsLocked(),
|
||||
showCurrentInputLocked(mCurFocusedWindow, statsToken,
|
||||
mVisibilityStateComputer.getImeShowFlags(),
|
||||
null /* resultReceiver */, SoftInputShowHideReason.ATTACH_NEW_INPUT);
|
||||
}
|
||||
|
||||
@@ -2518,17 +2461,20 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
|
||||
// Compute the final shown display ID with validated cs.selfReportedDisplayId for this
|
||||
// session & other conditions.
|
||||
mDisplayIdToShowIme = computeImeDisplayIdForTarget(cs.mSelfReportedDisplayId,
|
||||
mImeDisplayValidator);
|
||||
ImeTargetWindowState winState = mVisibilityStateComputer.getWindowStateOrNull(
|
||||
mCurFocusedWindow);
|
||||
if (winState == null) {
|
||||
return InputBindResult.NOT_IME_TARGET_WINDOW;
|
||||
}
|
||||
final int csDisplayId = cs.mSelfReportedDisplayId;
|
||||
mDisplayIdToShowIme = mVisibilityStateComputer.computeImeDisplayId(winState, csDisplayId);
|
||||
|
||||
if (mDisplayIdToShowIme == INVALID_DISPLAY) {
|
||||
mImeHiddenByDisplayPolicy = true;
|
||||
if (mVisibilityStateComputer.getImePolicy().isImeHiddenByDisplayPolicy()) {
|
||||
hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
|
||||
null /* resultReceiver */,
|
||||
SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE);
|
||||
return InputBindResult.NO_IME;
|
||||
}
|
||||
mImeHiddenByDisplayPolicy = false;
|
||||
|
||||
if (mCurClient != cs) {
|
||||
prepareClientSwitchLocked(cs);
|
||||
@@ -3385,6 +3331,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
void setRequestImeTokenToWindow(IBinder windowToken, IBinder token) {
|
||||
mVisibilityStateComputer.setRequestImeTokenToWindow(windowToken, token);
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) {
|
||||
@@ -3419,18 +3370,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
ImeTracker.ORIGIN_SERVER_START_INPUT, reason);
|
||||
}
|
||||
|
||||
// TODO(b/246309664): make mShowRequested as per-window state.
|
||||
mShowRequested = true;
|
||||
if (mAccessibilityRequestingNoSoftKeyboard || mImeHiddenByDisplayPolicy) {
|
||||
ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
|
||||
return false;
|
||||
}
|
||||
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
|
||||
|
||||
if ((flags & InputMethodManager.SHOW_FORCED) != 0) {
|
||||
mShowExplicitlyRequested = true;
|
||||
mShowForced = true;
|
||||
} else if ((flags & InputMethodManager.SHOW_IMPLICIT) == 0) {
|
||||
mShowExplicitlyRequested = true;
|
||||
if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mSystemReady) {
|
||||
@@ -3439,39 +3383,25 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
}
|
||||
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
|
||||
|
||||
mVisibilityStateComputer.requestImeVisibility(windowToken, true);
|
||||
|
||||
// Ensure binding the connection when IME is going to show.
|
||||
mBindingController.setCurrentMethodVisible();
|
||||
final IInputMethodInvoker curMethod = getCurMethodLocked();
|
||||
ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
|
||||
if (curMethod != null) {
|
||||
// create a placeholder token for IMS so that IMS cannot inject windows into client app.
|
||||
Binder showInputToken = new Binder();
|
||||
mShowRequestWindowMap.put(showInputToken, windowToken);
|
||||
ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
|
||||
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HAS_IME);
|
||||
mCurStatsToken = null;
|
||||
final int showFlags = getImeShowFlagsLocked();
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Calling " + curMethod + ".showSoftInput(" + showInputToken
|
||||
+ ", " + showFlags + ", " + resultReceiver + ") for reason: "
|
||||
+ InputMethodDebug.softInputDisplayReasonToString(reason));
|
||||
}
|
||||
|
||||
if (lastClickToolType != MotionEvent.TOOL_TYPE_UNKNOWN) {
|
||||
curMethod.updateEditorToolType(lastClickToolType);
|
||||
}
|
||||
// TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
|
||||
if (curMethod.showSoftInput(showInputToken, statsToken, showFlags, resultReceiver)) {
|
||||
if (DEBUG_IME_VISIBILITY) {
|
||||
EventLog.writeEvent(IMF_SHOW_IME, statsToken.getTag(),
|
||||
Objects.toString(mCurFocusedWindow),
|
||||
InputMethodDebug.softInputDisplayReasonToString(reason),
|
||||
InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode));
|
||||
}
|
||||
onShowHideSoftInputRequested(true /* show */, windowToken, reason, statsToken);
|
||||
}
|
||||
mVisibilityApplier.performShowIme(windowToken, statsToken,
|
||||
mVisibilityStateComputer.getImeShowFlags(), resultReceiver, reason);
|
||||
// TODO(b/246309664): make mInputShown tracked by the Ime visibility computer.
|
||||
mInputShown = true;
|
||||
return true;
|
||||
} else {
|
||||
ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
|
||||
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
|
||||
mCurStatsToken = statsToken;
|
||||
}
|
||||
@@ -3527,20 +3457,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
ImeTracker.ORIGIN_SERVER_HIDE_INPUT, reason);
|
||||
}
|
||||
|
||||
if ((flags & InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
|
||||
&& (mShowExplicitlyRequested || mShowForced)) {
|
||||
if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
|
||||
ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
|
||||
if (!mVisibilityStateComputer.canHideIme(statsToken, flags)) {
|
||||
return false;
|
||||
}
|
||||
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
|
||||
|
||||
if (mShowForced && (flags & InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
|
||||
if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
|
||||
ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
|
||||
return false;
|
||||
}
|
||||
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
|
||||
|
||||
// There is a chance that IMM#hideSoftInput() is called in a transient state where
|
||||
// IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
|
||||
@@ -3549,49 +3468,30 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
// application process as a valid request, and have even promised such a behavior with CTS
|
||||
// since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
|
||||
// IMMS#InputShown indicates that the software keyboard is shown.
|
||||
// TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
|
||||
// TODO(b/246309664): Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
|
||||
IInputMethodInvoker curMethod = getCurMethodLocked();
|
||||
final boolean shouldHideSoftInput = (curMethod != null)
|
||||
&& (mInputShown || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
|
||||
boolean res;
|
||||
|
||||
mVisibilityStateComputer.requestImeVisibility(windowToken, false);
|
||||
if (shouldHideSoftInput) {
|
||||
final Binder hideInputToken = new Binder();
|
||||
mHideRequestWindowMap.put(hideInputToken, windowToken);
|
||||
// The IME will report its visible state again after the following message finally
|
||||
// delivered to the IME process as an IPC. Hence the inconsistency between
|
||||
// IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
|
||||
// the final state.
|
||||
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Calling " + curMethod + ".hideSoftInput(0, " + hideInputToken
|
||||
+ ", " + resultReceiver + ") for reason: "
|
||||
+ InputMethodDebug.softInputDisplayReasonToString(reason));
|
||||
}
|
||||
// TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
|
||||
if (curMethod.hideSoftInput(hideInputToken, statsToken, 0 /* flags */,
|
||||
resultReceiver)) {
|
||||
if (DEBUG_IME_VISIBILITY) {
|
||||
EventLog.writeEvent(IMF_HIDE_IME, statsToken.getTag(),
|
||||
Objects.toString(mCurFocusedWindow),
|
||||
InputMethodDebug.softInputDisplayReasonToString(reason),
|
||||
InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode));
|
||||
}
|
||||
onShowHideSoftInputRequested(false /* show */, windowToken, reason, statsToken);
|
||||
}
|
||||
res = true;
|
||||
mVisibilityApplier.performHideIme(windowToken, statsToken, resultReceiver, reason);
|
||||
} else {
|
||||
ImeTracker.get().onCancelled(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
|
||||
res = false;
|
||||
}
|
||||
mBindingController.setCurrentMethodNotVisible();
|
||||
mVisibilityStateComputer.clearImeShowFlags();
|
||||
mInputShown = false;
|
||||
mShowRequested = false;
|
||||
mShowExplicitlyRequested = false;
|
||||
mShowForced = false;
|
||||
// Cancel existing statsToken for show IME as we got a hide request.
|
||||
ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
|
||||
mCurStatsToken = null;
|
||||
return res;
|
||||
return shouldHideSoftInput;
|
||||
}
|
||||
|
||||
private boolean isImeClientFocused(IBinder windowToken, ClientState cs) {
|
||||
@@ -3738,8 +3638,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
// In case mShowForced flag affects the next client to keep IME visible, when the current
|
||||
// client is leaving due to the next focused client, we clear mShowForced flag when the
|
||||
// next client's targetSdkVersion is T or higher.
|
||||
if (mCurFocusedWindow != windowToken && mShowForced && shouldClearFlag) {
|
||||
mShowForced = false;
|
||||
final boolean showForced = mVisibilityStateComputer.mShowForced;
|
||||
if (mCurFocusedWindow != windowToken && showForced && shouldClearFlag) {
|
||||
mVisibilityStateComputer.mShowForced = false;
|
||||
}
|
||||
|
||||
// cross-profile access is always allowed here to allow profile-switching.
|
||||
@@ -3763,6 +3664,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
final boolean startInputByWinGainedFocus =
|
||||
(startInputFlags & StartInputFlags.WINDOW_GAINED_FOCUS) != 0;
|
||||
|
||||
// Init the focused window state (e.g. whether the editor has focused or IME focus has
|
||||
// changed from another window).
|
||||
final ImeTargetWindowState windowState = new ImeTargetWindowState(
|
||||
softInputMode, !sameWindowFocused, isTextEditor);
|
||||
mVisibilityStateComputer.setWindowState(windowToken, windowState);
|
||||
|
||||
if (sameWindowFocused && isTextEditor) {
|
||||
if (DEBUG) {
|
||||
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
|
||||
@@ -3812,7 +3719,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
// Because the app might leverage these flags to hide soft-keyboard with showing their own
|
||||
// UI for input.
|
||||
if (isTextEditor && editorInfo != null
|
||||
&& shouldRestoreImeVisibility(windowToken, softInputMode)) {
|
||||
&& mVisibilityStateComputer.shouldRestoreImeVisibility(windowState)) {
|
||||
if (DEBUG) Slog.v(TAG, "Will show input to restore visibility");
|
||||
res = startInputUncheckedLocked(cs, inputContext, remoteAccessibilityInputConnection,
|
||||
editorInfo, startInputFlags, startInputReason, unverifiedTargetSdkVersion,
|
||||
@@ -4001,19 +3908,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean shouldRestoreImeVisibility(IBinder windowToken,
|
||||
@SoftInputModeFlags int softInputMode) {
|
||||
switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
|
||||
case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
|
||||
return false;
|
||||
case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
|
||||
if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return mWindowManagerInternal.shouldRestoreImeVisibility(windowToken);
|
||||
}
|
||||
|
||||
@GuardedBy("ImfLock.class")
|
||||
private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
|
||||
final int uid = Binder.getCallingUid();
|
||||
@@ -4746,8 +4640,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
}
|
||||
proto.write(CUR_ID, getCurIdLocked());
|
||||
proto.write(SHOW_REQUESTED, mShowRequested);
|
||||
proto.write(SHOW_EXPLICITLY_REQUESTED, mShowExplicitlyRequested);
|
||||
proto.write(SHOW_FORCED, mShowForced);
|
||||
mVisibilityStateComputer.dumpDebug(proto, fieldId);
|
||||
proto.write(INPUT_SHOWN, mInputShown);
|
||||
proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
|
||||
proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked()));
|
||||
@@ -4760,8 +4653,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
proto.write(BACK_DISPOSITION, mBackDisposition);
|
||||
proto.write(IME_WINDOW_VISIBILITY, mImeWindowVis);
|
||||
proto.write(SHOW_IME_WITH_HARD_KEYBOARD, mMenuController.getShowImeWithHardKeyboard());
|
||||
proto.write(ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD,
|
||||
mAccessibilityRequestingNoSoftKeyboard);
|
||||
proto.end(token);
|
||||
}
|
||||
}
|
||||
@@ -4795,25 +4686,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
|
||||
return;
|
||||
}
|
||||
if (!setVisible) {
|
||||
if (mCurClient != null) {
|
||||
ImeTracker.get().onProgress(statsToken,
|
||||
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
|
||||
|
||||
mWindowManagerInternal.hideIme(
|
||||
mHideRequestWindowMap.get(windowToken),
|
||||
mCurClient.mSelfReportedDisplayId, statsToken);
|
||||
} else {
|
||||
ImeTracker.get().onFailed(statsToken,
|
||||
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
|
||||
}
|
||||
} else {
|
||||
ImeTracker.get().onProgress(statsToken,
|
||||
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
|
||||
// Send to window manager to show IME after IME layout finishes.
|
||||
mWindowManagerInternal.showImePostLayout(mShowRequestWindowMap.get(windowToken),
|
||||
statsToken);
|
||||
}
|
||||
final IBinder requestToken = mVisibilityStateComputer.getWindowTokenFrom(windowToken);
|
||||
mVisibilityApplier.applyImeVisibility(requestToken, statsToken,
|
||||
setVisible ? ImeVisibilityStateComputer.STATE_SHOW_IME
|
||||
: ImeVisibilityStateComputer.STATE_HIDE_IME);
|
||||
}
|
||||
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
|
||||
}
|
||||
@@ -4857,7 +4733,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
|
||||
/** Called right after {@link com.android.internal.inputmethod.IInputMethod#showSoftInput}. */
|
||||
@GuardedBy("ImfLock.class")
|
||||
private void onShowHideSoftInputRequested(boolean show, IBinder requestToken,
|
||||
void onShowHideSoftInputRequested(boolean show, IBinder requestToken,
|
||||
@SoftInputShowHideReason int reason, @Nullable ImeTracker.Token statsToken) {
|
||||
final WindowManagerInternal.ImeTargetInfo info =
|
||||
mWindowManagerInternal.onToggleImeRequested(
|
||||
@@ -5988,14 +5864,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
|
||||
method = getCurMethodLocked();
|
||||
p.println(" mCurMethod=" + getCurMethodLocked());
|
||||
p.println(" mEnabledSession=" + mEnabledSession);
|
||||
p.println(" mShowRequested=" + mShowRequested
|
||||
+ " mShowExplicitlyRequested=" + mShowExplicitlyRequested
|
||||
+ " mShowForced=" + mShowForced
|
||||
+ " mInputShown=" + mInputShown);
|
||||
p.println(" mShowRequested=" + mShowRequested + " mInputShown=" + mInputShown);
|
||||
mVisibilityStateComputer.dump(pw);
|
||||
p.println(" mInFullscreenMode=" + mInFullscreenMode);
|
||||
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
|
||||
p.println(" mSettingsObserver=" + mSettingsObserver);
|
||||
p.println(" mImeHiddenByDisplayPolicy=" + mImeHiddenByDisplayPolicy);
|
||||
p.println(" mStylusIds=" + (mStylusIds != null
|
||||
? Arrays.toString(mStylusIds.toArray()) : ""));
|
||||
p.println(" mSwitchingController:");
|
||||
|
||||
Reference in New Issue
Block a user