InputMethodInfo.java revision fcedfa01907d8a5f804974a4a3585498e8d6c261
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 2007-2008 The Android Open Source Project
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License"); you may not
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * use this file except in compliance with the License. You may obtain a copy of
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the License at
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * http://www.apache.org/licenses/LICENSE-2.0
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License for the specific language governing permissions and limitations under
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the License.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package android.view.inputmethod;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.xmlpull.v1.XmlPullParser;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.xmlpull.v1.XmlPullParserException;
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.ComponentName;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.Context;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.pm.ApplicationInfo;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.pm.PackageManager;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.pm.PackageManager.NameNotFoundException;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.pm.ResolveInfo;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.pm.ServiceInfo;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.res.Resources;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.res.Resources.NotFoundException;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.res.TypedArray;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.res.XmlResourceParser;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.graphics.drawable.Drawable;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Parcel;
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.os.Parcelable;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.AttributeSet;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Printer;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Slog;
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.util.Xml;
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.inputmethod.InputMethodSubtypeArray;
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.IOException;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.ArrayList;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.List;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.Map;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This class is used to specify meta information of an input method.
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * <p>It should be defined in an XML resource file with an {@code &lt;input-method>} element.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * For more information, see the guide to
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * <a href="{@docRoot}guide/topics/text/creating-input-method.html">
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * Creating an Input Method</a>.</p>
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @see InputMethodSubtype
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @attr ref android.R.styleable#InputMethod_settingsActivity
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @attr ref android.R.styleable#InputMethod_isDefault
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public final class InputMethodInfo implements Parcelable {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String TAG = "InputMethodInfo";
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The Service that implements this input method component.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    final ResolveInfo mService;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The unique string Id to identify the input method.  This is generated
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * from the input method component.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    final String mId;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    /**
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The input method setting activity's name, used by the system settings to
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * launch the setting activity of this input method.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    final String mSettingsActivityName;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * The resource in the input method's .apk that holds a boolean indicating
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * whether it should be considered the default input method for this
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * system.  This is a resource ID instead of the final value so that it
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * can change based on the configuration (in particular locale).
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    final int mIsDefaultResId;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * An array-like container of the subtypes.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private final InputMethodSubtypeArray mSubtypes;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final boolean mIsAuxIme;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    /**
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Caveat: mForceDefault must be false for production. This flag is only for test.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private final boolean mForceDefault;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * The flag whether this IME supports ways to switch to a next input method (e.g. globe key.)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private final boolean mSupportsSwitchingToNextInputMethod;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Constructor.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param context The Context in which we are parsing the input method.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param service The ResolveInfo returned from the package manager about
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch     * this input method's component.
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch     */
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public InputMethodInfo(Context context, ResolveInfo service)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throws XmlPullParserException, IOException {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this(context, service, null);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Constructor.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param context The Context in which we are parsing the input method.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param service The ResolveInfo returned from the package manager about
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * this input method's component.
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * @param additionalSubtypes additional subtypes being added to this InputMethodInfo
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * @hide
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    public InputMethodInfo(Context context, ResolveInfo service,
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            Map<String, List<InputMethodSubtype>> additionalSubtypesMap)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throws XmlPullParserException, IOException {
131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        mService = service;
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ServiceInfo si = service.serviceInfo;
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        boolean isAuxIme = true;
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        boolean supportsSwitchingToNextInputMethod = false; // false as default
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mForceDefault = false;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PackageManager pm = context.getPackageManager();
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        String settingsActivityComponent = null;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int isDefaultResId = 0;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        XmlResourceParser parser = null;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            parser = si.loadXmlMetaData(pm, InputMethod.SERVICE_META_DATA);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (parser == null) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                throw new XmlPullParserException("No "
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        + InputMethod.SERVICE_META_DATA + " meta-data");
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            Resources res = pm.getResourcesForApplication(si.applicationInfo);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            AttributeSet attrs = Xml.asAttributeSet(parser);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            int type;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    && type != XmlPullParser.START_TAG) {
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String nodeName = parser.getName();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (!"input-method".equals(nodeName)) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                throw new XmlPullParserException(
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        "Meta-data does not start with input-method tag");
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            TypedArray sa = res.obtainAttributes(attrs,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    com.android.internal.R.styleable.InputMethod);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            settingsActivityComponent = sa.getString(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    com.android.internal.R.styleable.InputMethod_settingsActivity);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            isDefaultResId = sa.getResourceId(
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    com.android.internal.R.styleable.InputMethod_isDefault, 0);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            supportsSwitchingToNextInputMethod = sa.getBoolean(
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    com.android.internal.R.styleable.InputMethod_supportsSwitchingToNextInputMethod,
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    false);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sa.recycle();
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final int depth = parser.getDepth();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Parse all subtypes
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    && type != XmlPullParser.END_DOCUMENT) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (type == XmlPullParser.START_TAG) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    nodeName = parser.getName();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    if (!"subtype".equals(nodeName)) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        throw new XmlPullParserException(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                "Meta-data in input-method does not start with subtype tag");
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    final TypedArray a = res.obtainAttributes(
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            attrs, com.android.internal.R.styleable.InputMethod_Subtype);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    final InputMethodSubtype subtype = new InputMethodSubtypeBuilder()
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            .setSubtypeNameResId(a.getResourceId(com.android.internal.R.styleable
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    .InputMethod_Subtype_label, 0))
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            .setSubtypeIconResId(a.getResourceId(com.android.internal.R.styleable
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    .InputMethod_Subtype_icon, 0))
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            .setSubtypeLocale(a.getString(com.android.internal.R.styleable
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    .InputMethod_Subtype_imeSubtypeLocale))
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            .setSubtypeMode(a.getString(com.android.internal.R.styleable
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    .InputMethod_Subtype_imeSubtypeMode))
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            .setSubtypeExtraValue(a.getString(com.android.internal.R.styleable
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    .InputMethod_Subtype_imeSubtypeExtraValue))
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            .setIsAuxiliary(a.getBoolean(com.android.internal.R.styleable
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    .InputMethod_Subtype_isAuxiliary, false))
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            .setOverridesImplicitlyEnabledSubtype(a.getBoolean(
203ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                    com.android.internal.R.styleable
204ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                    .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false))
205ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                            .setSubtypeId(a.getInt(com.android.internal.R.styleable
206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                    .InputMethod_Subtype_subtypeId, 0 /* use Arrays.hashCode */))
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            .setIsAsciiCapable(a.getBoolean(com.android.internal.R.styleable
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    .InputMethod_Subtype_isAsciiCapable, false)).build();
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    if (!subtype.isAuxiliary()) {
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        isAuxIme = false;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    subtypes.add(subtype);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } catch (NameNotFoundException e) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throw new XmlPullParserException(
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Unable to create context for: " + si.packageName);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } finally {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (parser != null) parser.close();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (subtypes.size() == 0) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            isAuxIme = false;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (additionalSubtypesMap != null && additionalSubtypesMap.containsKey(mId)) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final List<InputMethodSubtype> additionalSubtypes = additionalSubtypesMap.get(mId);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final int N = additionalSubtypes.size();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for (int i = 0; i < N; ++i) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                final InputMethodSubtype subtype = additionalSubtypes.get(i);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (!subtypes.contains(subtype)) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    subtypes.add(subtype);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                } else {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    Slog.w(TAG, "Duplicated subtype definition found: "
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            + subtype.getLocale() + ", " + subtype.getMode());
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSubtypes = new InputMethodSubtypeArray(subtypes);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSettingsActivityName = settingsActivityComponent;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mIsDefaultResId = isDefaultResId;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mIsAuxIme = isAuxIme;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InputMethodInfo(Parcel source) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mId = source.readString();
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSettingsActivityName = source.readString();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mIsDefaultResId = source.readInt();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mIsAuxIme = source.readInt() == 1;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mService = ResolveInfo.CREATOR.createFromParcel(source);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSubtypes = new InputMethodSubtypeArray(source);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mForceDefault = false;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Temporary API for creating a built-in input method for test.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public InputMethodInfo(String packageName, String className,
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            CharSequence label, String settingsActivity) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this(buildDummyResolveInfo(packageName, className, label), false, settingsActivity, null,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                0, false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Temporary API for creating a built-in input method for test.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @hide
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public InputMethodInfo(ResolveInfo ri, boolean isAuxIme,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            boolean forceDefault) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId,
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                forceDefault, true /* supportsSwitchingToNextInputMethod */);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * Temporary API for creating a built-in input method for test.
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @hide
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     */
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public InputMethodInfo(ResolveInfo ri, boolean isAuxIme,
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            boolean forceDefault, boolean supportsSwitchingToNextInputMethod) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        final ServiceInfo si = ri.serviceInfo;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mService = ri;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSettingsActivityName = settingsActivity;
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mIsDefaultResId = isDefaultResId;
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mIsAuxIme = isAuxIme;
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mSubtypes = new InputMethodSubtypeArray(subtypes);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mForceDefault = forceDefault;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            CharSequence label) {
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ResolveInfo ri = new ResolveInfo();
298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ServiceInfo si = new ServiceInfo();
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ApplicationInfo ai = new ApplicationInfo();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ai.packageName = packageName;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ai.enabled = true;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        si.applicationInfo = ai;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        si.enabled = true;
304        si.packageName = packageName;
305        si.name = className;
306        si.exported = true;
307        si.nonLocalizedLabel = label;
308        ri.serviceInfo = si;
309        return ri;
310    }
311
312    /**
313     * Return a unique ID for this input method.  The ID is generated from
314     * the package and class name implementing the method.
315     */
316    public String getId() {
317        return mId;
318    }
319
320    /**
321     * Return the .apk package that implements this input method.
322     */
323    public String getPackageName() {
324        return mService.serviceInfo.packageName;
325    }
326
327    /**
328     * Return the class name of the service component that implements
329     * this input method.
330     */
331    public String getServiceName() {
332        return mService.serviceInfo.name;
333    }
334
335    /**
336     * Return the raw information about the Service implementing this
337     * input method.  Do not modify the returned object.
338     */
339    public ServiceInfo getServiceInfo() {
340        return mService.serviceInfo;
341    }
342
343    /**
344     * Return the component of the service that implements this input
345     * method.
346     */
347    public ComponentName getComponent() {
348        return new ComponentName(mService.serviceInfo.packageName,
349                mService.serviceInfo.name);
350    }
351
352    /**
353     * Load the user-displayed label for this input method.
354     *
355     * @param pm Supply a PackageManager used to load the input method's
356     * resources.
357     */
358    public CharSequence loadLabel(PackageManager pm) {
359        return mService.loadLabel(pm);
360    }
361
362    /**
363     * Load the user-displayed icon for this input method.
364     *
365     * @param pm Supply a PackageManager used to load the input method's
366     * resources.
367     */
368    public Drawable loadIcon(PackageManager pm) {
369        return mService.loadIcon(pm);
370    }
371
372    /**
373     * Return the class name of an activity that provides a settings UI for
374     * the input method.  You can launch this activity be starting it with
375     * an {@link android.content.Intent} whose action is MAIN and with an
376     * explicit {@link android.content.ComponentName}
377     * composed of {@link #getPackageName} and the class name returned here.
378     *
379     * <p>A null will be returned if there is no settings activity associated
380     * with the input method.</p>
381     */
382    public String getSettingsActivity() {
383        return mSettingsActivityName;
384    }
385
386    /**
387     * Return the count of the subtypes of Input Method.
388     */
389    public int getSubtypeCount() {
390        return mSubtypes.getCount();
391    }
392
393    /**
394     * Return the Input Method's subtype at the specified index.
395     *
396     * @param index the index of the subtype to return.
397     */
398    public InputMethodSubtype getSubtypeAt(int index) {
399        return mSubtypes.get(index);
400    }
401
402    /**
403     * Return the resource identifier of a resource inside of this input
404     * method's .apk that determines whether it should be considered a
405     * default input method for the system.
406     */
407    public int getIsDefaultResourceId() {
408        return mIsDefaultResId;
409    }
410
411    /**
412     * Return whether or not this ime is a default ime or not.
413     * @hide
414     */
415    public boolean isDefault(Context context) {
416        if (mForceDefault) {
417            return true;
418        }
419        try {
420            if (getIsDefaultResourceId() == 0) {
421                return false;
422            }
423            final Resources res = context.createPackageContext(getPackageName(), 0).getResources();
424            return res.getBoolean(getIsDefaultResourceId());
425        } catch (NameNotFoundException | NotFoundException e) {
426            return false;
427        }
428    }
429
430    public void dump(Printer pw, String prefix) {
431        pw.println(prefix + "mId=" + mId
432                + " mSettingsActivityName=" + mSettingsActivityName);
433        pw.println(prefix + "mIsDefaultResId=0x"
434                + Integer.toHexString(mIsDefaultResId));
435        pw.println(prefix + "Service:");
436        mService.dump(pw, prefix + "  ");
437    }
438
439    @Override
440    public String toString() {
441        return "InputMethodInfo{" + mId
442                + ", settings: "
443                + mSettingsActivityName + "}";
444    }
445
446    /**
447     * Used to test whether the given parameter object is an
448     * {@link InputMethodInfo} and its Id is the same to this one.
449     *
450     * @return true if the given parameter object is an
451     *         {@link InputMethodInfo} and its Id is the same to this one.
452     */
453    @Override
454    public boolean equals(Object o) {
455        if (o == this) return true;
456        if (o == null) return false;
457
458        if (!(o instanceof InputMethodInfo)) return false;
459
460        InputMethodInfo obj = (InputMethodInfo) o;
461        return mId.equals(obj.mId);
462    }
463
464    @Override
465    public int hashCode() {
466        return mId.hashCode();
467    }
468
469    /**
470     * @hide
471     */
472    public boolean isAuxiliaryIme() {
473        return mIsAuxIme;
474    }
475
476    /**
477     * @return true if this input method supports ways to switch to a next input method.
478     * @hide
479     */
480    public boolean supportsSwitchingToNextInputMethod() {
481        return mSupportsSwitchingToNextInputMethod;
482    }
483
484    /**
485     * Used to package this object into a {@link Parcel}.
486     *
487     * @param dest The {@link Parcel} to be written.
488     * @param flags The flags used for parceling.
489     */
490    @Override
491    public void writeToParcel(Parcel dest, int flags) {
492        dest.writeString(mId);
493        dest.writeString(mSettingsActivityName);
494        dest.writeInt(mIsDefaultResId);
495        dest.writeInt(mIsAuxIme ? 1 : 0);
496        dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
497        mService.writeToParcel(dest, flags);
498        mSubtypes.writeToParcel(dest);
499    }
500
501    /**
502     * Used to make this class parcelable.
503     */
504    public static final Parcelable.Creator<InputMethodInfo> CREATOR
505            = new Parcelable.Creator<InputMethodInfo>() {
506        @Override
507        public InputMethodInfo createFromParcel(Parcel source) {
508            return new InputMethodInfo(source);
509        }
510
511        @Override
512        public InputMethodInfo[] newArray(int size) {
513            return new InputMethodInfo[size];
514        }
515    };
516
517    @Override
518    public int describeContents() {
519        return 0;
520    }
521}
522