• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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