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 a 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 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      * Return the component of the service that implements.
    157      */
    158     public ComponentName getComponent() {
    159         return new ComponentName(
    160                 mService.serviceInfo.packageName, mService.serviceInfo.name);
    161     }
    162 
    163     /**
    164      * Return the .apk package that implements this.
    165      */
    166     public String getPackageName() {
    167         return mService.serviceInfo.packageName;
    168     }
    169 
    170     /**
    171      * Used to package this object into a {@link Parcel}.
    172      *
    173      * @param dest The {@link Parcel} to be written.
    174      * @param flags The flags used for parceling.
    175      */
    176     @Override
    177     public void writeToParcel(Parcel dest, int flags) {
    178         dest.writeInt(mLabel);
    179         dest.writeString(mId);
    180         dest.writeString(mSettingsActivityName);
    181         mService.writeToParcel(dest, flags);
    182         dest.writeTypedList(mSubtypes);
    183     }
    184 
    185 
    186     /**
    187      * Used to make this class parcelable.
    188      */
    189     public static final Parcelable.Creator<SpellCheckerInfo> CREATOR
    190             = new Parcelable.Creator<SpellCheckerInfo>() {
    191         @Override
    192         public SpellCheckerInfo createFromParcel(Parcel source) {
    193             return new SpellCheckerInfo(source);
    194         }
    195 
    196         @Override
    197         public SpellCheckerInfo[] newArray(int size) {
    198             return new SpellCheckerInfo[size];
    199         }
    200     };
    201 
    202     /**
    203      * Load the user-displayed label for this spell checker.
    204      *
    205      * @param pm Supply a PackageManager used to load the spell checker's resources.
    206      */
    207     public CharSequence loadLabel(PackageManager pm) {
    208         if (mLabel == 0 || pm == null) return "";
    209         return pm.getText(getPackageName(), mLabel, mService.serviceInfo.applicationInfo);
    210     }
    211 
    212     /**
    213      * Load the user-displayed icon for this spell checker.
    214      *
    215      * @param pm Supply a PackageManager used to load the spell checker's resources.
    216      */
    217     public Drawable loadIcon(PackageManager pm) {
    218         return mService.loadIcon(pm);
    219     }
    220 
    221 
    222     /**
    223      * Return the raw information about the Service implementing this
    224      * spell checker.  Do not modify the returned object.
    225      */
    226     public ServiceInfo getServiceInfo() {
    227         return mService.serviceInfo;
    228     }
    229 
    230     /**
    231      * Return the class name of an activity that provides a settings UI.
    232      * You can launch this activity be starting it with
    233      * an {@link android.content.Intent} whose action is MAIN and with an
    234      * explicit {@link android.content.ComponentName}
    235      * composed of {@link #getPackageName} and the class name returned here.
    236      *
    237      * <p>A null will be returned if there is no settings activity.
    238      */
    239     public String getSettingsActivity() {
    240         return mSettingsActivityName;
    241     }
    242 
    243     /**
    244      * Return the count of the subtypes.
    245      */
    246     public int getSubtypeCount() {
    247         return mSubtypes.size();
    248     }
    249 
    250     /**
    251      * Return the subtype at the specified index.
    252      *
    253      * @param index the index of the subtype to return.
    254      */
    255     public SpellCheckerSubtype getSubtypeAt(int index) {
    256         return mSubtypes.get(index);
    257     }
    258 
    259     /**
    260      * Used to make this class parcelable.
    261      */
    262     @Override
    263     public int describeContents() {
    264         return 0;
    265     }
    266 }
    267