Home | History | Annotate | Download | only in textservice
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package android.view.textservice;
     18 
     19 import org.xmlpull.v1.XmlPullParser;
     20 import org.xmlpull.v1.XmlPullParserException;
     21 
     22 import android.content.ComponentName;
     23 import android.content.Context;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.ResolveInfo;
     26 import android.content.pm.ServiceInfo;
     27 import android.content.res.Resources;
     28 import android.content.res.TypedArray;
     29 import android.content.res.XmlResourceParser;
     30 import android.graphics.drawable.Drawable;
     31 import android.os.Parcel;
     32 import android.os.Parcelable;
     33 import android.util.AttributeSet;
     34 import android.util.Slog;
     35 import android.util.Xml;
     36 
     37 import java.io.IOException;
     38 import java.util.ArrayList;
     39 
     40 /**
     41  * This class is used to specify meta information of an spell checker.
     42  */
     43 public final class SpellCheckerInfo implements Parcelable {
     44     private static final String TAG = SpellCheckerInfo.class.getSimpleName();
     45     private final ResolveInfo mService;
     46     private final String mId;
     47     private final int mLabel;
     48 
     49     /**
     50      * The spell checker setting activity's name, used by the system settings to
     51      * launch the setting activity.
     52      */
     53     private final String mSettingsActivityName;
     54 
     55     /**
     56      * The array of the subtypes.
     57      */
     58     private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<SpellCheckerSubtype>();
     59 
     60     /**
     61      * Constructor.
     62      * @hide
     63      */
     64     public SpellCheckerInfo(Context context, ResolveInfo service)
     65             throws XmlPullParserException, IOException {
     66         mService = service;
     67         ServiceInfo si = service.serviceInfo;
     68         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
     69 
     70         final PackageManager pm = context.getPackageManager();
     71         int label = 0;
     72         String settingsActivityComponent = null;
     73 
     74         XmlResourceParser parser = null;
     75         try {
     76             parser = si.loadXmlMetaData(pm, SpellCheckerSession.SERVICE_META_DATA);
     77             if (parser == null) {
     78                 throw new XmlPullParserException("No "
     79                         + SpellCheckerSession.SERVICE_META_DATA + " meta-data");
     80             }
     81 
     82             final Resources res = pm.getResourcesForApplication(si.applicationInfo);
     83             final AttributeSet attrs = Xml.asAttributeSet(parser);
     84             int type;
     85             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
     86                     && type != XmlPullParser.START_TAG) {
     87             }
     88 
     89             final String nodeName = parser.getName();
     90             if (!"spell-checker".equals(nodeName)) {
     91                 throw new XmlPullParserException(
     92                         "Meta-data does not start with spell-checker tag");
     93             }
     94 
     95             TypedArray sa = res.obtainAttributes(attrs,
     96                     com.android.internal.R.styleable.SpellChecker);
     97             label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0);
     98             settingsActivityComponent = sa.getString(
     99                     com.android.internal.R.styleable.SpellChecker_settingsActivity);
    100             sa.recycle();
    101 
    102             final int depth = parser.getDepth();
    103             // Parse all subtypes
    104             while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
    105                     && type != XmlPullParser.END_DOCUMENT) {
    106                 if (type == XmlPullParser.START_TAG) {
    107                     final String subtypeNodeName = parser.getName();
    108                     if (!"subtype".equals(subtypeNodeName)) {
    109                         throw new XmlPullParserException(
    110                                 "Meta-data in spell-checker does not start with subtype tag");
    111                     }
    112                     final TypedArray a = res.obtainAttributes(
    113                             attrs, com.android.internal.R.styleable.SpellChecker_Subtype);
    114                     SpellCheckerSubtype subtype = new SpellCheckerSubtype(
    115                             a.getResourceId(com.android.internal.R.styleable
    116                                     .SpellChecker_Subtype_label, 0),
    117                             a.getString(com.android.internal.R.styleable
    118                                     .SpellChecker_Subtype_subtypeLocale),
    119                             a.getString(com.android.internal.R.styleable
    120                                     .SpellChecker_Subtype_subtypeExtraValue));
    121                     mSubtypes.add(subtype);
    122                 }
    123             }
    124         } catch (Exception e) {
    125             Slog.e(TAG, "Caught exception: " + e);
    126             throw new XmlPullParserException(
    127                     "Unable to create context for: " + si.packageName);
    128         } finally {
    129             if (parser != null) parser.close();
    130         }
    131         mLabel = label;
    132         mSettingsActivityName = settingsActivityComponent;
    133     }
    134 
    135     /**
    136      * Constructor.
    137      * @hide
    138      */
    139     public SpellCheckerInfo(Parcel source) {
    140         mLabel = source.readInt();
    141         mId = source.readString();
    142         mSettingsActivityName = source.readString();
    143         mService = ResolveInfo.CREATOR.createFromParcel(source);
    144         source.readTypedList(mSubtypes, SpellCheckerSubtype.CREATOR);
    145     }
    146 
    147     /**
    148      * Return a unique ID for this spell checker.  The ID is generated from
    149      * the package and class name implementing the method.
    150      */
    151     public String getId() {
    152         return mId;
    153     }
    154 
    155 
    156     /**
    157      * Return the component of the service that implements.
    158      */
    159     public ComponentName getComponent() {
    160         return new ComponentName(
    161                 mService.serviceInfo.packageName, mService.serviceInfo.name);
    162     }
    163 
    164     /**
    165      * Return the .apk package that implements this.
    166      */
    167     public String getPackageName() {
    168         return mService.serviceInfo.packageName;
    169     }
    170 
    171     /**
    172      * Used to package this object into a {@link Parcel}.
    173      *
    174      * @param dest The {@link Parcel} to be written.
    175      * @param flags The flags used for parceling.
    176      */
    177     @Override
    178     public void writeToParcel(Parcel dest, int flags) {
    179         dest.writeInt(mLabel);
    180         dest.writeString(mId);
    181         dest.writeString(mSettingsActivityName);
    182         mService.writeToParcel(dest, flags);
    183         dest.writeTypedList(mSubtypes);
    184     }
    185 
    186 
    187     /**
    188      * Used to make this class parcelable.
    189      */
    190     public static final Parcelable.Creator<SpellCheckerInfo> CREATOR
    191             = new Parcelable.Creator<SpellCheckerInfo>() {
    192         @Override
    193         public SpellCheckerInfo createFromParcel(Parcel source) {
    194             return new SpellCheckerInfo(source);
    195         }
    196 
    197         @Override
    198         public SpellCheckerInfo[] newArray(int size) {
    199             return new SpellCheckerInfo[size];
    200         }
    201     };
    202 
    203     /**
    204      * Load the user-displayed label for this spell checker.
    205      *
    206      * @param pm Supply a PackageManager used to load the spell checker's resources.
    207      */
    208     public CharSequence loadLabel(PackageManager pm) {
    209         if (mLabel == 0 || pm == null) return "";
    210         return pm.getText(getPackageName(), mLabel, mService.serviceInfo.applicationInfo);
    211     }
    212 
    213     /**
    214      * Load the user-displayed icon for this spell checker.
    215      *
    216      * @param pm Supply a PackageManager used to load the spell checker's resources.
    217      */
    218     public Drawable loadIcon(PackageManager pm) {
    219         return mService.loadIcon(pm);
    220     }
    221 
    222 
    223     /**
    224      * Return the raw information about the Service implementing this
    225      * spell checker.  Do not modify the returned object.
    226      */
    227     public ServiceInfo getServiceInfo() {
    228         return mService.serviceInfo;
    229     }
    230 
    231     /**
    232      * Return the class name of an activity that provides a settings UI.
    233      * You can launch this activity be starting it with
    234      * an {@link android.content.Intent} whose action is MAIN and with an
    235      * explicit {@link android.content.ComponentName}
    236      * composed of {@link #getPackageName} and the class name returned here.
    237      *
    238      * <p>A null will be returned if there is no settings activity.
    239      */
    240     public String getSettingsActivity() {
    241         return mSettingsActivityName;
    242     }
    243 
    244     /**
    245      * Return the count of the subtypes.
    246      */
    247     public int getSubtypeCount() {
    248         return mSubtypes.size();
    249     }
    250 
    251     /**
    252      * Return the subtype at the specified index.
    253      *
    254      * @param index the index of the subtype to return.
    255      */
    256     public SpellCheckerSubtype getSubtypeAt(int index) {
    257         return mSubtypes.get(index);
    258     }
    259 
    260     /**
    261      * Used to make this class parcelable.
    262      */
    263     @Override
    264     public int describeContents() {
    265         return 0;
    266     }
    267 }
    268