Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7eaf0f8b authored by Cosmin Băieș's avatar Cosmin Băieș
Browse files

Optimize InputMethodSubtypeSwitchingController

This avoids re-computing the list of items in the
InputMethodSubtypeSwitchingController every time the IME Switcher Menu
is requested, by instead storing the full list of items. These are still
updated whenever necessary (e.g. user, context or language change).

As this will be a superset of all the enabled IMEs and subtypes we could
use, this requires iterating and filtering when creating the list used
for switching, and the one used for the menu. However, this avoids
repeatedly calling into package manager to resolve the IME and subtype
label resources. With these lists being usually small, this should
overall improve performance.

To enable this, the logic for creating the list suitable for hardware
keyboard switching was merged into the main method. This presents a few
changes for the hardware keyboard list:
  * sorted based on the IME label, and IME id
  * removes duplicates based on the subtype hashcode

These two behaviours were already present on the main method, thus
combining them will provide more consistency in switching IMEs.

Flag: EXEMPT cleanup
Bug: 347693610
Test: atest InputMethodSubtypeSwitchingControllerTest
Change-Id: I11280dd485faa06676e8292b95cecdb312d92460
parent 25730af6
Loading
Loading
Loading
Loading
+19 −21
Original line number Diff line number Diff line
@@ -4029,9 +4029,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
            return false;
        }
        final ImeSubtypeListItem nextSubtype = userData.mSwitchingController
                .getNextInputMethodLocked(onlyCurrentIme, currentImi,
                        bindingController.getCurrentSubtype(),
                        MODE_AUTO, true /* forward */);
                .getNextInputMethod(currentImi, bindingController.getCurrentSubtype(),
                        onlyCurrentIme, MODE_AUTO, true /* forward */);
        if (nextSubtype == null) {
            return false;
        }
@@ -4049,9 +4048,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
            return false;
        }
        final ImeSubtypeListItem nextSubtype = userData.mSwitchingController
                .getNextInputMethodLocked(false /* onlyCurrentIme */, currentImi,
                        bindingController.getCurrentSubtype(),
                        MODE_AUTO, true /* forward */);
                .getNextInputMethod(currentImi, bindingController.getCurrentSubtype(),
                        false /* onlyCurrentIme */, MODE_AUTO, true /* forward */);
        return nextSubtype != null;
    }

@@ -4425,8 +4423,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
        final var bindingController = userData.mBindingController;
        final InputMethodInfo imi = bindingController.getSelectedMethod();
        if (imi != null) {
            userData.mSwitchingController.onUserActionLocked(imi,
                    bindingController.getCurrentSubtype());
            userData.mSwitchingController.onUserAction(imi, bindingController.getCurrentSubtype());
        }
    }

@@ -4562,16 +4559,14 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
    @GuardedBy("ImfLock.class")
    private void showInputMethodPickerLocked(int auxiliarySubtypeMode, int displayId,
            @UserIdInt int userId) {
        final var userData = getUserData(userId);
        final boolean showAuxSubtypes;
        switch (auxiliarySubtypeMode) {
            // This is undocumented so far, but IMM#showInputMethodPicker() has been
            // implemented so that auxiliary subtypes will be excluded when the soft
            // keyboard is invisible.
            case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO -> {
                final var userData = getUserData(userId);
                final var visibilityStateComputer = userData.mVisibilityStateComputer;
                showAuxSubtypes = visibilityStateComputer.isInputShown();
            }
            case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO ->
                    showAuxSubtypes = userData.mVisibilityStateComputer.isInputShown();
            case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES ->
                    showAuxSubtypes = true;
            case InputMethodManager.SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES ->
@@ -4581,18 +4576,21 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
                return;
            }
        }
        final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
        final boolean isScreenLocked = mWindowManagerInternal.isKeyguardLocked()
                && mWindowManagerInternal.isKeyguardSecure(userId);
        final boolean includeAuxiliary = showAuxSubtypes && !isScreenLocked;
        if (DEBUG && isScreenLocked && showAuxSubtypes) {
            Slog.w(TAG, "Auxiliary subtypes are not allowed to be shown in lock screen.");
        }
        final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
        final String lastInputMethodId = settings.getSelectedInputMethod();
        final int lastInputMethodSubtypeIndex =
                settings.getSelectedInputMethodSubtypeIndex(lastInputMethodId);

        final List<ImeSubtypeListItem> imList = InputMethodSubtypeSwitchingController
                .getSortedInputMethodAndSubtypeList(showAuxSubtypes, isScreenLocked,
                        true /* forImeMenu */, mContext, settings);
        if (imList.isEmpty()) {
            Slog.w(TAG, "Show switching menu failed, imList is empty,"
        final List<ImeSubtypeListItem> items = userData.mSwitchingController
                .getItemsForImeSwitcherMenu(includeAuxiliary);
        if (items.isEmpty()) {
            Slog.w(TAG, "Show switching menu failed, items is empty,"
                    + " showAuxSubtypes: " + showAuxSubtypes
                    + " isScreenLocked: " + isScreenLocked
                    + " userId: " + userId);
@@ -4616,7 +4614,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
            }
        }

        mMenuController.show(imList, lastInputMethodId, selectedSubtypeIndex, isScreenLocked,
        mMenuController.show(items, lastInputMethodId, selectedSubtypeIndex, isScreenLocked,
                displayId, userId);
    }

@@ -5245,7 +5243,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
        }
        final var currentSubtype = bindingController.getCurrentSubtype();
        final var nextItem = userData.mSwitchingController.getNextInputMethodForHardware(
                false /* onlyCurrentIme */, currentImi, currentSubtype, MODE_AUTO,
                currentImi, currentSubtype, false /* onlyCurrentIme */, MODE_AUTO,
                direction > 0 /* forward */);
        if (nextItem == null) {
            Slog.i(TAG, "Hardware keyboard switching shortcut,"
+216 −163

File changed.

Preview size limit exceeded, changes collapsed.

+17 −33
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package com.android.server.inputmethod;

import static com.android.server.inputmethod.InputMethodMenuController.getMenuItems;
import static com.android.server.inputmethod.InputMethodMenuController.getSelectedIndex;
import static com.android.server.inputmethod.InputMethodSubtypeSwitchingControllerTest.addTestImeSubtypeListItems;
import static com.android.server.inputmethod.InputMethodSubtypeSwitchingControllerTest.createTestItems;
import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_INDEX;

import static com.google.common.truth.Truth.assertThat;
@@ -40,10 +40,8 @@ public class InputMethodMenuControllerTest {
    @Test
    public void testGetMenuItems() {
        final var items = new ArrayList<ImeSubtypeListItem>();
        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
                null, true /* supportsSwitchingToNextInputMethod */);
        createTestItems(items, "LatinIme", List.of("en", "fr"));
        createTestItems(items, "SimpleIme", null);

        final var menuItems = getMenuItems(items);

@@ -78,8 +76,7 @@ public class InputMethodMenuControllerTest {
    @Test
    public void testGetMenuItemsNoHeaderOrDividerForSingleInputMethod() {
        final var items = new ArrayList<ImeSubtypeListItem>();
        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
        createTestItems(items, "LatinIme", List.of("en", "fr"));

        final var menuItems = getMenuItems(items);

@@ -95,14 +92,10 @@ public class InputMethodMenuControllerTest {
    @Test
    public void testGetMenuItemsHeaders() {
        final var items = new ArrayList<ImeSubtypeListItem>();
        addTestImeSubtypeListItems(items, "DefaultIme", "DefaultIme",
                null, true /* supportsSwitchingToNextInputMethod */);
        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
        addTestImeSubtypeListItems(items, "ItalianIme", "ItalianIme",
                List.of("it"), true /* supportsSwitchingToNextInputMethod */);
        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
                null, true /* supportsSwitchingToNextInputMethod */);
        createTestItems(items, "DefaultIme", null);
        createTestItems(items, "LatinIme", List.of("en", "fr"));
        createTestItems(items, "ItalianIme", List.of("it"));
        createTestItems(items, "SimpleIme", null);

        final var menuItems = getMenuItems(items);

@@ -132,12 +125,9 @@ public class InputMethodMenuControllerTest {
    @Test
    public void testGetMenuItemsDivider() {
        final var items = new ArrayList<ImeSubtypeListItem>();
        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
        addTestImeSubtypeListItems(items, "ItalianIme", "ItalianIme",
                List.of("it"), true /* supportsSwitchingToNextInputMethod */);
        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
                null, true /* supportsSwitchingToNextInputMethod */);
        createTestItems(items, "LatinIme", List.of("en", "fr"));
        createTestItems(items, "ItalianIme", List.of("it"));
        createTestItems(items, "SimpleIme", null);

        final var menuItems = getMenuItems(items);

@@ -167,10 +157,8 @@ public class InputMethodMenuControllerTest {
    @Test
    public void testGetSelectedIndexWithSelectedSubtype() {
        final var items = new ArrayList<ImeSubtypeListItem>();
        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
                List.of("it", "jp", "pt"),  true /* supportsSwitchingToNextInputMethod */);
        createTestItems(items, "LatinIme", List.of("en", "fr"));
        createTestItems(items, "SimpleIme", List.of("it", "jp", "pt"));

        final var simpleImeId = items.get(2).mImi.getId();
        final var menuItems = getMenuItems(items);
@@ -187,10 +175,8 @@ public class InputMethodMenuControllerTest {
    @Test
    public void testGetSelectedIndexWithoutSelectedSubtype() {
        final var items = new ArrayList<ImeSubtypeListItem>();
        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
                List.of("it", "jp", "pt"),  true /* supportsSwitchingToNextInputMethod */);
        createTestItems(items, "LatinIme", List.of("en", "fr"));
        createTestItems(items, "SimpleIme", List.of("it", "jp", "pt"));

        final var simpleImeId = items.get(2).mImi.getId();
        final var menuItems = getMenuItems(items);
@@ -208,10 +194,8 @@ public class InputMethodMenuControllerTest {
    @Test
    public void getSelectedIndexNoSubtype() {
        final var items = new ArrayList<ImeSubtypeListItem>();
        addTestImeSubtypeListItems(items, "LatinIme", "LatinIme",
                List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
        addTestImeSubtypeListItems(items, "SimpleIme", "SimpleIme",
                null,  true /* supportsSwitchingToNextInputMethod */);
        createTestItems(items, "LatinIme", List.of("en", "fr"));
        createTestItems(items, "SimpleIme", null);

        final var simpleImeId = items.get(2).mImi.getId();
        final var menuItems = getMenuItems(items);
+200 −193

File changed.

Preview size limit exceeded, changes collapsed.