InputMethodSubtype.java revision 44b75030931d9c65c9e495a86d11d71da59b4429
1ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok/*
2ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok * Copyright (C) 2010 The Android Open Source Project
3ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok *
4ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok * Licensed under the Apache License, Version 2.0 (the "License");
5ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok * you may not use this file except in compliance with the License.
6ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok * You may obtain a copy of the License at
7ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok *
8ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok *      http://www.apache.org/licenses/LICENSE-2.0
9ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok *
10ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok * Unless required by applicable law or agreed to in writing, software
11ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok * distributed under the License is distributed on an "AS IS" BASIS,
12ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok * See the License for the specific language governing permissions and
14ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok * limitations under the License.
15ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok */
16ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
17ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokpackage android.view.inputmethod;
18ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
197265d9bd6d80c5bedaa6de2b80f6619a301a07c8satokimport android.content.Context;
204f31353cb3b00c77c9420ef27ec949fd570ede3bsatokimport android.content.pm.ApplicationInfo;
21ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.os.Parcel;
22ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport android.os.Parcelable;
234f31353cb3b00c77c9420ef27ec949fd570ede3bsatokimport android.text.TextUtils;
249c4cc03a354922df08efacfc486ef0e80144d3easatokimport android.util.Slog;
25ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
267265d9bd6d80c5bedaa6de2b80f6619a301a07c8satokimport java.util.ArrayList;
27ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokimport java.util.Arrays;
289c4cc03a354922df08efacfc486ef0e80144d3easatokimport java.util.HashMap;
297265d9bd6d80c5bedaa6de2b80f6619a301a07c8satokimport java.util.HashSet;
307265d9bd6d80c5bedaa6de2b80f6619a301a07c8satokimport java.util.List;
31a9778d4d442db65344e32318b1fd43ab54898389satokimport java.util.Locale;
32ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
33ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok/**
34e31e9424554d5f032f578830556913b4ba78f7f9Ken Wakasa * This class is used to specify meta information of a subtype contained in an input method.
35e31e9424554d5f032f578830556913b4ba78f7f9Ken Wakasa * Subtype can describe locale (e.g. en_US, fr_FR...) and mode (e.g. voice, keyboard...), and is
36e31e9424554d5f032f578830556913b4ba78f7f9Ken Wakasa * used for IME switch and settings. The input method subtype allows the system to bring up the
37e31e9424554d5f032f578830556913b4ba78f7f9Ken Wakasa * specified subtype of the designated input method directly.
3844b75030931d9c65c9e495a86d11d71da59b4429satok *
3944b75030931d9c65c9e495a86d11d71da59b4429satok * <p>It should be defined in an XML resource file of the input method
4044b75030931d9c65c9e495a86d11d71da59b4429satok * with the <code>&lt;subtype></code> element.
4144b75030931d9c65c9e495a86d11d71da59b4429satok * For more information, see the guide to
4244b75030931d9c65c9e495a86d11d71da59b4429satok * <a href="{@docRoot}resources/articles/creating-input-method.html">
4344b75030931d9c65c9e495a86d11d71da59b4429satok * Creating an Input Method</a>.</p>
4444b75030931d9c65c9e495a86d11d71da59b4429satok *
45ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok */
46ab751aa085433e9f735d2e7603459c6c7e9d2fb0satokpublic final class InputMethodSubtype implements Parcelable {
479c4cc03a354922df08efacfc486ef0e80144d3easatok    private static final String TAG = InputMethodSubtype.class.getSimpleName();
489c4cc03a354922df08efacfc486ef0e80144d3easatok    private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
499c4cc03a354922df08efacfc486ef0e80144d3easatok    private static final String EXTRA_VALUE_KEY_VALUE_SEPARATOR = "=";
509c4cc03a354922df08efacfc486ef0e80144d3easatok
519aabb95781bee6a44684a6f6feb155e115d24983satok    private final boolean mIsAuxiliary;
52a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    private final boolean mOverridesImplicitlyEnabledSubtype;
539aabb95781bee6a44684a6f6feb155e115d24983satok    private final int mSubtypeHashCode;
54ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private final int mSubtypeIconResId;
559aabb95781bee6a44684a6f6feb155e115d24983satok    private final int mSubtypeNameResId;
56ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private final String mSubtypeLocale;
579ef0283bdcd9534cc09ae37eb2b78771b95247b5satok    private final String mSubtypeMode;
58ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    private final String mSubtypeExtraValue;
599c4cc03a354922df08efacfc486ef0e80144d3easatok    private HashMap<String, String> mExtraValueHashMapCache;
60ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
61ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
62ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * Constructor
63ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @param nameId The name of the subtype
64ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @param iconId The icon of the subtype
65ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @param locale The locale supported by the subtype
66a9778d4d442db65344e32318b1fd43ab54898389satok     * @param mode The mode supported by the subtype
67ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @param extraValue The extra value of the subtype
68a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok     * @param isAuxiliary true when this subtype is one shot subtype.
693889e492bcad3c6f565d30da4e02d0dcde09d084satok     * @hide
70ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
71a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
72a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            boolean isAuxiliary) {
738b83a7297680911d666546ee0b3a464514dc2c27Ken Wakasa        this(nameId, iconId, locale, mode, extraValue, isAuxiliary, false);
749aabb95781bee6a44684a6f6feb155e115d24983satok    }
759aabb95781bee6a44684a6f6feb155e115d24983satok
769aabb95781bee6a44684a6f6feb155e115d24983satok    /**
779aabb95781bee6a44684a6f6feb155e115d24983satok     * Constructor
789aabb95781bee6a44684a6f6feb155e115d24983satok     * @param nameId The name of the subtype
799aabb95781bee6a44684a6f6feb155e115d24983satok     * @param iconId The icon of the subtype
809aabb95781bee6a44684a6f6feb155e115d24983satok     * @param locale The locale supported by the subtype
81a9778d4d442db65344e32318b1fd43ab54898389satok     * @param mode The mode supported by the subtype
829aabb95781bee6a44684a6f6feb155e115d24983satok     * @param extraValue The extra value of the subtype
839aabb95781bee6a44684a6f6feb155e115d24983satok     * @param isAuxiliary true when this subtype is one shot subtype.
84a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok     * @param overridesImplicitlyEnabledSubtype true when this subtype should be selected by default
85a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok     * if no other subtypes are selected explicitly. Note that a subtype with this parameter being
86a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok     * true will not be shown in the subtypes list.
879aabb95781bee6a44684a6f6feb155e115d24983satok     */
88a9778d4d442db65344e32318b1fd43ab54898389satok    public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
89a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
90ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        mSubtypeNameResId = nameId;
91ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        mSubtypeIconResId = iconId;
92af4bf400abab86baee44dacbcdf13444d06ee46esatok        mSubtypeLocale = locale != null ? locale : "";
93af4bf400abab86baee44dacbcdf13444d06ee46esatok        mSubtypeMode = mode != null ? mode : "";
94af4bf400abab86baee44dacbcdf13444d06ee46esatok        mSubtypeExtraValue = extraValue != null ? extraValue : "";
959aabb95781bee6a44684a6f6feb155e115d24983satok        mIsAuxiliary = isAuxiliary;
96a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        mOverridesImplicitlyEnabledSubtype = overridesImplicitlyEnabledSubtype;
97a9778d4d442db65344e32318b1fd43ab54898389satok        mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
98a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
99ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
100ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
101ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    InputMethodSubtype(Parcel source) {
102af4bf400abab86baee44dacbcdf13444d06ee46esatok        String s;
103ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        mSubtypeNameResId = source.readInt();
104ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        mSubtypeIconResId = source.readInt();
105af4bf400abab86baee44dacbcdf13444d06ee46esatok        s = source.readString();
106af4bf400abab86baee44dacbcdf13444d06ee46esatok        mSubtypeLocale = s != null ? s : "";
107af4bf400abab86baee44dacbcdf13444d06ee46esatok        s = source.readString();
108af4bf400abab86baee44dacbcdf13444d06ee46esatok        mSubtypeMode = s != null ? s : "";
109af4bf400abab86baee44dacbcdf13444d06ee46esatok        s = source.readString();
110af4bf400abab86baee44dacbcdf13444d06ee46esatok        mSubtypeExtraValue = s != null ? s : "";
1119aabb95781bee6a44684a6f6feb155e115d24983satok        mIsAuxiliary = (source.readInt() == 1);
112a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        mOverridesImplicitlyEnabledSubtype = (source.readInt() == 1);
113a9778d4d442db65344e32318b1fd43ab54898389satok        mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
114a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
115ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
116ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
117ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
118ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @return the name of the subtype
119ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
120ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public int getNameResId() {
121ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return mSubtypeNameResId;
122ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
123ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
124ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
125ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @return the icon of the subtype
126ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
127ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public int getIconResId() {
128ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return mSubtypeIconResId;
129ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
130ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
131ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
132ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @return the locale of the subtype
133ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
134ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public String getLocale() {
135ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return mSubtypeLocale;
136ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
137ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
138ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
139ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @return the mode of the subtype
140ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
1419ef0283bdcd9534cc09ae37eb2b78771b95247b5satok    public String getMode() {
1429ef0283bdcd9534cc09ae37eb2b78771b95247b5satok        return mSubtypeMode;
143ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
144ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
145ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    /**
146ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     * @return the extra value of the subtype
147ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok     */
148ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public String getExtraValue() {
149ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return mSubtypeExtraValue;
150ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
151ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
1529aabb95781bee6a44684a6f6feb155e115d24983satok    /**
1539aabb95781bee6a44684a6f6feb155e115d24983satok     * @return true if this subtype is one shot subtype. One shot subtype will not be shown in the
1549aabb95781bee6a44684a6f6feb155e115d24983satok     * ime switch list when this subtype is implicitly enabled. The framework will never
1559aabb95781bee6a44684a6f6feb155e115d24983satok     * switch the current ime to this subtype by switchToLastInputMethod in InputMethodManager.
1569aabb95781bee6a44684a6f6feb155e115d24983satok     */
1579aabb95781bee6a44684a6f6feb155e115d24983satok    public boolean isAuxiliary() {
1589aabb95781bee6a44684a6f6feb155e115d24983satok        return mIsAuxiliary;
1599aabb95781bee6a44684a6f6feb155e115d24983satok    }
1609aabb95781bee6a44684a6f6feb155e115d24983satok
1614f31353cb3b00c77c9420ef27ec949fd570ede3bsatok    /**
162a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok     * @return true when this subtype is selected by default if no other subtypes are selected
163a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok     * explicitly. Note that a subtype that returns true will not be shown in the subtypes list.
164a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok     */
165a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    public boolean overridesImplicitlyEnabledSubtype() {
166a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        return mOverridesImplicitlyEnabledSubtype;
167a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    }
168a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok
169a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok    /**
1704f31353cb3b00c77c9420ef27ec949fd570ede3bsatok     * @param context Context will be used for getting Locale and PackageManager.
1714f31353cb3b00c77c9420ef27ec949fd570ede3bsatok     * @param packageName The package name of the IME
1724f31353cb3b00c77c9420ef27ec949fd570ede3bsatok     * @param appInfo The application info of the IME
1734f31353cb3b00c77c9420ef27ec949fd570ede3bsatok     * @return a display name for this subtype. The string resource of the label (mSubtypeNameResId)
1744f31353cb3b00c77c9420ef27ec949fd570ede3bsatok     * can have only one %s in it. If there is, the %s part will be replaced with the locale's
1754f31353cb3b00c77c9420ef27ec949fd570ede3bsatok     * display name by the formatter. If there is not, this method simply returns the string
1764f31353cb3b00c77c9420ef27ec949fd570ede3bsatok     * specified by mSubtypeNameResId. If mSubtypeNameResId is not specified (== 0), it's up to the
1774f31353cb3b00c77c9420ef27ec949fd570ede3bsatok     * framework to generate an appropriate display name.
1784f31353cb3b00c77c9420ef27ec949fd570ede3bsatok     */
1794f31353cb3b00c77c9420ef27ec949fd570ede3bsatok    public CharSequence getDisplayName(
1804f31353cb3b00c77c9420ef27ec949fd570ede3bsatok            Context context, String packageName, ApplicationInfo appInfo) {
181a9778d4d442db65344e32318b1fd43ab54898389satok        final Locale locale = constructLocaleFromString(mSubtypeLocale);
182a9778d4d442db65344e32318b1fd43ab54898389satok        final String localeStr = locale != null ? locale.getDisplayName() : mSubtypeLocale;
1834f31353cb3b00c77c9420ef27ec949fd570ede3bsatok        if (mSubtypeNameResId == 0) {
184a9778d4d442db65344e32318b1fd43ab54898389satok            return localeStr;
1854f31353cb3b00c77c9420ef27ec949fd570ede3bsatok        }
18635412d63ee59b99a43725e466c5deef52b2324dfsatok        final CharSequence subtypeName = context.getPackageManager().getText(
18735412d63ee59b99a43725e466c5deef52b2324dfsatok                packageName, mSubtypeNameResId, appInfo);
1884f31353cb3b00c77c9420ef27ec949fd570ede3bsatok        if (!TextUtils.isEmpty(subtypeName)) {
18935412d63ee59b99a43725e466c5deef52b2324dfsatok            return String.format(subtypeName.toString(), localeStr);
1904f31353cb3b00c77c9420ef27ec949fd570ede3bsatok        } else {
191a9778d4d442db65344e32318b1fd43ab54898389satok            return localeStr;
1924f31353cb3b00c77c9420ef27ec949fd570ede3bsatok        }
1934f31353cb3b00c77c9420ef27ec949fd570ede3bsatok    }
1944f31353cb3b00c77c9420ef27ec949fd570ede3bsatok
1959c4cc03a354922df08efacfc486ef0e80144d3easatok    private HashMap<String, String> getExtraValueHashMap() {
1969c4cc03a354922df08efacfc486ef0e80144d3easatok        if (mExtraValueHashMapCache == null) {
1979c4cc03a354922df08efacfc486ef0e80144d3easatok            mExtraValueHashMapCache = new HashMap<String, String>();
1989c4cc03a354922df08efacfc486ef0e80144d3easatok            final String[] pairs = mSubtypeExtraValue.split(EXTRA_VALUE_PAIR_SEPARATOR);
1999c4cc03a354922df08efacfc486ef0e80144d3easatok            final int N = pairs.length;
2009c4cc03a354922df08efacfc486ef0e80144d3easatok            for (int i = 0; i < N; ++i) {
2019c4cc03a354922df08efacfc486ef0e80144d3easatok                final String[] pair = pairs[i].split(EXTRA_VALUE_KEY_VALUE_SEPARATOR);
2029c4cc03a354922df08efacfc486ef0e80144d3easatok                if (pair.length == 1) {
2039c4cc03a354922df08efacfc486ef0e80144d3easatok                    mExtraValueHashMapCache.put(pair[0], null);
2049c4cc03a354922df08efacfc486ef0e80144d3easatok                } else if (pair.length > 1) {
2059c4cc03a354922df08efacfc486ef0e80144d3easatok                    if (pair.length > 2) {
2069c4cc03a354922df08efacfc486ef0e80144d3easatok                        Slog.w(TAG, "ExtraValue has two or more '='s");
2079c4cc03a354922df08efacfc486ef0e80144d3easatok                    }
2089c4cc03a354922df08efacfc486ef0e80144d3easatok                    mExtraValueHashMapCache.put(pair[0], pair[1]);
2099c4cc03a354922df08efacfc486ef0e80144d3easatok                }
2109c4cc03a354922df08efacfc486ef0e80144d3easatok            }
2119c4cc03a354922df08efacfc486ef0e80144d3easatok        }
2129c4cc03a354922df08efacfc486ef0e80144d3easatok        return mExtraValueHashMapCache;
2139c4cc03a354922df08efacfc486ef0e80144d3easatok    }
2149c4cc03a354922df08efacfc486ef0e80144d3easatok
2159c4cc03a354922df08efacfc486ef0e80144d3easatok    /**
2169c4cc03a354922df08efacfc486ef0e80144d3easatok     * The string of ExtraValue in subtype should be defined as follows:
2179c4cc03a354922df08efacfc486ef0e80144d3easatok     * example: key0,key1=value1,key2,key3,key4=value4
2189c4cc03a354922df08efacfc486ef0e80144d3easatok     * @param key the key of extra value
2199c4cc03a354922df08efacfc486ef0e80144d3easatok     * @return the subtype contains specified the extra value
2209c4cc03a354922df08efacfc486ef0e80144d3easatok     */
2219c4cc03a354922df08efacfc486ef0e80144d3easatok    public boolean containsExtraValueKey(String key) {
2229c4cc03a354922df08efacfc486ef0e80144d3easatok        return getExtraValueHashMap().containsKey(key);
2239c4cc03a354922df08efacfc486ef0e80144d3easatok    }
2249c4cc03a354922df08efacfc486ef0e80144d3easatok
2259c4cc03a354922df08efacfc486ef0e80144d3easatok    /**
2269c4cc03a354922df08efacfc486ef0e80144d3easatok     * The string of ExtraValue in subtype should be defined as follows:
2279c4cc03a354922df08efacfc486ef0e80144d3easatok     * example: key0,key1=value1,key2,key3,key4=value4
2289c4cc03a354922df08efacfc486ef0e80144d3easatok     * @param key the key of extra value
2299c4cc03a354922df08efacfc486ef0e80144d3easatok     * @return the value of the specified key
2309c4cc03a354922df08efacfc486ef0e80144d3easatok     */
2319c4cc03a354922df08efacfc486ef0e80144d3easatok    public String getExtraValueOf(String key) {
2329c4cc03a354922df08efacfc486ef0e80144d3easatok        return getExtraValueHashMap().get(key);
2339c4cc03a354922df08efacfc486ef0e80144d3easatok    }
2349c4cc03a354922df08efacfc486ef0e80144d3easatok
235ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    @Override
236ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public int hashCode() {
237ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return mSubtypeHashCode;
238ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
239ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
240ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    @Override
241ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public boolean equals(Object o) {
242ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        if (o instanceof InputMethodSubtype) {
243ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            InputMethodSubtype subtype = (InputMethodSubtype) o;
244af4bf400abab86baee44dacbcdf13444d06ee46esatok            return (subtype.hashCode() == hashCode())
245af4bf400abab86baee44dacbcdf13444d06ee46esatok                && (subtype.getNameResId() == getNameResId())
246af4bf400abab86baee44dacbcdf13444d06ee46esatok                && (subtype.getMode().equals(getMode()))
247ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                && (subtype.getIconResId() == getIconResId())
248ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok                && (subtype.getLocale().equals(getLocale()))
249a9778d4d442db65344e32318b1fd43ab54898389satok                && (subtype.getExtraValue().equals(getExtraValue()))
250a9778d4d442db65344e32318b1fd43ab54898389satok                && (subtype.isAuxiliary() == isAuxiliary());
251ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
252ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return false;
253ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
254ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2559aabb95781bee6a44684a6f6feb155e115d24983satok    @Override
256ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public int describeContents() {
257ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        return 0;
258ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
259ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2609aabb95781bee6a44684a6f6feb155e115d24983satok    @Override
261ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public void writeToParcel(Parcel dest, int parcelableFlags) {
262ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        dest.writeInt(mSubtypeNameResId);
263ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        dest.writeInt(mSubtypeIconResId);
264ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        dest.writeString(mSubtypeLocale);
2659ef0283bdcd9534cc09ae37eb2b78771b95247b5satok        dest.writeString(mSubtypeMode);
266ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        dest.writeString(mSubtypeExtraValue);
2679aabb95781bee6a44684a6f6feb155e115d24983satok        dest.writeInt(mIsAuxiliary ? 1 : 0);
268a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        dest.writeInt(mOverridesImplicitlyEnabledSubtype ? 1 : 0);
269ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
270ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
271ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    public static final Parcelable.Creator<InputMethodSubtype> CREATOR
272ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            = new Parcelable.Creator<InputMethodSubtype>() {
2739aabb95781bee6a44684a6f6feb155e115d24983satok        @Override
274ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        public InputMethodSubtype createFromParcel(Parcel source) {
275ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            return new InputMethodSubtype(source);
276ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
277ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
2789aabb95781bee6a44684a6f6feb155e115d24983satok        @Override
279ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        public InputMethodSubtype[] newArray(int size) {
280ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok            return new InputMethodSubtype[size];
281ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok        }
282ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    };
283ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok
284a9778d4d442db65344e32318b1fd43ab54898389satok    private static Locale constructLocaleFromString(String localeStr) {
285a9778d4d442db65344e32318b1fd43ab54898389satok        if (TextUtils.isEmpty(localeStr))
286a9778d4d442db65344e32318b1fd43ab54898389satok            return null;
287a9778d4d442db65344e32318b1fd43ab54898389satok        String[] localeParams = localeStr.split("_", 3);
288a9778d4d442db65344e32318b1fd43ab54898389satok        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
289a9778d4d442db65344e32318b1fd43ab54898389satok        // because localeStr is not empty.
290a9778d4d442db65344e32318b1fd43ab54898389satok        if (localeParams.length == 1) {
291a9778d4d442db65344e32318b1fd43ab54898389satok            return new Locale(localeParams[0]);
292a9778d4d442db65344e32318b1fd43ab54898389satok        } else if (localeParams.length == 2) {
293a9778d4d442db65344e32318b1fd43ab54898389satok            return new Locale(localeParams[0], localeParams[1]);
294a9778d4d442db65344e32318b1fd43ab54898389satok        } else if (localeParams.length == 3) {
295a9778d4d442db65344e32318b1fd43ab54898389satok            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
296a9778d4d442db65344e32318b1fd43ab54898389satok        }
297a9778d4d442db65344e32318b1fd43ab54898389satok        return null;
298a9778d4d442db65344e32318b1fd43ab54898389satok    }
299a9778d4d442db65344e32318b1fd43ab54898389satok
300a9778d4d442db65344e32318b1fd43ab54898389satok    private static int hashCodeInternal(String locale, String mode, String extraValue,
301a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok            boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
302a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok        return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary,
303a86f5e448cd6d29340ca6cbe509bc6384bc0d711satok                overridesImplicitlyEnabledSubtype});
304ab751aa085433e9f735d2e7603459c6c7e9d2fb0satok    }
3057265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok
3067265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok    /**
3077265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok     * Sort the list of InputMethodSubtype
3087265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok     * @param context Context will be used for getting localized strings from IME
3097265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok     * @param flags Flags for the sort order
3107265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok     * @param imi InputMethodInfo of which subtypes are subject to be sorted
3117265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok     * @param subtypeList List of InputMethodSubtype which will be sorted
3127265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok     * @return Sorted list of subtypes
3137265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok     * @hide
3147265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok     */
3157265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok    public static List<InputMethodSubtype> sort(Context context, int flags, InputMethodInfo imi,
3167265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok            List<InputMethodSubtype> subtypeList) {
3177265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        if (imi == null) return subtypeList;
3187265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        final HashSet<InputMethodSubtype> inputSubtypesSet = new HashSet<InputMethodSubtype>(
3197265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok                subtypeList);
3207265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        final ArrayList<InputMethodSubtype> sortedList = new ArrayList<InputMethodSubtype>();
3217265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        int N = imi.getSubtypeCount();
3227265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        for (int i = 0; i < N; ++i) {
3237265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok            InputMethodSubtype subtype = imi.getSubtypeAt(i);
3247265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok            if (inputSubtypesSet.contains(subtype)) {
3257265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok                sortedList.add(subtype);
3267265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok                inputSubtypesSet.remove(subtype);
3277265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok            }
3287265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        }
3297265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        // If subtypes in inputSubtypesSet remain, that means these subtypes are not
3307265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        // contained in imi, so the remaining subtypes will be appended.
3317265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        for (InputMethodSubtype subtype: inputSubtypesSet) {
3327265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok            sortedList.add(subtype);
3337265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        }
3347265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok        return sortedList;
3357265d9bd6d80c5bedaa6de2b80f6619a301a07c8satok    }
336af4bf400abab86baee44dacbcdf13444d06ee46esatok}
337