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 | |
| 19 | import android.content.ComponentName; |
| 20 | import android.content.Context; |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 21 | import android.content.pm.PackageManager; |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 22 | import android.content.pm.ResolveInfo; |
| 23 | import android.content.pm.ServiceInfo; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 24 | import android.content.res.Resources; |
| 25 | import android.content.res.TypedArray; |
| 26 | import android.content.res.XmlResourceParser; |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 27 | import android.graphics.drawable.Drawable; |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 28 | import android.os.Parcel; |
| 29 | import android.os.Parcelable; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 30 | import android.util.AttributeSet; |
Yohei Yukawa | 85df698 | 2016-03-08 15:16:07 -0800 | [diff] [blame] | 31 | import android.util.PrintWriterPrinter; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 32 | import android.util.Slog; |
| 33 | import android.util.Xml; |
| 34 | |
Aurimas Liutikas | 67e2ae8 | 2016-10-11 18:17:42 -0700 | [diff] [blame] | 35 | import org.xmlpull.v1.XmlPullParser; |
| 36 | import org.xmlpull.v1.XmlPullParserException; |
| 37 | |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 38 | import java.io.IOException; |
Yohei Yukawa | 85df698 | 2016-03-08 15:16:07 -0800 | [diff] [blame] | 39 | import java.io.PrintWriter; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 40 | import java.util.ArrayList; |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 41 | |
| 42 | /** |
Ken Wakasa | f76a50c | 2012-03-09 19:56:35 +0900 | [diff] [blame] | 43 | * This class is used to specify meta information of a spell checker. |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 44 | */ |
| 45 | public final class SpellCheckerInfo implements Parcelable { |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 46 | private static final String TAG = SpellCheckerInfo.class.getSimpleName(); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 47 | private final ResolveInfo mService; |
| 48 | private final String mId; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 49 | private final int mLabel; |
| 50 | |
| 51 | /** |
| 52 | * The spell checker setting activity's name, used by the system settings to |
| 53 | * launch the setting activity. |
| 54 | */ |
| 55 | private final String mSettingsActivityName; |
| 56 | |
| 57 | /** |
Ken Wakasa | f76a50c | 2012-03-09 19:56:35 +0900 | [diff] [blame] | 58 | * The array of subtypes. |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 59 | */ |
Yohei Yukawa | 85df698 | 2016-03-08 15:16:07 -0800 | [diff] [blame] | 60 | private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<>(); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 61 | |
| 62 | /** |
| 63 | * Constructor. |
| 64 | * @hide |
| 65 | */ |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 66 | public SpellCheckerInfo(Context context, ResolveInfo service) |
| 67 | throws XmlPullParserException, IOException { |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 68 | mService = service; |
| 69 | ServiceInfo si = service.serviceInfo; |
| 70 | mId = new ComponentName(si.packageName, si.name).flattenToShortString(); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 71 | |
| 72 | final PackageManager pm = context.getPackageManager(); |
| 73 | int label = 0; |
| 74 | String settingsActivityComponent = null; |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 75 | |
| 76 | XmlResourceParser parser = null; |
| 77 | try { |
| 78 | parser = si.loadXmlMetaData(pm, SpellCheckerSession.SERVICE_META_DATA); |
| 79 | if (parser == null) { |
| 80 | throw new XmlPullParserException("No " |
| 81 | + SpellCheckerSession.SERVICE_META_DATA + " meta-data"); |
| 82 | } |
| 83 | |
| 84 | final Resources res = pm.getResourcesForApplication(si.applicationInfo); |
| 85 | final AttributeSet attrs = Xml.asAttributeSet(parser); |
| 86 | int type; |
| 87 | while ((type=parser.next()) != XmlPullParser.END_DOCUMENT |
| 88 | && type != XmlPullParser.START_TAG) { |
| 89 | } |
| 90 | |
| 91 | final String nodeName = parser.getName(); |
| 92 | if (!"spell-checker".equals(nodeName)) { |
| 93 | throw new XmlPullParserException( |
| 94 | "Meta-data does not start with spell-checker tag"); |
| 95 | } |
| 96 | |
| 97 | TypedArray sa = res.obtainAttributes(attrs, |
| 98 | com.android.internal.R.styleable.SpellChecker); |
| 99 | label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0); |
| 100 | settingsActivityComponent = sa.getString( |
| 101 | com.android.internal.R.styleable.SpellChecker_settingsActivity); |
| 102 | sa.recycle(); |
| 103 | |
| 104 | final int depth = parser.getDepth(); |
| 105 | // Parse all subtypes |
| 106 | while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) |
| 107 | && type != XmlPullParser.END_DOCUMENT) { |
| 108 | if (type == XmlPullParser.START_TAG) { |
| 109 | final String subtypeNodeName = parser.getName(); |
| 110 | if (!"subtype".equals(subtypeNodeName)) { |
| 111 | throw new XmlPullParserException( |
| 112 | "Meta-data in spell-checker does not start with subtype tag"); |
| 113 | } |
| 114 | final TypedArray a = res.obtainAttributes( |
| 115 | attrs, com.android.internal.R.styleable.SpellChecker_Subtype); |
| 116 | SpellCheckerSubtype subtype = new SpellCheckerSubtype( |
| 117 | a.getResourceId(com.android.internal.R.styleable |
| 118 | .SpellChecker_Subtype_label, 0), |
| 119 | a.getString(com.android.internal.R.styleable |
| 120 | .SpellChecker_Subtype_subtypeLocale), |
| 121 | a.getString(com.android.internal.R.styleable |
Yohei Yukawa | 868d19b | 2015-12-07 15:58:57 -0800 | [diff] [blame] | 122 | .SpellChecker_Subtype_languageTag), |
| 123 | a.getString(com.android.internal.R.styleable |
Yohei Yukawa | 0894319 | 2015-12-04 16:16:47 -0800 | [diff] [blame] | 124 | .SpellChecker_Subtype_subtypeExtraValue), |
| 125 | a.getInt(com.android.internal.R.styleable |
| 126 | .SpellChecker_Subtype_subtypeId, 0)); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 127 | mSubtypes.add(subtype); |
| 128 | } |
| 129 | } |
| 130 | } catch (Exception e) { |
| 131 | Slog.e(TAG, "Caught exception: " + e); |
| 132 | throw new XmlPullParserException( |
| 133 | "Unable to create context for: " + si.packageName); |
| 134 | } finally { |
| 135 | if (parser != null) parser.close(); |
| 136 | } |
| 137 | mLabel = label; |
| 138 | mSettingsActivityName = settingsActivityComponent; |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 139 | } |
| 140 | |
| 141 | /** |
| 142 | * Constructor. |
| 143 | * @hide |
| 144 | */ |
| 145 | public SpellCheckerInfo(Parcel source) { |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 146 | mLabel = source.readInt(); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 147 | mId = source.readString(); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 148 | mSettingsActivityName = source.readString(); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 149 | mService = ResolveInfo.CREATOR.createFromParcel(source); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 150 | source.readTypedList(mSubtypes, SpellCheckerSubtype.CREATOR); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | /** |
| 154 | * Return a unique ID for this spell checker. The ID is generated from |
| 155 | * the package and class name implementing the method. |
| 156 | */ |
| 157 | public String getId() { |
| 158 | return mId; |
| 159 | } |
| 160 | |
satok | f671061 | 2012-03-30 18:31:36 +0900 | [diff] [blame] | 161 | /** |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 162 | * Return the component of the service that implements. |
| 163 | */ |
| 164 | public ComponentName getComponent() { |
| 165 | return new ComponentName( |
| 166 | mService.serviceInfo.packageName, mService.serviceInfo.name); |
| 167 | } |
| 168 | |
| 169 | /** |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 170 | * Return the .apk package that implements this. |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 171 | */ |
| 172 | public String getPackageName() { |
| 173 | return mService.serviceInfo.packageName; |
| 174 | } |
| 175 | |
| 176 | /** |
| 177 | * Used to package this object into a {@link Parcel}. |
| 178 | * |
| 179 | * @param dest The {@link Parcel} to be written. |
| 180 | * @param flags The flags used for parceling. |
| 181 | */ |
| 182 | @Override |
| 183 | public void writeToParcel(Parcel dest, int flags) { |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 184 | dest.writeInt(mLabel); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 185 | dest.writeString(mId); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 186 | dest.writeString(mSettingsActivityName); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 187 | mService.writeToParcel(dest, flags); |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 188 | dest.writeTypedList(mSubtypes); |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | |
| 192 | /** |
| 193 | * Used to make this class parcelable. |
| 194 | */ |
Jeff Sharkey | 9e8f83d | 2019-02-28 12:06:45 -0700 | [diff] [blame] | 195 | public static final @android.annotation.NonNull Parcelable.Creator<SpellCheckerInfo> CREATOR |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 196 | = new Parcelable.Creator<SpellCheckerInfo>() { |
| 197 | @Override |
| 198 | public SpellCheckerInfo createFromParcel(Parcel source) { |
| 199 | return new SpellCheckerInfo(source); |
| 200 | } |
| 201 | |
| 202 | @Override |
| 203 | public SpellCheckerInfo[] newArray(int size) { |
| 204 | return new SpellCheckerInfo[size]; |
| 205 | } |
| 206 | }; |
| 207 | |
| 208 | /** |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 209 | * Load the user-displayed label for this spell checker. |
| 210 | * |
| 211 | * @param pm Supply a PackageManager used to load the spell checker's resources. |
| 212 | */ |
| 213 | public CharSequence loadLabel(PackageManager pm) { |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 214 | if (mLabel == 0 || pm == null) return ""; |
| 215 | return pm.getText(getPackageName(), mLabel, mService.serviceInfo.applicationInfo); |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 216 | } |
| 217 | |
| 218 | /** |
| 219 | * Load the user-displayed icon for this spell checker. |
| 220 | * |
| 221 | * @param pm Supply a PackageManager used to load the spell checker's resources. |
| 222 | */ |
| 223 | public Drawable loadIcon(PackageManager pm) { |
| 224 | return mService.loadIcon(pm); |
| 225 | } |
| 226 | |
satok | 2388a7b | 2011-08-26 14:35:09 +0900 | [diff] [blame] | 227 | |
| 228 | /** |
| 229 | * Return the raw information about the Service implementing this |
| 230 | * spell checker. Do not modify the returned object. |
| 231 | */ |
| 232 | public ServiceInfo getServiceInfo() { |
| 233 | return mService.serviceInfo; |
| 234 | } |
| 235 | |
satok | 562ab58 | 2011-07-25 10:12:21 +0900 | [diff] [blame] | 236 | /** |
satok | 03b2ea1 | 2011-08-03 17:36:14 +0900 | [diff] [blame] | 237 | * Return the class name of an activity that provides a settings UI. |
| 238 | * You can launch this activity be starting it with |
| 239 | * an {@link android.content.Intent} whose action is MAIN and with an |
| 240 | * explicit {@link android.content.ComponentName} |
| 241 | * composed of {@link #getPackageName} and the class name returned here. |
| 242 | * |
| 243 | * <p>A null will be returned if there is no settings activity. |
| 244 | */ |
| 245 | public String getSettingsActivity() { |
| 246 | return mSettingsActivityName; |
| 247 | } |
| 248 | |
| 249 | /** |
| 250 | * Return the count of the subtypes. |
| 251 | */ |
| 252 | public int getSubtypeCount() { |
| 253 | return mSubtypes.size(); |
| 254 | } |
| 255 | |
| 256 | /** |
| 257 | * Return the subtype at the specified index. |
| 258 | * |
| 259 | * @param index the index of the subtype to return. |
| 260 | */ |
| 261 | public SpellCheckerSubtype getSubtypeAt(int index) { |
| 262 | return mSubtypes.get(index); |
| 263 | } |
| 264 | |
| 265 | /** |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 266 | * Used to make this class parcelable. |
| 267 | */ |
| 268 | @Override |
| 269 | public int describeContents() { |
| 270 | return 0; |
| 271 | } |
Yohei Yukawa | 85df698 | 2016-03-08 15:16:07 -0800 | [diff] [blame] | 272 | |
| 273 | /** |
| 274 | * @hide |
| 275 | */ |
| 276 | public void dump(final PrintWriter pw, final String prefix) { |
| 277 | pw.println(prefix + "mId=" + mId); |
| 278 | pw.println(prefix + "mSettingsActivityName=" + mSettingsActivityName); |
| 279 | pw.println(prefix + "Service:"); |
| 280 | mService.dump(new PrintWriterPrinter(pw), prefix + " "); |
| 281 | final int N = getSubtypeCount(); |
| 282 | for (int i = 0; i < N; i++) { |
| 283 | final SpellCheckerSubtype st = getSubtypeAt(i); |
| 284 | pw.println(prefix + " " + "Subtype #" + i + ":"); |
| 285 | pw.println(prefix + " " + "locale=" + st.getLocale() |
| 286 | + " languageTag=" + st.getLanguageTag()); |
| 287 | pw.println(prefix + " " + "extraValue=" + st.getExtraValue()); |
| 288 | } |
| 289 | } |
satok | 988323c | 2011-06-22 16:38:13 +0900 | [diff] [blame] | 290 | } |