Add subtypeId for keeping enabled "InputMethodSubtype"s even if subtype parameters are changed
Bug: 6752230
Change-Id: I3a2d512e395fe8645edf6ab82108948b927c629a
diff --git a/api/current.txt b/api/current.txt
index fbda3c6..5307833 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -947,6 +947,7 @@
field public static final int subtitle = 16843473; // 0x10102d1
field public static final int subtitleTextStyle = 16843513; // 0x10102f9
field public static final int subtypeExtraValue = 16843674; // 0x101039a
+ field public static final int subtypeId = 16843713; // 0x10103c1
field public static final int subtypeLocale = 16843673; // 0x1010399
field public static final int suggestActionMsg = 16843228; // 0x10101dc
field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd
@@ -26642,6 +26643,7 @@
public final class InputMethodSubtype implements android.os.Parcelable {
ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean);
+ ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int);
method public boolean containsExtraValueKey(java.lang.String);
method public int describeContents();
method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 131f0ae..08e30aa 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -34,6 +34,7 @@
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Printer;
+import android.util.Slog;
import android.util.Xml;
import java.io.IOException;
@@ -169,7 +170,10 @@
a.getBoolean(com.android.internal.R.styleable
.InputMethod_Subtype_isAuxiliary, false),
a.getBoolean(com.android.internal.R.styleable
- .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false));
+ .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false),
+ a.getInt(com.android.internal.R.styleable
+ .InputMethod_Subtype_subtypeId, 0 /* use Arrays.hashCode */)
+ );
if (!subtype.isAuxiliary()) {
mIsAuxIme = false;
}
@@ -194,6 +198,9 @@
final InputMethodSubtype subtype = additionalSubtypes.get(i);
if (!mSubtypes.contains(subtype)) {
mSubtypes.add(subtype);
+ } else {
+ Slog.w(TAG, "Duplicated subtype definition found: "
+ + subtype.getLocale() + ", " + subtype.getMode());
}
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index b7c94a3..7895e6f 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -55,13 +55,14 @@
private final int mSubtypeHashCode;
private final int mSubtypeIconResId;
private final int mSubtypeNameResId;
+ private final int mSubtypeId;
private final String mSubtypeLocale;
private final String mSubtypeMode;
private final String mSubtypeExtraValue;
private volatile HashMap<String, String> mExtraValueHashMapCache;
/**
- * Constructor.
+ * Constructor with no subtype ID specified, overridesImplicitlyEnabledSubtype not specified.
* @param nameId Resource ID of the subtype name string. The string resource may have exactly
* one %s in it. If there is, the %s part will be replaced with the locale's display name by
* the formatter. Please refer to {@link #getDisplayName} for details.
@@ -87,7 +88,7 @@
}
/**
- * Constructor.
+ * Constructor with no subtype ID specified.
* @param nameId Resource ID of the subtype name string. The string resource may have exactly
* one %s in it. If there is, the %s part will be replaced with the locale's display name by
* the formatter. Please refer to {@link #getDisplayName} for details.
@@ -112,6 +113,41 @@
*/
public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
+ this(nameId, iconId, locale, mode, extraValue, isAuxiliary,
+ overridesImplicitlyEnabledSubtype, 0);
+ }
+
+ /**
+ * Constructor.
+ * @param nameId Resource ID of the subtype name string. The string resource may have exactly
+ * one %s in it. If there is, the %s part will be replaced with the locale's display name by
+ * the formatter. Please refer to {@link #getDisplayName} for details.
+ * @param iconId Resource ID of the subtype icon drawable.
+ * @param locale The locale supported by the subtype
+ * @param mode The mode supported by the subtype
+ * @param extraValue The extra value of the subtype. This string is free-form, but the API
+ * supplies tools to deal with a key-value comma-separated list; see
+ * {@link #containsExtraValueKey} and {@link #getExtraValueOf}.
+ * @param isAuxiliary true when this subtype is auxiliary, false otherwise. An auxiliary
+ * subtype will not be shown in the list of enabled IMEs for choosing the current IME in
+ * the Settings even when this subtype is enabled. Please note that this subtype will still
+ * be shown in the list of IMEs in the IME switcher to allow the user to tentatively switch
+ * to this subtype while an IME is shown. The framework will never switch the current IME to
+ * this subtype by {@link android.view.inputmethod.InputMethodManager#switchToLastInputMethod}.
+ * The intent of having this flag is to allow for IMEs that are invoked in a one-shot way as
+ * auxiliary input mode, and return to the previous IME once it is finished (e.g. voice input).
+ * @param overridesImplicitlyEnabledSubtype true when this subtype should be enabled by default
+ * if no other subtypes in the IME are enabled explicitly. Note that a subtype with this
+ * parameter being true will not be shown in the list of subtypes in each IME's subtype enabler.
+ * Having an "automatic" subtype is an example use of this flag.
+ * @param id The unique ID for the subtype. The input method framework keeps track of enabled
+ * subtypes by ID. When the IME package gets upgraded, enabled IDs will stay enabled even if
+ * other attributes are different. If the ID is unspecified or 0,
+ * Arrays.hashCode(new Object[] {locale, mode, extraValue,
+ * isAuxiliary, overridesImplicitlyEnabledSubtype}) will be used instead.
+ */
+ public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
+ boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, int id) {
mSubtypeNameResId = nameId;
mSubtypeIconResId = iconId;
mSubtypeLocale = locale != null ? locale : "";
@@ -119,8 +155,11 @@
mSubtypeExtraValue = extraValue != null ? extraValue : "";
mIsAuxiliary = isAuxiliary;
mOverridesImplicitlyEnabledSubtype = overridesImplicitlyEnabledSubtype;
- mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
- mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
+ // If hashCode() of this subtype is 0 and you want to specify it as an id of this subtype,
+ // just specify 0 as this subtype's id. Then, this subtype's id is treated as 0.
+ mSubtypeHashCode = id != 0 ? id : hashCodeInternal(mSubtypeLocale, mSubtypeMode,
+ mSubtypeExtraValue, mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
+ mSubtypeId = id;
}
InputMethodSubtype(Parcel source) {
@@ -135,8 +174,8 @@
mSubtypeExtraValue = s != null ? s : "";
mIsAuxiliary = (source.readInt() == 1);
mOverridesImplicitlyEnabledSubtype = (source.readInt() == 1);
- mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
- mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
+ mSubtypeHashCode = source.readInt();
+ mSubtypeId = source.readInt();
}
/**
@@ -288,6 +327,9 @@
public boolean equals(Object o) {
if (o instanceof InputMethodSubtype) {
InputMethodSubtype subtype = (InputMethodSubtype) o;
+ if (subtype.mSubtypeId != 0 || mSubtypeId != 0) {
+ return (subtype.hashCode() == hashCode());
+ }
return (subtype.hashCode() == hashCode())
&& (subtype.getNameResId() == getNameResId())
&& (subtype.getMode().equals(getMode()))
@@ -313,6 +355,8 @@
dest.writeString(mSubtypeExtraValue);
dest.writeInt(mIsAuxiliary ? 1 : 0);
dest.writeInt(mOverridesImplicitlyEnabledSubtype ? 1 : 0);
+ dest.writeInt(mSubtypeHashCode);
+ dest.writeInt(mSubtypeId);
}
public static final Parcelable.Creator<InputMethodSubtype> CREATOR
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3757afc..9601ad4 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2374,6 +2374,12 @@
<!-- The extra value of the subtype. This string can be any string and will be passed to
the IME when the framework calls the IME with the subtype. -->
<attr name="imeSubtypeExtraValue" format="string" />
+ <!-- The unique id for the subtype. The input method framework keeps track of enabled
+ subtypes by ID. When the IME package gets upgraded, enabled IDs will stay enabled even
+ if other attributes are different. If the ID is unspecified (by calling the other
+ constructor or 0. Arrays.hashCode(new Object[] {locale, mode, extraValue,
+ isAuxiliary, overridesImplicitlyEnabledSubtype}) will be used instead. -->
+ <attr name="subtypeId" format="integer"/>
</declare-styleable>
<!-- Use <code>spell-checker</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8e0eb15..5bb4a30 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3761,5 +3761,6 @@
<public type="attr" name="listPreferredItemPaddingEnd" />
<public type="attr" name="singleUser" />
<public type="attr" name="presentationTheme" />
+ <public type="attr" name="subtypeId"/>
</resources>
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 747cf0b..c685473 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -3579,7 +3579,7 @@
private static final String ATTR_IS_AUXILIARY = "isAuxiliary";
private final AtomicFile mAdditionalInputMethodSubtypeFile;
private final HashMap<String, InputMethodInfo> mMethodMap;
- private final HashMap<String, List<InputMethodSubtype>> mSubtypesMap =
+ private final HashMap<String, List<InputMethodSubtype>> mAdditionalSubtypesMap =
new HashMap<String, List<InputMethodSubtype>>();
public InputMethodFileManager(HashMap<String, InputMethodInfo> methodMap) {
if (methodMap == null) {
@@ -3595,18 +3595,19 @@
mAdditionalInputMethodSubtypeFile = new AtomicFile(subtypeFile);
if (!subtypeFile.exists()) {
// If "subtypes.xml" doesn't exist, create a blank file.
- writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile,
- methodMap);
+ writeAdditionalInputMethodSubtypes(
+ mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, methodMap);
} else {
- readAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile);
+ readAdditionalInputMethodSubtypes(
+ mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile);
}
}
private void deleteAllInputMethodSubtypes(String imiId) {
synchronized (mMethodMap) {
- mSubtypesMap.remove(imiId);
- writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile,
- mMethodMap);
+ mAdditionalSubtypesMap.remove(imiId);
+ writeAdditionalInputMethodSubtypes(
+ mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
}
}
@@ -3619,17 +3620,20 @@
final InputMethodSubtype subtype = additionalSubtypes[i];
if (!subtypes.contains(subtype)) {
subtypes.add(subtype);
+ } else {
+ Slog.w(TAG, "Duplicated subtype definition found: "
+ + subtype.getLocale() + ", " + subtype.getMode());
}
}
- mSubtypesMap.put(imi.getId(), subtypes);
- writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile,
- mMethodMap);
+ mAdditionalSubtypesMap.put(imi.getId(), subtypes);
+ writeAdditionalInputMethodSubtypes(
+ mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
}
}
public HashMap<String, List<InputMethodSubtype>> getAllAdditionalInputMethodSubtypes() {
synchronized (mMethodMap) {
- return mSubtypesMap;
+ return mAdditionalSubtypesMap;
}
}