diff options
Diffstat (limited to 'services/java/com/android/server/InputMethodManagerService.java')
-rw-r--r-- | services/java/com/android/server/InputMethodManagerService.java | 206 |
1 files changed, 181 insertions, 25 deletions
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 9efc708..675760f 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -61,18 +61,21 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.provider.Settings; import android.provider.Settings.Secure; +import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; import android.util.EventLog; +import android.util.Pair; import android.util.Slog; import android.util.PrintWriterPrinter; import android.util.Printer; import android.view.IWindowManager; import android.view.WindowManager; +import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodSubtype; import java.io.FileDescriptor; import java.io.IOException; @@ -93,6 +96,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub static final String TAG = "InputManagerService"; static final int MSG_SHOW_IM_PICKER = 1; + static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2; static final int MSG_UNBIND_INPUT = 1000; static final int MSG_BIND_INPUT = 1010; @@ -109,6 +113,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub static final long TIME_TO_RECONNECT = 10*1000; + private static final int NOT_A_SUBTYPE_ID = -1; + final Context mContext; final Handler mHandler; final SettingsObserver mSettingsObserver; @@ -224,6 +230,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub String mCurId; /** + * The current subtype of the current input method. + */ + private InputMethodSubtype mCurrentSubtype; + + + /** * Set to true if our ServiceConnection is currently actively bound to * a service (whether or not we have gotten its IBinder back yet). */ @@ -292,6 +304,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub AlertDialog mSwitchingDialog; InputMethodInfo[] mIms; CharSequence[] mItems; + int[] mSubtypeIds; class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler) { @@ -299,6 +312,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub ContentResolver resolver = mContext.getContentResolver(); resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.DEFAULT_INPUT_METHOD), false, this); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this); } @Override public void onChange(boolean selfChange) { @@ -351,9 +366,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (!doit) { return true; } - Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD, ""); + resetSelectedInputMethodSubtype(); chooseNewDefaultIMELocked(); return true; } @@ -409,16 +424,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (!chooseNewDefaultIMELocked()) { changed = true; curIm = null; - curInputMethodId = ""; Slog.i(TAG, "Unsetting current input method"); Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, - curInputMethodId); + Settings.Secure.DEFAULT_INPUT_METHOD, ""); + resetSelectedInputMethodSubtype(); } } } } - + if (curIm == null) { // We currently don't have a default input method... is // one now available? @@ -509,6 +523,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (defIm != null) { Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD, defIm.getId()); + putSelectedInputMethodSubtype(defIm, NOT_A_SUBTYPE_ID); } } @@ -964,10 +979,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // sync, so we will never have a DEFAULT_INPUT_METHOD that is not // enabled. String id = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD); + Settings.Secure.DEFAULT_INPUT_METHOD); if (id != null && id.length() > 0) { try { - setInputMethodLocked(id); + setInputMethodLocked(id, getSelectedInputMethodSubtypeId(id)); } catch (IllegalArgumentException e) { Slog.w(TAG, "Unknown input method from prefs: " + id, e); mCurMethodId = null; @@ -980,21 +995,44 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - void setInputMethodLocked(String id) { + /* package */ void setInputMethodLocked(String id, int subtypeId) { InputMethodInfo info = mMethodMap.get(id); if (info == null) { throw new IllegalArgumentException("Unknown id: " + id); } if (id.equals(mCurMethodId)) { + if (subtypeId != NOT_A_SUBTYPE_ID) { + InputMethodSubtype subtype = info.getSubtypes().get(subtypeId); + if (subtype != mCurrentSubtype) { + synchronized (mMethodMap) { + if (mCurMethod != null) { + try { + putSelectedInputMethodSubtype(info, subtypeId); + mCurMethod.changeInputMethodSubtype(subtype); + } catch (RemoteException e) { + return; + } + } + } + } + } return; } final long ident = Binder.clearCallingIdentity(); try { mCurMethodId = id; + // Set a subtype to this input method. + // subtypeId the name of a subtype which will be set. + if (putSelectedInputMethodSubtype(info, subtypeId)) { + mCurrentSubtype = info.getSubtypes().get(subtypeId); + } else { + mCurrentSubtype = null; + } + Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, id); + Settings.Secure.DEFAULT_INPUT_METHOD, id); if (ActivityManagerNative.isSystemReady()) { Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED); @@ -1226,7 +1264,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + public void showInputMethodSubtypePickerFromClient(IInputMethodClient client) { + synchronized (mMethodMap) { + if (mCurClient == null || client == null + || mCurClient.client.asBinder() != client.asBinder()) { + Slog.w(TAG, "Ignoring showInputSubtypeMethodDialogFromClient of: " + client); + } + + mHandler.sendEmptyMessage(MSG_SHOW_IM_SUBTYPE_PICKER); + } + } + public void setInputMethod(IBinder token, String id) { + setInputMethodWithSubtype(token, id, NOT_A_SUBTYPE_ID); + } + + private void setInputMethodWithSubtype(IBinder token, String id, int subtypeId) { synchronized (mMethodMap) { if (token == null) { if (mContext.checkCallingOrSelfPermission( @@ -1243,7 +1296,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub long ident = Binder.clearCallingIdentity(); try { - setInputMethodLocked(id); + setInputMethodLocked(id, subtypeId); } finally { Binder.restoreCallingIdentity(ident); } @@ -1307,6 +1360,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub showInputMethodMenu(); return true; + case MSG_SHOW_IM_SUBTYPE_PICKER: + showInputMethodSubtypeMenu(); + return true; + // --------------------------------------------------------- case MSG_UNBIND_INPUT: @@ -1417,9 +1474,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub break; } } + InputMethodInfo imi = enabled.get(i); Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, - enabled.get(i).getId()); + Settings.Secure.DEFAULT_INPUT_METHOD, imi.getId()); + putSelectedInputMethodSubtype(imi, NOT_A_SUBTYPE_ID); return true; } @@ -1490,7 +1548,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // ---------------------------------------------------------------------- - void showInputMethodMenu() { + private void showInputMethodMenu() { + showInputMethodMenuInternal(false); + } + + private void showInputMethodSubtypeMenu() { + showInputMethodMenuInternal(true); + } + + private void showInputMethodMenuInternal(boolean showSubtypes) { if (DEBUG) Slog.v(TAG, "Show switching menu"); final Context context = mContext; @@ -1499,42 +1565,78 @@ public class InputMethodManagerService extends IInputMethodManager.Stub String lastInputMethodId = Settings.Secure.getString(context .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); + int lastInputMethodSubtypeId = getSelectedInputMethodSubtypeId(lastInputMethodId); if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId); final List<InputMethodInfo> immis = getEnabledInputMethodList(); + ArrayList<Integer> subtypeIds = new ArrayList<Integer>(); if (immis == null) { return; } - + synchronized (mMethodMap) { hideInputMethodMenuLocked(); int N = immis.size(); - final Map<CharSequence, InputMethodInfo> imMap = - new TreeMap<CharSequence, InputMethodInfo>(Collator.getInstance()); + final Map<CharSequence, Pair<InputMethodInfo, Integer>> imMap = + new TreeMap<CharSequence, Pair<InputMethodInfo, Integer>>(Collator.getInstance()); for (int i = 0; i < N; ++i) { InputMethodInfo property = immis.get(i); if (property == null) { continue; } - imMap.put(property.loadLabel(pm), property); + // TODO: Show only enabled subtypes + ArrayList<InputMethodSubtype> subtypes = property.getSubtypes(); + CharSequence label = property.loadLabel(pm); + if (showSubtypes && subtypes.size() > 0) { + for (int j = 0; j < subtypes.size(); ++j) { + InputMethodSubtype subtype = subtypes.get(j); + CharSequence title; + int nameResId = subtype.getNameResId(); + int modeResId = subtype.getModeResId(); + if (nameResId != 0) { + title = pm.getText(property.getPackageName(), nameResId, + property.getServiceInfo().applicationInfo); + } else { + CharSequence language = subtype.getLocale(); + CharSequence mode = modeResId == 0 ? null + : pm.getText(property.getPackageName(), modeResId, + property.getServiceInfo().applicationInfo); + // TODO: Use more friendly Title and UI + title = label + "," + (mode == null ? "" : mode) + "," + + (language == null ? "" : language); + } + imMap.put(title, new Pair<InputMethodInfo, Integer>(property, j)); + } + } else { + imMap.put(label, + new Pair<InputMethodInfo, Integer>(property, NOT_A_SUBTYPE_ID)); + subtypeIds.add(0); + } } N = imMap.size(); mItems = imMap.keySet().toArray(new CharSequence[N]); - mIms = imMap.values().toArray(new InputMethodInfo[N]); - + mIms = new InputMethodInfo[N]; + mSubtypeIds = new int[N]; int checkedItem = 0; for (int i = 0; i < N; ++i) { + Pair<InputMethodInfo, Integer> value = imMap.get(mItems[i]); + mIms[i] = value.first; + mSubtypeIds[i] = value.second; if (mIms[i].getId().equals(lastInputMethodId)) { - checkedItem = i; - break; + int subtypeId = mSubtypeIds[i]; + if ((subtypeId == NOT_A_SUBTYPE_ID) + || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0) + || (subtypeId == lastInputMethodSubtypeId)) { + checkedItem = i; + } } } - + AlertDialog.OnClickListener adocl = new AlertDialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { hideInputMethodMenu(); @@ -1559,13 +1661,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub new AlertDialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { synchronized (mMethodMap) { - if (mIms == null || mIms.length <= which) { + if (mIms == null || mIms.length <= which + || mSubtypeIds == null || mSubtypeIds.length <= which) { return; } InputMethodInfo im = mIms[which]; + int subtypeId = mSubtypeIds[which]; hideInputMethodMenu(); if (im != null) { - setInputMethodLocked(im.getId()); + if ((subtypeId < 0) + || (subtypeId >= im.getSubtypes().size())) { + subtypeId = NOT_A_SUBTYPE_ID; + } + setInputMethodLocked(im.getId(), subtypeId); } } } @@ -1679,6 +1787,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD, firstId != null ? firstId : ""); + resetSelectedInputMethodSubtype(); } // Previous state was enabled. return true; @@ -1698,6 +1807,53 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return false; } + private void resetSelectedInputMethodSubtype() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, NOT_A_SUBTYPE_ID); + } + + private boolean putSelectedInputMethodSubtype(InputMethodInfo imi, int subtypeId) { + ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes(); + if (subtypeId >= 0 && subtypeId < subtypes.size()) { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, + subtypes.get(subtypeId).hashCode()); + return true; + } else { + resetSelectedInputMethodSubtype(); + return false; + } + } + + private int getSelectedInputMethodSubtypeId(String id) { + InputMethodInfo imi = mMethodMap.get(id); + if (imi == null) { + return NOT_A_SUBTYPE_ID; + } + ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes(); + int subtypeId; + try { + subtypeId = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE); + } catch (SettingNotFoundException e) { + return NOT_A_SUBTYPE_ID; + } + for (int i = 0; i < subtypes.size(); ++i) { + InputMethodSubtype ims = subtypes.get(i); + if (subtypeId == ims.hashCode()) { + return i; + } + } + return NOT_A_SUBTYPE_ID; + } + + /** + * @return Return the current subtype of this input method. + */ + public InputMethodSubtype getCurrentInputMethodSubtype() { + return mCurrentSubtype; + } + // ---------------------------------------------------------------------- @Override |