diff options
-rw-r--r-- | api/current.xml | 21 | ||||
-rw-r--r-- | core/java/android/view/inputmethod/InputMethodManager.java | 34 | ||||
-rw-r--r-- | core/java/com/android/internal/view/IInputMethodManager.aidl | 3 | ||||
-rw-r--r-- | services/java/com/android/server/InputMethodManagerService.java | 155 |
4 files changed, 186 insertions, 27 deletions
diff --git a/api/current.xml b/api/current.xml index 42cdaf2..4025f3c 100644 --- a/api/current.xml +++ b/api/current.xml @@ -156003,22 +156003,22 @@ visibility="public" > </field> -<field name="GROUP_VISIBLE" +<field name="GROUP_IS_READ_ONLY" type="java.lang.String" transient="false" volatile="false" - value=""group_visible"" + value=""group_is_read_only"" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> -<field name="GROUP_IS_READ_ONLY" +<field name="GROUP_VISIBLE" type="java.lang.String" transient="false" volatile="false" - value=""group_is_read_only"" + value=""group_visible"" static="true" final="true" deprecated="not deprecated" @@ -220894,6 +220894,17 @@ visibility="public" > </method> +<method name="getShortcutInputMethodsAndSubtypes" + return="java.util.List<android.util.Pair<android.view.inputmethod.InputMethodInfo, android.view.inputmethod.InputMethodSubtype>>" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="hideSoftInputFromInputMethod" return="void" abstract="false" @@ -248473,7 +248484,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="t" type="T"> +<parameter name="arg0" type="T"> </parameter> </method> </interface> diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index fe55f34..a5f3ade 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -23,6 +23,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.Parcelable; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -47,6 +48,7 @@ import com.android.internal.view.InputBindResult; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -1452,6 +1454,38 @@ public final class InputMethodManager { } } + public List<Pair<InputMethodInfo, InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() { + synchronized (mH) { + List<Pair<InputMethodInfo, InputMethodSubtype>> ret = + new ArrayList<Pair<InputMethodInfo, InputMethodSubtype>>(); + try { + // TODO: We should change the return type from List<Object> to List<Parcelable> + List<Object> info = mService.getShortcutInputMethodsAndSubtypes(); + // "info" has imi1, subtype1, imi2, subtype2, imi3, subtype3,..... in the list + Object imi; + Object subtype; + if (info != null && info.size() > 0) { + final int N = info.size(); + if (N % 2 == 0) { + for (int i = 0; i < N;) { + if ((imi = info.get(i++)) instanceof InputMethodInfo) { + subtype = info.get(i++); + ret.add(new Pair<InputMethodInfo, InputMethodSubtype> ( + (InputMethodInfo)imi, + (subtype instanceof InputMethodSubtype) ? + (InputMethodSubtype)subtype : null)); + } + } + } else { + Log.w(TAG, "The size of list was illegal."); + } + } + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + return ret; + } + } public boolean switchToLastInputMethod(IBinder imeToken) { synchronized (mH) { try { diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 63d05ec..125b210 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -32,6 +32,9 @@ interface IInputMethodManager { List<InputMethodInfo> getInputMethodList(); List<InputMethodInfo> getEnabledInputMethodList(); List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in InputMethodInfo imi); + // TODO: We should change the return type from List to List<Parcelable> + // Currently there is a bug that aidl doesn't accept List<Parcelable> + List getShortcutInputMethodsAndSubtypes(); void addClient(in IInputMethodClient client, in IInputContext inputContext, int uid, int pid); void removeClient(in IInputMethodClient client); diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index e14345b..b2cc6bd 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -55,6 +55,7 @@ import android.os.IBinder; import android.os.IInterface; import android.os.Message; import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -120,6 +121,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // If IME doesn't support the system locale, the default subtype will be the first defined one. private static final int DEFAULT_SUBTYPE_ID = 0; + private static final String SUBTYPE_MODE_KEYBOARD = "keyboard"; + private static final String SUBTYPE_MODE_VOICE = "voice"; + final Context mContext; final Handler mHandler; final InputMethodSettings mSettings; @@ -235,6 +239,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ private InputMethodSubtype mCurrentSubtype; + // This list contains the pairs of InputMethodInfo and InputMethodSubtype. + private List<Pair<InputMethodInfo, InputMethodSubtype>> mShortcutInputMethodsAndSubtypes; + // This list is used for returning the pairs of InputMethodInfo and InputMethodSubtype through + // aidl. This list has imi1, subtype1 imi2, subtype2... + private List mShortcutInputMethodsAndSubtypesObjectList; /** * Set to true if our ServiceConnection is currently actively bound to @@ -983,6 +992,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurMethodId = null; unbindCurrentMethodLocked(true); } + mShortcutInputMethodsAndSubtypes = null; } else { // There is no longer an input method set, so stop any current one. mCurMethodId = null; @@ -1910,25 +1920,31 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return NOT_A_SUBTYPE_ID; } - // If there are no selected subtypes, tries finding the most applicable one according to the - // current system locale - private int findApplicableSubtypeLocked(String id) { - InputMethodInfo imi = mMethodMap.get(id); - if (imi == null) { - return NOT_A_SUBTYPE_ID; - } - ArrayList<InputMethodSubtype> subtypes = imi.getSubtypes(); + /** + * If there are no selected subtypes, tries finding the most applicable one according to the + * given locale. + * @param subtypes this function will search the most applicable subtype in subtypes + * @param mode subtypes will be filtered by mode + * @param locale subtypes will be filtered by locale + * @param defaultSubtypeId if this function can't find the most applicable subtype, it will + * return defaultSubtypeId + * @return the most applicable subtypeId + */ + private int findLastResortApplicableSubtypeLocked( + List<InputMethodSubtype> subtypes, String mode, String locale, int defaultSubtypeId) { if (subtypes == null || subtypes.size() == 0) { return NOT_A_SUBTYPE_ID; } - final String locale = mContext.getResources().getConfiguration().locale.toString(); + if (TextUtils.isEmpty(locale)) { + locale = mContext.getResources().getConfiguration().locale.toString(); + } final String language = locale.substring(0, 2); boolean partialMatchFound = false; - int applicableSubtypeId = DEFAULT_SUBTYPE_ID; + int applicableSubtypeId = defaultSubtypeId; for (int i = 0; i < subtypes.size(); ++i) { final String subtypeLocale = subtypes.get(i).getLocale(); - // An applicable subtype should be a keyboard subtype - if (subtypes.get(i).getMode().equalsIgnoreCase("keyboard")) { + // An applicable subtype should match "mode". + if (subtypes.get(i).getMode().equalsIgnoreCase(mode)) { if (locale.equals(subtypeLocale)) { // Exact match (e.g. system locale is "en_US" and subtype locale is "en_US") applicableSubtypeId = i; @@ -1950,34 +1966,129 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return applicableSubtypeId; } + // If there are no selected shortcuts, tries finding the most applicable ones. + private Pair<InputMethodInfo, InputMethodSubtype> + findLastResortApplicableShortcutInputMethodAndSubtypeLocked(String mode) { + List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked(); + InputMethodInfo mostApplicableIMI = null; + int mostApplicableSubtypeId = NOT_A_SUBTYPE_ID; + boolean foundInSystemIME = false; + + // Search applicable subtype for each InputMethodInfo + for (InputMethodInfo imi: imis) { + int subtypeId = NOT_A_SUBTYPE_ID; + if (mCurrentSubtype != null) { + // 1. Search with the current subtype's locale and the enabled subtypes + subtypeId = findLastResortApplicableSubtypeLocked( + mSettings.getEnabledInputMethodSubtypeListLocked( + imi), mode, mCurrentSubtype.getLocale(), NOT_A_SUBTYPE_ID); + if (subtypeId == NOT_A_SUBTYPE_ID) { + // 2. Search with the current subtype's locale and all subtypes + subtypeId = findLastResortApplicableSubtypeLocked(imi.getSubtypes(), + mode, mCurrentSubtype.getLocale(), NOT_A_SUBTYPE_ID); + } + } + // 3. Search with the system locale and the enabled subtypes + if (subtypeId == NOT_A_SUBTYPE_ID) { + subtypeId = findLastResortApplicableSubtypeLocked( + mSettings.getEnabledInputMethodSubtypeListLocked( + imi), mode, null, NOT_A_SUBTYPE_ID); + } + if (subtypeId == NOT_A_SUBTYPE_ID) { + // 4. Search with the system locale and all subtypes + subtypeId = findLastResortApplicableSubtypeLocked(imi.getSubtypes(), + mode, null, NOT_A_SUBTYPE_ID); + } + if (subtypeId != NOT_A_SUBTYPE_ID) { + if (imi.getId().equals(mCurMethodId)) { + // The current input method is the most applicable IME. + mostApplicableIMI = imi; + mostApplicableSubtypeId = subtypeId; + break; + } else if ((imi.getServiceInfo().applicationInfo.flags + & ApplicationInfo.FLAG_SYSTEM) != 0) { + // The system input method is 2nd applicable IME. + mostApplicableIMI = imi; + mostApplicableSubtypeId = subtypeId; + foundInSystemIME = true; + } else if (!foundInSystemIME) { + mostApplicableIMI = imi; + mostApplicableSubtypeId = subtypeId; + } + } + } + if (DEBUG) { + Slog.w(TAG, "Most applicable shortcut input method subtype was:" + + mostApplicableIMI.getId() + "," + mostApplicableSubtypeId); + } + if (mostApplicableIMI != null && mostApplicableSubtypeId != NOT_A_SUBTYPE_ID) { + ArrayList<Parcelable> ret = new ArrayList<Parcelable>(2); + return new Pair<InputMethodInfo, InputMethodSubtype> (mostApplicableIMI, + mostApplicableIMI.getSubtypes().get(mostApplicableSubtypeId)); + } else { + return null; + } + } + /** * @return Return the current subtype of this input method. */ public InputMethodSubtype getCurrentInputMethodSubtype() { + boolean subtypeIsSelected = false; + try { + subtypeIsSelected = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE) != NOT_A_SUBTYPE_ID; + } catch (SettingNotFoundException e) { + } synchronized (mMethodMap) { - boolean subtypeIsSelected = false; - try { - subtypeIsSelected = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE) != NOT_A_SUBTYPE_ID; - } catch (SettingNotFoundException e) { - } if (!subtypeIsSelected || mCurrentSubtype == null) { - String lastInputMethodId = - Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD); + String lastInputMethodId = Settings.Secure.getString( + mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); int subtypeId = getSelectedInputMethodSubtypeId(lastInputMethodId); if (subtypeId == NOT_A_SUBTYPE_ID) { - subtypeId = findApplicableSubtypeLocked(lastInputMethodId); + InputMethodInfo imi = mMethodMap.get(lastInputMethodId); + if (imi != null) { + // If there are no selected subtypes, the framework will try to find + // the most applicable subtype from all subtypes whose mode is + // SUBTYPE_MODE_KEYBOARD. This is an exceptional case, so we will hardcode + // the mode. + subtypeId = findLastResortApplicableSubtypeLocked(imi.getSubtypes(), + SUBTYPE_MODE_KEYBOARD, null, DEFAULT_SUBTYPE_ID); + } } if (subtypeId != NOT_A_SUBTYPE_ID) { mCurrentSubtype = mMethodMap.get(lastInputMethodId).getSubtypes().get(subtypeId); + } else { + mCurrentSubtype = null; } } return mCurrentSubtype; } } + // TODO: We should change the return type from List to List<Parcelable> + public List getShortcutInputMethodsAndSubtypes() { + synchronized (mMethodMap) { + if (mShortcutInputMethodsAndSubtypesObjectList != null) { + // If there are no selected shortcut subtypes, the framework will try to find + // the most applicable subtype from all subtypes whose mode is + // SUBTYPE_MODE_VOICE. This is an exceptional case, so we will hardcode the mode. + mShortcutInputMethodsAndSubtypes = + new ArrayList<Pair<InputMethodInfo, InputMethodSubtype>>(); + mShortcutInputMethodsAndSubtypes.add( + findLastResortApplicableShortcutInputMethodAndSubtypeLocked( + SUBTYPE_MODE_VOICE)); + mShortcutInputMethodsAndSubtypesObjectList = new ArrayList<Parcelable>(); + for (Pair ime: mShortcutInputMethodsAndSubtypes) { + mShortcutInputMethodsAndSubtypesObjectList.add(ime.first); + mShortcutInputMethodsAndSubtypesObjectList.add(ime.second); + } + } + return mShortcutInputMethodsAndSubtypesObjectList; + } + } + public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) { synchronized (mMethodMap) { if (subtype != null && mCurMethodId != null) { |