satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 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 | |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 19 | import org.xmlpull.v1.XmlPullParser; |
| 20 | import org.xmlpull.v1.XmlPullParserException; |
| 21 | |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 22 | import android.content.ComponentName; |
| 23 | import android.content.Context; |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 24 | import android.content.pm.PackageManager; |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 25 | import android.content.pm.ResolveInfo; |
| 26 | import android.content.pm.ServiceInfo; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 27 | import android.content.res.Resources; |
| 28 | import android.content.res.TypedArray; |
| 29 | import android.content.res.XmlResourceParser; |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 30 | import android.graphics.drawable.Drawable; |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 31 | import android.os.Parcel; |
| 32 | import android.os.Parcelable; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 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; |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 39 | |
| 40 | /** |
Ken Wakasa | f76a50c | 2012-03-09 19:56:35 +0900 | [diff] [blame] | 41 | * This class is used to specify meta information of a spell checker. |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 42 | */ |
| 43 | public final class SpellCheckerInfo implements Parcelable { |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 44 | private static final String TAG = SpellCheckerInfo.class.getSimpleName(); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 45 | private final ResolveInfo mService; |
| 46 | private final String mId; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 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 | /** |
Ken Wakasa | f76a50c | 2012-03-09 19:56:35 +0900 | [diff] [blame] | 56 | * The array of subtypes. |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 57 | */ |
| 58 | private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<SpellCheckerSubtype>(); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 59 | |
| 60 | /** |
| 61 | * Constructor. |
| 62 | * @hide |
| 63 | */ |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 64 | public SpellCheckerInfo(Context context, ResolveInfo service) |
| 65 | throws XmlPullParserException, IOException { |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 66 | mService = service; |
| 67 | ServiceInfo si = service.serviceInfo; |
| 68 | mId = new ComponentName(si.packageName, si.name).flattenToShortString(); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 69 | |
| 70 | final PackageManager pm = context.getPackageManager(); |
| 71 | int label = 0; |
| 72 | String settingsActivityComponent = null; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 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 |
Yohei Yukawa | 868d19b | 2015-12-07 15:58:57 -0800 | [diff] [blame] | 120 | .SpellChecker_Subtype_languageTag), |
| 121 | a.getString(com.android.internal.R.styleable |
Yohei Yukawa | 0894319 | 2015-12-04 16:16:47 -0800 | [diff] [blame] | 122 | .SpellChecker_Subtype_subtypeExtraValue), |
| 123 | a.getInt(com.android.internal.R.styleable |
| 124 | .SpellChecker_Subtype_subtypeId, 0)); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 125 | mSubtypes.add(subtype); |
| 126 | } |
| 127 | } |
| 128 | } catch (Exception e) { |
| 129 | Slog.e(TAG, "Caught exception: " + e); |
| 130 | throw new XmlPullParserException( |
| 131 | "Unable to create context for: " + si.packageName); |
| 132 | } finally { |
| 133 | if (parser != null) parser.close(); |
| 134 | } |
| 135 | mLabel = label; |
| 136 | mSettingsActivityName = settingsActivityComponent; |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 137 | } |
| 138 | |
| 139 | /** |
| 140 | * Constructor. |
| 141 | * @hide |
| 142 | */ |
| 143 | public SpellCheckerInfo(Parcel source) { |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 144 | mLabel = source.readInt(); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 145 | mId = source.readString(); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 146 | mSettingsActivityName = source.readString(); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 147 | mService = ResolveInfo.CREATOR.createFromParcel(source); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 148 | source.readTypedList(mSubtypes, SpellCheckerSubtype.CREATOR); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | /** |
| 152 | * Return a unique ID for this spell checker. The ID is generated from |
| 153 | * the package and class name implementing the method. |
| 154 | */ |
| 155 | public String getId() { |
| 156 | return mId; |
| 157 | } |
| 158 | |
satok | f671061 | 2012-03-30 18:31:36 +0900 | [diff] [blame] | 159 | /** |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 160 | * Return the component of the service that implements. |
| 161 | */ |
| 162 | public ComponentName getComponent() { |
| 163 | return new ComponentName( |
| 164 | mService.serviceInfo.packageName, mService.serviceInfo.name); |
| 165 | } |
| 166 | |
| 167 | /** |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 168 | * Return the .apk package that implements this. |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 169 | */ |
| 170 | public String getPackageName() { |
| 171 | return mService.serviceInfo.packageName; |
| 172 | } |
| 173 | |
| 174 | /** |
| 175 | * Used to package this object into a {@link Parcel}. |
| 176 | * |
| 177 | * @param dest The {@link Parcel} to be written. |
| 178 | * @param flags The flags used for parceling. |
| 179 | */ |
| 180 | @Override |
| 181 | public void writeToParcel(Parcel dest, int flags) { |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 182 | dest.writeInt(mLabel); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 183 | dest.writeString(mId); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 184 | dest.writeString(mSettingsActivityName); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 185 | mService.writeToParcel(dest, flags); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 186 | dest.writeTypedList(mSubtypes); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | |
| 190 | /** |
| 191 | * Used to make this class parcelable. |
| 192 | */ |
| 193 | public static final Parcelable.Creator<SpellCheckerInfo> CREATOR |
| 194 | = new Parcelable.Creator<SpellCheckerInfo>() { |
| 195 | @Override |
| 196 | public SpellCheckerInfo createFromParcel(Parcel source) { |
| 197 | return new SpellCheckerInfo(source); |
| 198 | } |
| 199 | |
| 200 | @Override |
| 201 | public SpellCheckerInfo[] newArray(int size) { |
| 202 | return new SpellCheckerInfo[size]; |
| 203 | } |
| 204 | }; |
| 205 | |
| 206 | /** |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 207 | * Load the user-displayed label for this spell checker. |
| 208 | * |
| 209 | * @param pm Supply a PackageManager used to load the spell checker's resources. |
| 210 | */ |
| 211 | public CharSequence loadLabel(PackageManager pm) { |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 212 | if (mLabel == 0 || pm == null) return ""; |
| 213 | return pm.getText(getPackageName(), mLabel, mService.serviceInfo.applicationInfo); |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 214 | } |
| 215 | |
| 216 | /** |
| 217 | * Load the user-displayed icon for this spell checker. |
| 218 | * |
| 219 | * @param pm Supply a PackageManager used to load the spell checker's resources. |
| 220 | */ |
| 221 | public Drawable loadIcon(PackageManager pm) { |
| 222 | return mService.loadIcon(pm); |
| 223 | } |
| 224 | |
satok | 2388a7b | 2011-08-26 14:35:09 +0900 | [diff] [blame] | 225 | |
| 226 | /** |
| 227 | * Return the raw information about the Service implementing this |
| 228 | * spell checker. Do not modify the returned object. |
| 229 | */ |
| 230 | public ServiceInfo getServiceInfo() { |
| 231 | return mService.serviceInfo; |
| 232 | } |
| 233 | |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 234 | /** |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 235 | * Return the class name of an activity that provides a settings UI. |
| 236 | * You can launch this activity be starting it with |
| 237 | * an {@link android.content.Intent} whose action is MAIN and with an |
| 238 | * explicit {@link android.content.ComponentName} |
| 239 | * composed of {@link #getPackageName} and the class name returned here. |
| 240 | * |
| 241 | * <p>A null will be returned if there is no settings activity. |
| 242 | */ |
| 243 | public String getSettingsActivity() { |
| 244 | return mSettingsActivityName; |
| 245 | } |
| 246 | |
| 247 | /** |
| 248 | * Return the count of the subtypes. |
| 249 | */ |
| 250 | public int getSubtypeCount() { |
| 251 | return mSubtypes.size(); |
| 252 | } |
| 253 | |
| 254 | /** |
| 255 | * Return the subtype at the specified index. |
| 256 | * |
| 257 | * @param index the index of the subtype to return. |
| 258 | */ |
| 259 | public SpellCheckerSubtype getSubtypeAt(int index) { |
| 260 | return mSubtypes.get(index); |
| 261 | } |
| 262 | |
| 263 | /** |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 264 | * Used to make this class parcelable. |
| 265 | */ |
| 266 | @Override |
| 267 | public int describeContents() { |
| 268 | return 0; |
| 269 | } |
| 270 | } |