blob: 7aa2c23ae5e02c77418f160ff1019a592ff20c3b [file] [log] [blame]
satok988323c2011-06-22 16:38:13 +09001/*
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
17package android.view.textservice;
18
19import android.content.ComponentName;
20import android.content.Context;
satok562ab582011-07-25 10:12:21 +090021import android.content.pm.PackageManager;
satok988323c2011-06-22 16:38:13 +090022import android.content.pm.ResolveInfo;
23import android.content.pm.ServiceInfo;
satok03b2ea12011-08-03 17:36:14 +090024import android.content.res.Resources;
25import android.content.res.TypedArray;
26import android.content.res.XmlResourceParser;
satok562ab582011-07-25 10:12:21 +090027import android.graphics.drawable.Drawable;
satok988323c2011-06-22 16:38:13 +090028import android.os.Parcel;
29import android.os.Parcelable;
satok03b2ea12011-08-03 17:36:14 +090030import android.util.AttributeSet;
Yohei Yukawa85df6982016-03-08 15:16:07 -080031import android.util.PrintWriterPrinter;
satok03b2ea12011-08-03 17:36:14 +090032import android.util.Slog;
33import android.util.Xml;
34
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070035import org.xmlpull.v1.XmlPullParser;
36import org.xmlpull.v1.XmlPullParserException;
37
satok03b2ea12011-08-03 17:36:14 +090038import java.io.IOException;
Yohei Yukawa85df6982016-03-08 15:16:07 -080039import java.io.PrintWriter;
satok03b2ea12011-08-03 17:36:14 +090040import java.util.ArrayList;
satok988323c2011-06-22 16:38:13 +090041
42/**
Ken Wakasaf76a50c2012-03-09 19:56:35 +090043 * This class is used to specify meta information of a spell checker.
satok988323c2011-06-22 16:38:13 +090044 */
45public final class SpellCheckerInfo implements Parcelable {
satok03b2ea12011-08-03 17:36:14 +090046 private static final String TAG = SpellCheckerInfo.class.getSimpleName();
satok988323c2011-06-22 16:38:13 +090047 private final ResolveInfo mService;
48 private final String mId;
satok03b2ea12011-08-03 17:36:14 +090049 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 Wakasaf76a50c2012-03-09 19:56:35 +090058 * The array of subtypes.
satok03b2ea12011-08-03 17:36:14 +090059 */
Yohei Yukawa85df6982016-03-08 15:16:07 -080060 private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<>();
satok988323c2011-06-22 16:38:13 +090061
62 /**
63 * Constructor.
64 * @hide
65 */
satok03b2ea12011-08-03 17:36:14 +090066 public SpellCheckerInfo(Context context, ResolveInfo service)
67 throws XmlPullParserException, IOException {
satok988323c2011-06-22 16:38:13 +090068 mService = service;
69 ServiceInfo si = service.serviceInfo;
70 mId = new ComponentName(si.packageName, si.name).flattenToShortString();
satok03b2ea12011-08-03 17:36:14 +090071
72 final PackageManager pm = context.getPackageManager();
73 int label = 0;
74 String settingsActivityComponent = null;
satok03b2ea12011-08-03 17:36:14 +090075
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 Yukawa868d19b2015-12-07 15:58:57 -0800122 .SpellChecker_Subtype_languageTag),
123 a.getString(com.android.internal.R.styleable
Yohei Yukawa08943192015-12-04 16:16:47 -0800124 .SpellChecker_Subtype_subtypeExtraValue),
125 a.getInt(com.android.internal.R.styleable
126 .SpellChecker_Subtype_subtypeId, 0));
satok03b2ea12011-08-03 17:36:14 +0900127 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;
satok988323c2011-06-22 16:38:13 +0900139 }
140
141 /**
142 * Constructor.
143 * @hide
144 */
145 public SpellCheckerInfo(Parcel source) {
satok03b2ea12011-08-03 17:36:14 +0900146 mLabel = source.readInt();
satok988323c2011-06-22 16:38:13 +0900147 mId = source.readString();
satok03b2ea12011-08-03 17:36:14 +0900148 mSettingsActivityName = source.readString();
satok988323c2011-06-22 16:38:13 +0900149 mService = ResolveInfo.CREATOR.createFromParcel(source);
satok03b2ea12011-08-03 17:36:14 +0900150 source.readTypedList(mSubtypes, SpellCheckerSubtype.CREATOR);
satok988323c2011-06-22 16:38:13 +0900151 }
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
satokf6710612012-03-30 18:31:36 +0900161 /**
satok988323c2011-06-22 16:38:13 +0900162 * 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 /**
satok03b2ea12011-08-03 17:36:14 +0900170 * Return the .apk package that implements this.
satok988323c2011-06-22 16:38:13 +0900171 */
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) {
satok03b2ea12011-08-03 17:36:14 +0900184 dest.writeInt(mLabel);
satok988323c2011-06-22 16:38:13 +0900185 dest.writeString(mId);
satok03b2ea12011-08-03 17:36:14 +0900186 dest.writeString(mSettingsActivityName);
satok988323c2011-06-22 16:38:13 +0900187 mService.writeToParcel(dest, flags);
satok03b2ea12011-08-03 17:36:14 +0900188 dest.writeTypedList(mSubtypes);
satok988323c2011-06-22 16:38:13 +0900189 }
190
191
192 /**
193 * Used to make this class parcelable.
194 */
195 public static final Parcelable.Creator<SpellCheckerInfo> CREATOR
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 /**
satok562ab582011-07-25 10:12:21 +0900209 * 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) {
satok03b2ea12011-08-03 17:36:14 +0900214 if (mLabel == 0 || pm == null) return "";
215 return pm.getText(getPackageName(), mLabel, mService.serviceInfo.applicationInfo);
satok562ab582011-07-25 10:12:21 +0900216 }
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
satok2388a7b2011-08-26 14:35:09 +0900227
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
satok562ab582011-07-25 10:12:21 +0900236 /**
satok03b2ea12011-08-03 17:36:14 +0900237 * 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 /**
satok988323c2011-06-22 16:38:13 +0900266 * Used to make this class parcelable.
267 */
268 @Override
269 public int describeContents() {
270 return 0;
271 }
Yohei Yukawa85df6982016-03-08 15:16:07 -0800272
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 }
satok988323c2011-06-22 16:38:13 +0900290}