diff options
3 files changed, 171 insertions, 32 deletions
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java index d53efa0aa3c3..191b5a74d8ca 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java +++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java @@ -29,6 +29,9 @@ import android.os.RemoteException; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; +import android.text.TextUtils.SimpleStringSplitter; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Pair; import android.util.Slog; import android.view.inputmethod.InputMethodInfo; @@ -61,6 +64,8 @@ public class InputMethodUtils { private static final String TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE = "EnabledWhenDefaultIsNotAsciiCapable"; private static final String TAG_ASCII_CAPABLE = "AsciiCapable"; + private static final char INPUT_METHOD_SEPARATOR = ':'; + private static final char INPUT_METHOD_SUBTYPE_SEPARATOR = ';'; /** * Used in {@link #getFallbackLocaleForDefaultIme(ArrayList, Context)} to find the fallback IMEs * that are mainly used until the system becomes ready. Note that {@link Locale} in this array @@ -766,6 +771,40 @@ public class InputMethodUtils { } /** + * Parses the setting stored input methods and subtypes string value. + * + * @param inputMethodsAndSubtypesString The input method subtypes value stored in settings. + * @return Map from input method ID to set of input method subtypes IDs. + */ + @VisibleForTesting + public static ArrayMap<String, ArraySet<String>> parseInputMethodsAndSubtypesString( + @Nullable final String inputMethodsAndSubtypesString) { + + final ArrayMap<String, ArraySet<String>> imeMap = new ArrayMap<String, ArraySet<String>>(); + if (TextUtils.isEmpty(inputMethodsAndSubtypesString)) { + return imeMap; + } + + final SimpleStringSplitter typeSplitter = + new SimpleStringSplitter(INPUT_METHOD_SEPARATOR); + final SimpleStringSplitter subtypeSplitter = + new SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR); + + List<Pair<String, ArrayList<String>>> allImeSettings = + InputMethodSettings.buildInputMethodsAndSubtypeList(inputMethodsAndSubtypesString, + typeSplitter, + subtypeSplitter); + for (Pair<String, ArrayList<String>> ime : allImeSettings) { + ArraySet<String> subtypes = new ArraySet<String>(); + if (ime.second != null) { + subtypes.addAll(ime.second); + } + imeMap.put(ime.first, subtypes); + } + return imeMap; + } + + /** * Utility class for putting and getting settings for InputMethod * TODO: Move all putters and getters of settings to this class. */ diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java index 67f87a3dfc84..e2077a3c718f 100644 --- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java @@ -23,9 +23,11 @@ import android.content.pm.ServiceInfo; import android.os.Parcel; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.SmallTest; +import android.util.ArrayMap; +import android.util.ArraySet; import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; +import android.view.inputmethod.InputMethodSubtype; import java.util.ArrayList; import java.util.List; @@ -947,4 +949,129 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { assertEquals(Locale.ENGLISH, locales.get(4)); } } + + public void testParseInputMethodsAndSubtypesString() { + // Trivial cases. + { + assertTrue(InputMethodUtils.parseInputMethodsAndSubtypesString("").isEmpty()); + assertTrue(InputMethodUtils.parseInputMethodsAndSubtypesString(null).isEmpty()); + } + + // No subtype cases. + { + ArrayMap<String, ArraySet<String>> r = + InputMethodUtils.parseInputMethodsAndSubtypesString("ime0"); + assertEquals(1, r.size()); + assertTrue(r.containsKey("ime0")); + assertTrue(r.get("ime0").isEmpty()); + } + { + ArrayMap<String, ArraySet<String>> r = + InputMethodUtils.parseInputMethodsAndSubtypesString("ime0:ime1"); + assertEquals(2, r.size()); + assertTrue(r.containsKey("ime0")); + assertTrue(r.get("ime0").isEmpty()); + assertTrue(r.containsKey("ime1")); + assertTrue(r.get("ime1").isEmpty()); + } + + // Input metho IDs and their subtypes. + { + ArrayMap<String, ArraySet<String>> r = + InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0"); + assertEquals(1, r.size()); + assertTrue(r.containsKey("ime0")); + ArraySet<String> subtypes = r.get("ime0"); + assertEquals(1, subtypes.size()); + assertTrue(subtypes.contains("subtype0")); + } + { + ArrayMap<String, ArraySet<String>> r = + InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0;subtype0"); + assertEquals(1, r.size()); + assertTrue(r.containsKey("ime0")); + ArraySet<String> subtypes = r.get("ime0"); + assertEquals(1, subtypes.size()); + assertTrue(subtypes.contains("subtype0")); + } + { + ArrayMap<String, ArraySet<String>> r = + InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0;subtype1"); + assertEquals(1, r.size()); + assertTrue(r.containsKey("ime0")); + ArraySet<String> subtypes = r.get("ime0"); + assertEquals(2, subtypes.size()); + assertTrue(subtypes.contains("subtype0")); + assertTrue(subtypes.contains("subtype1")); + } + { + ArrayMap<String, ArraySet<String>> r = + InputMethodUtils.parseInputMethodsAndSubtypesString( + "ime0;subtype0:ime1;subtype1"); + assertEquals(2, r.size()); + assertTrue(r.containsKey("ime0")); + assertTrue(r.containsKey("ime1")); + ArraySet<String> subtypes0 = r.get("ime0"); + assertEquals(1, subtypes0.size()); + assertTrue(subtypes0.contains("subtype0")); + + ArraySet<String> subtypes1 = r.get("ime1"); + assertEquals(1, subtypes1.size()); + assertTrue(subtypes1.contains("subtype1")); + } + { + ArrayMap<String, ArraySet<String>> r = + InputMethodUtils.parseInputMethodsAndSubtypesString( + "ime0;subtype0;subtype1:ime1;subtype2"); + assertEquals(2, r.size()); + assertTrue(r.containsKey("ime0")); + assertTrue(r.containsKey("ime1")); + ArraySet<String> subtypes0 = r.get("ime0"); + assertEquals(2, subtypes0.size()); + assertTrue(subtypes0.contains("subtype0")); + assertTrue(subtypes0.contains("subtype1")); + + ArraySet<String> subtypes1 = r.get("ime1"); + assertEquals(1, subtypes1.size()); + assertTrue(subtypes1.contains("subtype2")); + } + { + ArrayMap<String, ArraySet<String>> r = + InputMethodUtils.parseInputMethodsAndSubtypesString( + "ime0;subtype0;subtype1:ime1;subtype1;subtype2"); + assertEquals(2, r.size()); + assertTrue(r.containsKey("ime0")); + assertTrue(r.containsKey("ime1")); + ArraySet<String> subtypes0 = r.get("ime0"); + assertEquals(2, subtypes0.size()); + assertTrue(subtypes0.contains("subtype0")); + assertTrue(subtypes0.contains("subtype1")); + + ArraySet<String> subtypes1 = r.get("ime1"); + assertEquals(2, subtypes1.size()); + assertTrue(subtypes0.contains("subtype1")); + assertTrue(subtypes1.contains("subtype2")); + } + { + ArrayMap<String, ArraySet<String>> r = + InputMethodUtils.parseInputMethodsAndSubtypesString( + "ime0;subtype0;subtype1:ime1;subtype1;subtype2:ime2"); + assertEquals(3, r.size()); + assertTrue(r.containsKey("ime0")); + assertTrue(r.containsKey("ime1")); + assertTrue(r.containsKey("ime2")); + ArraySet<String> subtypes0 = r.get("ime0"); + assertEquals(2, subtypes0.size()); + assertTrue(subtypes0.contains("subtype0")); + assertTrue(subtypes0.contains("subtype1")); + + ArraySet<String> subtypes1 = r.get("ime1"); + assertEquals(2, subtypes1.size()); + assertTrue(subtypes0.contains("subtype1")); + assertTrue(subtypes1.contains("subtype2")); + + ArraySet<String> subtypes2 = r.get("ime2"); + assertTrue(subtypes2.isEmpty()); + } + } } diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index f9f617ef4c26..66a23084b8d0 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -145,9 +145,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub static final boolean DEBUG_RESTORE = DEBUG || false; static final String TAG = "InputMethodManagerService"; - private static final char INPUT_METHOD_SEPARATOR = ':'; - private static final char INPUT_METHOD_SUBTYPE_SEPARATOR = ';'; - static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1; static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2; static final int MSG_SHOW_IM_CONFIG = 3; @@ -528,8 +525,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.i(TAG, " new=" + newValue); } // 'new' is the just-restored state, 'prev' is what was in settings prior to the restore - ArrayMap<String, ArraySet<String>> prevMap = parseInputMethodsAndSubtypesString(prevValue); - ArrayMap<String, ArraySet<String>> newMap = parseInputMethodsAndSubtypesString(newValue); + ArrayMap<String, ArraySet<String>> prevMap = + InputMethodUtils.parseInputMethodsAndSubtypesString(prevValue); + ArrayMap<String, ArraySet<String>> newMap = + InputMethodUtils.parseInputMethodsAndSubtypesString(newValue); // Merge the restored ime+subtype enabled states into the live state for (ArrayMap.Entry<String, ArraySet<String>> entry : newMap.entrySet()) { @@ -568,32 +567,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return InputMethodSettings.buildInputMethodsSettingString(imeMap); } - // TODO: Move this method to InputMethodUtils with adding unit tests. - static ArrayMap<String, ArraySet<String>> parseInputMethodsAndSubtypesString( - final String inputMethodsAndSubtypesString) { - final ArrayMap<String, ArraySet<String>> imeMap = new ArrayMap<>(); - if (TextUtils.isEmpty(inputMethodsAndSubtypesString)) { - return imeMap; - } - - final SimpleStringSplitter typeSplitter = - new SimpleStringSplitter(INPUT_METHOD_SEPARATOR); - final SimpleStringSplitter subtypeSplitter = - new SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR); - List<Pair<String, ArrayList<String>>> allImeSettings = - InputMethodSettings.buildInputMethodsAndSubtypeList(inputMethodsAndSubtypesString, - typeSplitter, - subtypeSplitter); - for (Pair<String, ArrayList<String>> ime : allImeSettings) { - ArraySet<String> subtypes = new ArraySet<>(); - if (ime.second != null) { - subtypes.addAll(ime.second); - } - imeMap.put(ime.first, subtypes); - } - return imeMap; - } - class MyPackageMonitor extends PackageMonitor { private boolean isChangingPackagesOfCurrentUser() { final int userId = getChangingUserId(); |