Loading core/java/android/provider/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -5375,6 +5375,7 @@ public final class Settings { BACKUP_AUTO_RESTORE, ENABLED_ACCESSIBILITY_SERVICES, ENABLED_NOTIFICATION_LISTENERS, ENABLED_INPUT_METHODS, TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, TOUCH_EXPLORATION_ENABLED, ACCESSIBILITY_ENABLED, Loading core/java/com/android/internal/inputmethod/InputMethodUtils.java +46 −26 Original line number Diff line number Diff line Loading @@ -764,17 +764,55 @@ public class InputMethodUtils { private int[] mCurrentProfileIds = new int[0]; private static void buildEnabledInputMethodsSettingString( StringBuilder builder, Pair<String, ArrayList<String>> pair) { String id = pair.first; ArrayList<String> subtypes = pair.second; builder.append(id); StringBuilder builder, Pair<String, ArrayList<String>> ime) { builder.append(ime.first); // Inputmethod and subtypes are saved in the settings as follows: // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1 for (String subtypeId: subtypes) { for (String subtypeId: ime.second) { builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId); } } public static String buildInputMethodsSettingString( List<Pair<String, ArrayList<String>>> allImeSettingsMap) { final StringBuilder b = new StringBuilder(); boolean needsSeparator = false; for (Pair<String, ArrayList<String>> ime : allImeSettingsMap) { if (needsSeparator) { b.append(INPUT_METHOD_SEPARATER); } buildEnabledInputMethodsSettingString(b, ime); needsSeparator = true; } return b.toString(); } public static List<Pair<String, ArrayList<String>>> buildInputMethodsAndSubtypeList( String enabledInputMethodsStr, TextUtils.SimpleStringSplitter inputMethodSplitter, TextUtils.SimpleStringSplitter subtypeSplitter) { ArrayList<Pair<String, ArrayList<String>>> imsList = new ArrayList<Pair<String, ArrayList<String>>>(); if (TextUtils.isEmpty(enabledInputMethodsStr)) { return imsList; } inputMethodSplitter.setString(enabledInputMethodsStr); while (inputMethodSplitter.hasNext()) { String nextImsStr = inputMethodSplitter.next(); subtypeSplitter.setString(nextImsStr); if (subtypeSplitter.hasNext()) { ArrayList<String> subtypeHashes = new ArrayList<String>(); // The first element is ime id. String imeId = subtypeSplitter.next(); while (subtypeSplitter.hasNext()) { subtypeHashes.add(subtypeSplitter.next()); } imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes)); } } return imsList; } public InputMethodSettings( Resources res, ContentResolver resolver, HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList, Loading Loading @@ -875,27 +913,9 @@ public class InputMethodUtils { } public List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() { ArrayList<Pair<String, ArrayList<String>>> imsList = new ArrayList<Pair<String, ArrayList<String>>>(); final String enabledInputMethodsStr = getEnabledInputMethodsStr(); if (TextUtils.isEmpty(enabledInputMethodsStr)) { return imsList; } mInputMethodSplitter.setString(enabledInputMethodsStr); while (mInputMethodSplitter.hasNext()) { String nextImsStr = mInputMethodSplitter.next(); mSubtypeSplitter.setString(nextImsStr); if (mSubtypeSplitter.hasNext()) { ArrayList<String> subtypeHashes = new ArrayList<String>(); // The first element is ime id. String imeId = mSubtypeSplitter.next(); while (mSubtypeSplitter.hasNext()) { subtypeHashes.add(mSubtypeSplitter.next()); } imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes)); } } return imsList; return buildInputMethodsAndSubtypeList(getEnabledInputMethodsStr(), mInputMethodSplitter, mSubtypeSplitter); } public void appendAndPutEnabledInputMethodLocked(String id, boolean reloadInputMethodStr) { Loading packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +2 −1 Original line number Diff line number Diff line Loading @@ -62,9 +62,10 @@ public class SettingsHelper { */ private static final ArraySet<String> sBroadcastOnRestore; static { sBroadcastOnRestore = new ArraySet<String>(2); sBroadcastOnRestore = new ArraySet<String>(3); sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS); } private interface SettingsLookup { Loading services/core/java/com/android/server/InputMethodManagerService.java +98 −0 Original line number Diff line number Diff line Loading @@ -86,7 +86,10 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; import android.text.style.SuggestionSpan; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.EventLog; import android.util.LruCache; Loading Loading @@ -125,6 +128,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; Loading @@ -134,8 +138,12 @@ import java.util.Locale; public class InputMethodManagerService extends IInputMethodManager.Stub implements ServiceConnection, Handler.Callback { static final boolean DEBUG = false; 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_PICKER = 1; static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2; static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 3; Loading Loading @@ -466,12 +474,101 @@ public class InputMethodManagerService extends IInputMethodManager.Stub || Intent.ACTION_USER_REMOVED.equals(action)) { updateCurrentProfileIds(); return; } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); if (Settings.Secure.ENABLED_INPUT_METHODS.equals(name)) { final String prevValue = intent.getStringExtra( Intent.EXTRA_SETTING_PREVIOUS_VALUE); final String newValue = intent.getStringExtra( Intent.EXTRA_SETTING_NEW_VALUE); restoreEnabledInputMethods(mContext, prevValue, newValue); } } else { Slog.w(TAG, "Unexpected intent " + intent); } } } // Apply the results of a restore operation to the set of enabled IMEs. Note that this // does not attempt to validate on the fly with any installed device policy, so must only // be run in the context of initial device setup. // // TODO: Move this method to InputMethodUtils with adding unit tests. static void restoreEnabledInputMethods(Context context, String prevValue, String newValue) { if (DEBUG_RESTORE) { Slog.i(TAG, "Restoring enabled input methods:"); Slog.i(TAG, "prev=" + prevValue); 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); // Merge the restored ime+subtype enabled states into the live state for (ArrayMap.Entry<String, ArraySet<String>> entry : newMap.entrySet()) { final String imeId = entry.getKey(); ArraySet<String> prevSubtypes = prevMap.get(imeId); if (prevSubtypes == null) { prevSubtypes = new ArraySet<String>(2); prevMap.put(imeId, prevSubtypes); } prevSubtypes.addAll(entry.getValue()); } final String mergedImesAndSubtypesString = buildInputMethodsAndSubtypesString(prevMap); if (DEBUG_RESTORE) { Slog.i(TAG, "Merged IME string:"); Slog.i(TAG, " " + mergedImesAndSubtypesString); } Settings.Secure.putString(context.getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS, mergedImesAndSubtypesString); } // TODO: Move this method to InputMethodUtils with adding unit tests. static String buildInputMethodsAndSubtypesString(ArrayMap<String, ArraySet<String>> map) { // we want to use the canonical InputMethodSettings implementation, // so we convert data structures first. List<Pair<String, ArrayList<String>>> imeMap = new ArrayList<Pair<String, ArrayList<String>>>(4); for (ArrayMap.Entry<String, ArraySet<String>> entry : map.entrySet()) { final String imeName = entry.getKey(); final ArraySet<String> subtypeSet = entry.getValue(); final ArrayList<String> subtypes = new ArrayList<String>(2); if (subtypeSet != null) { subtypes.addAll(subtypeSet); } imeMap.add(new Pair<String, ArrayList<String>>(imeName, subtypes)); } 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<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; } class MyPackageMonitor extends PackageMonitor { private boolean isChangingPackagesOfCurrentUser() { final int userId = getChangingUserId(); Loading Loading @@ -675,6 +772,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); broadcastFilter.addAction(Intent.ACTION_USER_ADDED); broadcastFilter.addAction(Intent.ACTION_USER_REMOVED); broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED); mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter); mNotificationShown = false; Loading Loading
core/java/android/provider/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -5375,6 +5375,7 @@ public final class Settings { BACKUP_AUTO_RESTORE, ENABLED_ACCESSIBILITY_SERVICES, ENABLED_NOTIFICATION_LISTENERS, ENABLED_INPUT_METHODS, TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, TOUCH_EXPLORATION_ENABLED, ACCESSIBILITY_ENABLED, Loading
core/java/com/android/internal/inputmethod/InputMethodUtils.java +46 −26 Original line number Diff line number Diff line Loading @@ -764,17 +764,55 @@ public class InputMethodUtils { private int[] mCurrentProfileIds = new int[0]; private static void buildEnabledInputMethodsSettingString( StringBuilder builder, Pair<String, ArrayList<String>> pair) { String id = pair.first; ArrayList<String> subtypes = pair.second; builder.append(id); StringBuilder builder, Pair<String, ArrayList<String>> ime) { builder.append(ime.first); // Inputmethod and subtypes are saved in the settings as follows: // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1 for (String subtypeId: subtypes) { for (String subtypeId: ime.second) { builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId); } } public static String buildInputMethodsSettingString( List<Pair<String, ArrayList<String>>> allImeSettingsMap) { final StringBuilder b = new StringBuilder(); boolean needsSeparator = false; for (Pair<String, ArrayList<String>> ime : allImeSettingsMap) { if (needsSeparator) { b.append(INPUT_METHOD_SEPARATER); } buildEnabledInputMethodsSettingString(b, ime); needsSeparator = true; } return b.toString(); } public static List<Pair<String, ArrayList<String>>> buildInputMethodsAndSubtypeList( String enabledInputMethodsStr, TextUtils.SimpleStringSplitter inputMethodSplitter, TextUtils.SimpleStringSplitter subtypeSplitter) { ArrayList<Pair<String, ArrayList<String>>> imsList = new ArrayList<Pair<String, ArrayList<String>>>(); if (TextUtils.isEmpty(enabledInputMethodsStr)) { return imsList; } inputMethodSplitter.setString(enabledInputMethodsStr); while (inputMethodSplitter.hasNext()) { String nextImsStr = inputMethodSplitter.next(); subtypeSplitter.setString(nextImsStr); if (subtypeSplitter.hasNext()) { ArrayList<String> subtypeHashes = new ArrayList<String>(); // The first element is ime id. String imeId = subtypeSplitter.next(); while (subtypeSplitter.hasNext()) { subtypeHashes.add(subtypeSplitter.next()); } imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes)); } } return imsList; } public InputMethodSettings( Resources res, ContentResolver resolver, HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList, Loading Loading @@ -875,27 +913,9 @@ public class InputMethodUtils { } public List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() { ArrayList<Pair<String, ArrayList<String>>> imsList = new ArrayList<Pair<String, ArrayList<String>>>(); final String enabledInputMethodsStr = getEnabledInputMethodsStr(); if (TextUtils.isEmpty(enabledInputMethodsStr)) { return imsList; } mInputMethodSplitter.setString(enabledInputMethodsStr); while (mInputMethodSplitter.hasNext()) { String nextImsStr = mInputMethodSplitter.next(); mSubtypeSplitter.setString(nextImsStr); if (mSubtypeSplitter.hasNext()) { ArrayList<String> subtypeHashes = new ArrayList<String>(); // The first element is ime id. String imeId = mSubtypeSplitter.next(); while (mSubtypeSplitter.hasNext()) { subtypeHashes.add(mSubtypeSplitter.next()); } imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes)); } } return imsList; return buildInputMethodsAndSubtypeList(getEnabledInputMethodsStr(), mInputMethodSplitter, mSubtypeSplitter); } public void appendAndPutEnabledInputMethodLocked(String id, boolean reloadInputMethodStr) { Loading
packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +2 −1 Original line number Diff line number Diff line Loading @@ -62,9 +62,10 @@ public class SettingsHelper { */ private static final ArraySet<String> sBroadcastOnRestore; static { sBroadcastOnRestore = new ArraySet<String>(2); sBroadcastOnRestore = new ArraySet<String>(3); sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS); } private interface SettingsLookup { Loading
services/core/java/com/android/server/InputMethodManagerService.java +98 −0 Original line number Diff line number Diff line Loading @@ -86,7 +86,10 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; import android.text.style.SuggestionSpan; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.EventLog; import android.util.LruCache; Loading Loading @@ -125,6 +128,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; Loading @@ -134,8 +138,12 @@ import java.util.Locale; public class InputMethodManagerService extends IInputMethodManager.Stub implements ServiceConnection, Handler.Callback { static final boolean DEBUG = false; 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_PICKER = 1; static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2; static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 3; Loading Loading @@ -466,12 +474,101 @@ public class InputMethodManagerService extends IInputMethodManager.Stub || Intent.ACTION_USER_REMOVED.equals(action)) { updateCurrentProfileIds(); return; } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); if (Settings.Secure.ENABLED_INPUT_METHODS.equals(name)) { final String prevValue = intent.getStringExtra( Intent.EXTRA_SETTING_PREVIOUS_VALUE); final String newValue = intent.getStringExtra( Intent.EXTRA_SETTING_NEW_VALUE); restoreEnabledInputMethods(mContext, prevValue, newValue); } } else { Slog.w(TAG, "Unexpected intent " + intent); } } } // Apply the results of a restore operation to the set of enabled IMEs. Note that this // does not attempt to validate on the fly with any installed device policy, so must only // be run in the context of initial device setup. // // TODO: Move this method to InputMethodUtils with adding unit tests. static void restoreEnabledInputMethods(Context context, String prevValue, String newValue) { if (DEBUG_RESTORE) { Slog.i(TAG, "Restoring enabled input methods:"); Slog.i(TAG, "prev=" + prevValue); 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); // Merge the restored ime+subtype enabled states into the live state for (ArrayMap.Entry<String, ArraySet<String>> entry : newMap.entrySet()) { final String imeId = entry.getKey(); ArraySet<String> prevSubtypes = prevMap.get(imeId); if (prevSubtypes == null) { prevSubtypes = new ArraySet<String>(2); prevMap.put(imeId, prevSubtypes); } prevSubtypes.addAll(entry.getValue()); } final String mergedImesAndSubtypesString = buildInputMethodsAndSubtypesString(prevMap); if (DEBUG_RESTORE) { Slog.i(TAG, "Merged IME string:"); Slog.i(TAG, " " + mergedImesAndSubtypesString); } Settings.Secure.putString(context.getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS, mergedImesAndSubtypesString); } // TODO: Move this method to InputMethodUtils with adding unit tests. static String buildInputMethodsAndSubtypesString(ArrayMap<String, ArraySet<String>> map) { // we want to use the canonical InputMethodSettings implementation, // so we convert data structures first. List<Pair<String, ArrayList<String>>> imeMap = new ArrayList<Pair<String, ArrayList<String>>>(4); for (ArrayMap.Entry<String, ArraySet<String>> entry : map.entrySet()) { final String imeName = entry.getKey(); final ArraySet<String> subtypeSet = entry.getValue(); final ArrayList<String> subtypes = new ArrayList<String>(2); if (subtypeSet != null) { subtypes.addAll(subtypeSet); } imeMap.add(new Pair<String, ArrayList<String>>(imeName, subtypes)); } 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<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; } class MyPackageMonitor extends PackageMonitor { private boolean isChangingPackagesOfCurrentUser() { final int userId = getChangingUserId(); Loading Loading @@ -675,6 +772,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); broadcastFilter.addAction(Intent.ACTION_USER_ADDED); broadcastFilter.addAction(Intent.ACTION_USER_REMOVED); broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED); mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter); mNotificationShown = false; Loading