Clean up ImeVisibilityApplier#perform{show, hide}Ime

To solve a ping-ponging between the computer state and the applier
that the ideal flow should as below to apply IME visiblity directly
rather than backing to computer to set another state (i.e. In applier,
setting show or hide input token to the computer):

(app window) -> Computer -> Applier -> (IME)

Fix: 246309664
Test: atest CtsInputMethodTestCases
Test: atest DefaultImeVisibilityApplierTest
Change-Id: I448bbb6770dcb8983ffd62979f64ced3b6c368d4
This commit is contained in:
Ming-Shin Lu
2023-01-30 16:28:45 +00:00
parent c6a55488cc
commit 10ba1119c7
5 changed files with 21 additions and 33 deletions

View File

@@ -27,7 +27,6 @@ import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SH
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT;
import android.annotation.Nullable;
import android.os.Binder;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.util.EventLog;
@@ -65,13 +64,10 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
@GuardedBy("ImfLock.class")
@Override
public void performShowIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
public void performShowIme(IBinder showInputToken, @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: "
@@ -86,7 +82,7 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
InputMethodDebug.softInputModeToString(
mService.mCurFocusedWindowSoftInputMode));
}
mService.onShowHideSoftInputRequested(true /* show */, windowToken, reason,
mService.onShowHideSoftInputRequested(true /* show */, showInputToken, reason,
statsToken);
}
}
@@ -94,12 +90,10 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
@GuardedBy("ImfLock.class")
@Override
public void performHideIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
public void performHideIme(IBinder hideInputToken, @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
@@ -118,7 +112,7 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
InputMethodDebug.softInputModeToString(
mService.mCurFocusedWindowSoftInputMode));
}
mService.onShowHideSoftInputRequested(false /* show */, windowToken, reason,
mService.onShowHideSoftInputRequested(false /* show */, hideInputToken, reason,
statsToken);
}
}

View File

@@ -31,26 +31,26 @@ interface ImeVisibilityApplier {
/**
* Performs showing IME on top of the given window.
*
* @param windowToken The token of a window that currently has focus.
* @param showInputToken A token that represents the requester to show IME.
* @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,
default void performShowIme(IBinder showInputToken, @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 hideInputToken A token that represents the requester to hide IME.
* @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,
default void performHideIme(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}
/**

View File

@@ -35,6 +35,7 @@ import android.accessibilityservice.AccessibilityService;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.IBinder;
import android.util.PrintWriterPrinter;
import android.util.Printer;
@@ -263,6 +264,8 @@ public final class ImeVisibilityStateComputer {
// policy.
mPolicy.mPendingA11yRequestingHideKeyboard = false;
}
// create a placeholder token for IMS so that IMS cannot inject windows into client app.
state.setRequestImeToken(new Binder());
setWindowStateInner(windowToken, state);
}
@@ -279,14 +282,6 @@ public final class ImeVisibilityStateComputer {
return state;
}
void setRequestImeTokenToWindow(IBinder windowToken, IBinder token) {
ImeTargetWindowState state = getWindowStateOrNull(windowToken);
if (state != null) {
state.setRequestImeToken(token);
setWindowStateInner(windowToken, state);
}
}
void setWindowState(IBinder windowToken, @NonNull ImeTargetWindowState newState) {
final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
if (state != null && newState.hasEdiorFocused()) {

View File

@@ -3344,11 +3344,6 @@ 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) {
@@ -4603,10 +4598,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
}
/** Called right after {@link com.android.internal.inputmethod.IInputMethod#showSoftInput}. */
/**
* Called right after {@link IInputMethod#showSoftInput} or {@link IInputMethod#hideSoftInput}.
*/
@GuardedBy("ImfLock.class")
void onShowHideSoftInputRequested(boolean show, IBinder requestToken,
void onShowHideSoftInputRequested(boolean show, IBinder requestImeToken,
@SoftInputShowHideReason int reason, @Nullable ImeTracker.Token statsToken) {
final IBinder requestToken = mVisibilityStateComputer.getWindowTokenFrom(requestImeToken);
final WindowManagerInternal.ImeTargetInfo info =
mWindowManagerInternal.onToggleImeRequested(
show, mCurFocusedWindow, requestToken, mCurTokenDisplayId);

View File

@@ -34,6 +34,7 @@ import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.os.Binder;
import android.os.RemoteException;
import android.view.inputmethod.InputMethodManager;
@@ -66,8 +67,8 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
@Test
public void testPerformShowIme() throws Exception {
synchronized (ImfLock.class) {
mVisibilityApplier.performShowIme(mWindowToken, null /* statsToken */,
InputMethodManager.SHOW_IMPLICIT, null, SHOW_SOFT_INPUT);
mVisibilityApplier.performShowIme(new Binder() /* showInputToken */,
null /* statsToken */, InputMethodManager.SHOW_IMPLICIT, null, SHOW_SOFT_INPUT);
}
verifyShowSoftInput(false, true, InputMethodManager.SHOW_IMPLICIT);
}
@@ -75,8 +76,8 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
@Test
public void testPerformHideIme() throws Exception {
synchronized (ImfLock.class) {
mVisibilityApplier.performHideIme(mWindowToken, null /* statsToken */, null,
HIDE_SOFT_INPUT);
mVisibilityApplier.performHideIme(new Binder() /* hideInputToken */,
null /* statsToken */, null, HIDE_SOFT_INPUT);
}
verifyHideSoftInput(false, true);
}