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 17 package android.view.inputmethod; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.TestApi; 22 import android.compat.annotation.UnsupportedAppUsage; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.pm.ActivityInfo; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageManager; 28 import android.content.pm.PackageManager.NameNotFoundException; 29 import android.content.pm.ResolveInfo; 30 import android.content.pm.ServiceInfo; 31 import android.content.res.Configuration; 32 import android.content.res.Resources; 33 import android.content.res.Resources.NotFoundException; 34 import android.content.res.TypedArray; 35 import android.content.res.XmlResourceParser; 36 import android.graphics.drawable.Drawable; 37 import android.inputmethodservice.InputMethodService; 38 import android.os.Parcel; 39 import android.os.Parcelable; 40 import android.util.AttributeSet; 41 import android.util.Printer; 42 import android.util.Slog; 43 import android.util.Xml; 44 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; 45 46 import org.xmlpull.v1.XmlPullParser; 47 import org.xmlpull.v1.XmlPullParserException; 48 49 import java.io.IOException; 50 import java.util.ArrayList; 51 import java.util.List; 52 53 /** 54 * This class is used to specify meta information of an input method. 55 * 56 * <p>It should be defined in an XML resource file with an {@code <input-method>} element. 57 * For more information, see the guide to 58 * <a href="{@docRoot}guide/topics/text/creating-input-method.html"> 59 * Creating an Input Method</a>.</p> 60 * 61 * @see InputMethodSubtype 62 * 63 * @attr ref android.R.styleable#InputMethod_settingsActivity 64 * @attr ref android.R.styleable#InputMethod_isDefault 65 * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod 66 * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions 67 * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestionsWithTouchExploration 68 * @attr ref android.R.styleable#InputMethod_suppressesSpellChecker 69 * @attr ref android.R.styleable#InputMethod_showInInputMethodPicker 70 * @attr ref android.R.styleable#InputMethod_configChanges 71 */ 72 public final class InputMethodInfo implements Parcelable { 73 static final String TAG = "InputMethodInfo"; 74 75 /** 76 * The Service that implements this input method component. 77 */ 78 final ResolveInfo mService; 79 80 /** 81 * IME only supports VR mode. 82 */ 83 final boolean mIsVrOnly; 84 85 /** 86 * The unique string Id to identify the input method. This is generated 87 * from the input method component. 88 */ 89 final String mId; 90 91 /** 92 * The input method setting activity's name, used by the system settings to 93 * launch the setting activity of this input method. 94 */ 95 final String mSettingsActivityName; 96 97 /** 98 * The resource in the input method's .apk that holds a boolean indicating 99 * whether it should be considered the default input method for this 100 * system. This is a resource ID instead of the final value so that it 101 * can change based on the configuration (in particular locale). 102 */ 103 final int mIsDefaultResId; 104 105 /** 106 * An array-like container of the subtypes. 107 */ 108 @UnsupportedAppUsage 109 private final InputMethodSubtypeArray mSubtypes; 110 111 private final boolean mIsAuxIme; 112 113 /** 114 * Caveat: mForceDefault must be false for production. This flag is only for test. 115 */ 116 private final boolean mForceDefault; 117 118 /** 119 * The flag whether this IME supports ways to switch to a next input method (e.g. globe key.) 120 */ 121 private final boolean mSupportsSwitchingToNextInputMethod; 122 123 /** 124 * The flag whether this IME supports inline suggestions. 125 */ 126 private final boolean mInlineSuggestionsEnabled; 127 128 /** 129 * The flag whether this IME supports inline suggestions when touch exploration is enabled. 130 */ 131 private final boolean mSupportsInlineSuggestionsWithTouchExploration; 132 133 /** 134 * The flag whether this IME suppresses spell checker. 135 */ 136 private final boolean mSuppressesSpellChecker; 137 138 /** 139 * The flag whether this IME should be shown as an option in the IME picker. 140 */ 141 private final boolean mShowInInputMethodPicker; 142 143 /** 144 * The flag for configurations IME assumes the responsibility for handling in 145 * {@link InputMethodService#onConfigurationChanged(Configuration)}}. 146 */ 147 private final int mHandledConfigChanges; 148 149 /** 150 * The flag whether this IME supports Handwriting using stylus input. 151 */ 152 private final boolean mSupportsStylusHandwriting; 153 154 155 /** 156 * @param service the {@link ResolveInfo} corresponds in which the IME is implemented. 157 * @return a unique ID to be returned by {@link #getId()}. We have used 158 * {@link ComponentName#flattenToShortString()} for this purpose (and it is already 159 * unrealistic to switch to a different scheme as it is already implicitly assumed in 160 * many places). 161 * @hide 162 */ computeId(@onNull ResolveInfo service)163 public static String computeId(@NonNull ResolveInfo service) { 164 final ServiceInfo si = service.serviceInfo; 165 return new ComponentName(si.packageName, si.name).flattenToShortString(); 166 } 167 168 /** 169 * Constructor. 170 * 171 * @param context The Context in which we are parsing the input method. 172 * @param service The ResolveInfo returned from the package manager about 173 * this input method's component. 174 */ InputMethodInfo(Context context, ResolveInfo service)175 public InputMethodInfo(Context context, ResolveInfo service) 176 throws XmlPullParserException, IOException { 177 this(context, service, null); 178 } 179 180 /** 181 * Constructor. 182 * 183 * @param context The Context in which we are parsing the input method. 184 * @param service The ResolveInfo returned from the package manager about 185 * this input method's component. 186 * @param additionalSubtypes additional subtypes being added to this InputMethodInfo 187 * @hide 188 */ InputMethodInfo(Context context, ResolveInfo service, List<InputMethodSubtype> additionalSubtypes)189 public InputMethodInfo(Context context, ResolveInfo service, 190 List<InputMethodSubtype> additionalSubtypes) 191 throws XmlPullParserException, IOException { 192 mService = service; 193 ServiceInfo si = service.serviceInfo; 194 mId = computeId(service); 195 boolean isAuxIme = true; 196 boolean supportsSwitchingToNextInputMethod = false; // false as default 197 boolean inlineSuggestionsEnabled = false; // false as default 198 boolean supportsInlineSuggestionsWithTouchExploration = false; // false as default 199 boolean suppressesSpellChecker = false; // false as default 200 boolean showInInputMethodPicker = true; // true as default 201 mForceDefault = false; 202 203 PackageManager pm = context.getPackageManager(); 204 String settingsActivityComponent = null; 205 boolean isVrOnly; 206 int isDefaultResId = 0; 207 208 XmlResourceParser parser = null; 209 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>(); 210 try { 211 parser = si.loadXmlMetaData(pm, InputMethod.SERVICE_META_DATA); 212 if (parser == null) { 213 throw new XmlPullParserException("No " 214 + InputMethod.SERVICE_META_DATA + " meta-data"); 215 } 216 217 Resources res = pm.getResourcesForApplication(si.applicationInfo); 218 219 AttributeSet attrs = Xml.asAttributeSet(parser); 220 221 int type; 222 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 223 && type != XmlPullParser.START_TAG) { 224 } 225 226 String nodeName = parser.getName(); 227 if (!"input-method".equals(nodeName)) { 228 throw new XmlPullParserException( 229 "Meta-data does not start with input-method tag"); 230 } 231 232 TypedArray sa = res.obtainAttributes(attrs, 233 com.android.internal.R.styleable.InputMethod); 234 settingsActivityComponent = sa.getString( 235 com.android.internal.R.styleable.InputMethod_settingsActivity); 236 isVrOnly = sa.getBoolean(com.android.internal.R.styleable.InputMethod_isVrOnly, false); 237 isDefaultResId = sa.getResourceId( 238 com.android.internal.R.styleable.InputMethod_isDefault, 0); 239 supportsSwitchingToNextInputMethod = sa.getBoolean( 240 com.android.internal.R.styleable.InputMethod_supportsSwitchingToNextInputMethod, 241 false); 242 inlineSuggestionsEnabled = sa.getBoolean( 243 com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false); 244 supportsInlineSuggestionsWithTouchExploration = sa.getBoolean( 245 com.android.internal.R.styleable 246 .InputMethod_supportsInlineSuggestionsWithTouchExploration, false); 247 suppressesSpellChecker = sa.getBoolean( 248 com.android.internal.R.styleable.InputMethod_suppressesSpellChecker, false); 249 showInInputMethodPicker = sa.getBoolean( 250 com.android.internal.R.styleable.InputMethod_showInInputMethodPicker, true); 251 mHandledConfigChanges = sa.getInt( 252 com.android.internal.R.styleable.InputMethod_configChanges, 0); 253 mSupportsStylusHandwriting = sa.getBoolean( 254 com.android.internal.R.styleable.InputMethod_supportsStylusHandwriting, false); 255 sa.recycle(); 256 257 final int depth = parser.getDepth(); 258 // Parse all subtypes 259 while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) 260 && type != XmlPullParser.END_DOCUMENT) { 261 if (type == XmlPullParser.START_TAG) { 262 nodeName = parser.getName(); 263 if (!"subtype".equals(nodeName)) { 264 throw new XmlPullParserException( 265 "Meta-data in input-method does not start with subtype tag"); 266 } 267 final TypedArray a = res.obtainAttributes( 268 attrs, com.android.internal.R.styleable.InputMethod_Subtype); 269 final InputMethodSubtype subtype = new InputMethodSubtypeBuilder() 270 .setSubtypeNameResId(a.getResourceId(com.android.internal.R.styleable 271 .InputMethod_Subtype_label, 0)) 272 .setSubtypeIconResId(a.getResourceId(com.android.internal.R.styleable 273 .InputMethod_Subtype_icon, 0)) 274 .setLanguageTag(a.getString(com.android.internal.R.styleable 275 .InputMethod_Subtype_languageTag)) 276 .setSubtypeLocale(a.getString(com.android.internal.R.styleable 277 .InputMethod_Subtype_imeSubtypeLocale)) 278 .setSubtypeMode(a.getString(com.android.internal.R.styleable 279 .InputMethod_Subtype_imeSubtypeMode)) 280 .setSubtypeExtraValue(a.getString(com.android.internal.R.styleable 281 .InputMethod_Subtype_imeSubtypeExtraValue)) 282 .setIsAuxiliary(a.getBoolean(com.android.internal.R.styleable 283 .InputMethod_Subtype_isAuxiliary, false)) 284 .setOverridesImplicitlyEnabledSubtype(a.getBoolean( 285 com.android.internal.R.styleable 286 .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false)) 287 .setSubtypeId(a.getInt(com.android.internal.R.styleable 288 .InputMethod_Subtype_subtypeId, 0 /* use Arrays.hashCode */)) 289 .setIsAsciiCapable(a.getBoolean(com.android.internal.R.styleable 290 .InputMethod_Subtype_isAsciiCapable, false)).build(); 291 a.recycle(); 292 if (!subtype.isAuxiliary()) { 293 isAuxIme = false; 294 } 295 subtypes.add(subtype); 296 } 297 } 298 } catch (NameNotFoundException | IndexOutOfBoundsException | NumberFormatException e) { 299 throw new XmlPullParserException( 300 "Unable to create context for: " + si.packageName); 301 } finally { 302 if (parser != null) parser.close(); 303 } 304 305 if (subtypes.size() == 0) { 306 isAuxIme = false; 307 } 308 309 if (additionalSubtypes != null) { 310 final int N = additionalSubtypes.size(); 311 for (int i = 0; i < N; ++i) { 312 final InputMethodSubtype subtype = additionalSubtypes.get(i); 313 if (!subtypes.contains(subtype)) { 314 subtypes.add(subtype); 315 } else { 316 Slog.w(TAG, "Duplicated subtype definition found: " 317 + subtype.getLocale() + ", " + subtype.getMode()); 318 } 319 } 320 } 321 mSubtypes = new InputMethodSubtypeArray(subtypes); 322 mSettingsActivityName = settingsActivityComponent; 323 mIsDefaultResId = isDefaultResId; 324 mIsAuxIme = isAuxIme; 325 mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod; 326 mInlineSuggestionsEnabled = inlineSuggestionsEnabled; 327 mSupportsInlineSuggestionsWithTouchExploration = 328 supportsInlineSuggestionsWithTouchExploration; 329 mSuppressesSpellChecker = suppressesSpellChecker; 330 mShowInInputMethodPicker = showInInputMethodPicker; 331 mIsVrOnly = isVrOnly; 332 } 333 InputMethodInfo(Parcel source)334 InputMethodInfo(Parcel source) { 335 mId = source.readString(); 336 mSettingsActivityName = source.readString(); 337 mIsDefaultResId = source.readInt(); 338 mIsAuxIme = source.readInt() == 1; 339 mSupportsSwitchingToNextInputMethod = source.readInt() == 1; 340 mInlineSuggestionsEnabled = source.readInt() == 1; 341 mSupportsInlineSuggestionsWithTouchExploration = source.readInt() == 1; 342 mSuppressesSpellChecker = source.readBoolean(); 343 mShowInInputMethodPicker = source.readBoolean(); 344 mIsVrOnly = source.readBoolean(); 345 mService = ResolveInfo.CREATOR.createFromParcel(source); 346 mSubtypes = new InputMethodSubtypeArray(source); 347 mHandledConfigChanges = source.readInt(); 348 mSupportsStylusHandwriting = source.readBoolean(); 349 mForceDefault = false; 350 } 351 352 /** 353 * Temporary API for creating a built-in input method for test. 354 */ InputMethodInfo(String packageName, String className, CharSequence label, String settingsActivity)355 public InputMethodInfo(String packageName, String className, 356 CharSequence label, String settingsActivity) { 357 this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */, 358 settingsActivity, null /* subtypes */, 0 /* isDefaultResId */, 359 false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */, 360 false /* inlineSuggestionsEnabled */, false /* isVrOnly */, 361 0 /* handledConfigChanges */, false /* supportsStylusHandwriting */, 362 false /* inlineSuggestionsEnabled */); 363 } 364 365 /** 366 * Temporary API for creating a built-in input method for test. 367 * @hide 368 */ 369 @TestApi InputMethodInfo(@onNull String packageName, @NonNull String className, @NonNull CharSequence label, @NonNull String settingsActivity, int handledConfigChanges)370 public InputMethodInfo(@NonNull String packageName, @NonNull String className, 371 @NonNull CharSequence label, @NonNull String settingsActivity, 372 int handledConfigChanges) { 373 this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */, 374 settingsActivity, null /* subtypes */, 0 /* isDefaultResId */, 375 false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */, 376 false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges, 377 false /* supportsStylusHandwriting */, 378 false /* inlineSuggestionsEnabled */); 379 } 380 381 /** 382 * Temporary API for creating a built-in input method for test. 383 * @hide 384 */ InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault)385 public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, 386 String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId, 387 boolean forceDefault) { 388 this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault, 389 true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */, 390 false /* isVrOnly */, 0 /* handledconfigChanges */, 391 false /* supportsStylusHandwriting */, 392 false /* inlineSuggestionsEnabled */); 393 } 394 395 /** 396 * Temporary API for creating a built-in input method for test. 397 * @hide 398 */ InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault, boolean supportsSwitchingToNextInputMethod, boolean isVrOnly)399 public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity, 400 List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault, 401 boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) { 402 this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault, 403 supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly, 404 0 /* handledConfigChanges */, false /* supportsStylusHandwriting */, 405 false /* inlineSuggestionsEnabled */); 406 } 407 408 /** 409 * Temporary API for creating a built-in input method for test. 410 * @hide 411 */ InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault, boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled, boolean isVrOnly, int handledConfigChanges, boolean supportsStylusHandwriting, boolean supportsInlineSuggestionsWithTouchExploration)412 public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity, 413 List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault, 414 boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled, 415 boolean isVrOnly, int handledConfigChanges, boolean supportsStylusHandwriting, 416 boolean supportsInlineSuggestionsWithTouchExploration) { 417 final ServiceInfo si = ri.serviceInfo; 418 mService = ri; 419 mId = new ComponentName(si.packageName, si.name).flattenToShortString(); 420 mSettingsActivityName = settingsActivity; 421 mIsDefaultResId = isDefaultResId; 422 mIsAuxIme = isAuxIme; 423 mSubtypes = new InputMethodSubtypeArray(subtypes); 424 mForceDefault = forceDefault; 425 mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod; 426 mInlineSuggestionsEnabled = inlineSuggestionsEnabled; 427 mSupportsInlineSuggestionsWithTouchExploration = 428 supportsInlineSuggestionsWithTouchExploration; 429 mSuppressesSpellChecker = false; 430 mShowInInputMethodPicker = true; 431 mIsVrOnly = isVrOnly; 432 mHandledConfigChanges = handledConfigChanges; 433 mSupportsStylusHandwriting = supportsStylusHandwriting; 434 } 435 buildFakeResolveInfo(String packageName, String className, CharSequence label)436 private static ResolveInfo buildFakeResolveInfo(String packageName, String className, 437 CharSequence label) { 438 ResolveInfo ri = new ResolveInfo(); 439 ServiceInfo si = new ServiceInfo(); 440 ApplicationInfo ai = new ApplicationInfo(); 441 ai.packageName = packageName; 442 ai.enabled = true; 443 si.applicationInfo = ai; 444 si.enabled = true; 445 si.packageName = packageName; 446 si.name = className; 447 si.exported = true; 448 si.nonLocalizedLabel = label; 449 ri.serviceInfo = si; 450 return ri; 451 } 452 453 /** 454 * @return a unique ID for this input method, which is guaranteed to be the same as the result 455 * of {@code getComponent().flattenToShortString()}. 456 * @see ComponentName#unflattenFromString(String) 457 */ getId()458 public String getId() { 459 return mId; 460 } 461 462 /** 463 * Return the .apk package that implements this input method. 464 */ getPackageName()465 public String getPackageName() { 466 return mService.serviceInfo.packageName; 467 } 468 469 /** 470 * Return the class name of the service component that implements 471 * this input method. 472 */ getServiceName()473 public String getServiceName() { 474 return mService.serviceInfo.name; 475 } 476 477 /** 478 * Return the raw information about the Service implementing this 479 * input method. Do not modify the returned object. 480 */ getServiceInfo()481 public ServiceInfo getServiceInfo() { 482 return mService.serviceInfo; 483 } 484 485 /** 486 * Return the component of the service that implements this input 487 * method. 488 */ getComponent()489 public ComponentName getComponent() { 490 return new ComponentName(mService.serviceInfo.packageName, 491 mService.serviceInfo.name); 492 } 493 494 /** 495 * Load the user-displayed label for this input method. 496 * 497 * @param pm Supply a PackageManager used to load the input method's 498 * resources. 499 */ loadLabel(PackageManager pm)500 public CharSequence loadLabel(PackageManager pm) { 501 return mService.loadLabel(pm); 502 } 503 504 /** 505 * Load the user-displayed icon for this input method. 506 * 507 * @param pm Supply a PackageManager used to load the input method's 508 * resources. 509 */ loadIcon(PackageManager pm)510 public Drawable loadIcon(PackageManager pm) { 511 return mService.loadIcon(pm); 512 } 513 514 /** 515 * Return the class name of an activity that provides a settings UI for 516 * the input method. You can launch this activity be starting it with 517 * an {@link android.content.Intent} whose action is MAIN and with an 518 * explicit {@link android.content.ComponentName} 519 * composed of {@link #getPackageName} and the class name returned here. 520 * 521 * <p>A null will be returned if there is no settings activity associated 522 * with the input method.</p> 523 */ getSettingsActivity()524 public String getSettingsActivity() { 525 return mSettingsActivityName; 526 } 527 528 /** 529 * Returns true if IME supports VR mode only. 530 * @hide 531 */ isVrOnly()532 public boolean isVrOnly() { 533 return mIsVrOnly; 534 } 535 536 /** 537 * Return the count of the subtypes of Input Method. 538 */ getSubtypeCount()539 public int getSubtypeCount() { 540 return mSubtypes.getCount(); 541 } 542 543 /** 544 * Return the Input Method's subtype at the specified index. 545 * 546 * @param index the index of the subtype to return. 547 */ getSubtypeAt(int index)548 public InputMethodSubtype getSubtypeAt(int index) { 549 return mSubtypes.get(index); 550 } 551 552 /** 553 * Return the resource identifier of a resource inside of this input 554 * method's .apk that determines whether it should be considered a 555 * default input method for the system. 556 */ getIsDefaultResourceId()557 public int getIsDefaultResourceId() { 558 return mIsDefaultResId; 559 } 560 561 /** 562 * Return whether or not this ime is a default ime or not. 563 * @hide 564 */ 565 @UnsupportedAppUsage isDefault(Context context)566 public boolean isDefault(Context context) { 567 if (mForceDefault) { 568 return true; 569 } 570 try { 571 if (getIsDefaultResourceId() == 0) { 572 return false; 573 } 574 final Resources res = context.createPackageContext(getPackageName(), 0).getResources(); 575 return res.getBoolean(getIsDefaultResourceId()); 576 } catch (NameNotFoundException | NotFoundException e) { 577 return false; 578 } 579 } 580 581 /** 582 * Returns the bit mask of kinds of configuration changes that this IME 583 * can handle itself (without being restarted by the system). 584 * 585 * @attr ref android.R.styleable#InputMethod_configChanges 586 */ 587 @ActivityInfo.Config getConfigChanges()588 public int getConfigChanges() { 589 return mHandledConfigChanges; 590 } 591 592 /** 593 * Returns if IME supports handwriting using stylus input. 594 * @attr ref android.R.styleable#InputMethod_supportsStylusHandwriting 595 */ supportsStylusHandwriting()596 public boolean supportsStylusHandwriting() { 597 return mSupportsStylusHandwriting; 598 } 599 dump(Printer pw, String prefix)600 public void dump(Printer pw, String prefix) { 601 pw.println(prefix + "mId=" + mId 602 + " mSettingsActivityName=" + mSettingsActivityName 603 + " mIsVrOnly=" + mIsVrOnly 604 + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod 605 + " mInlineSuggestionsEnabled=" + mInlineSuggestionsEnabled 606 + " mSupportsInlineSuggestionsWithTouchExploration=" 607 + mSupportsInlineSuggestionsWithTouchExploration 608 + " mSuppressesSpellChecker=" + mSuppressesSpellChecker 609 + " mShowInInputMethodPicker=" + mShowInInputMethodPicker 610 + " mSupportsStylusHandwriting=" + mSupportsStylusHandwriting); 611 pw.println(prefix + "mIsDefaultResId=0x" 612 + Integer.toHexString(mIsDefaultResId)); 613 pw.println(prefix + "Service:"); 614 mService.dump(pw, prefix + " "); 615 } 616 617 @Override toString()618 public String toString() { 619 return "InputMethodInfo{" + mId 620 + ", settings: " 621 + mSettingsActivityName + "}"; 622 } 623 624 /** 625 * Used to test whether the given parameter object is an 626 * {@link InputMethodInfo} and its Id is the same to this one. 627 * 628 * @return true if the given parameter object is an 629 * {@link InputMethodInfo} and its Id is the same to this one. 630 */ 631 @Override equals(@ullable Object o)632 public boolean equals(@Nullable Object o) { 633 if (o == this) return true; 634 if (o == null) return false; 635 636 if (!(o instanceof InputMethodInfo)) return false; 637 638 InputMethodInfo obj = (InputMethodInfo) o; 639 return mId.equals(obj.mId); 640 } 641 642 @Override hashCode()643 public int hashCode() { 644 return mId.hashCode(); 645 } 646 647 /** 648 * @hide 649 * @return {@code true} if the IME is a trusted system component (e.g. pre-installed) 650 */ isSystem()651 public boolean isSystem() { 652 return (mService.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 653 } 654 655 /** 656 * @hide 657 */ isAuxiliaryIme()658 public boolean isAuxiliaryIme() { 659 return mIsAuxIme; 660 } 661 662 /** 663 * @return true if this input method supports ways to switch to a next input method. 664 * @hide 665 */ supportsSwitchingToNextInputMethod()666 public boolean supportsSwitchingToNextInputMethod() { 667 return mSupportsSwitchingToNextInputMethod; 668 } 669 670 /** 671 * @return true if this input method supports inline suggestions. 672 * @hide 673 */ isInlineSuggestionsEnabled()674 public boolean isInlineSuggestionsEnabled() { 675 return mInlineSuggestionsEnabled; 676 } 677 678 /** 679 * Returns {@code true} if this input method supports inline suggestions when touch exploration 680 * is enabled. 681 * @hide 682 */ supportsInlineSuggestionsWithTouchExploration()683 public boolean supportsInlineSuggestionsWithTouchExploration() { 684 return mSupportsInlineSuggestionsWithTouchExploration; 685 } 686 687 /** 688 * Return {@code true} if this input method suppresses spell checker. 689 */ suppressesSpellChecker()690 public boolean suppressesSpellChecker() { 691 return mSuppressesSpellChecker; 692 } 693 694 /** 695 * Returns {@code true} if this input method should be shown in menus for selecting an Input 696 * Method, such as the system Input Method Picker. This is {@code false} if the IME is intended 697 * to be accessed programmatically. 698 */ shouldShowInInputMethodPicker()699 public boolean shouldShowInInputMethodPicker() { 700 return mShowInInputMethodPicker; 701 } 702 703 /** 704 * Used to package this object into a {@link Parcel}. 705 * 706 * @param dest The {@link Parcel} to be written. 707 * @param flags The flags used for parceling. 708 */ 709 @Override writeToParcel(Parcel dest, int flags)710 public void writeToParcel(Parcel dest, int flags) { 711 dest.writeString(mId); 712 dest.writeString(mSettingsActivityName); 713 dest.writeInt(mIsDefaultResId); 714 dest.writeInt(mIsAuxIme ? 1 : 0); 715 dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0); 716 dest.writeInt(mInlineSuggestionsEnabled ? 1 : 0); 717 dest.writeInt(mSupportsInlineSuggestionsWithTouchExploration ? 1 : 0); 718 dest.writeBoolean(mSuppressesSpellChecker); 719 dest.writeBoolean(mShowInInputMethodPicker); 720 dest.writeBoolean(mIsVrOnly); 721 mService.writeToParcel(dest, flags); 722 mSubtypes.writeToParcel(dest); 723 dest.writeInt(mHandledConfigChanges); 724 dest.writeBoolean(mSupportsStylusHandwriting); 725 } 726 727 /** 728 * Used to make this class parcelable. 729 */ 730 public static final @android.annotation.NonNull Parcelable.Creator<InputMethodInfo> CREATOR 731 = new Parcelable.Creator<InputMethodInfo>() { 732 @Override 733 public InputMethodInfo createFromParcel(Parcel source) { 734 return new InputMethodInfo(source); 735 } 736 737 @Override 738 public InputMethodInfo[] newArray(int size) { 739 return new InputMethodInfo[size]; 740 } 741 }; 742 743 @Override describeContents()744 public int describeContents() { 745 return 0; 746 } 747 } 748