InputMethodInfo.java revision c50232d517d7b99ae3c3e073f04eb6799c876e8c
1/* 2 * Copyright (C) 2007-2008 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.inputmethod; 18 19import org.xmlpull.v1.XmlPullParser; 20import org.xmlpull.v1.XmlPullParserException; 21 22import android.content.ComponentName; 23import android.content.Context; 24import android.content.pm.ApplicationInfo; 25import android.content.pm.PackageManager; 26import android.content.pm.ResolveInfo; 27import android.content.pm.ServiceInfo; 28import android.content.pm.PackageManager.NameNotFoundException; 29import android.content.res.Resources; 30import android.content.res.TypedArray; 31import android.content.res.XmlResourceParser; 32import android.graphics.drawable.Drawable; 33import android.os.Parcel; 34import android.os.Parcelable; 35import android.util.AttributeSet; 36import android.util.Printer; 37import android.util.Xml; 38 39import java.io.IOException; 40import java.util.ArrayList; 41 42/** 43 * This class is used to specify meta information of an input method. 44 */ 45public final class InputMethodInfo implements Parcelable { 46 static final String TAG = "InputMethodInfo"; 47 48 /** 49 * The Service that implements this input method component. 50 */ 51 final ResolveInfo mService; 52 53 /** 54 * The unique string Id to identify the input method. This is generated 55 * from the input method component. 56 */ 57 final String mId; 58 59 /** 60 * The input method setting activity's name, used by the system settings to 61 * launch the setting activity of this input method. 62 */ 63 final String mSettingsActivityName; 64 65 /** 66 * The resource in the input method's .apk that holds a boolean indicating 67 * whether it should be considered the default input method for this 68 * system. This is a resource ID instead of the final value so that it 69 * can change based on the configuration (in particular locale). 70 */ 71 final int mIsDefaultResId; 72 73 /** 74 * The array of the subtypes. 75 */ 76 private final ArrayList<InputMethodSubtype> mSubtypes = new ArrayList<InputMethodSubtype>(); 77 78 /** 79 * Constructor. 80 * 81 * @param context The Context in which we are parsing the input method. 82 * @param service The ResolveInfo returned from the package manager about 83 * this input method's component. 84 */ 85 public InputMethodInfo(Context context, ResolveInfo service) 86 throws XmlPullParserException, IOException { 87 mService = service; 88 ServiceInfo si = service.serviceInfo; 89 mId = new ComponentName(si.packageName, si.name).flattenToShortString(); 90 91 PackageManager pm = context.getPackageManager(); 92 String settingsActivityComponent = null; 93 int isDefaultResId = 0; 94 95 XmlResourceParser parser = null; 96 try { 97 parser = si.loadXmlMetaData(pm, InputMethod.SERVICE_META_DATA); 98 if (parser == null) { 99 throw new XmlPullParserException("No " 100 + InputMethod.SERVICE_META_DATA + " meta-data"); 101 } 102 103 Resources res = pm.getResourcesForApplication(si.applicationInfo); 104 105 AttributeSet attrs = Xml.asAttributeSet(parser); 106 107 int type; 108 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 109 && type != XmlPullParser.START_TAG) { 110 } 111 112 String nodeName = parser.getName(); 113 if (!"input-method".equals(nodeName)) { 114 throw new XmlPullParserException( 115 "Meta-data does not start with input-method tag"); 116 } 117 118 TypedArray sa = res.obtainAttributes(attrs, 119 com.android.internal.R.styleable.InputMethod); 120 settingsActivityComponent = sa.getString( 121 com.android.internal.R.styleable.InputMethod_settingsActivity); 122 isDefaultResId = sa.getResourceId( 123 com.android.internal.R.styleable.InputMethod_isDefault, 0); 124 sa.recycle(); 125 126 final int depth = parser.getDepth(); 127 // Parse all subtypes 128 while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 129 && type != XmlPullParser.END_DOCUMENT) { 130 if (type == XmlPullParser.START_TAG) { 131 nodeName = parser.getName(); 132 if (!"subtype".equals(nodeName)) { 133 throw new XmlPullParserException( 134 "Meta-data in input-method does not start with subtype tag"); 135 } 136 final TypedArray a = res.obtainAttributes( 137 attrs, com.android.internal.R.styleable.InputMethod_Subtype); 138 InputMethodSubtype subtype = new InputMethodSubtype( 139 a.getResourceId(com.android.internal.R.styleable 140 .InputMethod_Subtype_label, 0), 141 a.getResourceId(com.android.internal.R.styleable 142 .InputMethod_Subtype_icon, 0), 143 a.getString(com.android.internal.R.styleable 144 .InputMethod_Subtype_imeSubtypeLocale), 145 a.getString(com.android.internal.R.styleable 146 .InputMethod_Subtype_imeSubtypeMode), 147 a.getString(com.android.internal.R.styleable 148 .InputMethod_Subtype_imeSubtypeExtraValue)); 149 mSubtypes.add(subtype); 150 } 151 } 152 } catch (NameNotFoundException e) { 153 throw new XmlPullParserException( 154 "Unable to create context for: " + si.packageName); 155 } finally { 156 if (parser != null) parser.close(); 157 } 158 mSettingsActivityName = settingsActivityComponent; 159 mIsDefaultResId = isDefaultResId; 160 } 161 162 InputMethodInfo(Parcel source) { 163 mId = source.readString(); 164 mSettingsActivityName = source.readString(); 165 mIsDefaultResId = source.readInt(); 166 mService = ResolveInfo.CREATOR.createFromParcel(source); 167 source.readTypedList(mSubtypes, InputMethodSubtype.CREATOR); 168 } 169 170 /** 171 * Temporary API for creating a built-in input method. 172 */ 173 public InputMethodInfo(String packageName, String className, 174 CharSequence label, String settingsActivity) { 175 ResolveInfo ri = new ResolveInfo(); 176 ServiceInfo si = new ServiceInfo(); 177 ApplicationInfo ai = new ApplicationInfo(); 178 ai.packageName = packageName; 179 ai.enabled = true; 180 si.applicationInfo = ai; 181 si.enabled = true; 182 si.packageName = packageName; 183 si.name = className; 184 si.exported = true; 185 si.nonLocalizedLabel = label; 186 ri.serviceInfo = si; 187 mService = ri; 188 mId = new ComponentName(si.packageName, si.name).flattenToShortString(); 189 mSettingsActivityName = settingsActivity; 190 mIsDefaultResId = 0; 191 } 192 193 /** 194 * Return a unique ID for this input method. The ID is generated from 195 * the package and class name implementing the method. 196 */ 197 public String getId() { 198 return mId; 199 } 200 201 /** 202 * Return the .apk package that implements this input method. 203 */ 204 public String getPackageName() { 205 return mService.serviceInfo.packageName; 206 } 207 208 /** 209 * Return the class name of the service component that implements 210 * this input method. 211 */ 212 public String getServiceName() { 213 return mService.serviceInfo.name; 214 } 215 216 /** 217 * Return the raw information about the Service implementing this 218 * input method. Do not modify the returned object. 219 */ 220 public ServiceInfo getServiceInfo() { 221 return mService.serviceInfo; 222 } 223 224 /** 225 * Return the component of the service that implements this input 226 * method. 227 */ 228 public ComponentName getComponent() { 229 return new ComponentName(mService.serviceInfo.packageName, 230 mService.serviceInfo.name); 231 } 232 233 /** 234 * Load the user-displayed label for this input method. 235 * 236 * @param pm Supply a PackageManager used to load the input method's 237 * resources. 238 */ 239 public CharSequence loadLabel(PackageManager pm) { 240 return mService.loadLabel(pm); 241 } 242 243 /** 244 * Load the user-displayed icon for this input method. 245 * 246 * @param pm Supply a PackageManager used to load the input method's 247 * resources. 248 */ 249 public Drawable loadIcon(PackageManager pm) { 250 return mService.loadIcon(pm); 251 } 252 253 /** 254 * Return the class name of an activity that provides a settings UI for 255 * the input method. You can launch this activity be starting it with 256 * an {@link android.content.Intent} whose action is MAIN and with an 257 * explicit {@link android.content.ComponentName} 258 * composed of {@link #getPackageName} and the class name returned here. 259 * 260 * <p>A null will be returned if there is no settings activity associated 261 * with the input method. 262 */ 263 public String getSettingsActivity() { 264 return mSettingsActivityName; 265 } 266 267 /** 268 * Return the count of the subtypes of Input Method. 269 */ 270 public int getSubtypeCount() { 271 return mSubtypes.size(); 272 } 273 274 /** 275 * Return the Input Method's subtype at the specified index. 276 * 277 * @param index the index of the subtype to return. 278 */ 279 public InputMethodSubtype getSubtypeAt(int index) { 280 return mSubtypes.get(index); 281 } 282 283 /** 284 * Return the resource identifier of a resource inside of this input 285 * method's .apk that determines whether it should be considered a 286 * default input method for the system. 287 */ 288 public int getIsDefaultResourceId() { 289 return mIsDefaultResId; 290 } 291 292 public void dump(Printer pw, String prefix) { 293 pw.println(prefix + "mId=" + mId 294 + " mSettingsActivityName=" + mSettingsActivityName); 295 pw.println(prefix + "mIsDefaultResId=0x" 296 + Integer.toHexString(mIsDefaultResId)); 297 pw.println(prefix + "Service:"); 298 mService.dump(pw, prefix + " "); 299 } 300 301 @Override 302 public String toString() { 303 return "InputMethodInfo{" + mId 304 + ", settings: " 305 + mSettingsActivityName + "}"; 306 } 307 308 /** 309 * Used to test whether the given parameter object is an 310 * {@link InputMethodInfo} and its Id is the same to this one. 311 * 312 * @return true if the given parameter object is an 313 * {@link InputMethodInfo} and its Id is the same to this one. 314 */ 315 @Override 316 public boolean equals(Object o) { 317 if (o == this) return true; 318 if (o == null) return false; 319 320 if (!(o instanceof InputMethodInfo)) return false; 321 322 InputMethodInfo obj = (InputMethodInfo) o; 323 return mId.equals(obj.mId); 324 } 325 326 @Override 327 public int hashCode() { 328 return mId.hashCode(); 329 } 330 331 /** 332 * Used to package this object into a {@link Parcel}. 333 * 334 * @param dest The {@link Parcel} to be written. 335 * @param flags The flags used for parceling. 336 */ 337 public void writeToParcel(Parcel dest, int flags) { 338 dest.writeString(mId); 339 dest.writeString(mSettingsActivityName); 340 dest.writeInt(mIsDefaultResId); 341 mService.writeToParcel(dest, flags); 342 dest.writeTypedList(mSubtypes); 343 } 344 345 /** 346 * Used to make this class parcelable. 347 */ 348 public static final Parcelable.Creator<InputMethodInfo> CREATOR 349 = new Parcelable.Creator<InputMethodInfo>() { 350 public InputMethodInfo createFromParcel(Parcel source) { 351 return new InputMethodInfo(source); 352 } 353 354 public InputMethodInfo[] newArray(int size) { 355 return new InputMethodInfo[size]; 356 } 357 }; 358 359 public int describeContents() { 360 return 0; 361 } 362} 363