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

Commit 19e9179b authored by Cosmin Băieș's avatar Cosmin Băieș Committed by Android (Google) Code Review
Browse files

Merge "Cleanup IME subtype switching controller and tests" into main

parents 6c1b577a a1e9a882
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -1300,8 +1300,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.

            final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);

            mSwitchingController =
                    InputMethodSubtypeSwitchingController.createInstanceLocked(context,
            mSwitchingController = new InputMethodSubtypeSwitchingController(context,
                    settings.getMethodMap(), settings.getUserId());
            mHardwareKeyboardShortcutController =
                    new HardwareKeyboardShortcutController(settings.getMethodMap(),
@@ -3049,8 +3048,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
        if (userId == mSwitchingController.getUserId()) {
            mSwitchingController.resetCircularListLocked(settings.getMethodMap());
        } else {
            mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
                    mContext, settings.getMethodMap(), userId);
            mSwitchingController = new InputMethodSubtypeSwitchingController(mContext,
                    settings.getMethodMap(), userId);
        }
        // TODO: Instantiate mHardwareKeyboardShortcutController for each user.
        if (userId == mHardwareKeyboardShortcutController.getUserId()) {
@@ -5320,8 +5319,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
        if (userId == mSwitchingController.getUserId()) {
            mSwitchingController.resetCircularListLocked(settings.getMethodMap());
        } else {
            mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
                    mContext, settings.getMethodMap(), mCurrentUserId);
            mSwitchingController = new InputMethodSubtypeSwitchingController(mContext,
                    settings.getMethodMap(), mCurrentUserId);
        }
        // TODO: Instantiate mHardwareKeyboardShortcutController for each user.
        if (userId == mHardwareKeyboardShortcutController.getUserId()) {
+83 −96
Original line number Diff line number Diff line
@@ -48,15 +48,20 @@ final class InputMethodSubtypeSwitchingController {
    private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;

    public static class ImeSubtypeListItem implements Comparable<ImeSubtypeListItem> {

        @NonNull
        public final CharSequence mImeName;
        @Nullable
        public final CharSequence mSubtypeName;
        @NonNull
        public final InputMethodInfo mImi;
        public final int mSubtypeId;
        public final boolean mIsSystemLocale;
        public final boolean mIsSystemLanguage;

        ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName,
                InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale) {
        ImeSubtypeListItem(@NonNull CharSequence imeName, @Nullable CharSequence subtypeName,
                @NonNull InputMethodInfo imi, int subtypeId, @Nullable String subtypeLocale,
                @NonNull String systemLocale) {
            mImeName = imeName;
            mSubtypeName = subtypeName;
            mImi = imi;
@@ -69,7 +74,6 @@ final class InputMethodSubtypeSwitchingController {
                if (mIsSystemLocale) {
                    mIsSystemLanguage = true;
                } else {
                    // TODO: Use Locale#getLanguage or Locale#toLanguageTag
                    final String systemLanguage = LocaleUtils.getLanguageFromLocaleString(
                            systemLocale);
                    final String subtypeLanguage = LocaleUtils.getLanguageFromLocaleString(
@@ -101,8 +105,9 @@ final class InputMethodSubtypeSwitchingController {
         *   <li>{@link #mSubtypeName}</li>
         *   <li>{@link #mImi} with {@link InputMethodInfo#getId()}</li>
         * </ol>
         * Note: this class has a natural ordering that is inconsistent with {@link #equals(Object).
         * This method doesn't compare {@link #mSubtypeId} but {@link #equals(Object)} does.
         * Note: this class has a natural ordering that is inconsistent with
         * {@link #equals(Object)}. This method doesn't compare {@link #mSubtypeId} but
         * {@link #equals(Object)} does.
         *
         * @param other the object to be compared.
         * @return a negative integer, zero, or positive integer as this object is less than, equal
@@ -155,6 +160,7 @@ final class InputMethodSubtypeSwitchingController {
        }
    }

    @NonNull
    static List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(
            boolean includeAuxiliarySubtypes, boolean isScreenLocked, boolean forImeMenu,
            @NonNull Context context, @NonNull InputMethodMap methodMap,
@@ -190,7 +196,7 @@ final class InputMethodSubtypeSwitchingController {
                enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
            }
            final CharSequence imeLabel = imi.loadLabel(userAwareContext.getPackageManager());
            if (enabledSubtypeSet.size() > 0) {
            if (!enabledSubtypeSet.isEmpty()) {
                final int subtypeCount = imi.getSubtypeCount();
                if (DEBUG) {
                    Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
@@ -223,14 +229,18 @@ final class InputMethodSubtypeSwitchingController {
        return imList;
    }

    private static int calculateSubtypeId(InputMethodInfo imi, InputMethodSubtype subtype) {
    private static int calculateSubtypeId(@NonNull InputMethodInfo imi,
            @Nullable InputMethodSubtype subtype) {
        return subtype != null ? SubtypeUtils.getSubtypeIdFromHashCode(imi, subtype.hashCode())
                : NOT_A_SUBTYPE_ID;
    }

    private static class StaticRotationList {

        @NonNull
        private final List<ImeSubtypeListItem> mImeSubtypeList;
        StaticRotationList(final List<ImeSubtypeListItem> imeSubtypeList) {

        StaticRotationList(@NonNull List<ImeSubtypeListItem> imeSubtypeList) {
            mImeSubtypeList = imeSubtypeList;
        }

@@ -242,24 +252,22 @@ final class InputMethodSubtypeSwitchingController {
         *                does not have a subtype.
         * @return The index in the given list. -1 if not found.
         */
        private int getIndex(InputMethodInfo imi, InputMethodSubtype subtype) {
        private int getIndex(@NonNull InputMethodInfo imi, @Nullable InputMethodSubtype subtype) {
            final int currentSubtypeId = calculateSubtypeId(imi, subtype);
            final int numSubtypes = mImeSubtypeList.size();
            for (int i = 0; i < numSubtypes; ++i) {
                final ImeSubtypeListItem isli = mImeSubtypeList.get(i);
                final ImeSubtypeListItem item = mImeSubtypeList.get(i);
                // Skip until the current IME/subtype is found.
                if (imi.equals(isli.mImi) && isli.mSubtypeId == currentSubtypeId) {
                if (imi.equals(item.mImi) && item.mSubtypeId == currentSubtypeId) {
                    return i;
                }
            }
            return -1;
        }

        @Nullable
        public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
                InputMethodInfo imi, InputMethodSubtype subtype) {
            if (imi == null) {
                return null;
            }
                @NonNull InputMethodInfo imi, @Nullable InputMethodSubtype subtype) {
            if (mImeSubtypeList.size() <= 1) {
                return null;
            }
@@ -282,22 +290,24 @@ final class InputMethodSubtypeSwitchingController {
            return null;
        }

        protected void dump(final Printer pw, final String prefix) {
        protected void dump(@NonNull Printer pw, @NonNull String prefix) {
            final int numSubtypes = mImeSubtypeList.size();
            for (int i = 0; i < numSubtypes; ++i) {
                final int rank = i;
                final ImeSubtypeListItem item = mImeSubtypeList.get(i);
            for (int rank = 0; rank < numSubtypes; ++rank) {
                final ImeSubtypeListItem item = mImeSubtypeList.get(rank);
                pw.println(prefix + "rank=" + rank + " item=" + item);
            }
        }
    }

    private static class DynamicRotationList {

        private static final String TAG = DynamicRotationList.class.getSimpleName();
        @NonNull
        private final List<ImeSubtypeListItem> mImeSubtypeList;
        @NonNull
        private final int[] mUsageHistoryOfSubtypeListItemIndex;

        private DynamicRotationList(final List<ImeSubtypeListItem> imeSubtypeListItems) {
        private DynamicRotationList(@NonNull List<ImeSubtypeListItem> imeSubtypeListItems) {
            mImeSubtypeList = imeSubtypeListItems;
            mUsageHistoryOfSubtypeListItemIndex = new int[mImeSubtypeList.size()];
            final int numSubtypes = mImeSubtypeList.size();
@@ -314,7 +324,8 @@ final class InputMethodSubtypeSwitchingController {
         *
         * @return -1 when the specified item doesn't belong to {@link #mImeSubtypeList} actually.
         */
        private int getUsageRank(final InputMethodInfo imi, InputMethodSubtype subtype) {
        private int getUsageRank(@NonNull InputMethodInfo imi,
                @Nullable InputMethodSubtype subtype) {
            final int currentSubtypeId = calculateSubtypeId(imi, subtype);
            final int numItems = mUsageHistoryOfSubtypeListItemIndex.length;
            for (int usageRank = 0; usageRank < numItems; usageRank++) {
@@ -330,7 +341,8 @@ final class InputMethodSubtypeSwitchingController {
            return -1;
        }

        public void onUserAction(InputMethodInfo imi, InputMethodSubtype subtype) {
        public void onUserAction(@NonNull InputMethodInfo imi,
                @Nullable InputMethodSubtype subtype) {
            final int currentUsageRank = getUsageRank(imi, subtype);
            // Do nothing if currentUsageRank == -1 (not found), or currentUsageRank == 0
            if (currentUsageRank <= 0) {
@@ -342,8 +354,9 @@ final class InputMethodSubtypeSwitchingController {
            mUsageHistoryOfSubtypeListItemIndex[0] = currentItemIndex;
        }

        @Nullable
        public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
                InputMethodInfo imi, InputMethodSubtype subtype) {
                @NonNull InputMethodInfo imi, @Nullable InputMethodSubtype subtype) {
            int currentUsageRank = getUsageRank(imi, subtype);
            if (currentUsageRank < 0) {
                if (DEBUG) {
@@ -366,7 +379,7 @@ final class InputMethodSubtypeSwitchingController {
            return null;
        }

        protected void dump(final Printer pw, final String prefix) {
        protected void dump(@NonNull Printer pw, @NonNull String prefix) {
            for (int rank = 0; rank < mUsageHistoryOfSubtypeListItemIndex.length; ++rank) {
                final int index = mUsageHistoryOfSubtypeListItemIndex[rank];
                final ImeSubtypeListItem item = mImeSubtypeList.get(index);
@@ -377,58 +390,52 @@ final class InputMethodSubtypeSwitchingController {

    @VisibleForTesting
    public static class ControllerImpl {

        @NonNull
        private final DynamicRotationList mSwitchingAwareRotationList;
        @NonNull
        private final StaticRotationList mSwitchingUnawareRotationList;

        public static ControllerImpl createFrom(final ControllerImpl currentInstance,
                final List<ImeSubtypeListItem> sortedEnabledItems) {
            DynamicRotationList switchingAwareRotationList = null;
            {
                final List<ImeSubtypeListItem> switchingAwareImeSubtypes =
                        filterImeSubtypeList(sortedEnabledItems,
        @NonNull
        public static ControllerImpl createFrom(@Nullable ControllerImpl currentInstance,
                @NonNull List<ImeSubtypeListItem> sortedEnabledItems) {
            final var switchingAwareImeSubtypes = filterImeSubtypeList(sortedEnabledItems,
                    true /* supportsSwitchingToNextInputMethod */);
                if (currentInstance != null
                        && currentInstance.mSwitchingAwareRotationList != null
                        && Objects.equals(
            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;
                }
                if (switchingAwareRotationList == null) {
            } else {
                switchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes);
            }
            }

            StaticRotationList switchingUnawareRotationList = null;
            {
                final List<ImeSubtypeListItem> switchingUnawareImeSubtypes = filterImeSubtypeList(
                        sortedEnabledItems, false /* supportsSwitchingToNextInputMethod */);
                if (currentInstance != null
                        && currentInstance.mSwitchingUnawareRotationList != null
                        && Objects.equals(
            final StaticRotationList switchingUnawareRotationList;
            if (currentInstance != null && Objects.equals(
                    currentInstance.mSwitchingUnawareRotationList.mImeSubtypeList,
                    switchingUnawareImeSubtypes)) {
                // Can reuse the current instance.
                switchingUnawareRotationList = currentInstance.mSwitchingUnawareRotationList;
                }
                if (switchingUnawareRotationList == null) {
                    switchingUnawareRotationList =
                            new StaticRotationList(switchingUnawareImeSubtypes);
                }
            } else {
                switchingUnawareRotationList = new StaticRotationList(switchingUnawareImeSubtypes);
            }

            return new ControllerImpl(switchingAwareRotationList, switchingUnawareRotationList);
        }

        private ControllerImpl(final DynamicRotationList switchingAwareRotationList,
                final StaticRotationList switchingUnawareRotationList) {
        private ControllerImpl(@NonNull DynamicRotationList switchingAwareRotationList,
                @NonNull StaticRotationList switchingUnawareRotationList) {
            mSwitchingAwareRotationList = switchingAwareRotationList;
            mSwitchingUnawareRotationList = switchingUnawareRotationList;
        }

        public ImeSubtypeListItem getNextInputMethod(boolean onlyCurrentIme, InputMethodInfo imi,
                InputMethodSubtype subtype) {
        @Nullable
        public ImeSubtypeListItem getNextInputMethod(boolean onlyCurrentIme,
                @Nullable InputMethodInfo imi, @Nullable InputMethodSubtype subtype) {
            if (imi == null) {
                return null;
            }
@@ -441,18 +448,17 @@ final class InputMethodSubtypeSwitchingController {
            }
        }

        public void onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype) {
            if (imi == null) {
                return;
            }
        public void onUserActionLocked(@NonNull InputMethodInfo imi,
                @Nullable InputMethodSubtype subtype) {
            if (imi.supportsSwitchingToNextInputMethod()) {
                mSwitchingAwareRotationList.onUserAction(imi, subtype);
            }
        }

        @NonNull
        private static List<ImeSubtypeListItem> filterImeSubtypeList(
                final List<ImeSubtypeListItem> items,
                final boolean supportsSwitchingToNextInputMethod) {
                @NonNull List<ImeSubtypeListItem> items,
                boolean supportsSwitchingToNextInputMethod) {
            final ArrayList<ImeSubtypeListItem> result = new ArrayList<>();
            final int numItems = items.size();
            for (int i = 0; i < numItems; i++) {
@@ -473,12 +479,14 @@ final class InputMethodSubtypeSwitchingController {
        }
    }

    @NonNull
    private final Context mContext;
    @UserIdInt
    private final int mUserId;
    @NonNull
    private ControllerImpl mController;

    private InputMethodSubtypeSwitchingController(@NonNull Context context,
    InputMethodSubtypeSwitchingController(@NonNull Context context,
            @NonNull InputMethodMap methodMap, @UserIdInt int userId) {
        mContext = context;
        mUserId = userId;
@@ -488,26 +496,14 @@ final class InputMethodSubtypeSwitchingController {
                        false /* forImeMenu */, context, methodMap, userId));
    }

    @NonNull
    public static InputMethodSubtypeSwitchingController createInstanceLocked(
            @NonNull Context context,
            @NonNull InputMethodMap methodMap, @UserIdInt int userId) {
        return new InputMethodSubtypeSwitchingController(context, methodMap, userId);
    }

    @AnyThread
    @UserIdInt
    int getUserId() {
        return mUserId;
    }

    public void onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype) {
        if (mController == null) {
            if (DEBUG) {
                Slog.e(TAG, "mController shouldn't be null.");
            }
            return;
        }
    public void onUserActionLocked(@NonNull InputMethodInfo imi,
            @Nullable InputMethodSubtype subtype) {
        mController.onUserActionLocked(imi, subtype);
    }

@@ -518,22 +514,13 @@ final class InputMethodSubtypeSwitchingController {
                        false /* forImeMenu */, mContext, methodMap, mUserId));
    }

    public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme, InputMethodInfo imi,
            InputMethodSubtype subtype) {
        if (mController == null) {
            if (DEBUG) {
                Slog.e(TAG, "mController shouldn't be null.");
            }
            return null;
        }
    @Nullable
    public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
            @Nullable InputMethodInfo imi, @Nullable InputMethodSubtype subtype) {
        return mController.getNextInputMethod(onlyCurrentIme, imi, subtype);
    }

    public void dump(@NonNull Printer pw, @NonNull String prefix) {
        if (mController != null) {
        mController.dump(pw, prefix);
        } else {
            pw.println(prefix + "mController=null");
        }
    }
}
+127 −120

File changed.

Preview size limit exceeded, changes collapsed.