summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Cosmin Băieș <cosminbaies@google.com> 2023-07-12 14:45:40 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-07-12 14:45:40 +0000
commit38df3d2ed842ed21069a542fe4e9ec91f42119fc (patch)
tree692c0c26e236621bc190c38048f4692e4926020d
parent04922bdd34c8e84c3d5dd2045f2cec7a9c6f53fd (diff)
parentfed109a5eeab5efafc42800d7a7fae8c5bdab438 (diff)
Merge "Fix SHOW_IMPLICIT and SHOW_EXPLICIT handling" into udc-qpr-dev
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java2
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java43
-rw-r--r--core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java6
-rw-r--r--core/java/android/view/inputmethod/InputMethod.java25
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java71
-rw-r--r--core/java/android/view/inputmethod/InputMethodSession.java9
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java13
-rw-r--r--services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java4
-rw-r--r--services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java5
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java5
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java46
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java36
-rw-r--r--services/tests/InputMethodSystemServerTests/AndroidManifest.xml1
-rw-r--r--services/tests/InputMethodSystemServerTests/TEST_MAPPING11
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml2
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java484
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java7
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java30
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodBindingControllerTest.java6
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp2
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml2
21 files changed, 594 insertions, 216 deletions
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 70b72c809524..b99996ff83c8 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -433,7 +433,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
@BinderThread
@Override
public void showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
- int flags, ResultReceiver resultReceiver) {
+ @InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_SHOW_SOFT_INPUT,
flags, showInputToken, resultReceiver, statsToken));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index a9c4818393a8..e1d2c32fe101 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -607,6 +607,7 @@ public class InputMethodService extends AbstractInputMethodService {
InputConnection mStartedInputConnection;
EditorInfo mInputEditorInfo;
+ @InputMethod.ShowFlags
int mShowInputFlags;
boolean mShowInputRequested;
boolean mLastShowInputRequested;
@@ -931,8 +932,9 @@ public class InputMethodService extends AbstractInputMethodService {
*/
@MainThread
@Override
- public void showSoftInputWithToken(int flags, ResultReceiver resultReceiver,
- IBinder showInputToken, @Nullable ImeTracker.Token statsToken) {
+ public void showSoftInputWithToken(@InputMethod.ShowFlags int flags,
+ ResultReceiver resultReceiver, IBinder showInputToken,
+ @Nullable ImeTracker.Token statsToken) {
mSystemCallingShowSoftInput = true;
mCurShowInputToken = showInputToken;
mCurStatsToken = statsToken;
@@ -950,7 +952,7 @@ public class InputMethodService extends AbstractInputMethodService {
*/
@MainThread
@Override
- public void showSoftInput(int flags, ResultReceiver resultReceiver) {
+ public void showSoftInput(@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
ImeTracker.forLogging().onProgress(
mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
if (DEBUG) Log.v(TAG, "showSoftInput()");
@@ -1321,7 +1323,8 @@ public class InputMethodService extends AbstractInputMethodService {
* InputMethodService#requestShowSelf} or {@link InputMethodService#requestHideSelf}
*/
@Deprecated
- public void toggleSoftInput(int showFlags, int hideFlags) {
+ public void toggleSoftInput(@InputMethodManager.ShowFlags int showFlags,
+ @InputMethodManager.HideFlags int hideFlags) {
InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
}
@@ -2793,18 +2796,16 @@ public class InputMethodService extends AbstractInputMethodService {
* {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()},
* and the current configuration to decide whether the input view should
* be shown at this point.
- *
- * @param flags Provides additional information about the show request,
- * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
+ *
* @param configChange This is true if we are re-showing due to a
* configuration change.
* @return Returns true to indicate that the window should be shown.
*/
- public boolean onShowInputRequested(int flags, boolean configChange) {
+ public boolean onShowInputRequested(@InputMethod.ShowFlags int flags, boolean configChange) {
if (!onEvaluateInputViewShown()) {
return false;
}
- if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
+ if ((flags & InputMethod.SHOW_EXPLICIT) == 0) {
if (!configChange && onEvaluateFullscreenMode() && !isInputViewShown()) {
// Don't show if this is not explicitly requested by the user and
// the input method is fullscreen unless it is already shown. That
@@ -2830,14 +2831,14 @@ public class InputMethodService extends AbstractInputMethodService {
* exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
* to have this method to ensure that those internal states are always updated no matter how
* {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
- * @param flags Provides additional information about the show request,
- * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
+ *
* @param configChange This is true if we are re-showing due to a
* configuration change.
* @return Returns true to indicate that the window should be shown.
* @see #onShowInputRequested(int, boolean)
*/
- private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
+ private boolean dispatchOnShowInputRequested(@InputMethod.ShowFlags int flags,
+ boolean configChange) {
final boolean result = onShowInputRequested(flags, configChange);
mInlineSuggestionSessionController.notifyOnShowInputRequested(result);
if (result) {
@@ -3270,16 +3271,13 @@ public class InputMethodService extends AbstractInputMethodService {
*
* The input method will continue running, but the user can no longer use it to generate input
* by touching the screen.
- *
- * @see InputMethodManager#HIDE_IMPLICIT_ONLY
- * @see InputMethodManager#HIDE_NOT_ALWAYS
- * @param flags Provides additional operating flags.
*/
- public void requestHideSelf(int flags) {
+ public void requestHideSelf(@InputMethodManager.HideFlags int flags) {
requestHideSelf(flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME);
}
- private void requestHideSelf(int flags, @SoftInputShowHideReason int reason) {
+ private void requestHideSelf(@InputMethodManager.HideFlags int flags,
+ @SoftInputShowHideReason int reason) {
ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper,
null /* icProto */);
mPrivOps.hideMySoftInput(flags, reason);
@@ -3288,12 +3286,8 @@ public class InputMethodService extends AbstractInputMethodService {
/**
* Show the input method's soft input area, so the user sees the input method window and can
* interact with it.
- *
- * @see InputMethodManager#SHOW_IMPLICIT
- * @see InputMethodManager#SHOW_FORCED
- * @param flags Provides additional operating flags.
*/
- public final void requestShowSelf(int flags) {
+ public final void requestShowSelf(@InputMethodManager.ShowFlags int flags) {
ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper,
null /* icProto */);
mPrivOps.showMySoftInput(flags);
@@ -3453,7 +3447,8 @@ public class InputMethodService extends AbstractInputMethodService {
/**
* Handle a request by the system to toggle the soft input area.
*/
- private void onToggleSoftInput(int showFlags, int hideFlags) {
+ private void onToggleSoftInput(@InputMethodManager.ShowFlags int showFlags,
+ @InputMethodManager.HideFlags int hideFlags) {
if (DEBUG) Log.v(TAG, "toggleSoftInput()");
if (isInputViewShown()) {
requestHideSelf(
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index ce2c18080b91..467daa028afd 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -295,8 +295,8 @@ final class IInputMethodManagerGlobalInvoker {
@AnyThread
static boolean showSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, int flags, int lastClickToolType,
- @Nullable ResultReceiver resultReceiver,
+ @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+ int lastClickToolType, @Nullable ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -312,7 +312,7 @@ final class IInputMethodManagerGlobalInvoker {
@AnyThread
static boolean hideSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, int flags,
+ @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
@Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
final IInputMethodManager service = getService();
if (service == null) {
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 92380ed7a7bc..9340f46b257f 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -17,6 +17,7 @@
package android.view.inputmethod;
import android.annotation.DurationMillisLong;
+import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,6 +37,8 @@ import com.android.internal.inputmethod.IInputMethod;
import com.android.internal.inputmethod.InlineSuggestionsRequestInfo;
import com.android.internal.inputmethod.InputMethodNavButtonFlags;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -269,6 +272,14 @@ public interface InputMethod {
*/
@MainThread
public void revokeSession(InputMethodSession session);
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "SHOW_" }, value = {
+ SHOW_EXPLICIT,
+ SHOW_FORCED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ShowFlags {}
/**
* Flag for {@link #showSoftInput}: this show has been explicitly
@@ -288,8 +299,6 @@ public interface InputMethod {
/**
* Request that any soft input part of the input method be shown to the user.
*
- * @param flags Provides additional information about the show request.
- * Currently may be 0 or have the bit {@link #SHOW_EXPLICIT} set.
* @param resultReceiver The client requesting the show may wish to
* be told the impact of their request, which should be supplied here.
* The result code should be
@@ -304,7 +313,7 @@ public interface InputMethod {
* @hide
*/
@MainThread
- public default void showSoftInputWithToken(int flags, ResultReceiver resultReceiver,
+ public default void showSoftInputWithToken(@ShowFlags int flags, ResultReceiver resultReceiver,
IBinder showInputToken, @Nullable ImeTracker.Token statsToken) {
showSoftInput(flags, resultReceiver);
}
@@ -312,8 +321,6 @@ public interface InputMethod {
/**
* Request that any soft input part of the input method be shown to the user.
*
- * @param flags Provides additional information about the show request.
- * Currently may be 0 or have the bit {@link #SHOW_EXPLICIT} set.
* @param resultReceiver The client requesting the show may wish to
* be told the impact of their request, which should be supplied here.
* The result code should be
@@ -323,11 +330,12 @@ public interface InputMethod {
* {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}.
*/
@MainThread
- public void showSoftInput(int flags, ResultReceiver resultReceiver);
+ public void showSoftInput(@ShowFlags int flags, ResultReceiver resultReceiver);
/**
* Request that any soft input part of the input method be hidden from the user.
- * @param flags Provides additional information about the show request.
+ *
+ * @param flags Provides additional information about the hide request.
* Currently always 0.
* @param resultReceiver The client requesting the show may wish to
* be told the impact of their request, which should be supplied here.
@@ -350,7 +358,8 @@ public interface InputMethod {
/**
* Request that any soft input part of the input method be hidden from the user.
- * @param flags Provides additional information about the show request.
+ *
+ * @param flags Provides additional information about the hide request.
* Currently always 0.
* @param resultReceiver The client requesting the show may wish to
* be told the impact of their request, which should be supplied here.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3f308e6fccee..52b7d1d41727 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -39,6 +39,7 @@ import android.Manifest;
import android.annotation.DisplayContext;
import android.annotation.DrawableRes;
import android.annotation.DurationMillisLong;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
@@ -121,6 +122,8 @@ import com.android.internal.view.IInputMethodManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
@@ -2004,6 +2007,14 @@ public final class InputMethodManager {
}
}
+ /** @hide */
+ @IntDef(flag = true, prefix = { "SHOW_" }, value = {
+ SHOW_IMPLICIT,
+ SHOW_FORCED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ShowFlags {}
+
/**
* Flag for {@link #showSoftInput} to indicate that this is an implicit
* request to show the input window, not as the result of a direct request
@@ -2035,10 +2046,8 @@ public final class InputMethodManager {
* {@link View#isFocused view focus}, and its containing window has
* {@link View#hasWindowFocus window focus}. Otherwise the call fails and
* returns {@code false}.
- * @param flags Provides additional operating flags. Currently may be
- * 0 or have the {@link #SHOW_IMPLICIT} bit set.
*/
- public boolean showSoftInput(View view, int flags) {
+ public boolean showSoftInput(View view, @ShowFlags int flags) {
// Re-dispatch if there is a context mismatch.
final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
if (fallbackImm != null) {
@@ -2101,21 +2110,20 @@ public final class InputMethodManager {
* {@link View#isFocused view focus}, and its containing window has
* {@link View#hasWindowFocus window focus}. Otherwise the call fails and
* returns {@code false}.
- * @param flags Provides additional operating flags. Currently may be
- * 0 or have the {@link #SHOW_IMPLICIT} bit set.
* @param resultReceiver If non-null, this will be called by the IME when
* it has processed your request to tell you what it has done. The result
* code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
* {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
* {@link #RESULT_HIDDEN}.
*/
- public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
+ public boolean showSoftInput(View view, @ShowFlags int flags, ResultReceiver resultReceiver) {
return showSoftInput(view, null /* statsToken */, flags, resultReceiver,
SoftInputShowHideReason.SHOW_SOFT_INPUT);
}
- private boolean showSoftInput(View view, @Nullable ImeTracker.Token statsToken, int flags,
- ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+ private boolean showSoftInput(View view, @Nullable ImeTracker.Token statsToken,
+ @ShowFlags int flags, ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason) {
if (statsToken == null) {
statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, reason);
@@ -2169,7 +2177,7 @@ public final class InputMethodManager {
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
- public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
+ public void showSoftInputUnchecked(@ShowFlags int flags, ResultReceiver resultReceiver) {
synchronized (mH) {
final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestShow(
null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
@@ -2200,6 +2208,14 @@ public final class InputMethodManager {
}
}
+ /** @hide */
+ @IntDef(flag = true, prefix = { "HIDE_" }, value = {
+ HIDE_IMPLICIT_ONLY,
+ HIDE_NOT_ALWAYS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HideFlags {}
+
/**
* Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestHideSelf(int)}
* to indicate that the soft input window should only be hidden if it was not explicitly shown
@@ -2221,10 +2237,8 @@ public final class InputMethodManager {
*
* @param windowToken The token of the window that is making the request,
* as returned by {@link View#getWindowToken() View.getWindowToken()}.
- * @param flags Provides additional operating flags. Currently may be
- * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
*/
- public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) {
+ public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags) {
return hideSoftInputFromWindow(windowToken, flags, null);
}
@@ -2246,21 +2260,19 @@ public final class InputMethodManager {
*
* @param windowToken The token of the window that is making the request,
* as returned by {@link View#getWindowToken() View.getWindowToken()}.
- * @param flags Provides additional operating flags. Currently may be
- * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
* @param resultReceiver If non-null, this will be called by the IME when
* it has processed your request to tell you what it has done. The result
* code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
* {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
* {@link #RESULT_HIDDEN}.
*/
- public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
+ public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags,
ResultReceiver resultReceiver) {
return hideSoftInputFromWindow(windowToken, flags, resultReceiver,
SoftInputShowHideReason.HIDE_SOFT_INPUT);
}
- private boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
+ private boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
null /* component */, Process.myUid(),
@@ -2463,12 +2475,6 @@ public final class InputMethodManager {
* If not the input window will be displayed.
* @param windowToken The token of the window that is making the request,
* as returned by {@link View#getWindowToken() View.getWindowToken()}.
- * @param showFlags Provides additional operating flags. May be
- * 0 or have the {@link #SHOW_IMPLICIT},
- * {@link #SHOW_FORCED} bit set.
- * @param hideFlags Provides additional operating flags. May be
- * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
- * {@link #HIDE_NOT_ALWAYS} bit set.
*
* @deprecated Use {@link #showSoftInput(View, int)} or
* {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead.
@@ -2477,7 +2483,8 @@ public final class InputMethodManager {
* has an effect if the calling app is the current IME focus.
*/
@Deprecated
- public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
+ public void toggleSoftInputFromWindow(IBinder windowToken, @ShowFlags int showFlags,
+ @HideFlags int hideFlags) {
ImeTracing.getInstance().triggerClientDump(
"InputMethodManager#toggleSoftInputFromWindow", InputMethodManager.this,
null /* icProto */);
@@ -2495,12 +2502,6 @@ public final class InputMethodManager {
*
* If the input window is already displayed, it gets hidden.
* If not the input window will be displayed.
- * @param showFlags Provides additional operating flags. May be
- * 0 or have the {@link #SHOW_IMPLICIT},
- * {@link #SHOW_FORCED} bit set.
- * @param hideFlags Provides additional operating flags. May be
- * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
- * {@link #HIDE_NOT_ALWAYS} bit set.
*
* @deprecated Use {@link #showSoftInput(View, int)} or
* {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead.
@@ -2509,7 +2510,7 @@ public final class InputMethodManager {
* has an effect if the calling app is the current IME focus.
*/
@Deprecated
- public void toggleSoftInput(int showFlags, int hideFlags) {
+ public void toggleSoftInput(@ShowFlags int showFlags, @HideFlags int hideFlags) {
ImeTracing.getInstance().triggerClientDump(
"InputMethodManager#toggleSoftInput", InputMethodManager.this,
null /* icProto */);
@@ -3522,15 +3523,12 @@ public final class InputMethodManager {
* @param token Supplies the identifying token given to an input method
* when it was started, which allows it to perform this operation on
* itself.
- * @param flags Provides additional operating flags. Currently may be
- * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
- * {@link #HIDE_NOT_ALWAYS} bit set.
* @deprecated Use {@link InputMethodService#requestHideSelf(int)} instead. This method was
* intended for IME developers who should be accessing APIs through the service. APIs in this
* class are intended for app developers interacting with the IME.
*/
@Deprecated
- public void hideSoftInputFromInputMethod(IBinder token, int flags) {
+ public void hideSoftInputFromInputMethod(IBinder token, @HideFlags int flags) {
InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(
flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION);
}
@@ -3544,15 +3542,12 @@ public final class InputMethodManager {
* @param token Supplies the identifying token given to an input method
* when it was started, which allows it to perform this operation on
* itself.
- * @param flags Provides additional operating flags. Currently may be
- * 0 or have the {@link #SHOW_IMPLICIT} or
- * {@link #SHOW_FORCED} bit set.
* @deprecated Use {@link InputMethodService#requestShowSelf(int)} instead. This method was
* intended for IME developers who should be accessing APIs through the service. APIs in this
* class are intended for app developers interacting with the IME.
*/
@Deprecated
- public void showSoftInputFromInputMethod(IBinder token, int flags) {
+ public void showSoftInputFromInputMethod(IBinder token, @ShowFlags int flags) {
InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(flags);
}
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index af6af14472db..4f48cb684e8c 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -169,12 +169,6 @@ public interface InputMethodSession {
/**
* Toggle the soft input window.
* Applications can toggle the state of the soft input window.
- * @param showFlags Provides additional operating flags. May be
- * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT},
- * {@link InputMethodManager#SHOW_FORCED} bit set.
- * @param hideFlags Provides additional operating flags. May be
- * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY},
- * {@link InputMethodManager#HIDE_NOT_ALWAYS} bit set.
*
* @deprecated Starting in {@link android.os.Build.VERSION_CODES#S} the system no longer invokes
* this method, instead it explicitly shows or hides the IME. An {@code InputMethodService}
@@ -182,7 +176,8 @@ public interface InputMethodSession {
* InputMethodService#requestShowSelf} or {@link InputMethodService#requestHideSelf}
*/
@Deprecated
- public void toggleSoftInput(int showFlags, int hideFlags);
+ public void toggleSoftInput(@InputMethodManager.ShowFlags int showFlags,
+ @InputMethodManager.HideFlags int hideFlags);
/**
* This method is called when the cursor and/or the character position relevant to text input
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 66e3333acf7c..8a5c7ef18621 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -26,6 +26,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.ImeTracker;
+import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
@@ -253,13 +254,11 @@ public final class InputMethodPrivilegedOperations {
/**
* Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int, int, AndroidFuture)}
*
- * @param flags additional operating flags
* @param reason the reason to hide soft input
- * @see android.view.inputmethod.InputMethodManager#HIDE_IMPLICIT_ONLY
- * @see android.view.inputmethod.InputMethodManager#HIDE_NOT_ALWAYS
*/
@AnyThread
- public void hideMySoftInput(int flags, @SoftInputShowHideReason int reason) {
+ public void hideMySoftInput(@InputMethodManager.HideFlags int flags,
+ @SoftInputShowHideReason int reason) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
return;
@@ -275,13 +274,9 @@ public final class InputMethodPrivilegedOperations {
/**
* Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, AndroidFuture)}
- *
- * @param flags additional operating flags
- * @see android.view.inputmethod.InputMethodManager#SHOW_IMPLICIT
- * @see android.view.inputmethod.InputMethodManager#SHOW_FORCED
*/
@AnyThread
- public void showMySoftInput(int flags) {
+ public void showMySoftInput(@InputMethodManager.ShowFlags int flags) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
return;
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index a1b67e105dd4..f1698dd0f025 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -37,6 +37,7 @@ import android.os.ResultReceiver;
import android.util.EventLog;
import android.util.Slog;
import android.view.inputmethod.ImeTracker;
+import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.annotations.GuardedBy;
@@ -75,7 +76,8 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {
@GuardedBy("ImfLock.class")
@Override
public void performShowIme(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
- int showFlags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+ @InputMethod.ShowFlags int showFlags, ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason) {
final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
if (curMethod != null) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index c53f1a52306d..b12a816738da 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -30,6 +30,7 @@ import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ImeTracker;
import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSubtype;
import android.window.ImeOnBackInvokedDispatcher;
@@ -198,8 +199,8 @@ final class IInputMethodInvoker {
// TODO(b/192412909): Convert this back to void method
@AnyThread
- boolean showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken, int flags,
- ResultReceiver resultReceiver) {
+ boolean showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
+ @InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
try {
mTarget.showSoftInput(showInputToken, statsToken, flags, resultReceiver);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
index 27f6a89a73b3..29fa36982351 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.view.inputmethod.ImeTracker;
+import android.view.inputmethod.InputMethod;
import com.android.internal.inputmethod.SoftInputShowHideReason;
@@ -34,13 +35,13 @@ interface ImeVisibilityApplier {
*
* @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 showInputToken, @Nullable ImeTracker.Token statsToken,
- int showFlags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}
+ @InputMethod.ShowFlags int showFlags, ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason) {}
/**
* Performs hiding IME to the given window
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index f012d917b05e..9ad4628596fc 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -221,17 +221,21 @@ public final class ImeVisibilityStateComputer {
/**
* 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.
+ *
+ * @param statsToken The token for tracking this show request.
+ * @return {@code true} when the show request can proceed.
*/
- boolean onImeShowFlags(@NonNull ImeTracker.Token statsToken, int showFlags) {
+ boolean onImeShowFlags(@NonNull ImeTracker.Token statsToken,
+ @InputMethodManager.ShowFlags int showFlags) {
if (mPolicy.mA11yRequestingNoSoftKeyboard || mPolicy.mImeHiddenByDisplayPolicy) {
ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
return false;
}
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
+ // We only "set" the state corresponding to the flags, as this will be reset
+ // in clearImeShowFlags during a hide request.
+ // Thus, we keep the strongest values set (e.g. an implicit show right after
+ // an explicit show will still be considered explicit, likewise for forced).
if ((showFlags & InputMethodManager.SHOW_FORCED) != 0) {
mRequestedShowExplicitly = true;
mShowForced = true;
@@ -243,12 +247,12 @@ public final class ImeVisibilityStateComputer {
/**
* 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.
+ *
+ * @param statsToken The token for tracking this hide request.
+ * @return {@code true} when the hide request can proceed.
*/
- boolean canHideIme(@NonNull ImeTracker.Token statsToken, int hideFlags) {
+ boolean canHideIme(@NonNull ImeTracker.Token statsToken,
+ @InputMethodManager.HideFlags 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");
@@ -264,13 +268,31 @@ public final class ImeVisibilityStateComputer {
return true;
}
- int getImeShowFlags() {
+ /**
+ * Returns the show flags for IME. This translates from {@link InputMethodManager.ShowFlags}
+ * to {@link InputMethod.ShowFlags}.
+ */
+ @InputMethod.ShowFlags
+ int getShowFlagsForInputMethodServiceOnly() {
int flags = 0;
if (mShowForced) {
flags |= InputMethod.SHOW_FORCED | InputMethod.SHOW_EXPLICIT;
} else if (mRequestedShowExplicitly) {
flags |= InputMethod.SHOW_EXPLICIT;
- } else {
+ }
+ return flags;
+ }
+
+ /**
+ * Returns the show flags for IMM. This translates from {@link InputMethod.ShowFlags}
+ * to {@link InputMethodManager.ShowFlags}.
+ */
+ @InputMethodManager.ShowFlags
+ int getShowFlags() {
+ int flags = 0;
+ if (mShowForced) {
+ flags |= InputMethodManager.SHOW_FORCED;
+ } else if (!mRequestedShowExplicitly) {
flags |= InputMethodManager.SHOW_IMPLICIT;
}
return flags;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 02ee96a04b1f..0bf282059066 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2462,7 +2462,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final ImeTracker.Token statsToken = mCurStatsToken;
mCurStatsToken = null;
showCurrentInputLocked(mCurFocusedWindow, statsToken,
- mVisibilityStateComputer.getImeShowFlags(),
+ mVisibilityStateComputer.getShowFlags(),
null /* resultReceiver */, SoftInputShowHideReason.ATTACH_NEW_INPUT);
}
@@ -3398,8 +3398,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public boolean showSoftInput(IInputMethodClient client, IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, int flags, int lastClickTooType,
- ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+ @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+ int lastClickTooType, ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
@@ -3572,15 +3573,17 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@GuardedBy("ImfLock.class")
boolean showCurrentInputLocked(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
- int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+ @InputMethodManager.ShowFlags int flags, ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason) {
return showCurrentInputLocked(windowToken, statsToken, flags,
MotionEvent.TOOL_TYPE_UNKNOWN, resultReceiver, reason);
}
@GuardedBy("ImfLock.class")
private boolean showCurrentInputLocked(IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, int flags, int lastClickToolType,
- ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+ @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+ int lastClickToolType, ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason) {
// Create statsToken is none exists.
if (statsToken == null) {
statsToken = createStatsTokenForFocusedClient(true /* show */,
@@ -3611,7 +3614,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
curMethod.updateEditorToolType(lastClickToolType);
}
mVisibilityApplier.performShowIme(windowToken, statsToken,
- mVisibilityStateComputer.getImeShowFlags(), resultReceiver, reason);
+ mVisibilityStateComputer.getShowFlagsForInputMethodServiceOnly(),
+ resultReceiver, reason);
mVisibilityStateComputer.setInputShown(true);
return true;
} else {
@@ -3623,8 +3627,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, int flags, ResultReceiver resultReceiver,
- @SoftInputShowHideReason int reason) {
+ @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
+ ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#hideSoftInput");
@@ -3654,7 +3658,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@GuardedBy("ImfLock.class")
boolean hideCurrentInputLocked(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
- int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+ @InputMethodManager.HideFlags int flags, ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason) {
// Create statsToken is none exists.
if (statsToken == null) {
statsToken = createStatsTokenForFocusedClient(false /* show */,
@@ -4841,7 +4846,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@BinderThread
- private void hideMySoftInput(@NonNull IBinder token, int flags,
+ private void hideMySoftInput(@NonNull IBinder token, @InputMethodManager.HideFlags int flags,
@SoftInputShowHideReason int reason) {
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
@@ -4863,7 +4868,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@BinderThread
- private void showMySoftInput(@NonNull IBinder token, int flags) {
+ private void showMySoftInput(@NonNull IBinder token, @InputMethodManager.ShowFlags int flags) {
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showMySoftInput");
synchronized (ImfLock.class) {
@@ -6822,8 +6827,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@Override
- public void hideMySoftInput(int flags, @SoftInputShowHideReason int reason,
- AndroidFuture future /* T=Void */) {
+ public void hideMySoftInput(@InputMethodManager.HideFlags int flags,
+ @SoftInputShowHideReason int reason, AndroidFuture future /* T=Void */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Void> typedFuture = future;
try {
@@ -6836,7 +6841,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@Override
- public void showMySoftInput(int flags, AndroidFuture future /* T=Void */) {
+ public void showMySoftInput(@InputMethodManager.ShowFlags int flags,
+ AndroidFuture future /* T=Void */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Void> typedFuture = future;
try {
diff --git a/services/tests/InputMethodSystemServerTests/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/AndroidManifest.xml
index 212ec14b4939..bef56cec3385 100644
--- a/services/tests/InputMethodSystemServerTests/AndroidManifest.xml
+++ b/services/tests/InputMethodSystemServerTests/AndroidManifest.xml
@@ -17,7 +17,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.inputmethodtests">
- <uses-sdk android:targetSdkVersion="31" />
<queries>
<intent>
<action android:name="android.view.InputMethod" />
diff --git a/services/tests/InputMethodSystemServerTests/TEST_MAPPING b/services/tests/InputMethodSystemServerTests/TEST_MAPPING
index 77e32a776d57..cedbfd2b2dde 100644
--- a/services/tests/InputMethodSystemServerTests/TEST_MAPPING
+++ b/services/tests/InputMethodSystemServerTests/TEST_MAPPING
@@ -9,5 +9,16 @@
{"exclude-annotation": "org.junit.Ignore"}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "FrameworksImeTests",
+ "options": [
+ {"include-filter": "com.android.inputmethodservice"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ }
]
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml
index 0104f7142bea..b7de74987eb8 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidManifest.xml
@@ -18,8 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.inputmethod.imetests">
- <uses-sdk android:targetSdkVersion="31" />
-
<!-- Permissions required for granting and logging -->
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 898658e759c0..e8acb067f625 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -20,6 +20,8 @@ import static com.android.compatibility.common.util.SystemUtil.eventually;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
import android.app.Instrumentation;
import android.content.Context;
import android.content.res.Configuration;
@@ -45,6 +47,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -56,9 +59,9 @@ public class InputMethodServiceTest {
private static final String EDIT_TEXT_DESC = "Input box";
private static final long TIMEOUT_IN_SECONDS = 3;
private static final String ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD =
- "settings put secure show_ime_with_hard_keyboard 1";
+ "settings put secure " + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD + " 1";
private static final String DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD =
- "settings put secure show_ime_with_hard_keyboard 0";
+ "settings put secure " + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD + " 0";
private Instrumentation mInstrumentation;
private UiDevice mUiDevice;
@@ -82,29 +85,19 @@ public class InputMethodServiceTest {
mUiDevice.freezeRotation();
mUiDevice.setOrientationNatural();
// Waits for input binding ready.
- eventually(
- () -> {
- mInputMethodService =
- InputMethodServiceWrapper.getInputMethodServiceWrapperForTesting();
- assertThat(mInputMethodService).isNotNull();
-
- // The editor won't bring up keyboard by default.
- assertThat(mInputMethodService.getCurrentInputStarted()).isTrue();
- assertThat(mInputMethodService.getCurrentInputViewStarted()).isFalse();
- });
- // Save the original value of show_ime_with_hard_keyboard in Settings.
+ eventually(() -> {
+ mInputMethodService =
+ InputMethodServiceWrapper.getInputMethodServiceWrapperForTesting();
+ assertThat(mInputMethodService).isNotNull();
+
+ // The editor won't bring up keyboard by default.
+ assertThat(mInputMethodService.getCurrentInputStarted()).isTrue();
+ assertThat(mInputMethodService.getCurrentInputViewStarted()).isFalse();
+ });
+ // Save the original value of show_ime_with_hard_keyboard from Settings.
mShowImeWithHardKeyboardEnabled = Settings.Secure.getInt(
mInputMethodService.getContentResolver(),
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0;
- // Disable showing Ime with hard keyboard because it is the precondition the for most test
- // cases
- if (mShowImeWithHardKeyboardEnabled) {
- executeShellCommand(DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD);
- }
- mInputMethodService.getResources().getConfiguration().keyboard =
- Configuration.KEYBOARD_NOKEYS;
- mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
- Configuration.HARDKEYBOARDHIDDEN_YES;
}
@After
@@ -112,82 +105,141 @@ public class InputMethodServiceTest {
mUiDevice.unfreezeRotation();
executeShellCommand("ime disable " + mInputMethodId);
// Change back the original value of show_ime_with_hard_keyboard in Settings.
- executeShellCommand(mShowImeWithHardKeyboardEnabled ? ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD
+ executeShellCommand(mShowImeWithHardKeyboardEnabled
+ ? ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD
: DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD);
}
+ /**
+ * This checks that the IME can be shown and hidden by user actions
+ * (i.e. tapping on an EditText, tapping the Home button).
+ */
@Test
- public void testShowHideKeyboard_byUserAction() throws InterruptedException {
+ public void testShowHideKeyboard_byUserAction() throws Exception {
+ setShowImeWithHardKeyboard(true /* enabled */);
+
// Performs click on editor box to bring up the soft keyboard.
Log.i(TAG, "Click on EditText.");
- verifyInputViewStatus(() -> clickOnEditorText(), true /* inputViewStarted */);
+ verifyInputViewStatus(
+ () -> clickOnEditorText(),
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
- // Press back key to hide soft keyboard.
- Log.i(TAG, "Press back");
+ // Press home key to hide soft keyboard.
+ Log.i(TAG, "Press home");
verifyInputViewStatus(
- () -> assertThat(mUiDevice.pressHome()).isTrue(), false /* inputViewStarted */);
+ () -> assertThat(mUiDevice.pressHome()).isTrue(),
+ true /* expected */,
+ false /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
}
+ /**
+ * This checks that the IME can be shown and hidden using the WindowInsetsController APIs.
+ */
@Test
- public void testShowHideKeyboard_byApi() throws InterruptedException {
+ public void testShowHideKeyboard_byApi() throws Exception {
+ setShowImeWithHardKeyboard(true /* enabled */);
+
// Triggers to show IME via public API.
verifyInputViewStatus(
() -> assertThat(mActivity.showImeWithWindowInsetsController()).isTrue(),
+ true /* expected */,
true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
// Triggers to hide IME via public API.
verifyInputViewStatusOnMainSync(
- () -> assertThat(mActivity.hideImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ () -> assertThat(mActivity.hideImeWithWindowInsetsController()).isTrue(),
+ true /* expected */,
false /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
}
+ /**
+ * This checks the result of calling IMS#requestShowSelf and IMS#requestHideSelf.
+ */
@Test
- public void testShowHideSelf() throws InterruptedException {
- // IME requests to show itself without any flags: expect shown.
+ public void testShowHideSelf() throws Exception {
+ setShowImeWithHardKeyboard(true /* enabled */);
+
+ // IME request to show itself without any flags, expect shown.
Log.i(TAG, "Call IMS#requestShowSelf(0)");
verifyInputViewStatusOnMainSync(
- () -> mInputMethodService.requestShowSelf(0), true /* inputViewStarted */);
+ () -> mInputMethodService.requestShowSelf(0 /* flags */),
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
- // IME requests to hide itself with flag: HIDE_IMPLICIT_ONLY, expect not hide (shown).
+ // IME request to hide itself with flag HIDE_IMPLICIT_ONLY, expect not hide (shown).
Log.i(TAG, "Call IMS#requestHideSelf(InputMethodManager.HIDE_IMPLICIT_ONLY)");
verifyInputViewStatusOnMainSync(
() -> mInputMethodService.requestHideSelf(InputMethodManager.HIDE_IMPLICIT_ONLY),
+ false /* expected */,
true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
- // IME request to hide itself without any flags: expect hidden.
+ // IME request to hide itself without any flags, expect hidden.
Log.i(TAG, "Call IMS#requestHideSelf(0)");
verifyInputViewStatusOnMainSync(
- () -> mInputMethodService.requestHideSelf(0), false /* inputViewStarted */);
+ () -> mInputMethodService.requestHideSelf(0 /* flags */),
+ true /* expected */,
+ false /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
- // IME request to show itself with flag SHOW_IMPLICIT: expect shown.
+ // IME request to show itself with flag SHOW_IMPLICIT, expect shown.
Log.i(TAG, "Call IMS#requestShowSelf(InputMethodManager.SHOW_IMPLICIT)");
verifyInputViewStatusOnMainSync(
() -> mInputMethodService.requestShowSelf(InputMethodManager.SHOW_IMPLICIT),
+ true /* expected */,
true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
- // IME request to hide itself with flag: HIDE_IMPLICIT_ONLY, expect hidden.
+ // IME request to hide itself with flag HIDE_IMPLICIT_ONLY, expect hidden.
Log.i(TAG, "Call IMS#requestHideSelf(InputMethodManager.HIDE_IMPLICIT_ONLY)");
verifyInputViewStatusOnMainSync(
() -> mInputMethodService.requestHideSelf(InputMethodManager.HIDE_IMPLICIT_ONLY),
+ true /* expected */,
false /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
}
+ /**
+ * This checks the return value of IMS#onEvaluateInputViewShown,
+ * when show_ime_with_hard_keyboard is enabled.
+ */
@Test
public void testOnEvaluateInputViewShown_showImeWithHardKeyboard() throws Exception {
- executeShellCommand(ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD);
- mInstrumentation.waitForIdleSync();
+ setShowImeWithHardKeyboard(true /* enabled */);
- // Simulate connecting a hard keyboard
mInputMethodService.getResources().getConfiguration().keyboard =
Configuration.KEYBOARD_QWERTY;
mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
Configuration.HARDKEYBOARDHIDDEN_NO;
+ eventually(() -> assertThat(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_NOKEYS;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_NO;
+ eventually(() -> assertThat(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
eventually(() -> assertThat(mInputMethodService.onEvaluateInputViewShown()).isTrue());
}
+ /**
+ * This checks the return value of IMSonEvaluateInputViewShown,
+ * when show_ime_with_hard_keyboard is disabled.
+ */
@Test
- public void testOnEvaluateInputViewShown_disableShowImeWithHardKeyboard() {
+ public void testOnEvaluateInputViewShown_disableShowImeWithHardKeyboard() throws Exception {
+ setShowImeWithHardKeyboard(false /* enabled */);
+
mInputMethodService.getResources().getConfiguration().keyboard =
Configuration.KEYBOARD_QWERTY;
mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
@@ -196,6 +248,8 @@ public class InputMethodServiceTest {
mInputMethodService.getResources().getConfiguration().keyboard =
Configuration.KEYBOARD_NOKEYS;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_NO;
eventually(() -> assertThat(mInputMethodService.onEvaluateInputViewShown()).isTrue());
mInputMethodService.getResources().getConfiguration().keyboard =
@@ -205,149 +259,386 @@ public class InputMethodServiceTest {
eventually(() -> assertThat(mInputMethodService.onEvaluateInputViewShown()).isTrue());
}
+ /**
+ * This checks that any (implicit or explicit) show request,
+ * when IMS#onEvaluateInputViewShown returns false, results in the IME not being shown.
+ */
@Test
public void testShowSoftInput_disableShowImeWithHardKeyboard() throws Exception {
- // Simulate connecting a hard keyboard
+ setShowImeWithHardKeyboard(false /* enabled */);
+
+ // Simulate connecting a hard keyboard.
mInputMethodService.getResources().getConfiguration().keyboard =
Configuration.KEYBOARD_QWERTY;
mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
Configuration.HARDKEYBOARDHIDDEN_NO;
+
// When InputMethodService#onEvaluateInputViewShown() returns false, the Ime should not be
// shown no matter what the show flag is.
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ false /* expected */,
false /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
+
verifyInputViewStatusOnMainSync(
() -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ false /* expected */,
false /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
}
+ /**
+ * This checks that an explicit show request results in the IME being shown.
+ */
@Test
public void testShowSoftInputExplicitly() throws Exception {
+ setShowImeWithHardKeyboard(true /* enabled */);
+
// When InputMethodService#onEvaluateInputViewShown() returns true and flag is EXPLICIT, the
// Ime should be shown.
verifyInputViewStatusOnMainSync(
() -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ true /* expected */,
true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
}
+ /**
+ * This checks that an implicit show request results in the IME being shown.
+ */
@Test
public void testShowSoftInputImplicitly() throws Exception {
- // When InputMethodService#onEvaluateInputViewShown() returns true and flag is IMPLICIT, the
- // Ime should be shown.
+ setShowImeWithHardKeyboard(true /* enabled */);
+
+ // When InputMethodService#onEvaluateInputViewShown() returns true and flag is IMPLICIT,
+ // the IME should be shown.
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ true /* expected */,
true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
}
+ /**
+ * This checks that an explicit show request when the IME is not previously shown,
+ * and it should be shown in fullscreen mode, results in the IME being shown.
+ */
@Test
- public void testShowSoftInputImplicitly_fullScreenMode() throws Exception {
- // When keyboard is off, InputMethodService#onEvaluateInputViewShown returns true, flag is
- // IMPLICIT and InputMethodService#onEvaluateFullScreenMode returns true, the Ime should not
- // be shown.
+ public void testShowSoftInputExplicitly_fullScreenMode() throws Exception {
+ setShowImeWithHardKeyboard(true /* enabled */);
+
+ // Set orientation landscape to enable fullscreen mode.
setOrientation(2);
eventually(() -> assertThat(mUiDevice.isNaturalOrientation()).isFalse());
- // Wait for the TestActivity to be recreated
+ // Wait for the TestActivity to be recreated.
eventually(() ->
assertThat(TestActivity.getLastCreatedInstance()).isNotEqualTo(mActivity));
- // Get the new TestActivity
+ // Get the new TestActivity.
mActivity = TestActivity.getLastCreatedInstance();
assertThat(mActivity).isNotNull();
InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
- // Wait for the new EditText to be served by InputMethodManager
+ // Wait for the new EditText to be served by InputMethodManager.
+ eventually(() -> assertThat(
+ imm.hasActiveInputConnection(mActivity.getEditText())).isTrue());
+
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+ }
+
+ /**
+ * This checks that an implicit show request when the IME is not previously shown,
+ * and it should be shown in fullscreen mode, results in the IME not being shown.
+ */
+ @Test
+ public void testShowSoftInputImplicitly_fullScreenMode() throws Exception {
+ setShowImeWithHardKeyboard(true /* enabled */);
+
+ // Set orientation landscape to enable fullscreen mode.
+ setOrientation(2);
+ eventually(() -> assertThat(mUiDevice.isNaturalOrientation()).isFalse());
+ // Wait for the TestActivity to be recreated.
eventually(() ->
- assertThat(imm.hasActiveInputConnection(mActivity.getEditText())).isTrue());
+ assertThat(TestActivity.getLastCreatedInstance()).isNotEqualTo(mActivity));
+ // Get the new TestActivity.
+ mActivity = TestActivity.getLastCreatedInstance();
+ assertThat(mActivity).isNotNull();
+ InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
+ // Wait for the new EditText to be served by InputMethodManager.
+ eventually(() -> assertThat(
+ imm.hasActiveInputConnection(mActivity.getEditText())).isTrue());
+
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ false /* expected */,
false /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
}
+ /**
+ * This checks that an explicit show request when a hard keyboard is connected,
+ * results in the IME being shown.
+ */
+ @Test
+ public void testShowSoftInputExplicitly_withHardKeyboard() throws Exception {
+ setShowImeWithHardKeyboard(false /* enabled */);
+
+ // Simulate connecting a hard keyboard.
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
+
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+ }
+
+ /**
+ * This checks that an implicit show request when a hard keyboard is connected,
+ * results in the IME not being shown.
+ */
@Test
public void testShowSoftInputImplicitly_withHardKeyboard() throws Exception {
+ setShowImeWithHardKeyboard(false /* enabled */);
+
+ // Simulate connecting a hard keyboard.
mInputMethodService.getResources().getConfiguration().keyboard =
Configuration.KEYBOARD_QWERTY;
- // When connecting to a hard keyboard and the flag is IMPLICIT, the Ime should not be shown.
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
+
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ false /* expected */,
false /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
}
+ /**
+ * This checks that an explicit show request followed by connecting a hard keyboard
+ * and a configuration change, still results in the IME being shown.
+ */
@Test
- public void testConfigurationChanged_withKeyboardShownExplicitly() throws InterruptedException {
+ public void testShowSoftInputExplicitly_thenConfigurationChanged() throws Exception {
+ setShowImeWithHardKeyboard(false /* enabled */);
+
+ // Start with no hard keyboard.
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_NOKEYS;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
+
verifyInputViewStatusOnMainSync(
() -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ true /* expected */,
true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+
+ // Simulate connecting a hard keyboard.
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
+
// Simulate a fake configuration change to avoid triggering the recreation of TestActivity.
mInputMethodService.getResources().getConfiguration().orientation =
Configuration.ORIENTATION_LANDSCAPE;
+
verifyInputViewStatusOnMainSync(() -> mInputMethodService.onConfigurationChanged(
mInputMethodService.getResources().getConfiguration()),
+ true /* expected */,
true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
}
+ /**
+ * This checks that an implicit show request followed by connecting a hard keyboard
+ * and a configuration change, does not trigger IMS#onFinishInputView,
+ * but results in the IME being hidden.
+ */
@Test
- public void testConfigurationChanged_withKeyboardShownImplicitly() throws InterruptedException {
+ public void testShowSoftInputImplicitly_thenConfigurationChanged() throws Exception {
+ setShowImeWithHardKeyboard(false /* enabled */);
+
+ // Start with no hard keyboard.
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_NOKEYS;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
+
verifyInputViewStatusOnMainSync(() -> assertThat(
mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ true /* expected */,
true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+
+ // Simulate connecting a hard keyboard.
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
+
// Simulate a fake configuration change to avoid triggering the recreation of TestActivity.
mInputMethodService.getResources().getConfiguration().orientation =
Configuration.ORIENTATION_LANDSCAPE;
- mInputMethodService.getResources().getConfiguration().keyboard =
- Configuration.KEYBOARD_QWERTY;
// Normally, IMS#onFinishInputView will be called when finishing the input view by the user.
// But if IMS#hideWindow is called when receiving a new configuration change, we don't
// expect that it's user-driven to finish the lifecycle of input view with
// IMS#onFinishInputView, because the input view will be re-initialized according to the
- // last mShowSoftRequested state. So in this case we treat the input view is still alive.
+ // last #mShowInputRequested state. So in this case we treat the input view as still alive.
verifyInputViewStatusOnMainSync(() -> mInputMethodService.onConfigurationChanged(
- mInputMethodService.getResources().getConfiguration()),
+ mInputMethodService.getResources().getConfiguration()),
+ true /* expected */,
true /* inputViewStarted */);
assertThat(mInputMethodService.isInputViewShown()).isFalse();
}
- private void verifyInputViewStatus(Runnable runnable, boolean inputViewStarted)
+ /**
+ * This checks that an explicit show request directly followed by an implicit show request,
+ * while a hardware keyboard is connected, still results in the IME being shown
+ * (i.e. the implicit show request is treated as explicit).
+ */
+ @Test
+ public void testShowSoftInputExplicitly_thenShowSoftInputImplicitly_withHardKeyboard()
+ throws Exception {
+ setShowImeWithHardKeyboard(false /* enabled */);
+
+ // Simulate connecting a hard keyboard.
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
+
+ // Explicit show request.
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+
+ // Implicit show request.
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ false /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+
+ // Simulate a fake configuration change to avoid triggering the recreation of TestActivity.
+ // This should now consider the implicit show request, but keep the state from the
+ // explicit show request, and thus not hide the keyboard.
+ verifyInputViewStatusOnMainSync(() -> mInputMethodService.onConfigurationChanged(
+ mInputMethodService.getResources().getConfiguration()),
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+ }
+
+ /**
+ * This checks that a forced show request directly followed by an explicit show request,
+ * and then a hide not always request, still results in the IME being shown
+ * (i.e. the explicit show request retains the forced state).
+ */
+ @Test
+ public void testShowSoftInputForced_testShowSoftInputExplicitly_thenHideSoftInputNotAlways()
+ throws Exception {
+ setShowImeWithHardKeyboard(true /* enabled */);
+
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_FORCED)).isTrue(),
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ false /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+
+ verifyInputViewStatusOnMainSync(() ->
+ mActivity.hideImeWithInputMethodManager(InputMethodManager.HIDE_NOT_ALWAYS),
+ false /* expected */,
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isTrue();
+ }
+
+ /**
+ * This checks that the IME fullscreen mode state is updated after changing orientation.
+ */
+ @Test
+ public void testFullScreenMode() throws Exception {
+ setShowImeWithHardKeyboard(true /* enabled */);
+
+ Log.i(TAG, "Set orientation natural");
+ verifyFullscreenMode(() -> setOrientation(0),
+ false /* expected */,
+ true /* orientationPortrait */);
+
+ Log.i(TAG, "Set orientation left");
+ verifyFullscreenMode(() -> setOrientation(1),
+ true /* expected */,
+ false /* orientationPortrait */);
+
+ Log.i(TAG, "Set orientation right");
+ verifyFullscreenMode(() -> setOrientation(2),
+ false /* expected */,
+ false /* orientationPortrait */);
+ }
+
+ private void verifyInputViewStatus(
+ Runnable runnable, boolean expected, boolean inputViewStarted)
throws InterruptedException {
- verifyInputViewStatusInternal(runnable, inputViewStarted, false /*runOnMainSync*/);
+ verifyInputViewStatusInternal(runnable, expected, inputViewStarted,
+ false /* runOnMainSync */);
}
- private void verifyInputViewStatusOnMainSync(Runnable runnable, boolean inputViewStarted)
+ private void verifyInputViewStatusOnMainSync(
+ Runnable runnable, boolean expected, boolean inputViewStarted)
throws InterruptedException {
- verifyInputViewStatusInternal(runnable, inputViewStarted, true /*runOnMainSync*/);
+ verifyInputViewStatusInternal(runnable, expected, inputViewStarted,
+ true /* runOnMainSync */);
}
+ /**
+ * Verifies the status of the Input View after executing the given runnable.
+ *
+ * @param runnable the runnable to execute for showing or hiding the IME.
+ * @param expected whether the runnable is expected to trigger the signal.
+ * @param inputViewStarted the expected state of the Input View after executing the runnable.
+ * @param runOnMainSync whether to execute the runnable on the main thread.
+ */
private void verifyInputViewStatusInternal(
- Runnable runnable, boolean inputViewStarted, boolean runOnMainSync)
+ Runnable runnable, boolean expected, boolean inputViewStarted, boolean runOnMainSync)
throws InterruptedException {
CountDownLatch signal = new CountDownLatch(1);
mInputMethodService.setCountDownLatchForTesting(signal);
- // Runnable to trigger onStartInputView()/ onFinishInputView()
+ // Runnable to trigger onStartInputView() / onFinishInputView() / onConfigurationChanged()
if (runOnMainSync) {
mInstrumentation.runOnMainSync(runnable);
} else {
runnable.run();
}
- // Waits for onStartInputView() to finish.
mInstrumentation.waitForIdleSync();
- signal.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
+ boolean completed = signal.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
+ if (expected && !completed) {
+ fail("Timed out waiting for"
+ + " onStartInputView() / onFinishInputView() / onConfigurationChanged()");
+ } else if (!expected && completed) {
+ fail("Unexpected call"
+ + " onStartInputView() / onFinishInputView() / onConfigurationChanged()");
+ }
// Input is not finished.
assertThat(mInputMethodService.getCurrentInputStarted()).isTrue();
assertThat(mInputMethodService.getCurrentInputViewStarted()).isEqualTo(inputViewStarted);
}
- @Test
- public void testFullScreenMode() throws Exception {
- Log.i(TAG, "Set orientation natural");
- verifyFullscreenMode(() -> setOrientation(0), true /* orientationPortrait */);
-
- Log.i(TAG, "Set orientation left");
- verifyFullscreenMode(() -> setOrientation(1), false /* orientationPortrait */);
-
- Log.i(TAG, "Set orientation right");
- verifyFullscreenMode(() -> setOrientation(2), false /* orientationPortrait */);
- }
-
private void setOrientation(int orientation) {
// Simple wrapper for catching RemoteException.
try {
@@ -366,7 +657,15 @@ public class InputMethodServiceTest {
}
}
- private void verifyFullscreenMode(Runnable runnable, boolean orientationPortrait)
+ /**
+ * Verifies the IME fullscreen mode state after executing the given runnable.
+ *
+ * @param runnable the runnable to execute for setting the orientation.
+ * @param expected whether the runnable is expected to trigger the signal.
+ * @param orientationPortrait whether the orientation is expected to be portrait.
+ */
+ private void verifyFullscreenMode(
+ Runnable runnable, boolean expected, boolean orientationPortrait)
throws InterruptedException {
CountDownLatch signal = new CountDownLatch(1);
mInputMethodService.setCountDownLatchForTesting(signal);
@@ -379,7 +678,12 @@ public class InputMethodServiceTest {
}
// Waits for onConfigurationChanged() to finish.
mInstrumentation.waitForIdleSync();
- signal.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
+ boolean completed = signal.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
+ if (expected && !completed) {
+ fail("Timed out waiting for onConfigurationChanged()");
+ } else if (!expected && completed) {
+ fail("Unexpected call onConfigurationChanged()");
+ }
clickOnEditorText();
eventually(() -> assertThat(mInputMethodService.isInputViewShown()).isTrue());
@@ -416,7 +720,21 @@ public class InputMethodServiceTest {
return mTargetPackageName + "/" + INPUT_METHOD_SERVICE_NAME;
}
- private String executeShellCommand(String cmd) throws Exception {
+ /**
+ * Sets the value of show_ime_with_hard_keyboard, only if it is different to the default value.
+ *
+ * @param enabled the value to be set.
+ */
+ private void setShowImeWithHardKeyboard(boolean enabled) throws IOException {
+ if (mShowImeWithHardKeyboardEnabled != enabled) {
+ executeShellCommand(enabled
+ ? ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD
+ : DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD);
+ mInstrumentation.waitForIdleSync();
+ }
+ }
+
+ private String executeShellCommand(String cmd) throws IOException {
Log.i(TAG, "Run command: " + cmd);
return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
.executeShellCommand(cmd);
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
index 869497c28def..3199e062418f 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -40,7 +40,6 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.Display;
-import android.view.inputmethod.InputMethodManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -77,9 +76,9 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
public void testPerformShowIme() throws Exception {
synchronized (ImfLock.class) {
mVisibilityApplier.performShowIme(new Binder() /* showInputToken */,
- null /* statsToken */, InputMethodManager.SHOW_IMPLICIT, null, SHOW_SOFT_INPUT);
+ null /* statsToken */, 0 /* showFlags */, null, SHOW_SOFT_INPUT);
}
- verifyShowSoftInput(false, true, InputMethodManager.SHOW_IMPLICIT);
+ verifyShowSoftInput(false, true, 0 /* showFlags */);
}
@Test
@@ -126,7 +125,7 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
@Test
public void testApplyImeVisibility_showImeImplicit() throws Exception {
mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_SHOW_IME_IMPLICIT);
- verifyShowSoftInput(true, true, InputMethodManager.SHOW_IMPLICIT);
+ verifyShowSoftInput(true, true, 0 /* showFlags */);
}
@Test
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
index a38c1626aea1..fae5f86e4007 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
@@ -106,7 +106,7 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes
@Test
public void testRequestImeVisibility_showExplicit() {
initImeTargetWindowState(mWindowToken);
- boolean res = mComputer.onImeShowFlags(null, 0 /* show explicit */);
+ boolean res = mComputer.onImeShowFlags(null, 0 /* showFlags */);
mComputer.requestImeVisibility(mWindowToken, res);
final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -118,6 +118,34 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes
assertThat(mComputer.mRequestedShowExplicitly).isTrue();
}
+ /**
+ * This checks that the state after an explicit show request does not get reset during
+ * a subsequent implicit show request, without an intermediary hide request.
+ */
+ @Test
+ public void testRequestImeVisibility_showExplicit_thenShowImplicit() {
+ initImeTargetWindowState(mWindowToken);
+ mComputer.onImeShowFlags(null, 0 /* showFlags */);
+ assertThat(mComputer.mRequestedShowExplicitly).isTrue();
+
+ mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+ assertThat(mComputer.mRequestedShowExplicitly).isTrue();
+ }
+
+ /**
+ * This checks that the state after a forced show request does not get reset during
+ * a subsequent explicit show request, without an intermediary hide request.
+ */
+ @Test
+ public void testRequestImeVisibility_showForced_thenShowExplicit() {
+ initImeTargetWindowState(mWindowToken);
+ mComputer.onImeShowFlags(null, InputMethodManager.SHOW_FORCED);
+ assertThat(mComputer.mShowForced).isTrue();
+
+ mComputer.onImeShowFlags(null, 0 /* showFlags */);
+ assertThat(mComputer.mShowForced).isTrue();
+ }
+
@Test
public void testRequestImeVisibility_showImplicit_a11yNoImePolicy() {
// Precondition: set AccessibilityService#SHOW_MODE_HIDDEN policy
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodBindingControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodBindingControllerTest.java
index 42d373b9bf3e..e87a34ea17d7 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodBindingControllerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodBindingControllerTest.java
@@ -19,6 +19,7 @@ package com.android.server.inputmethod;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
@@ -162,7 +163,10 @@ public class InputMethodBindingControllerTest extends InputMethodManagerServiceT
assertThat(mBindingController.getCurToken()).isNotNull();
}
// Wait for onServiceConnected()
- mCountDownLatch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
+ boolean completed = mCountDownLatch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
+ if (!completed) {
+ fail("Timed out waiting for onServiceConnected()");
+ }
// Verify onServiceConnected() is called and bound successfully.
synchronized (ImfLock.class) {
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp
index 8d0e0c4260e8..e1fd2b34d881 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp
@@ -43,6 +43,8 @@ android_test_helper_app {
},
export_package_resources: true,
sdk_version: "current",
+
+ certificate: "platform",
}
android_library {
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
index 996322de2c5e..cf7d660a68ef 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
@@ -18,8 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.apps.inputmethod.simpleime">
- <uses-sdk android:targetSdkVersion="31" />
-
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<application android:debuggable="true"