diff options
2 files changed, 222 insertions, 323 deletions
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java index c77b76864176..202543c7e7a5 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java @@ -614,242 +614,61 @@ final class InputMethodSubtypeSwitchingController { } } - @VisibleForTesting - public static class ControllerImpl { - - @NonNull - private final DynamicRotationList mSwitchingAwareRotationList; - @NonNull - private final StaticRotationList mSwitchingUnawareRotationList; - /** List of input methods and subtypes. */ - @Nullable - private final RotationList mRotationList; - /** List of input methods and subtypes suitable for hardware keyboards. */ - @Nullable - private final RotationList mHardwareRotationList; - - /** - * Whether there was a user action since the last input method and subtype switch. - * Used to determine the switching behaviour for {@link #MODE_AUTO}. - */ - private boolean mUserActionSinceSwitch; - - @NonNull - public static ControllerImpl createFrom(@Nullable ControllerImpl currentInstance, - @NonNull List<ImeSubtypeListItem> sortedEnabledItems, - @NonNull List<ImeSubtypeListItem> hardwareKeyboardItems) { - final var switchingAwareImeSubtypes = filterImeSubtypeList(sortedEnabledItems, - true /* supportsSwitchingToNextInputMethod */); - final var switchingUnawareImeSubtypes = filterImeSubtypeList(sortedEnabledItems, - false /* supportsSwitchingToNextInputMethod */); - - final DynamicRotationList switchingAwareRotationList; - if (currentInstance != null && Objects.equals( - currentInstance.mSwitchingAwareRotationList.mImeSubtypeList, - switchingAwareImeSubtypes)) { - // Can reuse the current instance. - switchingAwareRotationList = currentInstance.mSwitchingAwareRotationList; - } else { - switchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes); - } - - final StaticRotationList switchingUnawareRotationList; - if (currentInstance != null && Objects.equals( - currentInstance.mSwitchingUnawareRotationList.mImeSubtypeList, - switchingUnawareImeSubtypes)) { - // Can reuse the current instance. - switchingUnawareRotationList = currentInstance.mSwitchingUnawareRotationList; - } else { - switchingUnawareRotationList = new StaticRotationList(switchingUnawareImeSubtypes); - } - - final RotationList rotationList; - if (!Flags.imeSwitcherRevamp()) { - rotationList = null; - } else if (currentInstance != null && currentInstance.mRotationList != null - && Objects.equals( - currentInstance.mRotationList.mItems, sortedEnabledItems)) { - // Can reuse the current instance. - rotationList = currentInstance.mRotationList; - } else { - rotationList = new RotationList(sortedEnabledItems); - } - - final RotationList hardwareRotationList; - if (!Flags.imeSwitcherRevamp()) { - hardwareRotationList = null; - } else if (currentInstance != null && currentInstance.mHardwareRotationList != null - && Objects.equals( - currentInstance.mHardwareRotationList.mItems, hardwareKeyboardItems)) { - // Can reuse the current instance. - hardwareRotationList = currentInstance.mHardwareRotationList; - } else { - hardwareRotationList = new RotationList(hardwareKeyboardItems); - } - - return new ControllerImpl(switchingAwareRotationList, switchingUnawareRotationList, - rotationList, hardwareRotationList); - } - - private ControllerImpl(@NonNull DynamicRotationList switchingAwareRotationList, - @NonNull StaticRotationList switchingUnawareRotationList, - @Nullable RotationList rotationList, - @Nullable RotationList hardwareRotationList) { - mSwitchingAwareRotationList = switchingAwareRotationList; - mSwitchingUnawareRotationList = switchingUnawareRotationList; - mRotationList = rotationList; - mHardwareRotationList = hardwareRotationList; - } + @NonNull + private DynamicRotationList mSwitchingAwareRotationList = + new DynamicRotationList(Collections.emptyList()); + @NonNull + private StaticRotationList mSwitchingUnawareRotationList = + new StaticRotationList(Collections.emptyList()); + /** List of input methods and subtypes. */ + @NonNull + private RotationList mRotationList = new RotationList(Collections.emptyList()); + /** List of input methods and subtypes suitable for hardware keyboards. */ + @NonNull + private RotationList mHardwareRotationList = new RotationList(Collections.emptyList()); - @Nullable - public ImeSubtypeListItem getNextInputMethod(boolean onlyCurrentIme, - @Nullable InputMethodInfo imi, @Nullable InputMethodSubtype subtype, - @SwitchMode int mode, boolean forward) { - if (imi == null) { - return null; - } - if (Flags.imeSwitcherRevamp() && mRotationList != null) { - return mRotationList.next(imi, subtype, onlyCurrentIme, - isRecency(mode, forward), forward); - } else if (imi.supportsSwitchingToNextInputMethod()) { - return mSwitchingAwareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi, - subtype); - } else { - return mSwitchingUnawareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi, - subtype); - } - } + /** + * Whether there was a user action since the last input method and subtype switch. + * Used to determine the switching behaviour for {@link #MODE_AUTO}. + */ + private boolean mUserActionSinceSwitch; - @Nullable - public ImeSubtypeListItem getNextInputMethodForHardware(boolean onlyCurrentIme, - @NonNull InputMethodInfo imi, @Nullable InputMethodSubtype subtype, - @SwitchMode int mode, boolean forward) { - if (Flags.imeSwitcherRevamp() && mHardwareRotationList != null) { - return mHardwareRotationList.next(imi, subtype, onlyCurrentIme, - isRecency(mode, forward), forward); - } - return null; - } + /** + * Updates the list of input methods and subtypes used for switching. If the given items are + * equal to the existing ones (regardless of recency order), the update is skipped and the + * current recency order is kept. Otherwise, the recency order is reset. + * + * @param sortedEnabledItems the sorted list of enabled input methods and subtypes. + * @param hardwareKeyboardItems the unsorted list of enabled input method and subtypes + * suitable for hardware keyboards. + */ + @VisibleForTesting + void update(@NonNull List<ImeSubtypeListItem> sortedEnabledItems, + @NonNull List<ImeSubtypeListItem> hardwareKeyboardItems) { + final var switchingAwareImeSubtypes = filterImeSubtypeList(sortedEnabledItems, + true /* supportsSwitchingToNextInputMethod */); + final var switchingUnawareImeSubtypes = filterImeSubtypeList(sortedEnabledItems, + false /* supportsSwitchingToNextInputMethod */); - /** - * Called when the user took an action that should update the recency of the current - * input method and subtype in the switching list. - * - * @param imi the currently selected input method. - * @param subtype the currently selected input method subtype, if any. - * @return {@code true} if the recency was updated, otherwise {@code false}. - * @see android.inputmethodservice.InputMethodServiceInternal#notifyUserActionIfNecessary() - */ - public boolean onUserActionLocked(@NonNull InputMethodInfo imi, - @Nullable InputMethodSubtype subtype) { - boolean recencyUpdated = false; - if (Flags.imeSwitcherRevamp()) { - if (mRotationList != null) { - recencyUpdated |= mRotationList.setMostRecent(imi, subtype); - } - if (mHardwareRotationList != null) { - recencyUpdated |= mHardwareRotationList.setMostRecent(imi, subtype); - } - if (recencyUpdated) { - mUserActionSinceSwitch = true; - } - } else if (imi.supportsSwitchingToNextInputMethod()) { - mSwitchingAwareRotationList.onUserAction(imi, subtype); - } - return recencyUpdated; + if (!Objects.equals(mSwitchingAwareRotationList.mImeSubtypeList, + switchingAwareImeSubtypes)) { + mSwitchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes); } - /** Called when the input method and subtype was changed. */ - public void onInputMethodSubtypeChanged() { - mUserActionSinceSwitch = false; + if (!Objects.equals(mSwitchingUnawareRotationList.mImeSubtypeList, + switchingUnawareImeSubtypes)) { + mSwitchingUnawareRotationList = new StaticRotationList(switchingUnawareImeSubtypes); } - /** - * Whether the given mode and direction result in recency or static order. - * - * <p>{@link #MODE_AUTO} resolves to the recency order for the first forwards switch - * after an {@link #onUserActionLocked user action}, and otherwise to the static order.</p> - * - * @param mode the switching mode. - * @param forward the switching direction. - * @return {@code true} for the recency order, otherwise {@code false}. - */ - private boolean isRecency(@SwitchMode int mode, boolean forward) { - if (mode == MODE_AUTO && mUserActionSinceSwitch && forward) { - return true; - } else { - return mode == MODE_RECENT; - } + if (Flags.imeSwitcherRevamp() + && !Objects.equals(mRotationList.mItems, sortedEnabledItems)) { + mRotationList = new RotationList(sortedEnabledItems); } - @NonNull - private static List<ImeSubtypeListItem> filterImeSubtypeList( - @NonNull List<ImeSubtypeListItem> items, - boolean supportsSwitchingToNextInputMethod) { - final ArrayList<ImeSubtypeListItem> result = new ArrayList<>(); - final int numItems = items.size(); - for (int i = 0; i < numItems; i++) { - final ImeSubtypeListItem item = items.get(i); - if (item.mImi.supportsSwitchingToNextInputMethod() - == supportsSwitchingToNextInputMethod) { - result.add(item); - } - } - return result; + if (Flags.imeSwitcherRevamp() + && !Objects.equals(mHardwareRotationList.mItems, hardwareKeyboardItems)) { + mHardwareRotationList = new RotationList(hardwareKeyboardItems); } - - protected void dump(@NonNull Printer pw, @NonNull String prefix) { - pw.println(prefix + "mSwitchingAwareRotationList:"); - mSwitchingAwareRotationList.dump(pw, prefix + " "); - pw.println(prefix + "mSwitchingUnawareRotationList:"); - mSwitchingUnawareRotationList.dump(pw, prefix + " "); - if (Flags.imeSwitcherRevamp()) { - if (mRotationList != null) { - pw.println(prefix + "mRotationList:"); - mRotationList.dump(pw, prefix + " "); - } - if (mHardwareRotationList != null) { - pw.println(prefix + "mHardwareRotationList:"); - mHardwareRotationList.dump(pw, prefix + " "); - } - pw.println(prefix + "User action since last switch: " + mUserActionSinceSwitch); - } - } - } - - @NonNull - private ControllerImpl mController; - - InputMethodSubtypeSwitchingController() { - mController = ControllerImpl.createFrom(null, Collections.emptyList(), - Collections.emptyList()); - } - - /** - * Called when the user took an action that should update the recency of the current - * input method and subtype in the switching list. - * - * @param imi the currently selected input method. - * @param subtype the currently selected input method subtype, if any. - * @see android.inputmethodservice.InputMethodServiceInternal#notifyUserActionIfNecessary() - */ - public void onUserActionLocked(@NonNull InputMethodInfo imi, - @Nullable InputMethodSubtype subtype) { - mController.onUserActionLocked(imi, subtype); - } - - /** Called when the input method and subtype was changed. */ - public void onInputMethodSubtypeChanged() { - mController.onInputMethodSubtypeChanged(); - } - - public void resetCircularListLocked(@NonNull Context context, - @NonNull InputMethodSettings settings) { - mController = ControllerImpl.createFrom(mController, - getSortedInputMethodAndSubtypeList( - false /* includeAuxiliarySubtypes */, false /* isScreenLocked */, - false /* forImeMenu */, context, settings), - getInputMethodAndSubtypeListForHardwareKeyboard(context, settings)); } /** @@ -869,7 +688,19 @@ final class InputMethodSubtypeSwitchingController { public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme, @Nullable InputMethodInfo imi, @Nullable InputMethodSubtype subtype, @SwitchMode int mode, boolean forward) { - return mController.getNextInputMethod(onlyCurrentIme, imi, subtype, mode, forward); + if (imi == null) { + return null; + } + if (Flags.imeSwitcherRevamp()) { + return mRotationList.next(imi, subtype, onlyCurrentIme, + isRecency(mode, forward), forward); + } else if (imi.supportsSwitchingToNextInputMethod()) { + return mSwitchingAwareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi, + subtype); + } else { + return mSwitchingUnawareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi, + subtype); + } } /** @@ -890,11 +721,98 @@ final class InputMethodSubtypeSwitchingController { public ImeSubtypeListItem getNextInputMethodForHardware(boolean onlyCurrentIme, @NonNull InputMethodInfo imi, @Nullable InputMethodSubtype subtype, @SwitchMode int mode, boolean forward) { - return mController.getNextInputMethodForHardware(onlyCurrentIme, imi, subtype, mode, - forward); + if (Flags.imeSwitcherRevamp()) { + return mHardwareRotationList.next(imi, subtype, onlyCurrentIme, + isRecency(mode, forward), forward); + } + return null; } - public void dump(@NonNull Printer pw, @NonNull String prefix) { - mController.dump(pw, prefix); + /** + * Called when the user took an action that should update the recency of the current + * input method and subtype in the switching list. + * + * @param imi the currently selected input method. + * @param subtype the currently selected input method subtype, if any. + * @return {@code true} if the recency was updated, otherwise {@code false}. + * @see android.inputmethodservice.InputMethodServiceInternal#notifyUserActionIfNecessary() + */ + public boolean onUserActionLocked(@NonNull InputMethodInfo imi, + @Nullable InputMethodSubtype subtype) { + boolean recencyUpdated = false; + if (Flags.imeSwitcherRevamp()) { + recencyUpdated |= mRotationList.setMostRecent(imi, subtype); + recencyUpdated |= mHardwareRotationList.setMostRecent(imi, subtype); + if (recencyUpdated) { + mUserActionSinceSwitch = true; + } + } else if (imi.supportsSwitchingToNextInputMethod()) { + mSwitchingAwareRotationList.onUserAction(imi, subtype); + } + return recencyUpdated; + } + + /** Called when the input method and subtype was changed. */ + public void onInputMethodSubtypeChanged() { + mUserActionSinceSwitch = false; + } + + /** + * Whether the given mode and direction result in recency or static order. + * + * <p>{@link #MODE_AUTO} resolves to the recency order for the first forwards switch + * after an {@link #onUserActionLocked user action}, and otherwise to the static order.</p> + * + * @param mode the switching mode. + * @param forward the switching direction. + * @return {@code true} for the recency order, otherwise {@code false}. + */ + private boolean isRecency(@SwitchMode int mode, boolean forward) { + if (mode == MODE_AUTO && mUserActionSinceSwitch && forward) { + return true; + } else { + return mode == MODE_RECENT; + } + } + + @NonNull + private static List<ImeSubtypeListItem> filterImeSubtypeList( + @NonNull List<ImeSubtypeListItem> items, + boolean supportsSwitchingToNextInputMethod) { + final ArrayList<ImeSubtypeListItem> result = new ArrayList<>(); + final int numItems = items.size(); + for (int i = 0; i < numItems; i++) { + final ImeSubtypeListItem item = items.get(i); + if (item.mImi.supportsSwitchingToNextInputMethod() + == supportsSwitchingToNextInputMethod) { + result.add(item); + } + } + return result; + } + + void dump(@NonNull Printer pw, @NonNull String prefix) { + pw.println(prefix + "mSwitchingAwareRotationList:"); + mSwitchingAwareRotationList.dump(pw, prefix + " "); + pw.println(prefix + "mSwitchingUnawareRotationList:"); + mSwitchingUnawareRotationList.dump(pw, prefix + " "); + if (Flags.imeSwitcherRevamp()) { + pw.println(prefix + "mRotationList:"); + mRotationList.dump(pw, prefix + " "); + pw.println(prefix + "mHardwareRotationList:"); + mHardwareRotationList.dump(pw, prefix + " "); + pw.println(prefix + "User action since last switch: " + mUserActionSinceSwitch); + } + } + + InputMethodSubtypeSwitchingController() { + } + + public void resetCircularListLocked(@NonNull Context context, + @NonNull InputMethodSettings settings) { + update(getSortedInputMethodAndSubtypeList( + false /* includeAuxiliarySubtypes */, false /* isScreenLocked */, + false /* forImeMenu */, context, settings), + getInputMethodAndSubtypeListForHardwareKeyboard(context, settings)); } } diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java index a27ad9a0f4e6..770451cc838d 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java @@ -44,7 +44,6 @@ import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl; import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; import org.junit.Rule; @@ -178,19 +177,20 @@ public final class InputMethodSubtypeSwitchingControllerTest { return items; } - private void assertNextInputMethod(@NonNull ControllerImpl controller, boolean onlyCurrentIme, - @NonNull ImeSubtypeListItem currentItem, @Nullable ImeSubtypeListItem nextItem) { + private void assertNextInputMethod(@NonNull InputMethodSubtypeSwitchingController controller, + boolean onlyCurrentIme, @NonNull ImeSubtypeListItem currentItem, + @Nullable ImeSubtypeListItem nextItem) { InputMethodSubtype subtype = null; if (currentItem.mSubtypeName != null) { subtype = createTestSubtype(currentItem.mSubtypeName.toString()); } - final ImeSubtypeListItem nextIme = controller.getNextInputMethod(onlyCurrentIme, + final ImeSubtypeListItem nextIme = controller.getNextInputMethodLocked(onlyCurrentIme, currentItem.mImi, subtype, MODE_STATIC, true /* forward */); assertEquals(nextItem, nextIme); } - private void assertRotationOrder(@NonNull ControllerImpl controller, boolean onlyCurrentIme, - ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) { + private void assertRotationOrder(@NonNull InputMethodSubtypeSwitchingController controller, + boolean onlyCurrentIme, ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) { final int numItems = expectedRotationOrderOfImeSubtypeList.length; for (int i = 0; i < numItems; i++) { final int nextIndex = (i + 1) % numItems; @@ -200,7 +200,7 @@ public final class InputMethodSubtypeSwitchingControllerTest { } } - private boolean onUserAction(@NonNull ControllerImpl controller, + private boolean onUserAction(@NonNull InputMethodSubtypeSwitchingController controller, @NonNull ImeSubtypeListItem subtypeListItem) { InputMethodSubtype subtype = null; if (subtypeListItem.mSubtypeName != null) { @@ -228,8 +228,8 @@ public final class InputMethodSubtypeSwitchingControllerTest { final ImeSubtypeListItem japaneseIme_ja_jp = enabledItems.get(6); final ImeSubtypeListItem switchUnawareJapaneseIme_ja_jp = enabledItems.get(7); - final ControllerImpl controller = ControllerImpl.createFrom( - null /* currentInstance */, enabledItems, new ArrayList<>()); + final var controller = new InputMethodSubtypeSwitchingController(); + controller.update(enabledItems, new ArrayList<>()); // switching-aware loop assertRotationOrder(controller, false /* onlyCurrentIme */, @@ -286,8 +286,8 @@ public final class InputMethodSubtypeSwitchingControllerTest { final ImeSubtypeListItem japaneseIme_ja_jp = enabledItems.get(6); final ImeSubtypeListItem switchUnawareJapaneseIme_ja_jp = enabledItems.get(7); - final ControllerImpl controller = ControllerImpl.createFrom( - null /* currentInstance */, enabledItems, new ArrayList<>()); + final var controller = new InputMethodSubtypeSwitchingController(); + controller.update(enabledItems, new ArrayList<>()); // === switching-aware loop === assertRotationOrder(controller, false /* onlyCurrentIme */, @@ -336,11 +336,10 @@ public final class InputMethodSubtypeSwitchingControllerTest { // Rotation order should be preserved when created with the same subtype list. final List<ImeSubtypeListItem> sameEnabledItems = createEnabledImeSubtypes(); - final ControllerImpl newController = ControllerImpl.createFrom(controller, - sameEnabledItems, new ArrayList<>()); - assertRotationOrder(newController, false /* onlyCurrentIme */, + controller.update(sameEnabledItems, new ArrayList<>()); + assertRotationOrder(controller, false /* onlyCurrentIme */, subtypeAwareIme, latinIme_fr, latinIme_en_us, japaneseIme_ja_jp); - assertRotationOrder(newController, false /* onlyCurrentIme */, + assertRotationOrder(controller, false /* onlyCurrentIme */, switchingUnawareLatinIme_en_uk, switchingUnawareLatinIme_hi, subtypeUnawareIme, switchUnawareJapaneseIme_ja_jp); @@ -348,11 +347,10 @@ public final class InputMethodSubtypeSwitchingControllerTest { final List<ImeSubtypeListItem> differentEnabledItems = List.of( latinIme_en_us, latinIme_fr, subtypeAwareIme, switchingUnawareLatinIme_en_uk, switchUnawareJapaneseIme_ja_jp, subtypeUnawareIme); - final ControllerImpl anotherController = ControllerImpl.createFrom(controller, - differentEnabledItems, new ArrayList<>()); - assertRotationOrder(anotherController, false /* onlyCurrentIme */, + controller.update(differentEnabledItems, new ArrayList<>()); + assertRotationOrder(controller, false /* onlyCurrentIme */, latinIme_en_us, latinIme_fr, subtypeAwareIme); - assertRotationOrder(anotherController, false /* onlyCurrentIme */, + assertRotationOrder(controller, false /* onlyCurrentIme */, switchingUnawareLatinIme_en_uk, switchUnawareJapaneseIme_ja_jp, subtypeUnawareIme); } @@ -520,8 +518,8 @@ public final class InputMethodSubtypeSwitchingControllerTest { final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian); final var hardwareSimpleIme = List.of(hardwareSimple); - final var controller = ControllerImpl.createFrom(null /* currentInstance */, items, - hardwareItems); + final var controller = new InputMethodSubtypeSwitchingController(); + controller.update(items, hardwareItems); final int mode = MODE_STATIC; @@ -583,8 +581,8 @@ public final class InputMethodSubtypeSwitchingControllerTest { final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian); final var hardwareSimpleIme = List.of(hardwareSimple); - final var controller = ControllerImpl.createFrom(null /* currentInstance */, items, - hardwareItems); + final var controller = new InputMethodSubtypeSwitchingController(); + controller.update(items, hardwareItems); final int mode = MODE_RECENT; @@ -666,8 +664,8 @@ public final class InputMethodSubtypeSwitchingControllerTest { final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian); final var hardwareSimpleIme = List.of(hardwareSimple); - final var controller = ControllerImpl.createFrom(null /* currentInstance */, items, - hardwareItems); + final var controller = new InputMethodSubtypeSwitchingController(); + controller.update(items, hardwareItems); final int mode = MODE_AUTO; @@ -777,92 +775,73 @@ public final class InputMethodSubtypeSwitchingControllerTest { final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian); final var hardwareSimpleIme = List.of(hardwareSimple); - final var controller = ControllerImpl.createFrom(null /* currentInstance */, items, - hardwareItems); + final var controller = new InputMethodSubtypeSwitchingController(); + controller.update(items, hardwareItems); final int mode = MODE_RECENT; // Recency order is initialized to static order. assertNextOrder(controller, false /* forHardware */, mode, items, List.of(latinIme, simpleIme)); - assertNextOrder(controller, true /* forHardware */, mode, hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme)); // User action on french IME. assertTrue("Recency updated for french IME", onUserAction(controller, french)); - final var equalItems = new ArrayList<>(items); - final var otherItems = new ArrayList<>(items); - otherItems.remove(simple); - - final var equalController = ControllerImpl.createFrom(controller, equalItems, - hardwareItems); - final var otherController = ControllerImpl.createFrom(controller, otherItems, - hardwareItems); - final var recencyItems = List.of(french, english, italian, simple); final var recencyLatinIme = List.of(french, english, italian); final var recencySimpleIme = List.of(simple); - assertNextOrder(controller, false /* forHardware */, mode, - recencyItems, List.of(recencyLatinIme, recencySimpleIme)); + final var equalItems = new ArrayList<>(items); + controller.update(equalItems, hardwareItems); - // The order of equal non-hardware items is unchanged. - assertNextOrder(equalController, false /* forHardware */, mode, + // The order of non-hardware items remains unchanged when updated with equal items. + assertNextOrder(controller, false /* forHardware */, mode, recencyItems, List.of(recencyLatinIme, recencySimpleIme)); - - // The order of other hardware items is reset. - assertNextOrder(otherController, false /* forHardware */, mode, - latinIme, List.of(latinIme)); - - // The order of hardware remains unchanged. + // The order of hardware items remains unchanged when only non-hardware items are updated. assertNextOrder(controller, true /* forHardware */, mode, hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme)); - assertNextOrder(equalController, true /* forHardware */, mode, - hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme)); + final var otherItems = new ArrayList<>(items); + otherItems.remove(simple); + controller.update(otherItems, hardwareItems); - assertNextOrder(otherController, true /* forHardware */, mode, + // The order of non-hardware items is reset when updated with other items. + assertNextOrder(controller, false /* forHardware */, mode, + latinIme, List.of(latinIme)); + // The order of hardware items remains unchanged when only non-hardware items are updated. + assertNextOrder(controller, true /* forHardware */, mode, hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme)); assertTrue("Recency updated for french hardware IME", onUserAction(controller, hardwareFrench)); - final var equalHardwareItems = new ArrayList<>(hardwareItems); - final var otherHardwareItems = new ArrayList<>(hardwareItems); - otherHardwareItems.remove(hardwareSimple); - - final var equalHardwareController = ControllerImpl.createFrom(controller, items, - equalHardwareItems); - final var otherHardwareController = ControllerImpl.createFrom(controller, items, - otherHardwareItems); - final var recencyHardwareItems = List.of(hardwareFrench, hardwareEnglish, hardwareItalian, hardwareSimple); final var recencyHardwareLatinIme = List.of(hardwareFrench, hardwareEnglish, hardwareItalian); final var recencyHardwareSimpleIme = List.of(hardwareSimple); - // The order of non-hardware items remains unchanged. - assertNextOrder(controller, false /* forHardware */, mode, - recencyItems, List.of(recencyLatinIme, recencySimpleIme)); - - assertNextOrder(equalHardwareController, false /* forHardware */, mode, - recencyItems, List.of(recencyLatinIme, recencySimpleIme)); - - assertNextOrder(otherHardwareController, false /* forHardware */, mode, - recencyItems, List.of(recencyLatinIme, recencySimpleIme)); + final var equalHardwareItems = new ArrayList<>(hardwareItems); + controller.update(otherItems, equalHardwareItems); + // The order of non-hardware items remains unchanged when only hardware items are updated. + assertNextOrder(controller, false /* forHardware */, mode, + latinIme, List.of(latinIme)); + // The order of hardware items remains unchanged when updated with equal items. assertNextOrder(controller, true /* forHardware */, mode, recencyHardwareItems, List.of(recencyHardwareLatinIme, recencyHardwareSimpleIme)); - // The order of equal hardware items is unchanged. - assertNextOrder(equalHardwareController, true /* forHardware */, mode, - recencyHardwareItems, List.of(recencyHardwareLatinIme, recencyHardwareSimpleIme)); + final var otherHardwareItems = new ArrayList<>(hardwareItems); + otherHardwareItems.remove(hardwareSimple); + controller.update(otherItems, otherHardwareItems); - // The order of other hardware items is reset. - assertNextOrder(otherHardwareController, true /* forHardware */, mode, + // The order of non-hardware items remains unchanged when only hardware items are updated. + assertNextOrder(controller, false /* forHardware */, mode, + latinIme, List.of(latinIme)); + // The order of hardware items is reset when updated with other items. + assertNextOrder(controller, true /* forHardware */, mode, hardwareLatinIme, List.of(hardwareLatinIme)); } @@ -882,8 +861,8 @@ public final class InputMethodSubtypeSwitchingControllerTest { addTestImeSubtypeListItems(hardwareItems, "hardwareSwitchUnaware", "hardwareSwitchUnaware", null, false /* supportsSwitchingToNextInputMethod*/); - final var controller = ControllerImpl.createFrom(null /* currentInstance */, items, - hardwareItems); + final var controller = new InputMethodSubtypeSwitchingController(); + controller.update(items, hardwareItems); for (int mode = MODE_STATIC; mode <= MODE_AUTO; mode++) { assertNextOrder(controller, false /* forHardware */, false /* onlyCurrentIme */, @@ -910,8 +889,7 @@ public final class InputMethodSubtypeSwitchingControllerTest { addTestImeSubtypeListItems(hardwareItems, "HardwareIme", "HardwareIme", List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */); - final var controller = ControllerImpl.createFrom(null /* currentInstance */, List.of(), - List.of()); + final var controller = new InputMethodSubtypeSwitchingController(); assertNextItemNoAction(controller, false /* forHardware */, items, null /* expectedNext */); @@ -940,8 +918,8 @@ public final class InputMethodSubtypeSwitchingControllerTest { addTestImeSubtypeListItems(unknownHardwareItems, "HardwareUnknownIme", "HardwareUnknownIme", List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */); - final var controller = ControllerImpl.createFrom(null /* currentInstance */, - items, hardwareItems); + final var controller = new InputMethodSubtypeSwitchingController(); + controller.update(items, hardwareItems); assertNextItemNoAction(controller, false /* forHardware */, items, null /* expectedNext */); @@ -979,8 +957,8 @@ public final class InputMethodSubtypeSwitchingControllerTest { addTestImeSubtypeListItems(unknownHardwareItems, "HardwareUnknownIme", "HardwareUnknownIme", List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */); - final var controller = ControllerImpl.createFrom(null /* currentInstance */, items, - hardwareItems); + final var controller = new InputMethodSubtypeSwitchingController(); + controller.update(items, hardwareItems); assertTrue("Recency updated for french IME", onUserAction(controller, french)); @@ -1118,8 +1096,9 @@ public final class InputMethodSubtypeSwitchingControllerTest { * @param allItems the list of items across all IMEs. * @param perImeItems the list of lists of items per IME. */ - private static void assertNextOrder(@NonNull ControllerImpl controller, boolean forHardware, - @SwitchMode int mode, boolean forward, @NonNull List<ImeSubtypeListItem> allItems, + private static void assertNextOrder(@NonNull InputMethodSubtypeSwitchingController controller, + boolean forHardware, @SwitchMode int mode, boolean forward, + @NonNull List<ImeSubtypeListItem> allItems, @NonNull List<List<ImeSubtypeListItem>> perImeItems) { assertNextOrder(controller, forHardware, false /* onlyCurrentIme */, mode, forward, allItems); @@ -1142,8 +1121,8 @@ public final class InputMethodSubtypeSwitchingControllerTest { * @param allItems the list of items across all IMEs. * @param perImeItems the list of lists of items per IME. */ - private static void assertNextOrder(@NonNull ControllerImpl controller, boolean forHardware, - @SwitchMode int mode, @NonNull List<ImeSubtypeListItem> allItems, + private static void assertNextOrder(@NonNull InputMethodSubtypeSwitchingController controller, + boolean forHardware, @SwitchMode int mode, @NonNull List<ImeSubtypeListItem> allItems, @NonNull List<List<ImeSubtypeListItem>> perImeItems) { assertNextOrder(controller, forHardware, false /* onlyCurrentIme */, mode, true /* forward */, allItems); @@ -1170,7 +1149,7 @@ public final class InputMethodSubtypeSwitchingControllerTest { * @param forward whether to search forwards or backwards in the list. * @param items the list of items to verify, in the expected order. */ - private static void assertNextOrder(@NonNull ControllerImpl controller, + private static void assertNextOrder(@NonNull InputMethodSubtypeSwitchingController controller, boolean forHardware, boolean onlyCurrentIme, @SwitchMode int mode, boolean forward, @NonNull List<ImeSubtypeListItem> items) { final int numItems = items.size(); @@ -1214,7 +1193,7 @@ public final class InputMethodSubtypeSwitchingControllerTest { * @param item the item to find the next value from. * @param expectedNext the expected next value. */ - private static void assertNextItem(@NonNull ControllerImpl controller, + private static void assertNextItem(@NonNull InputMethodSubtypeSwitchingController controller, boolean forHardware, boolean onlyCurrentIme, @SwitchMode int mode, boolean forward, @NonNull ImeSubtypeListItem item, @Nullable ImeSubtypeListItem expectedNext) { final var nextItem = getNextItem(controller, forHardware, onlyCurrentIme, mode, forward, @@ -1234,15 +1213,16 @@ public final class InputMethodSubtypeSwitchingControllerTest { * @return the next item found, otherwise {@code null}. */ @Nullable - private static ImeSubtypeListItem getNextItem(@NonNull ControllerImpl controller, - boolean forHardware, boolean onlyCurrentIme, @SwitchMode int mode, boolean forward, + private static ImeSubtypeListItem getNextItem( + @NonNull InputMethodSubtypeSwitchingController controller, boolean forHardware, + boolean onlyCurrentIme, @SwitchMode int mode, boolean forward, @NonNull ImeSubtypeListItem item) { final var subtype = item.mSubtypeName != null ? createTestSubtype(item.mSubtypeName.toString()) : null; return forHardware ? controller.getNextInputMethodForHardware( onlyCurrentIme, item.mImi, subtype, mode, forward) - : controller.getNextInputMethod( + : controller.getNextInputMethodLocked( onlyCurrentIme, item.mImi, subtype, mode, forward); } @@ -1255,8 +1235,9 @@ public final class InputMethodSubtypeSwitchingControllerTest { * @param items the list of items to verify. * @param expectedNext the expected next item. */ - private void assertNextItemNoAction(@NonNull ControllerImpl controller, boolean forHardware, - @NonNull List<ImeSubtypeListItem> items, @Nullable ImeSubtypeListItem expectedNext) { + private void assertNextItemNoAction(@NonNull InputMethodSubtypeSwitchingController controller, + boolean forHardware, @NonNull List<ImeSubtypeListItem> items, + @Nullable ImeSubtypeListItem expectedNext) { for (var item : items) { for (int mode = MODE_STATIC; mode <= MODE_AUTO; mode++) { assertNextItem(controller, forHardware, false /* onlyCurrentIme */, mode, |