summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/provider/Settings.java1
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodUtils.java72
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java3
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java98
4 files changed, 147 insertions, 27 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e6b39b5..de536bd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -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,
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 57fcf57..06bdb24 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -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,
@@ -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) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 30786f0..952b220 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -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 {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index fd35b5e..4677f65 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -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;
@@ -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;
@@ -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;
@@ -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();
@@ -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;