Add an API to get shortcut IMEs
- If there are no selected shortcut IMEs, the most applicable voice input will be selected as a shortcut IME Change-Id: Ibd0f7ef5101013569c303820a3adc9038a97356d
This commit is contained in:
@ -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) {
|
||||
|
Reference in New Issue
Block a user