Switch to next IME on switcher button short click
This changes the IME switcher button short click behaviour to switch to
the next input method or subtype if available, and otherwise show the
IME switcher menu.
Flag: android.view.inputmethod.ime_switcher_revamp
Test: atest InputMethodServiceTest#testImeSwitchButtonClick
Bug: 311791923
Change-Id: I8ad283b9fc12a30df6abdfc14fed6078b33ffbf4
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 855c309..da7997d 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -4341,7 +4341,8 @@
}
/**
- * Called when the IME switch button was clicked from the client. This will show the input
+ * Called when the IME switch button was clicked from the client. Depending on the number of
+ * enabled IME subtypes, this will either switch to the next IME/subtype, or show the input
* method picker dialog.
*
* @hide
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index dbbfff0..c9d2eec 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -4354,7 +4354,8 @@
}
/**
- * Called when the IME switch button was clicked from the system. This will show the input
+ * Called when the IME switch button was clicked from the system. Depending on the number of
+ * enabled IME subtypes, this will either switch to the next IME/subtype, or show the input
* method picker dialog.
*
* @param displayId The ID of the display where the input method picker dialog should be shown.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8fd2033..0b3aaef 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2625,6 +2625,18 @@
}
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
+ return hasMultipleSubtypesForSwitcher(false /* nonAuxOnly */, settings);
+ }
+
+ /**
+ * Checks whether there at least two subtypes that should be shown for the IME switcher menu,
+ * across all enabled IMEs for the given user.
+ *
+ * @param nonAuxOnly whether to check only for non auxiliary subtypes.
+ * @param settings the input method settings under the given user ID.
+ */
+ private static boolean hasMultipleSubtypesForSwitcher(boolean nonAuxOnly,
+ @NonNull InputMethodSettings settings) {
List<InputMethodInfo> imes = settings.getEnabledInputMethodListWithFilter(
InputMethodInfo::shouldShowInInputMethodPicker);
final int numImes = imes.size();
@@ -2654,7 +2666,9 @@
}
}
}
- if (nonAuxCount > 1 || auxCount > 1) {
+ if (Flags.imeSwitcherRevamp() && nonAuxOnly) {
+ return nonAuxCount > 1;
+ } else if (nonAuxCount > 1 || auxCount > 1) {
return true;
} else if (nonAuxCount == 1 && auxCount == 1) {
if (nonAuxSubtype != null && auxSubtype != null
@@ -3976,16 +3990,45 @@
if (!calledWithValidTokenLocked(token, userData)) {
return;
}
- showInputMethodPickerFromSystem(
- InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES, displayId);
+ onImeSwitchButtonClickLocked(token, displayId, userData);
}
}
@IInputMethodManagerImpl.PermissionVerified(Manifest.permission.WRITE_SECURE_SETTINGS)
@Override
public void onImeSwitchButtonClickFromSystem(int displayId) {
- showInputMethodPickerFromSystem(
- InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES, displayId);
+ synchronized (ImfLock.class) {
+ final int userId = mCurrentUserId;
+ final var userData = getUserData(userId);
+ final var bindingController = userData.mBindingController;
+ final var curToken = bindingController.getCurToken();
+ if (curToken == null) {
+ return;
+ }
+
+ onImeSwitchButtonClickLocked(curToken, displayId, userData);
+ }
+ }
+
+ /**
+ * Handles a click on the IME switch button. Depending on the number of enabled IME subtypes,
+ * this will either switch to the next IME/subtype, or show the input method picker dialog.
+ *
+ * @param token The token identifying the input method that triggered this.
+ * @param displayId The ID of the display where the input method picker dialog should be shown.
+ * @param userData The data of the user for which to switch IMEs or show the picker dialog.
+ */
+ @GuardedBy("ImfLock.class")
+ private void onImeSwitchButtonClickLocked(@NonNull IBinder token, int displayId,
+ @NonNull UserData userData) {
+ final int userId = userData.mUserId;
+ final var settings = InputMethodSettingsRepository.get(userId);
+ if (hasMultipleSubtypesForSwitcher(true /* nonAuxOnly */, settings)) {
+ switchToNextInputMethodLocked(token, false /* onlyCurrentIme */, userData);
+ } else {
+ showInputMethodPickerFromSystem(
+ InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES, displayId);
+ }
}
@NonNull
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index ce68b86..0787058 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -60,6 +60,7 @@
import org.junit.runner.RunWith;
import java.io.IOException;
+import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -769,7 +770,8 @@
}
/**
- * Verifies that clicking on the IME switch button shows the Input Method Switcher Menu.
+ * Verifies that clicking on the IME switch button either shows the Input Method Switcher Menu,
+ * or switches the input method.
*/
@Test
public void testImeSwitchButtonClick() throws Exception {
@@ -794,13 +796,16 @@
assertThat(mInputMethodService.isInputViewShown()).isTrue();
final var imm = mContext.getSystemService(InputMethodManager.class);
+ final var initialInfo = imm.getCurrentInputMethodInfo();
final var imeSwitchButtonUiObject = getUiObjectById(INPUT_METHOD_NAV_IME_SWITCHER_ID);
imeSwitchButtonUiObject.click();
mInstrumentation.waitForIdleSync();
- assertWithMessage("Input Method Switcher Menu is shown")
- .that(isInputMethodPickerShown(imm))
+ final var newInfo = imm.getCurrentInputMethodInfo();
+
+ assertWithMessage("Input Method Switcher Menu is shown or input method was switched")
+ .that(isInputMethodPickerShown(imm) || !Objects.equals(initialInfo, newInfo))
.isTrue();
assertThat(mInputMethodService.isInputViewShown()).isTrue();