Add utility of enabled InputMethod settings to InputMethodManagerService

- Add setter of enabled InputMethodSubtypes
- Enabled InputMethods are saved as follows:
-- enabled_inputmethod0;enabled_subtype0;enabled_subtype1:enabled_inputmethod1
- TODO: Fix Settings application to parse new Enabled InputMethod string.
-- Currently IMMS doesn't save InputMethodSubtypes so this will not break Settings application.

Change-Id: Icd0f13de396ce286ff6563e8c2775d53bcdacbf3
This commit is contained in:
satok
2010-09-29 11:52:06 +09:00
parent 2fe9a8f6f6
commit d87c2594c6

View File

@ -117,6 +117,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final Context mContext;
final Handler mHandler;
final InputMethodSettings mSettings;
final SettingsObserver mSettingsObserver;
final StatusBarManagerService mStatusBar;
final IWindowManager mIWindowManager;
@ -126,13 +127,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// All known input methods. mMethodMap also serves as the global
// lock for this class.
final ArrayList<InputMethodInfo> mMethodList
= new ArrayList<InputMethodInfo>();
final HashMap<String, InputMethodInfo> mMethodMap
= new HashMap<String, InputMethodInfo>();
final TextUtils.SimpleStringSplitter mStringColonSplitter
= new TextUtils.SimpleStringSplitter(':');
final ArrayList<InputMethodInfo> mMethodList = new ArrayList<InputMethodInfo>();
final HashMap<String, InputMethodInfo> mMethodMap = new HashMap<String, InputMethodInfo>();
class SessionState {
final ClientState client;
@ -483,27 +479,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mStatusBar = statusBar;
statusBar.setIconVisibility("ime", false);
// mSettings should be created before buildInputMethodListLocked
mSettings = new InputMethodSettings(context.getContentResolver(), mMethodMap, mMethodList);
buildInputMethodListLocked(mMethodList, mMethodMap);
mSettings.enableAllIMEsIfThereIsNoEnabledIME();
final String enabledStr = Settings.Secure.getString(
mContext.getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS);
Slog.i(TAG, "Enabled input methods: " + enabledStr);
final String defaultIme = Settings.Secure.getString(mContext
.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
if (enabledStr == null || TextUtils.isEmpty(defaultIme)) {
Slog.i(TAG, "Enabled input methods or default IME has not been set, enabling all");
if (TextUtils.isEmpty(Settings.Secure.getString(
mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD))) {
InputMethodInfo defIm = null;
StringBuilder sb = new StringBuilder(256);
final int N = mMethodList.size();
for (int i=0; i<N; i++) {
InputMethodInfo imi = mMethodList.get(i);
Slog.i(TAG, "Adding: " + imi.getId());
if (i > 0) sb.append(':');
sb.append(imi.getId());
for (InputMethodInfo imi: mMethodList) {
if (defIm == null && imi.getIsDefaultResourceId() != 0) {
try {
Resources res = mContext.createPackageContext(
Resources res = context.createPackageContext(
imi.getPackageName(), 0).getResources();
if (res.getBoolean(imi.getIsDefaultResourceId())) {
defIm = imi;
@ -514,12 +501,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
if (defIm == null && N > 0) {
if (defIm == null && mMethodList.size() > 0) {
defIm = mMethodList.get(0);
Slog.i(TAG, "No default found, using " + defIm.getId());
}
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS, sb.toString());
if (defIm != null) {
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, defIm.getId());
@ -567,31 +552,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public List<InputMethodInfo> getEnabledInputMethodList() {
synchronized (mMethodMap) {
return getEnabledInputMethodListLocked();
return mSettings.getEnabledInputMethodListLocked();
}
}
List<InputMethodInfo> getEnabledInputMethodListLocked() {
final ArrayList<InputMethodInfo> res = new ArrayList<InputMethodInfo>();
final String enabledStr = Settings.Secure.getString(
mContext.getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS);
if (enabledStr != null) {
final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
splitter.setString(enabledStr);
while (splitter.hasNext()) {
InputMethodInfo info = mMethodMap.get(splitter.next());
if (info != null) {
res.add(info);
}
}
}
return res;
}
public void addClient(IInputMethodClient client,
IInputContext inputContext, int uid, int pid) {
synchronized (mMethodMap) {
@ -1471,7 +1435,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
private boolean chooseNewDefaultIMELocked() {
List<InputMethodInfo> enabled = getEnabledInputMethodListLocked();
List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
if (enabled != null && enabled.size() > 0) {
// We'd prefer to fall back on a system IME, since that is safer.
int i=enabled.size();
@ -1650,7 +1614,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
hideInputMethodMenu();
}
};
TypedArray a = context.obtainStyledAttributes(null,
com.android.internal.R.styleable.DialogPreference,
com.android.internal.R.attr.alertDialogStyle, 0);
@ -1664,7 +1628,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
.setIcon(a.getDrawable(
com.android.internal.R.styleable.DialogPreference_dialogTitle));
a.recycle();
mDialogBuilder.setSingleChoiceItems(mItems, checkedItem,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
@ -1738,81 +1702,45 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// Make sure this is a valid input method.
InputMethodInfo imm = mMethodMap.get(id);
if (imm == null) {
if (imm == null) {
throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
}
throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
}
StringBuilder builder = new StringBuilder(256);
List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
.getEnabledInputMethodsAndSubtypeListLocked();
boolean removed = false;
String firstId = null;
// Look through the currently enabled input methods.
String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS);
if (enabledStr != null) {
final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
splitter.setString(enabledStr);
while (splitter.hasNext()) {
String curId = splitter.next();
if (curId.equals(id)) {
if (enabled) {
// We are enabling this input method, but it is
// already enabled. Nothing to do. The previous
// state was enabled.
return true;
}
// We are disabling this input method, and it is
// currently enabled. Skip it to remove from the
// new list.
removed = true;
} else if (!enabled) {
// We are building a new list of input methods that
// doesn't contain the given one.
if (firstId == null) firstId = curId;
if (builder.length() > 0) builder.append(':');
builder.append(curId);
if (enabled) {
for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
if (pair.first.equals(id)) {
// We are enabling this input method, but it is already enabled.
// Nothing to do. The previous state was enabled.
return true;
}
}
}
if (!enabled) {
if (!removed) {
// We are disabling the input method but it is already
// disabled. Nothing to do. The previous state was
// disabled.
mSettings.appendAndPutEnabledInputMethodLocked(id, false);
// Previous state was disabled.
return false;
} else {
StringBuilder builder = new StringBuilder();
if (mSettings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
builder, enabledInputMethodsList, id)) {
// Disabled input method is currently selected, switch to another one.
String selId = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
if (id.equals(selId)) {
Settings.Secure.putString(
mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD,
enabledInputMethodsList.size() > 0
? enabledInputMethodsList.get(0).first : "");
resetSelectedInputMethodSubtype();
}
// Previous state was enabled.
return true;
} else {
// We are disabling the input method but it is already disabled.
// Nothing to do. The previous state was disabled.
return false;
}
// Update the setting with the new list of input methods.
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
// We the disabled input method is currently selected, switch
// to another one.
String selId = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
if (id.equals(selId)) {
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD,
firstId != null ? firstId : "");
resetSelectedInputMethodSubtype();
}
// Previous state was enabled.
return true;
}
// Add in the newly enabled input method.
if (enabledStr == null || enabledStr.length() == 0) {
enabledStr = id;
} else {
enabledStr = enabledStr + ':' + id;
}
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
// Previous state was disabled.
return false;
}
private void resetSelectedInputMethodSubtype() {
@ -1862,6 +1790,161 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return mCurrentSubtype;
}
/**
* Utility class for putting and getting settings for InputMethod
* TODO: Move all putters and getters of settings to this class.
*/
private static class InputMethodSettings {
// The string for enabled input method is saved as follows:
// example: ("ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0")
private static final char INPUT_METHOD_SEPARATER = ':';
private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';';
private final TextUtils.SimpleStringSplitter mStringColonSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER);
private final TextUtils.SimpleStringSplitter mStringSemiColonSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER);
private final ContentResolver mResolver;
private final HashMap<String, InputMethodInfo> mMethodMap;
private final ArrayList<InputMethodInfo> mMethodList;
private String mEnabledInputMethodsStrCache;
private static void buildEnabledInputMethodsSettingString(
StringBuilder builder, Pair<String, ArrayList<String>> pair) {
String id = pair.first;
ArrayList<String> subtypes = pair.second;
builder.append(id);
if (subtypes.size() > 0) {
builder.append(subtypes.get(0));
for (int i = 1; i < subtypes.size(); ++i) {
builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypes.get(i));
}
}
}
public InputMethodSettings(
ContentResolver resolver, HashMap<String, InputMethodInfo> methodMap,
ArrayList<InputMethodInfo> methodList) {
mResolver = resolver;
mMethodMap = methodMap;
mMethodList = methodList;
}
public List<InputMethodInfo> getEnabledInputMethodListLocked() {
return createEnabledInputMethodListLocked(
getEnabledInputMethodsAndSubtypeListLocked());
}
// At the initial boot, the settings for input methods are not set,
// so we need to enable IME in that case.
public void enableAllIMEsIfThereIsNoEnabledIME() {
if (TextUtils.isEmpty(getEnabledInputMethodsStr())) {
StringBuilder sb = new StringBuilder();
final int N = mMethodList.size();
for (int i = 0; i < N; i++) {
InputMethodInfo imi = mMethodList.get(i);
Slog.i(TAG, "Adding: " + imi.getId());
if (i > 0) sb.append(':');
sb.append(imi.getId());
}
putEnabledInputMethodsStr(sb.toString());
}
}
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;
}
mStringColonSplitter.setString(enabledInputMethodsStr);
while (mStringColonSplitter.hasNext()) {
String nextImsStr = mStringColonSplitter.next();
mStringSemiColonSplitter.setString(nextImsStr);
if (mStringSemiColonSplitter.hasNext()) {
ArrayList<String> subtypeHashes = new ArrayList<String>();
// The first element is ime id.
String imeId = mStringSemiColonSplitter.next();
while (mStringSemiColonSplitter.hasNext()) {
subtypeHashes.add(mStringSemiColonSplitter.next());
}
imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
}
}
return imsList;
}
public void appendAndPutEnabledInputMethodLocked(String id, boolean reloadInputMethodStr) {
if (reloadInputMethodStr) {
getEnabledInputMethodsStr();
}
if (TextUtils.isEmpty(mEnabledInputMethodsStrCache)) {
// Add in the newly enabled input method.
putEnabledInputMethodsStr(id);
} else {
putEnabledInputMethodsStr(
mEnabledInputMethodsStrCache + INPUT_METHOD_SEPARATER + id);
}
}
/**
* Build and put a string of EnabledInputMethods with removing specified Id.
* @return the specified id was removed or not.
*/
public boolean buildAndPutEnabledInputMethodsStrRemovingIdLocked(
StringBuilder builder, List<Pair<String, ArrayList<String>>> imsList, String id) {
boolean isRemoved = false;
boolean needsAppendSeparator = false;
for (Pair<String, ArrayList<String>> ims: imsList) {
String curId = ims.first;
if (curId.equals(id)) {
// We are disabling this input method, and it is
// currently enabled. Skip it to remove from the
// new list.
isRemoved = true;
} else {
if (needsAppendSeparator) {
builder.append(INPUT_METHOD_SEPARATER);
} else {
needsAppendSeparator = true;
}
buildEnabledInputMethodsSettingString(builder, ims);
}
}
if (isRemoved) {
// Update the setting with the new list of input methods.
putEnabledInputMethodsStr(builder.toString());
}
return isRemoved;
}
private List<InputMethodInfo> createEnabledInputMethodListLocked(
List<Pair<String, ArrayList<String>>> imsList) {
final ArrayList<InputMethodInfo> res = new ArrayList<InputMethodInfo>();
for (Pair<String, ArrayList<String>> ims: imsList) {
InputMethodInfo info = mMethodMap.get(ims.first);
if (info != null) {
res.add(info);
}
}
return res;
}
private void putEnabledInputMethodsStr(String str) {
Settings.Secure.putString(mResolver, Settings.Secure.ENABLED_INPUT_METHODS, str);
mEnabledInputMethodsStrCache = str;
}
private String getEnabledInputMethodsStr() {
mEnabledInputMethodsStrCache = Settings.Secure.getString(
mResolver, Settings.Secure.ENABLED_INPUT_METHODS);
return mEnabledInputMethodsStrCache;
}
}
// ----------------------------------------------------------------------
@Override