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 static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
20 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
21 
22 import android.annotation.DrawableRes;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.RequiresFeature;
26 import android.annotation.RequiresPermission;
27 import android.annotation.SystemService;
28 import android.annotation.TestApi;
29 import android.annotation.UserIdInt;
30 import android.app.ActivityThread;
31 import android.compat.annotation.UnsupportedAppUsage;
32 import android.content.ComponentName;
33 import android.content.ContentResolver;
34 import android.content.Context;
35 import android.content.pm.PackageManager;
36 import android.graphics.Matrix;
37 import android.graphics.Rect;
38 import android.inputmethodservice.InputMethodService;
39 import android.os.Binder;
40 import android.os.Build;
41 import android.os.Bundle;
42 import android.os.Handler;
43 import android.os.IBinder;
44 import android.os.Looper;
45 import android.os.Message;
46 import android.os.Process;
47 import android.os.RemoteException;
48 import android.os.ResultReceiver;
49 import android.os.ServiceManager;
50 import android.os.ServiceManager.ServiceNotFoundException;
51 import android.os.Trace;
52 import android.os.UserHandle;
53 import android.provider.Settings;
54 import android.text.style.SuggestionSpan;
55 import android.util.Log;
56 import android.util.Pools.Pool;
57 import android.util.Pools.SimplePool;
58 import android.util.PrintWriterPrinter;
59 import android.util.Printer;
60 import android.util.SparseArray;
61 import android.view.Display;
62 import android.view.ImeInsetsSourceConsumer;
63 import android.view.InputChannel;
64 import android.view.InputEvent;
65 import android.view.InputEventSender;
66 import android.view.KeyEvent;
67 import android.view.View;
68 import android.view.ViewRootImpl;
69 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
70 import android.view.autofill.AutofillManager;
71 
72 import com.android.internal.annotations.GuardedBy;
73 import com.android.internal.inputmethod.InputMethodDebug;
74 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
75 import com.android.internal.inputmethod.StartInputFlags;
76 import com.android.internal.inputmethod.StartInputReason;
77 import com.android.internal.inputmethod.UnbindReason;
78 import com.android.internal.os.SomeArgs;
79 import com.android.internal.view.IInputConnectionWrapper;
80 import com.android.internal.view.IInputContext;
81 import com.android.internal.view.IInputMethodClient;
82 import com.android.internal.view.IInputMethodManager;
83 import com.android.internal.view.IInputMethodSession;
84 import com.android.internal.view.InputBindResult;
85 
86 import java.io.FileDescriptor;
87 import java.io.PrintWriter;
88 import java.lang.reflect.Proxy;
89 import java.util.Arrays;
90 import java.util.Collections;
91 import java.util.Comparator;
92 import java.util.List;
93 import java.util.Map;
94 import java.util.Objects;
95 import java.util.concurrent.CountDownLatch;
96 import java.util.concurrent.TimeUnit;
97 
98 /**
99  * Central system API to the overall input method framework (IMF) architecture,
100  * which arbitrates interaction between applications and the current input method.
101  *
102  * <p>Topics covered here:
103  * <ol>
104  * <li><a href="#ArchitectureOverview">Architecture Overview</a>
105  * <li><a href="#Applications">Applications</a>
106  * <li><a href="#InputMethods">Input Methods</a>
107  * <li><a href="#Security">Security</a>
108  * </ol>
109  *
110  * <a name="ArchitectureOverview"></a>
111  * <h3>Architecture Overview</h3>
112  *
113  * <p>There are three primary parties involved in the input method
114  * framework (IMF) architecture:</p>
115  *
116  * <ul>
117  * <li> The <strong>input method manager</strong> as expressed by this class
118  * is the central point of the system that manages interaction between all
119  * other parts.  It is expressed as the client-side API here which exists
120  * in each application context and communicates with a global system service
121  * that manages the interaction across all processes.
122  * <li> An <strong>input method (IME)</strong> implements a particular
123  * interaction model allowing the user to generate text.  The system binds
124  * to the current input method that is in use, causing it to be created and run,
125  * and tells it when to hide and show its UI.  Only one IME is running at a time.
126  * <li> Multiple <strong>client applications</strong> arbitrate with the input
127  * method manager for input focus and control over the state of the IME.  Only
128  * one such client is ever active (working with the IME) at a time.
129  * </ul>
130  *
131  *
132  * <a name="Applications"></a>
133  * <h3>Applications</h3>
134  *
135  * <p>In most cases, applications that are using the standard
136  * {@link android.widget.TextView} or its subclasses will have little they need
137  * to do to work well with soft input methods.  The main things you need to
138  * be aware of are:</p>
139  *
140  * <ul>
141  * <li> Properly set the {@link android.R.attr#inputType} in your editable
142  * text views, so that the input method will have enough context to help the
143  * user in entering text into them.
144  * <li> Deal well with losing screen space when the input method is
145  * displayed.  Ideally an application should handle its window being resized
146  * smaller, but it can rely on the system performing panning of the window
147  * if needed.  You should set the {@link android.R.attr#windowSoftInputMode}
148  * attribute on your activity or the corresponding values on windows you
149  * create to help the system determine whether to pan or resize (it will
150  * try to determine this automatically but may get it wrong).
151  * <li> You can also control the preferred soft input state (open, closed, etc)
152  * for your window using the same {@link android.R.attr#windowSoftInputMode}
153  * attribute.
154  * </ul>
155  *
156  * <p>More finer-grained control is available through the APIs here to directly
157  * interact with the IMF and its IME -- either showing or hiding the input
158  * area, letting the user pick an input method, etc.</p>
159  *
160  * <p>For the rare people amongst us writing their own text editors, you
161  * will need to implement {@link android.view.View#onCreateInputConnection}
162  * to return a new instance of your own {@link InputConnection} interface
163  * allowing the IME to interact with your editor.</p>
164  *
165  *
166  * <a name="InputMethods"></a>
167  * <h3>Input Methods</h3>
168  *
169  * <p>An input method (IME) is implemented
170  * as a {@link android.app.Service}, typically deriving from
171  * {@link android.inputmethodservice.InputMethodService}.  It must provide
172  * the core {@link InputMethod} interface, though this is normally handled by
173  * {@link android.inputmethodservice.InputMethodService} and implementors will
174  * only need to deal with the higher-level API there.</p>
175  *
176  * See the {@link android.inputmethodservice.InputMethodService} class for
177  * more information on implementing IMEs.
178  *
179  *
180  * <a name="Security"></a>
181  * <h3>Security</h3>
182  *
183  * <p>There are a lot of security issues associated with input methods,
184  * since they essentially have freedom to completely drive the UI and monitor
185  * everything the user enters.  The Android input method framework also allows
186  * arbitrary third party IMEs, so care must be taken to restrict their
187  * selection and interactions.</p>
188  *
189  * <p>Here are some key points about the security architecture behind the
190  * IMF:</p>
191  *
192  * <ul>
193  * <li> <p>Only the system is allowed to directly access an IME's
194  * {@link InputMethod} interface, via the
195  * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission.  This is
196  * enforced in the system by not binding to an input method service that does
197  * not require this permission, so the system can guarantee no other untrusted
198  * clients are accessing the current input method outside of its control.</p>
199  *
200  * <li> <p>There may be many client processes of the IMF, but only one may
201  * be active at a time.  The inactive clients can not interact with key
202  * parts of the IMF through the mechanisms described below.</p>
203  *
204  * <li> <p>Clients of an input method are only given access to its
205  * {@link InputMethodSession} interface.  One instance of this interface is
206  * created for each client, and only calls from the session associated with
207  * the active client will be processed by the current IME.  This is enforced
208  * by {@link android.inputmethodservice.AbstractInputMethodService} for normal
209  * IMEs, but must be explicitly handled by an IME that is customizing the
210  * raw {@link InputMethodSession} implementation.</p>
211  *
212  * <li> <p>Only the active client's {@link InputConnection} will accept
213  * operations.  The IMF tells each client process whether it is active, and
214  * the framework enforces that in inactive processes calls on to the current
215  * InputConnection will be ignored.  This ensures that the current IME can
216  * only deliver events and text edits to the UI that the user sees as
217  * being in focus.</p>
218  *
219  * <li> <p>An IME can never interact with an {@link InputConnection} while
220  * the screen is off.  This is enforced by making all clients inactive while
221  * the screen is off, and prevents bad IMEs from driving the UI when the user
222  * can not be aware of its behavior.</p>
223  *
224  * <li> <p>A client application can ask that the system let the user pick a
225  * new IME, but can not programmatically switch to one itself.  This avoids
226  * malicious applications from switching the user to their own IME, which
227  * remains running when the user navigates away to another application.  An
228  * IME, on the other hand, <em>is</em> allowed to programmatically switch
229  * the system to another IME, since it already has full control of user
230  * input.</p>
231  *
232  * <li> <p>The user must explicitly enable a new IME in settings before
233  * they can switch to it, to confirm with the system that they know about it
234  * and want to make it available for use.</p>
235  * </ul>
236  */
237 @SystemService(Context.INPUT_METHOD_SERVICE)
238 @RequiresFeature(PackageManager.FEATURE_INPUT_METHODS)
239 public final class InputMethodManager {
240     static final boolean DEBUG = false;
241     static final String TAG = "InputMethodManager";
242 
243     static final String PENDING_EVENT_COUNTER = "aq:imm";
244 
245     private static final int NOT_A_SUBTYPE_ID = -1;
246 
247     /**
248      * A constant that represents Voice IME.
249      *
250      * @see InputMethodSubtype#getMode()
251      */
252     private static final String SUBTYPE_MODE_VOICE = "voice";
253 
254     /**
255      * Ensures that {@link #sInstance} becomes non-{@code null} for application that have directly
256      * or indirectly relied on {@link #sInstance} via reflection or something like that.
257      *
258      * <p>Here are scenarios we know and there could be more scenarios we are not
259      * aware of right know.</p>
260      *
261      * <ul>
262      *     <li>Apps that directly access {@link #sInstance} via reflection, which is currently
263      *     allowed because of {@link UnsupportedAppUsage} annotation.  Currently
264      *     {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that
265      *     {@link #sInstance} is not {@code null} when such an app is accessing it, but removing
266      *     that code from {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal
267      *     untested code paths in their apps, which probably happen in an early startup time of that
268      *     app.</li>
269      *     <li>Apps that directly access {@link #peekInstance()} via reflection, which is currently
270      *     allowed because of {@link UnsupportedAppUsage} annotation.  Currently
271      *     {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that
272      *     {@link #peekInstance()} returns non-{@code null} object when such an app is calling
273      *     {@link #peekInstance()}, but removing that code from
274      *     {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal untested code
275      *     paths in their apps, which probably happen in an early startup time of that app. The good
276      *     news is that unlike {@link #sInstance}'s case we can at least work around this scenario
277      *     by changing the semantics of {@link #peekInstance()}, which is currently defined as
278      *     "retrieve the global {@link InputMethodManager} instance, if it exists" to something that
279      *     always returns non-{@code null} {@link InputMethodManager}.  However, introducing such an
280      *     workaround can also trigger different compatibility issues if {@link #peekInstance()} was
281      *     called before {@link android.view.WindowManagerGlobal#getWindowSession()} and it expected
282      *     {@link #peekInstance()} to return {@code null} as written in the JavaDoc.</li>
283      * </ul>
284      *
285      * <p>Since this is purely a compatibility hack, this method must be used only from
286      * {@link android.view.WindowManagerGlobal#getWindowSession()} and {@link #getInstance()}.</p>
287      *
288      * <p>TODO(Bug 116157766): Remove this method once we clean up {@link UnsupportedAppUsage}.</p>
289      * @hide
290      */
ensureDefaultInstanceForDefaultDisplayIfNecessary()291     public static void ensureDefaultInstanceForDefaultDisplayIfNecessary() {
292         forContextInternal(Display.DEFAULT_DISPLAY, Looper.getMainLooper());
293     }
294 
295     private static final Object sLock = new Object();
296 
297     /**
298      * @deprecated This cannot be compatible with multi-display. Please do not use this.
299      */
300     @Deprecated
301     @GuardedBy("sLock")
302     @UnsupportedAppUsage
303     static InputMethodManager sInstance;
304 
305     /**
306      * Global map between display to {@link InputMethodManager}.
307      *
308      * <p>Currently this map works like a so-called leaky singleton.  Once an instance is registered
309      * for the associated display ID, that instance will never be garbage collected.</p>
310      *
311      * <p>TODO(Bug 116699479): Implement instance clean up mechanism.</p>
312      */
313     @GuardedBy("sLock")
314     private static final SparseArray<InputMethodManager> sInstanceMap = new SparseArray<>();
315 
316     /**
317      * Timeout in milliseconds for delivering a key to an IME.
318      */
319     static final long INPUT_METHOD_NOT_RESPONDING_TIMEOUT = 2500;
320 
321     /** @hide */
322     public static final int DISPATCH_IN_PROGRESS = -1;
323 
324     /** @hide */
325     public static final int DISPATCH_NOT_HANDLED = 0;
326 
327     /** @hide */
328     public static final int DISPATCH_HANDLED = 1;
329 
330     /** @hide */
331     public static final int SHOW_IM_PICKER_MODE_AUTO = 0;
332     /** @hide */
333     public static final int SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES = 1;
334     /** @hide */
335     public static final int SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES = 2;
336 
337     @UnsupportedAppUsage
338     final IInputMethodManager mService;
339     final Looper mMainLooper;
340 
341     // For scheduling work on the main thread.  This also serves as our
342     // global lock.
343     // Remark on @UnsupportedAppUsage: there were context leaks on old versions
344     // of android (b/37043700), so developers used this field to perform manual clean up.
345     // Leaks were fixed, hacks were backported to AppCompatActivity,
346     // so an access to the field is closed.
347     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
348     final H mH;
349 
350     // Our generic input connection if the current target does not have its own.
351     final IInputContext mIInputContext;
352 
353     private final int mDisplayId;
354 
355     /**
356      * True if this input method client is active, initially false.
357      */
358     boolean mActive = false;
359 
360     /**
361      * {@code true} if next {@link #onPostWindowFocus(View, View, int, boolean, int)} needs to
362      * restart input.
363      */
364     boolean mRestartOnNextWindowFocus = true;
365 
366     /**
367      * As reported by IME through InputConnection.
368      */
369     boolean mFullscreenMode;
370 
371     // -----------------------------------------------------------
372 
373     /**
374      * This is the root view of the overall window that currently has input
375      * method focus.
376      */
377     @UnsupportedAppUsage
378     View mCurRootView;
379     /**
380      * This is the view that should currently be served by an input method,
381      * regardless of the state of setting that up.
382      */
383     // See comment to mH field in regard to @UnsupportedAppUsage
384     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
385     View mServedView;
386     /**
387      * This is then next view that will be served by the input method, when
388      * we get around to updating things.
389      */
390     // See comment to mH field in regard to @UnsupportedAppUsage
391     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
392     View mNextServedView;
393     /**
394      * This is set when we are in the process of connecting, to determine
395      * when we have actually finished.
396      */
397     boolean mServedConnecting;
398     /**
399      * This is non-null when we have connected the served view; it holds
400      * the attributes that were last retrieved from the served view and given
401      * to the input connection.
402      */
403     EditorInfo mCurrentTextBoxAttribute;
404     /**
405      * The InputConnection that was last retrieved from the served view.
406      */
407     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
408     ControlledInputConnectionWrapper mServedInputConnectionWrapper;
409     /**
410      * The completions that were last provided by the served view.
411      */
412     CompletionInfo[] mCompletions;
413 
414     // Cursor position on the screen.
415     @UnsupportedAppUsage
416     Rect mTmpCursorRect = new Rect();
417     @UnsupportedAppUsage
418     Rect mCursorRect = new Rect();
419     int mCursorSelStart;
420     int mCursorSelEnd;
421     int mCursorCandStart;
422     int mCursorCandEnd;
423 
424     /**
425      * The instance that has previously been sent to the input method.
426      */
427     private CursorAnchorInfo mCursorAnchorInfo = null;
428 
429     /**
430      * A special {@link Matrix} that can be provided by the system when this instance is running
431      * inside a virtual display that is managed by {@link android.app.ActivityView}.
432      *
433      * <p>If this is non-{@code null}, {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}
434      * should be adjusted with this {@link Matrix}.</p>
435      *
436      * <p>{@code null} when not used.</p>
437      */
438     private Matrix mActivityViewToScreenMatrix = null;
439 
440     // -----------------------------------------------------------
441 
442     /**
443      * Sequence number of this binding, as returned by the server.
444      */
445     int mBindSequence = -1;
446     /**
447      * ID of the method we are bound to.
448      */
449     @UnsupportedAppUsage
450     String mCurId;
451     /**
452      * The actual instance of the method to make calls on it.
453      */
454     @UnsupportedAppUsage
455     IInputMethodSession mCurMethod;
456     InputChannel mCurChannel;
457     ImeInputEventSender mCurSender;
458 
459     private static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE = 0x0;
460 
461     /**
462      * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
463      */
464     private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
465 
466     /**
467      * When {@link ViewRootImpl#sNewInsetsMode} is set to
468      * >= {@link ViewRootImpl#NEW_INSETS_MODE_IME}, {@link ImeInsetsSourceConsumer} applies the
469      * IME visibility and listens for other state changes.
470      */
471     private ImeInsetsSourceConsumer mImeInsetsConsumer;
472 
473     final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
474     final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
475 
476     // -----------------------------------------------------------
477 
478     static final int MSG_DUMP = 1;
479     static final int MSG_BIND = 2;
480     static final int MSG_UNBIND = 3;
481     static final int MSG_SET_ACTIVE = 4;
482     static final int MSG_SEND_INPUT_EVENT = 5;
483     static final int MSG_TIMEOUT_INPUT_EVENT = 6;
484     static final int MSG_FLUSH_INPUT_EVENT = 7;
485     static final int MSG_REPORT_FULLSCREEN_MODE = 10;
486     static final int MSG_REPORT_PRE_RENDERED = 15;
487     static final int MSG_APPLY_IME_VISIBILITY = 20;
488     static final int MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX = 30;
489 
isAutofillUIShowing(View servedView)490     private static boolean isAutofillUIShowing(View servedView) {
491         AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
492         return afm != null && afm.isAutofillUiShowing();
493     }
494 
495     /**
496      * Returns fallback {@link InputMethodManager} if the called one is not likely to be compatible
497      * with the given {@code view}.
498      *
499      * @param view {@link View} to be checked.
500      * @return {@code null} when it is unnecessary (or impossible) to use fallback
501      *         {@link InputMethodManager} to which IME API calls need to be re-dispatched.
502      *          Non-{@code null} {@link InputMethodManager} if this method believes it'd be safer to
503      *          re-dispatch IME APIs calls on it.
504      */
505     @Nullable
getFallbackInputMethodManagerIfNecessary(@ullable View view)506     private InputMethodManager getFallbackInputMethodManagerIfNecessary(@Nullable View view) {
507         if (view == null) {
508             return null;
509         }
510         // As evidenced in Bug 118341760, view.getViewRootImpl().getDisplayId() is supposed to be
511         // more reliable to determine with which display the given view is interacting than
512         // view.getContext().getDisplayId() / view.getContext().getSystemService(), which can be
513         // easily messed up by app developers (or library authors) by creating inconsistent
514         // ContextWrapper objects that re-dispatch those methods to other Context such as
515         // ApplicationContext.
516         final ViewRootImpl viewRootImpl = view.getViewRootImpl();
517         if (viewRootImpl == null) {
518             return null;
519         }
520         final int viewRootDisplayId = viewRootImpl.getDisplayId();
521         if (viewRootDisplayId == mDisplayId) {
522             // Expected case.  Good to go.
523             return null;
524         }
525         final InputMethodManager fallbackImm =
526                 viewRootImpl.mContext.getSystemService(InputMethodManager.class);
527         if (fallbackImm == null) {
528             Log.e(TAG, "b/117267690: Failed to get non-null fallback IMM. view=" + view);
529             return null;
530         }
531         if (fallbackImm.mDisplayId != viewRootDisplayId) {
532             Log.e(TAG, "b/117267690: Failed to get fallback IMM with expected displayId="
533                     + viewRootDisplayId + " actual IMM#displayId=" + fallbackImm.mDisplayId
534                     + " view=" + view);
535             return null;
536         }
537         Log.w(TAG, "b/117267690: Display ID mismatch found."
538                 + " ViewRootImpl displayId=" + viewRootDisplayId
539                 + " InputMethodManager displayId=" + mDisplayId
540                 + ". Use the right InputMethodManager instance to avoid performance overhead.",
541                 new Throwable());
542         return fallbackImm;
543     }
544 
canStartInput(View servedView)545     private static boolean canStartInput(View servedView) {
546         // We can start input ether the servedView has window focus
547         // or the activity is showing autofill ui.
548         return servedView.hasWindowFocus() || isAutofillUIShowing(servedView);
549     }
550 
551     class H extends Handler {
H(Looper looper)552         H(Looper looper) {
553             super(looper, null, true);
554         }
555 
556         @Override
handleMessage(Message msg)557         public void handleMessage(Message msg) {
558             switch (msg.what) {
559                 case MSG_DUMP: {
560                     SomeArgs args = (SomeArgs)msg.obj;
561                     try {
562                         doDump((FileDescriptor)args.arg1,
563                                 (PrintWriter)args.arg2, (String[])args.arg3);
564                     } catch (RuntimeException e) {
565                         ((PrintWriter)args.arg2).println("Exception: " + e);
566                     }
567                     synchronized (args.arg4) {
568                         ((CountDownLatch)args.arg4).countDown();
569                     }
570                     args.recycle();
571                     return;
572                 }
573                 case MSG_BIND: {
574                     final InputBindResult res = (InputBindResult)msg.obj;
575                     if (DEBUG) {
576                         Log.i(TAG, "handleMessage: MSG_BIND " + res.sequence + "," + res.id);
577                     }
578                     synchronized (mH) {
579                         if (mBindSequence < 0 || mBindSequence != res.sequence) {
580                             Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
581                                     + ", given seq=" + res.sequence);
582                             if (res.channel != null && res.channel != mCurChannel) {
583                                 res.channel.dispose();
584                             }
585                             return;
586                         }
587 
588                         mRequestUpdateCursorAnchorInfoMonitorMode =
589                                 REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
590 
591                         setInputChannelLocked(res.channel);
592                         mCurMethod = res.method;
593                         mCurId = res.id;
594                         mBindSequence = res.sequence;
595                         mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
596                     }
597                     startInputInner(StartInputReason.BOUND_TO_IMMS, null, 0, 0, 0);
598                     return;
599                 }
600                 case MSG_UNBIND: {
601                     final int sequence = msg.arg1;
602                     @UnbindReason
603                     final int reason = msg.arg2;
604                     if (DEBUG) {
605                         Log.i(TAG, "handleMessage: MSG_UNBIND " + sequence +
606                                 " reason=" + InputMethodDebug.unbindReasonToString(reason));
607                     }
608                     final boolean startInput;
609                     synchronized (mH) {
610                         if (mBindSequence != sequence) {
611                             return;
612                         }
613                         clearBindingLocked();
614                         // If we were actively using the last input method, then
615                         // we would like to re-connect to the next input method.
616                         if (mServedView != null && mServedView.isFocused()) {
617                             mServedConnecting = true;
618                         }
619                         startInput = mActive;
620                     }
621                     if (startInput) {
622                         startInputInner(
623                                 StartInputReason.UNBOUND_FROM_IMMS, null, 0, 0, 0);
624                     }
625                     return;
626                 }
627                 case MSG_SET_ACTIVE: {
628                     final boolean active = msg.arg1 != 0;
629                     final boolean fullscreen = msg.arg2 != 0;
630                     if (DEBUG) {
631                         Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
632                     }
633                     synchronized (mH) {
634                         mActive = active;
635                         mFullscreenMode = fullscreen;
636                         if (!active) {
637                             // Some other client has starting using the IME, so note
638                             // that this happened and make sure our own editor's
639                             // state is reset.
640                             mRestartOnNextWindowFocus = true;
641                             try {
642                                 // Note that finishComposingText() is allowed to run
643                                 // even when we are not active.
644                                 mIInputContext.finishComposingText();
645                             } catch (RemoteException e) {
646                             }
647                         }
648                         // Check focus again in case that "onWindowFocus" is called before
649                         // handling this message.
650                         if (mServedView != null && canStartInput(mServedView)) {
651                             if (checkFocusNoStartInput(mRestartOnNextWindowFocus)) {
652                                 final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS
653                                         : StartInputReason.DEACTIVATED_BY_IMMS;
654                                 startInputInner(reason, null, 0, 0, 0);
655                             }
656                         }
657                     }
658                     return;
659                 }
660                 case MSG_SEND_INPUT_EVENT: {
661                     sendInputEventAndReportResultOnMainLooper((PendingEvent)msg.obj);
662                     return;
663                 }
664                 case MSG_TIMEOUT_INPUT_EVENT: {
665                     finishedInputEvent(msg.arg1, false, true);
666                     return;
667                 }
668                 case MSG_FLUSH_INPUT_EVENT: {
669                     finishedInputEvent(msg.arg1, false, false);
670                     return;
671                 }
672                 case MSG_REPORT_FULLSCREEN_MODE: {
673                     final boolean fullscreen = msg.arg1 != 0;
674                     InputConnection ic = null;
675                     synchronized (mH) {
676                         mFullscreenMode = fullscreen;
677                         if (mServedInputConnectionWrapper != null) {
678                             ic = mServedInputConnectionWrapper.getInputConnection();
679                         }
680                     }
681                     if (ic != null) {
682                         ic.reportFullscreenMode(fullscreen);
683                     }
684                     return;
685                 }
686                 case MSG_REPORT_PRE_RENDERED: {
687                     synchronized (mH) {
688                         if (mImeInsetsConsumer != null) {
689                             mImeInsetsConsumer.onPreRendered((EditorInfo) msg.obj);
690                         }
691                     }
692                     return;
693 
694                 }
695                 case MSG_APPLY_IME_VISIBILITY: {
696                     synchronized (mH) {
697                         if (mImeInsetsConsumer != null) {
698                             mImeInsetsConsumer.applyImeVisibility(msg.arg1 != 0);
699                         }
700                     }
701                     return;
702                 }
703                 case MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX: {
704                     final float[] matrixValues = (float[]) msg.obj;
705                     final int bindSequence = msg.arg1;
706                     synchronized (mH) {
707                         if (mBindSequence != bindSequence) {
708                             return;
709                         }
710                         if (matrixValues == null || mActivityViewToScreenMatrix == null) {
711                             // Either InputBoundResult#mActivityViewToScreenMatrixValues is null
712                             // OR this app is unbound from the parent ActivityView. In this case,
713                             // calling updateCursorAnchorInfo() isn't safe. Only clear the matrix.
714                             mActivityViewToScreenMatrix = null;
715                             return;
716                         }
717 
718                         final float[] currentValues = new float[9];
719                         mActivityViewToScreenMatrix.getValues(currentValues);
720                         if (Arrays.equals(currentValues, matrixValues)) {
721                             return;
722                         }
723                         mActivityViewToScreenMatrix.setValues(matrixValues);
724 
725                         if (mCursorAnchorInfo == null || mCurMethod == null
726                                 || mServedInputConnectionWrapper == null) {
727                             return;
728                         }
729                         final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode
730                                 & InputConnection.CURSOR_UPDATE_MONITOR) != 0;
731                         if (!isMonitoring) {
732                             return;
733                         }
734                         // Since the host ActivityView is moved, we need to issue
735                         // IMS#updateCursorAnchorInfo() again.
736                         try {
737                             mCurMethod.updateCursorAnchorInfo(
738                                     CursorAnchorInfo.createForAdditionalParentMatrix(
739                                             mCursorAnchorInfo, mActivityViewToScreenMatrix));
740                         } catch (RemoteException e) {
741                             Log.w(TAG, "IME died: " + mCurId, e);
742                         }
743                     }
744                     return;
745                 }
746             }
747         }
748     }
749 
750     private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
751         private final InputMethodManager mParentInputMethodManager;
752 
ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn, final InputMethodManager inputMethodManager)753         public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
754                 final InputMethodManager inputMethodManager) {
755             super(mainLooper, conn);
756             mParentInputMethodManager = inputMethodManager;
757         }
758 
759         @Override
isActive()760         public boolean isActive() {
761             return mParentInputMethodManager.mActive && !isFinished();
762         }
763 
deactivate()764         void deactivate() {
765             if (isFinished()) {
766                 // This is a small performance optimization.  Still only the 1st call of
767                 // reportFinish() will take effect.
768                 return;
769             }
770             closeConnection();
771         }
772 
773         @Override
toString()774         public String toString() {
775             return "ControlledInputConnectionWrapper{"
776                     + "connection=" + getInputConnection()
777                     + " finished=" + isFinished()
778                     + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
779                     + "}";
780         }
781     }
782 
783     final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
784         @Override
785         protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
786             // No need to check for dump permission, since we only give this
787             // interface to the system.
788             CountDownLatch latch = new CountDownLatch(1);
789             SomeArgs sargs = SomeArgs.obtain();
790             sargs.arg1 = fd;
791             sargs.arg2 = fout;
792             sargs.arg3 = args;
793             sargs.arg4 = latch;
794             mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs));
795             try {
796                 if (!latch.await(5, TimeUnit.SECONDS)) {
797                     fout.println("Timeout waiting for dump");
798                 }
799             } catch (InterruptedException e) {
800                 fout.println("Interrupted waiting for dump");
801             }
802         }
803 
804         @Override
805         public void onBindMethod(InputBindResult res) {
806             mH.obtainMessage(MSG_BIND, res).sendToTarget();
807         }
808 
809         @Override
810         public void onUnbindMethod(int sequence, @UnbindReason int unbindReason) {
811             mH.obtainMessage(MSG_UNBIND, sequence, unbindReason).sendToTarget();
812         }
813 
814         @Override
815         public void setActive(boolean active, boolean fullscreen) {
816             mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0).sendToTarget();
817         }
818 
819         @Override
820         public void reportFullscreenMode(boolean fullscreen) {
821             mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0)
822                     .sendToTarget();
823         }
824 
825         @Override
826         public void reportPreRendered(EditorInfo info) {
827             mH.obtainMessage(MSG_REPORT_PRE_RENDERED, 0, 0, info)
828                     .sendToTarget();
829         }
830 
831         @Override
832         public void applyImeVisibility(boolean setVisible) {
833             mH.obtainMessage(MSG_APPLY_IME_VISIBILITY, setVisible ? 1 : 0, 0)
834                     .sendToTarget();
835         }
836 
837         @Override
838         public void updateActivityViewToScreenMatrix(int bindSequence, float[] matrixValues) {
839             mH.obtainMessage(MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX, bindSequence, 0,
840                     matrixValues).sendToTarget();
841         }
842     };
843 
844     final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
845 
846     /**
847      * For layoutlib to clean up static objects inside {@link InputMethodManager}.
848      */
tearDownEditMode()849     static void tearDownEditMode() {
850         if (!isInEditMode()) {
851             throw new UnsupportedOperationException(
852                     "This method must be called only from layoutlib");
853         }
854         synchronized (sLock) {
855             sInstance = null;
856         }
857     }
858 
859     /**
860      * For layoutlib to override this method to return {@code true}.
861      *
862      * @return {@code true} if the process is running for developer tools
863      * @see View#isInEditMode()
864      */
isInEditMode()865     private static boolean isInEditMode() {
866         return false;
867     }
868 
869     @NonNull
createInstance(int displayId, Looper looper)870     private static InputMethodManager createInstance(int displayId, Looper looper) {
871         return isInEditMode() ? createStubInstance(displayId, looper)
872                 : createRealInstance(displayId, looper);
873     }
874 
875     @NonNull
createRealInstance(int displayId, Looper looper)876     private static InputMethodManager createRealInstance(int displayId, Looper looper) {
877         final IInputMethodManager service;
878         try {
879             service = IInputMethodManager.Stub.asInterface(
880                     ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
881         } catch (ServiceNotFoundException e) {
882             throw new IllegalStateException(e);
883         }
884         final InputMethodManager imm = new InputMethodManager(service, displayId, looper);
885         // InputMethodManagerService#addClient() relies on Binder.getCalling{Pid, Uid}() to
886         // associate PID/UID with each IME client. This means:
887         //  A. if this method call will be handled as an IPC, there is no problem.
888         //  B. if this method call will be handled as an in-proc method call, we need to
889         //     ensure that Binder.getCalling{Pid, Uid}() return Process.my{Pid, Uid}()
890         // Either ways we can always call Binder.{clear, restore}CallingIdentity() because
891         // 1) doing so has no effect for A and 2) doing so is sufficient for B.
892         final long identity = Binder.clearCallingIdentity();
893         try {
894             service.addClient(imm.mClient, imm.mIInputContext, displayId);
895         } catch (RemoteException e) {
896             e.rethrowFromSystemServer();
897         } finally {
898             Binder.restoreCallingIdentity(identity);
899         }
900         return imm;
901     }
902 
903     @NonNull
createStubInstance(int displayId, Looper looper)904     private static InputMethodManager createStubInstance(int displayId, Looper looper) {
905         // If InputMethodManager is running for layoutlib, stub out IPCs into IMMS.
906         final Class<IInputMethodManager> c = IInputMethodManager.class;
907         final IInputMethodManager stubInterface =
908                 (IInputMethodManager) Proxy.newProxyInstance(c.getClassLoader(),
909                         new Class[]{c}, (proxy, method, args) -> {
910                             final Class<?> returnType = method.getReturnType();
911                             if (returnType == boolean.class) {
912                                 return false;
913                             } else if (returnType == int.class) {
914                                 return 0;
915                             } else if (returnType == long.class) {
916                                 return 0L;
917                             } else if (returnType == short.class) {
918                                 return 0;
919                             } else if (returnType == char.class) {
920                                 return 0;
921                             } else if (returnType == byte.class) {
922                                 return 0;
923                             } else if (returnType == float.class) {
924                                 return 0f;
925                             } else if (returnType == double.class) {
926                                 return 0.0;
927                             } else {
928                                 return null;
929                             }
930                         });
931         return new InputMethodManager(stubInterface, displayId, looper);
932     }
933 
InputMethodManager(IInputMethodManager service, int displayId, Looper looper)934     private InputMethodManager(IInputMethodManager service, int displayId, Looper looper) {
935         mService = service;
936         mMainLooper = looper;
937         mH = new H(looper);
938         mDisplayId = displayId;
939         mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this);
940     }
941 
942     /**
943      * Retrieve an instance for the given {@link Context}, creating it if it doesn't already exist.
944      *
945      * @param context {@link Context} for which IME APIs need to work
946      * @return {@link InputMethodManager} instance
947      * @hide
948      */
949     @NonNull
forContext(Context context)950     public static InputMethodManager forContext(Context context) {
951         final int displayId = context.getDisplayId();
952         // For better backward compatibility, we always use Looper.getMainLooper() for the default
953         // display case.
954         final Looper looper = displayId == Display.DEFAULT_DISPLAY
955                 ? Looper.getMainLooper() : context.getMainLooper();
956         return forContextInternal(displayId, looper);
957     }
958 
959     @NonNull
forContextInternal(int displayId, Looper looper)960     private static InputMethodManager forContextInternal(int displayId, Looper looper) {
961         final boolean isDefaultDisplay = displayId == Display.DEFAULT_DISPLAY;
962         synchronized (sLock) {
963             InputMethodManager instance = sInstanceMap.get(displayId);
964             if (instance != null) {
965                 return instance;
966             }
967             instance = createInstance(displayId, looper);
968             // For backward compatibility, store the instance also to sInstance for default display.
969             if (sInstance == null && isDefaultDisplay) {
970                 sInstance = instance;
971             }
972             sInstanceMap.put(displayId, instance);
973             return instance;
974         }
975     }
976 
977     /**
978      * Deprecated. Do not use.
979      *
980      * @return global {@link InputMethodManager} instance
981      * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully
982      *             support multi-display scenario.
983      * @hide
984      */
985     @Deprecated
986     @UnsupportedAppUsage
getInstance()987     public static InputMethodManager getInstance() {
988         Log.w(TAG, "InputMethodManager.getInstance() is deprecated because it cannot be"
989                         + " compatible with multi-display."
990                         + " Use context.getSystemService(InputMethodManager.class) instead.",
991                 new Throwable());
992         ensureDefaultInstanceForDefaultDisplayIfNecessary();
993         return peekInstance();
994     }
995 
996     /**
997      * Deprecated. Do not use.
998      *
999      * @return {@link #sInstance}
1000      * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully
1001      *             support multi-display scenario.
1002      * @hide
1003      */
1004     @Deprecated
1005     @UnsupportedAppUsage
peekInstance()1006     public static InputMethodManager peekInstance() {
1007         Log.w(TAG, "InputMethodManager.peekInstance() is deprecated because it cannot be"
1008                         + " compatible with multi-display."
1009                         + " Use context.getSystemService(InputMethodManager.class) instead.",
1010                 new Throwable());
1011         synchronized (sLock) {
1012             return sInstance;
1013         }
1014     }
1015 
1016     /** @hide */
1017     @UnsupportedAppUsage
getClient()1018     public IInputMethodClient getClient() {
1019         return mClient;
1020     }
1021 
1022     /** @hide */
1023     @UnsupportedAppUsage
getInputContext()1024     public IInputContext getInputContext() {
1025         return mIInputContext;
1026     }
1027 
1028     /**
1029      * Returns the list of installed input methods.
1030      *
1031      * <p>On multi user environment, this API returns a result for the calling process user.</p>
1032      *
1033      * @return {@link List} of {@link InputMethodInfo}.
1034      */
getInputMethodList()1035     public List<InputMethodInfo> getInputMethodList() {
1036         try {
1037             // We intentionally do not use UserHandle.getCallingUserId() here because for system
1038             // services InputMethodManagerInternal.getInputMethodListAsUser() should be used
1039             // instead.
1040             return mService.getInputMethodList(UserHandle.myUserId());
1041         } catch (RemoteException e) {
1042             throw e.rethrowFromSystemServer();
1043         }
1044     }
1045 
1046     /**
1047      * Returns the list of installed input methods for the specified user.
1048      *
1049      * @param userId user ID to query
1050      * @return {@link List} of {@link InputMethodInfo}.
1051      * @hide
1052      */
1053     @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
getInputMethodListAsUser(@serIdInt int userId)1054     public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
1055         try {
1056             return mService.getInputMethodList(userId);
1057         } catch (RemoteException e) {
1058             throw e.rethrowFromSystemServer();
1059         }
1060     }
1061 
1062     /**
1063      * Returns the list of enabled input methods.
1064      *
1065      * <p>On multi user environment, this API returns a result for the calling process user.</p>
1066      *
1067      * @return {@link List} of {@link InputMethodInfo}.
1068      */
getEnabledInputMethodList()1069     public List<InputMethodInfo> getEnabledInputMethodList() {
1070         try {
1071             // We intentionally do not use UserHandle.getCallingUserId() here because for system
1072             // services InputMethodManagerInternal.getEnabledInputMethodListAsUser() should be used
1073             // instead.
1074             return mService.getEnabledInputMethodList(UserHandle.myUserId());
1075         } catch (RemoteException e) {
1076             throw e.rethrowFromSystemServer();
1077         }
1078     }
1079 
1080     /**
1081      * Returns the list of enabled input methods for the specified user.
1082      *
1083      * @param userId user ID to query
1084      * @return {@link List} of {@link InputMethodInfo}.
1085      * @hide
1086      */
1087     @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
getEnabledInputMethodListAsUser(@serIdInt int userId)1088     public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
1089         try {
1090             return mService.getEnabledInputMethodList(userId);
1091         } catch (RemoteException e) {
1092             throw e.rethrowFromSystemServer();
1093         }
1094     }
1095 
1096     /**
1097      * Returns a list of enabled input method subtypes for the specified input method info.
1098      *
1099      * <p>On multi user environment, this API returns a result for the calling process user.</p>
1100      *
1101      * @param imi An input method info whose subtypes list will be returned.
1102      * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly
1103      * selected subtypes. If an input method info doesn't have enabled subtypes, the framework
1104      * will implicitly enable subtypes according to the current system language.
1105      */
getEnabledInputMethodSubtypeList(InputMethodInfo imi, boolean allowsImplicitlySelectedSubtypes)1106     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
1107             boolean allowsImplicitlySelectedSubtypes) {
1108         try {
1109             return mService.getEnabledInputMethodSubtypeList(
1110                     imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
1111         } catch (RemoteException e) {
1112             throw e.rethrowFromSystemServer();
1113         }
1114     }
1115 
1116     /**
1117      * @deprecated Use {@link InputMethodService#showStatusIcon(int)} instead. This method was
1118      * intended for IME developers who should be accessing APIs through the service. APIs in this
1119      * class are intended for app developers interacting with the IME.
1120      */
1121     @Deprecated
showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId)1122     public void showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId) {
1123         InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIcon(packageName, iconId);
1124     }
1125 
1126     /**
1127      * @deprecated Use {@link InputMethodService#hideStatusIcon()} instead. This method was
1128      * intended for IME developers who should be accessing APIs through the service. APIs in
1129      * this class are intended for app developers interacting with the IME.
1130      */
1131     @Deprecated
hideStatusIcon(IBinder imeToken)1132     public void hideStatusIcon(IBinder imeToken) {
1133         InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIcon(null, 0);
1134     }
1135 
1136     /**
1137      * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing.
1138      *
1139      * @param spans will be ignored.
1140      *
1141      * @deprecated Do not use.
1142      * @hide
1143      */
1144     @Deprecated
1145     @UnsupportedAppUsage
registerSuggestionSpansForNotification(SuggestionSpan[] spans)1146     public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
1147         Log.w(TAG, "registerSuggestionSpansForNotification() is deprecated.  Does nothing.");
1148     }
1149 
1150     /**
1151      * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing.
1152      *
1153      * @deprecated Do not use.
1154      * @hide
1155      */
1156     @Deprecated
1157     @UnsupportedAppUsage
notifySuggestionPicked(SuggestionSpan span, String originalString, int index)1158     public void notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
1159         Log.w(TAG, "notifySuggestionPicked() is deprecated.  Does nothing.");
1160     }
1161 
1162     /**
1163      * Allows you to discover whether the attached input method is running
1164      * in fullscreen mode.  Return true if it is fullscreen, entirely covering
1165      * your UI, else returns false.
1166      */
isFullscreenMode()1167     public boolean isFullscreenMode() {
1168         synchronized (mH) {
1169             return mFullscreenMode;
1170         }
1171     }
1172 
1173     /**
1174      * Return true if the given view is the currently active view for the
1175      * input method.
1176      */
isActive(View view)1177     public boolean isActive(View view) {
1178         // Re-dispatch if there is a context mismatch.
1179         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
1180         if (fallbackImm != null) {
1181             return fallbackImm.isActive(view);
1182         }
1183 
1184         checkFocus();
1185         synchronized (mH) {
1186             return (mServedView == view
1187                     || (mServedView != null
1188                             && mServedView.checkInputConnectionProxy(view)))
1189                     && mCurrentTextBoxAttribute != null;
1190         }
1191     }
1192 
1193     /**
1194      * Return true if any view is currently active in the input method.
1195      */
isActive()1196     public boolean isActive() {
1197         checkFocus();
1198         synchronized (mH) {
1199             return mServedView != null && mCurrentTextBoxAttribute != null;
1200         }
1201     }
1202 
1203     /**
1204      * Return true if the currently served view is accepting full text edits.
1205      * If false, it has no input connection, so can only handle raw key events.
1206      */
isAcceptingText()1207     public boolean isAcceptingText() {
1208         checkFocus();
1209         return mServedInputConnectionWrapper != null &&
1210                 mServedInputConnectionWrapper.getInputConnection() != null;
1211     }
1212 
1213     /**
1214      * Reset all of the state associated with being bound to an input method.
1215      */
clearBindingLocked()1216     void clearBindingLocked() {
1217         if (DEBUG) Log.v(TAG, "Clearing binding!");
1218         clearConnectionLocked();
1219         setInputChannelLocked(null);
1220         mBindSequence = -1;
1221         mCurId = null;
1222         mCurMethod = null;
1223     }
1224 
setInputChannelLocked(InputChannel channel)1225     void setInputChannelLocked(InputChannel channel) {
1226         if (mCurChannel != channel) {
1227             if (mCurSender != null) {
1228                 flushPendingEventsLocked();
1229                 mCurSender.dispose();
1230                 mCurSender = null;
1231             }
1232             if (mCurChannel != null) {
1233                 mCurChannel.dispose();
1234             }
1235             mCurChannel = channel;
1236         }
1237     }
1238 
1239     /**
1240      * Reset all of the state associated with a served view being connected
1241      * to an input method
1242      */
clearConnectionLocked()1243     void clearConnectionLocked() {
1244         mCurrentTextBoxAttribute = null;
1245         if (mServedInputConnectionWrapper != null) {
1246             mServedInputConnectionWrapper.deactivate();
1247             mServedInputConnectionWrapper = null;
1248         }
1249     }
1250 
1251     /**
1252      * Disconnect any existing input connection, clearing the served view.
1253      */
1254     @UnsupportedAppUsage
finishInputLocked()1255     void finishInputLocked() {
1256         mNextServedView = null;
1257         mActivityViewToScreenMatrix = null;
1258         if (mServedView != null) {
1259             if (DEBUG) Log.v(TAG, "FINISH INPUT: mServedView=" + dumpViewInfo(mServedView));
1260             mServedView = null;
1261             mCompletions = null;
1262             mServedConnecting = false;
1263             clearConnectionLocked();
1264         }
1265     }
1266 
displayCompletions(View view, CompletionInfo[] completions)1267     public void displayCompletions(View view, CompletionInfo[] completions) {
1268         // Re-dispatch if there is a context mismatch.
1269         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
1270         if (fallbackImm != null) {
1271             fallbackImm.displayCompletions(view, completions);
1272             return;
1273         }
1274 
1275         checkFocus();
1276         synchronized (mH) {
1277             if (mServedView != view && (mServedView == null
1278                             || !mServedView.checkInputConnectionProxy(view))) {
1279                 return;
1280             }
1281 
1282             mCompletions = completions;
1283             if (mCurMethod != null) {
1284                 try {
1285                     mCurMethod.displayCompletions(mCompletions);
1286                 } catch (RemoteException e) {
1287                 }
1288             }
1289         }
1290     }
1291 
updateExtractedText(View view, int token, ExtractedText text)1292     public void updateExtractedText(View view, int token, ExtractedText text) {
1293         // Re-dispatch if there is a context mismatch.
1294         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
1295         if (fallbackImm != null) {
1296             fallbackImm.updateExtractedText(view, token, text);
1297             return;
1298         }
1299 
1300         checkFocus();
1301         synchronized (mH) {
1302             if (mServedView != view && (mServedView == null
1303                     || !mServedView.checkInputConnectionProxy(view))) {
1304                 return;
1305             }
1306 
1307             if (mCurMethod != null) {
1308                 try {
1309                     mCurMethod.updateExtractedText(token, text);
1310                 } catch (RemoteException e) {
1311                 }
1312             }
1313         }
1314     }
1315 
1316     /**
1317      * Flag for {@link #showSoftInput} to indicate that this is an implicit
1318      * request to show the input window, not as the result of a direct request
1319      * by the user.  The window may not be shown in this case.
1320      */
1321     public static final int SHOW_IMPLICIT = 0x0001;
1322 
1323     /**
1324      * Flag for {@link #showSoftInput} to indicate that the user has forced
1325      * the input method open (such as by long-pressing menu) so it should
1326      * not be closed until they explicitly do so.
1327      */
1328     public static final int SHOW_FORCED = 0x0002;
1329 
1330     /**
1331      * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
1332      * a result receiver: explicitly request that the current input method's
1333      * soft input area be shown to the user, if needed.
1334      *
1335      * @param view The currently focused view, which would like to receive
1336      * soft keyboard input.
1337      * @param flags Provides additional operating flags.  Currently may be
1338      * 0 or have the {@link #SHOW_IMPLICIT} bit set.
1339      */
showSoftInput(View view, int flags)1340     public boolean showSoftInput(View view, int flags) {
1341         // Re-dispatch if there is a context mismatch.
1342         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
1343         if (fallbackImm != null) {
1344             return fallbackImm.showSoftInput(view, flags);
1345         }
1346 
1347         return showSoftInput(view, flags, null);
1348     }
1349 
1350     /**
1351      * Flag for the {@link ResultReceiver} result code from
1352      * {@link #showSoftInput(View, int, ResultReceiver)} and
1353      * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
1354      * state of the soft input window was unchanged and remains shown.
1355      */
1356     public static final int RESULT_UNCHANGED_SHOWN = 0;
1357 
1358     /**
1359      * Flag for the {@link ResultReceiver} result code from
1360      * {@link #showSoftInput(View, int, ResultReceiver)} and
1361      * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
1362      * state of the soft input window was unchanged and remains hidden.
1363      */
1364     public static final int RESULT_UNCHANGED_HIDDEN = 1;
1365 
1366     /**
1367      * Flag for the {@link ResultReceiver} result code from
1368      * {@link #showSoftInput(View, int, ResultReceiver)} and
1369      * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
1370      * state of the soft input window changed from hidden to shown.
1371      */
1372     public static final int RESULT_SHOWN = 2;
1373 
1374     /**
1375      * Flag for the {@link ResultReceiver} result code from
1376      * {@link #showSoftInput(View, int, ResultReceiver)} and
1377      * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
1378      * state of the soft input window changed from shown to hidden.
1379      */
1380     public static final int RESULT_HIDDEN = 3;
1381 
1382     /**
1383      * Explicitly request that the current input method's soft input area be
1384      * shown to the user, if needed.  Call this if the user interacts with
1385      * your view in such a way that they have expressed they would like to
1386      * start performing input into it.
1387      *
1388      * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
1389      * this method can be a long-lived object, because it may not be
1390      * garbage-collected until all the corresponding {@link ResultReceiver}
1391      * objects transferred to different processes get garbage-collected.
1392      * Follow the general patterns to avoid memory leaks in Android.
1393      * Consider to use {@link java.lang.ref.WeakReference} so that application
1394      * logic objects such as {@link android.app.Activity} and {@link Context}
1395      * can be garbage collected regardless of the lifetime of
1396      * {@link ResultReceiver}.
1397      *
1398      * @param view The currently focused view, which would like to receive
1399      * soft keyboard input.
1400      * @param flags Provides additional operating flags.  Currently may be
1401      * 0 or have the {@link #SHOW_IMPLICIT} bit set.
1402      * @param resultReceiver If non-null, this will be called by the IME when
1403      * it has processed your request to tell you what it has done.  The result
1404      * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
1405      * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
1406      * {@link #RESULT_HIDDEN}.
1407      */
showSoftInput(View view, int flags, ResultReceiver resultReceiver)1408     public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
1409         // Re-dispatch if there is a context mismatch.
1410         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
1411         if (fallbackImm != null) {
1412             return fallbackImm.showSoftInput(view, flags, resultReceiver);
1413         }
1414 
1415         checkFocus();
1416         synchronized (mH) {
1417             if (mServedView != view && (mServedView == null
1418                     || !mServedView.checkInputConnectionProxy(view))) {
1419                 return false;
1420             }
1421 
1422             try {
1423                 return mService.showSoftInput(mClient, flags, resultReceiver);
1424             } catch (RemoteException e) {
1425                 throw e.rethrowFromSystemServer();
1426             }
1427         }
1428     }
1429 
1430     /**
1431      * This method is still kept for a while until android.support.v7.widget.SearchView ver. 26.0
1432      * is publicly released because previous implementations of that class had relied on this method
1433      * via reflection.
1434      *
1435      * @deprecated This is a hidden API. You should never use this.
1436      * @hide
1437      */
1438     @Deprecated
1439     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
showSoftInputUnchecked(int flags, ResultReceiver resultReceiver)1440     public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
1441         try {
1442             Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be removed "
1443                     + "soon. If you are using android.support.v7.widget.SearchView, please update "
1444                     + "to version 26.0 or newer version.");
1445             mService.showSoftInput(mClient, flags, resultReceiver);
1446         } catch (RemoteException e) {
1447             throw e.rethrowFromSystemServer();
1448         }
1449     }
1450 
1451     /**
1452      * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestHideSelf(int)}
1453      * to indicate that the soft input window should only be hidden if it was not explicitly shown
1454      * by the user.
1455      */
1456     public static final int HIDE_IMPLICIT_ONLY = 0x0001;
1457 
1458     /**
1459      * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestShowSelf(int)}
1460      * to indicate that the soft input window should normally be hidden, unless it was originally
1461      * shown with {@link #SHOW_FORCED}.
1462      */
1463     public static final int HIDE_NOT_ALWAYS = 0x0002;
1464 
1465     /**
1466      * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}
1467      * without a result: request to hide the soft input window from the
1468      * context of the window that is currently accepting input.
1469      *
1470      * @param windowToken The token of the window that is making the request,
1471      * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1472      * @param flags Provides additional operating flags.  Currently may be
1473      * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
1474      */
hideSoftInputFromWindow(IBinder windowToken, int flags)1475     public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) {
1476         return hideSoftInputFromWindow(windowToken, flags, null);
1477     }
1478 
1479     /**
1480      * Request to hide the soft input window from the context of the window
1481      * that is currently accepting input.  This should be called as a result
1482      * of the user doing some actually than fairly explicitly requests to
1483      * have the input window hidden.
1484      *
1485      * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
1486      * this method can be a long-lived object, because it may not be
1487      * garbage-collected until all the corresponding {@link ResultReceiver}
1488      * objects transferred to different processes get garbage-collected.
1489      * Follow the general patterns to avoid memory leaks in Android.
1490      * Consider to use {@link java.lang.ref.WeakReference} so that application
1491      * logic objects such as {@link android.app.Activity} and {@link Context}
1492      * can be garbage collected regardless of the lifetime of
1493      * {@link ResultReceiver}.
1494      *
1495      * @param windowToken The token of the window that is making the request,
1496      * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1497      * @param flags Provides additional operating flags.  Currently may be
1498      * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
1499      * @param resultReceiver If non-null, this will be called by the IME when
1500      * it has processed your request to tell you what it has done.  The result
1501      * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
1502      * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
1503      * {@link #RESULT_HIDDEN}.
1504      */
hideSoftInputFromWindow(IBinder windowToken, int flags, ResultReceiver resultReceiver)1505     public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
1506             ResultReceiver resultReceiver) {
1507         checkFocus();
1508         synchronized (mH) {
1509             if (mServedView == null || mServedView.getWindowToken() != windowToken) {
1510                 return false;
1511             }
1512 
1513             try {
1514                 return mService.hideSoftInput(mClient, flags, resultReceiver);
1515             } catch (RemoteException e) {
1516                 throw e.rethrowFromSystemServer();
1517             }
1518         }
1519     }
1520 
1521     /**
1522      * This method toggles the input method window display.
1523      * If the input window is already displayed, it gets hidden.
1524      * If not the input window will be displayed.
1525      * @param windowToken The token of the window that is making the request,
1526      * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1527      * @param showFlags Provides additional operating flags.  May be
1528      * 0 or have the {@link #SHOW_IMPLICIT},
1529      * {@link #SHOW_FORCED} bit set.
1530      * @param hideFlags Provides additional operating flags.  May be
1531      * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1532      * {@link #HIDE_NOT_ALWAYS} bit set.
1533      **/
toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags)1534     public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
1535         synchronized (mH) {
1536             if (mServedView == null || mServedView.getWindowToken() != windowToken) {
1537                 return;
1538             }
1539             if (mCurMethod != null) {
1540                 try {
1541                     mCurMethod.toggleSoftInput(showFlags, hideFlags);
1542                 } catch (RemoteException e) {
1543                 }
1544             }
1545         }
1546     }
1547 
1548     /**
1549      * This method toggles the input method window display.
1550      *
1551      * If the input window is already displayed, it gets hidden.
1552      * If not the input window will be displayed.
1553      * @param showFlags Provides additional operating flags.  May be
1554      * 0 or have the {@link #SHOW_IMPLICIT},
1555      * {@link #SHOW_FORCED} bit set.
1556      * @param hideFlags Provides additional operating flags.  May be
1557      * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1558      * {@link #HIDE_NOT_ALWAYS} bit set.
1559      */
toggleSoftInput(int showFlags, int hideFlags)1560     public void toggleSoftInput(int showFlags, int hideFlags) {
1561         if (mCurMethod != null) {
1562             try {
1563                 mCurMethod.toggleSoftInput(showFlags, hideFlags);
1564             } catch (RemoteException e) {
1565             }
1566         }
1567     }
1568 
1569     /**
1570      * If the input method is currently connected to the given view,
1571      * restart it with its new contents.  You should call this when the text
1572      * within your view changes outside of the normal input method or key
1573      * input flow, such as when an application calls TextView.setText().
1574      *
1575      * @param view The view whose text has changed.
1576      */
restartInput(View view)1577     public void restartInput(View view) {
1578         // Re-dispatch if there is a context mismatch.
1579         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
1580         if (fallbackImm != null) {
1581             fallbackImm.restartInput(view);
1582             return;
1583         }
1584 
1585         checkFocus();
1586         synchronized (mH) {
1587             if (mServedView != view && (mServedView == null
1588                     || !mServedView.checkInputConnectionProxy(view))) {
1589                 return;
1590             }
1591 
1592             mServedConnecting = true;
1593         }
1594 
1595         startInputInner(StartInputReason.APP_CALLED_RESTART_INPUT_API, null, 0, 0, 0);
1596     }
1597 
startInputInner(@tartInputReason int startInputReason, @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags)1598     boolean startInputInner(@StartInputReason int startInputReason,
1599             @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags,
1600             @SoftInputModeFlags int softInputMode, int windowFlags) {
1601         final View view;
1602         synchronized (mH) {
1603             view = mServedView;
1604 
1605             // Make sure we have a window token for the served view.
1606             if (DEBUG) {
1607                 Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) +
1608                         " reason=" + InputMethodDebug.startInputReasonToString(startInputReason));
1609             }
1610             if (view == null) {
1611                 if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
1612                 return false;
1613             }
1614         }
1615 
1616         if (windowGainingFocus == null) {
1617             windowGainingFocus = view.getWindowToken();
1618             if (windowGainingFocus == null) {
1619                 Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
1620                 return false;
1621             }
1622             startInputFlags |= StartInputFlags.VIEW_HAS_FOCUS;
1623             if (view.onCheckIsTextEditor()) {
1624                 startInputFlags |= StartInputFlags.IS_TEXT_EDITOR;
1625             }
1626             softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
1627             windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
1628         }
1629 
1630         // Now we need to get an input connection from the served view.
1631         // This is complicated in a couple ways: we can't be holding our lock
1632         // when calling out to the view, and we need to make sure we call into
1633         // the view on the same thread that is driving its view hierarchy.
1634         Handler vh = view.getHandler();
1635         if (vh == null) {
1636             // If the view doesn't have a handler, something has changed out
1637             // from under us, so just close the current input.
1638             // If we don't close the current input, the current input method can remain on the
1639             // screen without a connection.
1640             if (DEBUG) Log.v(TAG, "ABORT input: no handler for view! Close current input.");
1641             closeCurrentInput();
1642             return false;
1643         }
1644         if (vh.getLooper() != Looper.myLooper()) {
1645             // The view is running on a different thread than our own, so
1646             // we need to reschedule our work for over there.
1647             if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
1648             vh.post(() -> startInputInner(startInputReason, null, 0, 0, 0));
1649             return false;
1650         }
1651 
1652         // Okay we are now ready to call into the served view and have it
1653         // do its stuff.
1654         // Life is good: let's hook everything up!
1655         EditorInfo tba = new EditorInfo();
1656         // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the
1657         // system can verify the consistency between the uid of this process and package name passed
1658         // from here. See comment of Context#getOpPackageName() for details.
1659         tba.packageName = view.getContext().getOpPackageName();
1660         tba.fieldId = view.getId();
1661         InputConnection ic = view.onCreateInputConnection(tba);
1662         if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
1663 
1664         synchronized (mH) {
1665             // Now that we are locked again, validate that our state hasn't
1666             // changed.
1667             if (mServedView != view || !mServedConnecting) {
1668                 // Something else happened, so abort.
1669                 if (DEBUG) Log.v(TAG,
1670                         "Starting input: finished by someone else. view=" + dumpViewInfo(view)
1671                         + " mServedView=" + dumpViewInfo(mServedView)
1672                         + " mServedConnecting=" + mServedConnecting);
1673                 return false;
1674             }
1675 
1676             // If we already have a text box, then this view is already
1677             // connected so we want to restart it.
1678             if (mCurrentTextBoxAttribute == null) {
1679                 startInputFlags |= StartInputFlags.INITIAL_CONNECTION;
1680             }
1681 
1682             // Hook 'em up and let 'er rip.
1683             mCurrentTextBoxAttribute = tba;
1684             maybeCallServedViewChangedLocked(tba);
1685             mServedConnecting = false;
1686             if (mServedInputConnectionWrapper != null) {
1687                 mServedInputConnectionWrapper.deactivate();
1688                 mServedInputConnectionWrapper = null;
1689             }
1690             ControlledInputConnectionWrapper servedContext;
1691             final int missingMethodFlags;
1692             if (ic != null) {
1693                 mCursorSelStart = tba.initialSelStart;
1694                 mCursorSelEnd = tba.initialSelEnd;
1695                 mCursorCandStart = -1;
1696                 mCursorCandEnd = -1;
1697                 mCursorRect.setEmpty();
1698                 mCursorAnchorInfo = null;
1699                 final Handler icHandler;
1700                 missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);
1701                 if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER)
1702                         != 0) {
1703                     // InputConnection#getHandler() is not implemented.
1704                     icHandler = null;
1705                 } else {
1706                     icHandler = ic.getHandler();
1707                 }
1708                 servedContext = new ControlledInputConnectionWrapper(
1709                         icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
1710             } else {
1711                 servedContext = null;
1712                 missingMethodFlags = 0;
1713             }
1714             mServedInputConnectionWrapper = servedContext;
1715 
1716             try {
1717                 if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
1718                         + ic + " tba=" + tba + " startInputFlags="
1719                         + InputMethodDebug.startInputFlagsToString(startInputFlags));
1720                 final InputBindResult res = mService.startInputOrWindowGainedFocus(
1721                         startInputReason, mClient, windowGainingFocus, startInputFlags,
1722                         softInputMode, windowFlags, tba, servedContext, missingMethodFlags,
1723                         view.getContext().getApplicationInfo().targetSdkVersion);
1724                 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
1725                 if (res == null) {
1726                     Log.wtf(TAG, "startInputOrWindowGainedFocus must not return"
1727                             + " null. startInputReason="
1728                             + InputMethodDebug.startInputReasonToString(startInputReason)
1729                             + " editorInfo=" + tba
1730                             + " startInputFlags="
1731                             + InputMethodDebug.startInputFlagsToString(startInputFlags));
1732                     return false;
1733                 }
1734                 mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
1735                 if (res.id != null) {
1736                     setInputChannelLocked(res.channel);
1737                     mBindSequence = res.sequence;
1738                     mCurMethod = res.method;
1739                     mCurId = res.id;
1740                 } else if (res.channel != null && res.channel != mCurChannel) {
1741                     res.channel.dispose();
1742                 }
1743                 switch (res.result) {
1744                     case InputBindResult.ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
1745                         mRestartOnNextWindowFocus = true;
1746                         break;
1747                 }
1748                 if (mCurMethod != null && mCompletions != null) {
1749                     try {
1750                         mCurMethod.displayCompletions(mCompletions);
1751                     } catch (RemoteException e) {
1752                     }
1753                 }
1754             } catch (RemoteException e) {
1755                 Log.w(TAG, "IME died: " + mCurId, e);
1756             }
1757         }
1758 
1759         return true;
1760     }
1761 
1762     /**
1763      * When the focused window is dismissed, this method is called to finish the
1764      * input method started before.
1765      * @hide
1766      */
1767     @UnsupportedAppUsage
windowDismissed(IBinder appWindowToken)1768     public void windowDismissed(IBinder appWindowToken) {
1769         checkFocus();
1770         synchronized (mH) {
1771             if (mServedView != null &&
1772                     mServedView.getWindowToken() == appWindowToken) {
1773                 finishInputLocked();
1774             }
1775             if (mCurRootView != null &&
1776                     mCurRootView.getWindowToken() == appWindowToken) {
1777                 mCurRootView = null;
1778             }
1779         }
1780     }
1781 
1782     /**
1783      * Call this when a view receives focus.
1784      * @hide
1785      */
1786     @UnsupportedAppUsage
focusIn(View view)1787     public void focusIn(View view) {
1788         synchronized (mH) {
1789             focusInLocked(view);
1790         }
1791     }
1792 
focusInLocked(View view)1793     void focusInLocked(View view) {
1794         if (DEBUG) Log.v(TAG, "focusIn: " + dumpViewInfo(view));
1795 
1796         if (view != null && view.isTemporarilyDetached()) {
1797             // This is a request from a view that is temporarily detached from a window.
1798             if (DEBUG) Log.v(TAG, "Temporarily detached view, ignoring");
1799             return;
1800         }
1801 
1802         if (mCurRootView != view.getRootView()) {
1803             // This is a request from a window that isn't in the window with
1804             // IME focus, so ignore it.
1805             if (DEBUG) Log.v(TAG, "Not IME target window, ignoring");
1806             return;
1807         }
1808 
1809         mNextServedView = view;
1810         scheduleCheckFocusLocked(view);
1811     }
1812 
1813     /**
1814      * Call this when a view loses focus.
1815      * @hide
1816      */
1817     @UnsupportedAppUsage
focusOut(View view)1818     public void focusOut(View view) {
1819         synchronized (mH) {
1820             if (DEBUG) Log.v(TAG, "focusOut: view=" + dumpViewInfo(view)
1821                     + " mServedView=" + dumpViewInfo(mServedView));
1822             if (mServedView != view) {
1823                 // The following code would auto-hide the IME if we end up
1824                 // with no more views with focus.  This can happen, however,
1825                 // whenever we go into touch mode, so it ends up hiding
1826                 // at times when we don't really want it to.  For now it
1827                 // seems better to just turn it all off.
1828                 // TODO: Check view.isTemporarilyDetached() when re-enable the following code.
1829                 if (false && canStartInput(view)) {
1830                     mNextServedView = null;
1831                     scheduleCheckFocusLocked(view);
1832                 }
1833             }
1834         }
1835     }
1836 
1837     /**
1838      * Call this when a view is being detached from a {@link android.view.Window}.
1839      * @hide
1840      */
onViewDetachedFromWindow(View view)1841     public void onViewDetachedFromWindow(View view) {
1842         synchronized (mH) {
1843             if (DEBUG) Log.v(TAG, "onViewDetachedFromWindow: view=" + dumpViewInfo(view)
1844                     + " mServedView=" + dumpViewInfo(mServedView));
1845             if (mServedView == view) {
1846                 mNextServedView = null;
1847                 scheduleCheckFocusLocked(view);
1848             }
1849         }
1850     }
1851 
scheduleCheckFocusLocked(View view)1852     static void scheduleCheckFocusLocked(View view) {
1853         ViewRootImpl viewRootImpl = view.getViewRootImpl();
1854         if (viewRootImpl != null) {
1855             viewRootImpl.dispatchCheckFocus();
1856         }
1857     }
1858 
1859     /**
1860      * @hide
1861      */
1862     @UnsupportedAppUsage
checkFocus()1863     public void checkFocus() {
1864         if (checkFocusNoStartInput(false)) {
1865             startInputInner(StartInputReason.CHECK_FOCUS, null, 0, 0, 0);
1866         }
1867     }
1868 
checkFocusNoStartInput(boolean forceNewFocus)1869     private boolean checkFocusNoStartInput(boolean forceNewFocus) {
1870         // This is called a lot, so short-circuit before locking.
1871         if (mServedView == mNextServedView && !forceNewFocus) {
1872             return false;
1873         }
1874 
1875         final ControlledInputConnectionWrapper ic;
1876         synchronized (mH) {
1877             if (mServedView == mNextServedView && !forceNewFocus) {
1878                 return false;
1879             }
1880             if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
1881                     + " next=" + mNextServedView
1882                     + " forceNewFocus=" + forceNewFocus
1883                     + " package="
1884                     + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>"));
1885 
1886             if (mNextServedView == null) {
1887                 finishInputLocked();
1888                 // In this case, we used to have a focused view on the window,
1889                 // but no longer do.  We should make sure the input method is
1890                 // no longer shown, since it serves no purpose.
1891                 closeCurrentInput();
1892                 return false;
1893             }
1894 
1895             ic = mServedInputConnectionWrapper;
1896 
1897             mServedView = mNextServedView;
1898             mCurrentTextBoxAttribute = null;
1899             mCompletions = null;
1900             mServedConnecting = true;
1901             // servedView has changed and it's not editable.
1902             if (!mServedView.onCheckIsTextEditor()) {
1903                 maybeCallServedViewChangedLocked(null);
1904             }
1905         }
1906 
1907         if (ic != null) {
1908             ic.finishComposingText();
1909         }
1910 
1911         return true;
1912     }
1913 
1914     @UnsupportedAppUsage
closeCurrentInput()1915     void closeCurrentInput() {
1916         try {
1917             mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
1918         } catch (RemoteException e) {
1919             throw e.rethrowFromSystemServer();
1920         }
1921     }
1922 
1923     /**
1924      * Called by ViewAncestor when its window gets input focus.
1925      * @hide
1926      */
onPostWindowFocus(View rootView, View focusedView, @SoftInputModeFlags int softInputMode, boolean first, int windowFlags)1927     public void onPostWindowFocus(View rootView, View focusedView,
1928             @SoftInputModeFlags int softInputMode, boolean first, int windowFlags) {
1929         boolean forceNewFocus = false;
1930         synchronized (mH) {
1931             if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
1932                     + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
1933                     + " first=" + first + " flags=#"
1934                     + Integer.toHexString(windowFlags));
1935             if (mRestartOnNextWindowFocus) {
1936                 if (DEBUG) Log.v(TAG, "Restarting due to mRestartOnNextWindowFocus");
1937                 mRestartOnNextWindowFocus = false;
1938                 forceNewFocus = true;
1939             }
1940             focusInLocked(focusedView != null ? focusedView : rootView);
1941         }
1942 
1943         int startInputFlags = 0;
1944         if (focusedView != null) {
1945             startInputFlags |= StartInputFlags.VIEW_HAS_FOCUS;
1946             if (focusedView.onCheckIsTextEditor()) {
1947                 startInputFlags |= StartInputFlags.IS_TEXT_EDITOR;
1948             }
1949         }
1950         if (first) {
1951             startInputFlags |= StartInputFlags.FIRST_WINDOW_FOCUS_GAIN;
1952         }
1953 
1954         if (checkFocusNoStartInput(forceNewFocus)) {
1955             // We need to restart input on the current focus view.  This
1956             // should be done in conjunction with telling the system service
1957             // about the window gaining focus, to help make the transition
1958             // smooth.
1959             if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(),
1960                     startInputFlags, softInputMode, windowFlags)) {
1961                 return;
1962             }
1963         }
1964 
1965         // For some reason we didn't do a startInput + windowFocusGain, so
1966         // we'll just do a window focus gain and call it a day.
1967         synchronized (mH) {
1968             try {
1969                 if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
1970                 mService.startInputOrWindowGainedFocus(
1971                         StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
1972                         rootView.getWindowToken(), startInputFlags, softInputMode, windowFlags,
1973                         null, null, 0 /* missingMethodFlags */,
1974                         rootView.getContext().getApplicationInfo().targetSdkVersion);
1975             } catch (RemoteException e) {
1976                 throw e.rethrowFromSystemServer();
1977             }
1978         }
1979     }
1980 
1981     /** @hide */
1982     @UnsupportedAppUsage
onPreWindowFocus(View rootView, boolean hasWindowFocus)1983     public void onPreWindowFocus(View rootView, boolean hasWindowFocus) {
1984         synchronized (mH) {
1985             if (rootView == null) {
1986                 mCurRootView = null;
1987             } if (hasWindowFocus) {
1988                 mCurRootView = rootView;
1989             } else if (rootView == mCurRootView) {
1990                 // If the mCurRootView is losing window focus, release the strong reference to it
1991                 // so as not to prevent it from being garbage-collected.
1992                 mCurRootView = null;
1993             } else {
1994                 if (DEBUG) {
1995                     Log.v(TAG, "Ignoring onPreWindowFocus()."
1996                             + " mCurRootView=" + mCurRootView + " rootView=" + rootView);
1997                 }
1998             }
1999         }
2000     }
2001 
2002     /**
2003      * Register for IME state callbacks and applying visibility in
2004      * {@link android.view.ImeInsetsSourceConsumer}.
2005      * @hide
2006      */
registerImeConsumer(@onNull ImeInsetsSourceConsumer imeInsetsConsumer)2007     public void registerImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) {
2008         if (imeInsetsConsumer == null) {
2009             throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null.");
2010         }
2011 
2012         synchronized (mH) {
2013             mImeInsetsConsumer = imeInsetsConsumer;
2014         }
2015     }
2016 
2017     /**
2018      * Unregister for IME state callbacks and applying visibility in
2019      * {@link android.view.ImeInsetsSourceConsumer}.
2020      * @hide
2021      */
unregisterImeConsumer(@onNull ImeInsetsSourceConsumer imeInsetsConsumer)2022     public void unregisterImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) {
2023         if (imeInsetsConsumer == null) {
2024             throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null.");
2025         }
2026 
2027         synchronized (mH) {
2028             if (mImeInsetsConsumer == imeInsetsConsumer) {
2029                 mImeInsetsConsumer = null;
2030             }
2031         }
2032     }
2033 
2034     /**
2035      * Call showSoftInput with currently focused view.
2036      * @return {@code true} if IME can be shown.
2037      * @hide
2038      */
requestImeShow(ResultReceiver resultReceiver)2039     public boolean requestImeShow(ResultReceiver resultReceiver) {
2040         synchronized (mH) {
2041             if (mServedView == null) {
2042                 return false;
2043             }
2044             showSoftInput(mServedView, 0 /* flags */, resultReceiver);
2045             return true;
2046         }
2047     }
2048 
2049     /**
2050      * Notify IME directly that it is no longer visible.
2051      * @hide
2052      */
notifyImeHidden()2053     public void notifyImeHidden() {
2054         synchronized (mH) {
2055             try {
2056                 if (mCurMethod != null) {
2057                     mCurMethod.notifyImeHidden();
2058                 }
2059             } catch (RemoteException re) {
2060             }
2061         }
2062     }
2063 
2064     /**
2065      * Report the current selection range.
2066      *
2067      * <p><strong>Editor authors</strong>, you need to call this method whenever
2068      * the cursor moves in your editor. Remember that in addition to doing this, your
2069      * editor needs to always supply current cursor values in
2070      * {@link EditorInfo#initialSelStart} and {@link EditorInfo#initialSelEnd} every
2071      * time {@link android.view.View#onCreateInputConnection(EditorInfo)} is
2072      * called, which happens whenever the keyboard shows up or the focus changes
2073      * to a text field, among other cases.</p>
2074      */
updateSelection(View view, int selStart, int selEnd, int candidatesStart, int candidatesEnd)2075     public void updateSelection(View view, int selStart, int selEnd,
2076             int candidatesStart, int candidatesEnd) {
2077         // Re-dispatch if there is a context mismatch.
2078         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2079         if (fallbackImm != null) {
2080             fallbackImm.updateSelection(view, selStart, selEnd, candidatesStart, candidatesEnd);
2081             return;
2082         }
2083 
2084         checkFocus();
2085         synchronized (mH) {
2086             if ((mServedView != view && (mServedView == null
2087                         || !mServedView.checkInputConnectionProxy(view)))
2088                     || mCurrentTextBoxAttribute == null || mCurMethod == null) {
2089                 return;
2090             }
2091 
2092             if (mCursorSelStart != selStart || mCursorSelEnd != selEnd
2093                     || mCursorCandStart != candidatesStart
2094                     || mCursorCandEnd != candidatesEnd) {
2095                 if (DEBUG) Log.d(TAG, "updateSelection");
2096 
2097                 try {
2098                     if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
2099                     final int oldSelStart = mCursorSelStart;
2100                     final int oldSelEnd = mCursorSelEnd;
2101                     // Update internal values before sending updateSelection to the IME, because
2102                     // if it changes the text within its onUpdateSelection handler in a way that
2103                     // does not move the cursor we don't want to call it again with the same values.
2104                     mCursorSelStart = selStart;
2105                     mCursorSelEnd = selEnd;
2106                     mCursorCandStart = candidatesStart;
2107                     mCursorCandEnd = candidatesEnd;
2108                     mCurMethod.updateSelection(oldSelStart, oldSelEnd,
2109                             selStart, selEnd, candidatesStart, candidatesEnd);
2110                 } catch (RemoteException e) {
2111                     Log.w(TAG, "IME died: " + mCurId, e);
2112                 }
2113             }
2114         }
2115     }
2116 
2117     /**
2118      * Notify the event when the user tapped or clicked the text view.
2119      *
2120      * @param view {@link View} which is being clicked.
2121      * @see InputMethodService#onViewClicked(boolean)
2122      * @deprecated The semantics of this method can never be defined well for composite {@link View}
2123      *             that works as a giant "Canvas", which can host its own UI hierarchy and sub focus
2124      *             state. {@link android.webkit.WebView} is a good example. Application / IME
2125      *             developers should not rely on this method.
2126      */
2127     @Deprecated
viewClicked(View view)2128     public void viewClicked(View view) {
2129         // Re-dispatch if there is a context mismatch.
2130         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2131         if (fallbackImm != null) {
2132             fallbackImm.viewClicked(view);
2133             return;
2134         }
2135 
2136         final boolean focusChanged = mServedView != mNextServedView;
2137         checkFocus();
2138         synchronized (mH) {
2139             if ((mServedView != view && (mServedView == null
2140                     || !mServedView.checkInputConnectionProxy(view)))
2141                     || mCurrentTextBoxAttribute == null || mCurMethod == null) {
2142                 return;
2143             }
2144             try {
2145                 if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
2146                 mCurMethod.viewClicked(focusChanged);
2147             } catch (RemoteException e) {
2148                 Log.w(TAG, "IME died: " + mCurId, e);
2149             }
2150         }
2151     }
2152 
2153     /**
2154      * Return true if the current input method wants to watch the location
2155      * of the input editor's cursor in its window.
2156      *
2157      * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead.
2158      */
2159     @Deprecated
isWatchingCursor(View view)2160     public boolean isWatchingCursor(View view) {
2161         return false;
2162     }
2163 
2164     /**
2165      * Return true if the current input method wants to be notified when cursor/anchor location
2166      * is changed.
2167      *
2168      * @hide
2169      */
2170     @UnsupportedAppUsage
isCursorAnchorInfoEnabled()2171     public boolean isCursorAnchorInfoEnabled() {
2172         synchronized (mH) {
2173             final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
2174                     InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0;
2175             final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode &
2176                     InputConnection.CURSOR_UPDATE_MONITOR) != 0;
2177             return isImmediate || isMonitoring;
2178         }
2179     }
2180 
2181     /**
2182      * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
2183      *
2184      * @hide
2185      */
2186     @UnsupportedAppUsage
setUpdateCursorAnchorInfoMode(int flags)2187     public void setUpdateCursorAnchorInfoMode(int flags) {
2188         synchronized (mH) {
2189             mRequestUpdateCursorAnchorInfoMonitorMode = flags;
2190         }
2191     }
2192 
2193     /**
2194      * Report the current cursor location in its window.
2195      *
2196      * @deprecated Use {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)} instead.
2197      */
2198     @Deprecated
updateCursor(View view, int left, int top, int right, int bottom)2199     public void updateCursor(View view, int left, int top, int right, int bottom) {
2200         // Re-dispatch if there is a context mismatch.
2201         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2202         if (fallbackImm != null) {
2203             fallbackImm.updateCursor(view, left, top, right, bottom);
2204             return;
2205         }
2206 
2207         checkFocus();
2208         synchronized (mH) {
2209             if ((mServedView != view && (mServedView == null
2210                         || !mServedView.checkInputConnectionProxy(view)))
2211                     || mCurrentTextBoxAttribute == null || mCurMethod == null) {
2212                 return;
2213             }
2214 
2215             mTmpCursorRect.set(left, top, right, bottom);
2216             if (!mCursorRect.equals(mTmpCursorRect)) {
2217                 if (DEBUG) Log.d(TAG, "updateCursor");
2218 
2219                 try {
2220                     if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
2221                     mCurMethod.updateCursor(mTmpCursorRect);
2222                     mCursorRect.set(mTmpCursorRect);
2223                 } catch (RemoteException e) {
2224                     Log.w(TAG, "IME died: " + mCurId, e);
2225                 }
2226             }
2227         }
2228     }
2229 
2230     /**
2231      * Report positional change of the text insertion point and/or characters in the composition
2232      * string.
2233      */
updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo)2234     public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) {
2235         if (view == null || cursorAnchorInfo == null) {
2236             return;
2237         }
2238         // Re-dispatch if there is a context mismatch.
2239         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2240         if (fallbackImm != null) {
2241             fallbackImm.updateCursorAnchorInfo(view, cursorAnchorInfo);
2242             return;
2243         }
2244 
2245         checkFocus();
2246         synchronized (mH) {
2247             if ((mServedView != view &&
2248                     (mServedView == null || !mServedView.checkInputConnectionProxy(view)))
2249                     || mCurrentTextBoxAttribute == null || mCurMethod == null) {
2250                 return;
2251             }
2252             // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has
2253             // not been changed from the previous call.
2254             final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
2255                     InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0;
2256             if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) {
2257                 // TODO: Consider always emitting this message once we have addressed redundant
2258                 // calls of this method from android.widget.Editor.
2259                 if (DEBUG) {
2260                     Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info="
2261                             + cursorAnchorInfo);
2262                 }
2263                 return;
2264             }
2265             if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
2266             try {
2267                 if (mActivityViewToScreenMatrix != null) {
2268                     mCurMethod.updateCursorAnchorInfo(
2269                             CursorAnchorInfo.createForAdditionalParentMatrix(
2270                                     cursorAnchorInfo, mActivityViewToScreenMatrix));
2271                 } else {
2272                     mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
2273                 }
2274                 mCursorAnchorInfo = cursorAnchorInfo;
2275                 // Clear immediate bit (if any).
2276                 mRequestUpdateCursorAnchorInfoMonitorMode &=
2277                         ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
2278             } catch (RemoteException e) {
2279                 Log.w(TAG, "IME died: " + mCurId, e);
2280             }
2281         }
2282     }
2283 
2284     /**
2285      * Call {@link InputMethodSession#appPrivateCommand(String, Bundle)
2286      * InputMethodSession.appPrivateCommand()} on the current Input Method.
2287      * @param view Optional View that is sending the command, or null if
2288      * you want to send the command regardless of the view that is attached
2289      * to the input method.
2290      * @param action Name of the command to be performed.  This <em>must</em>
2291      * be a scoped name, i.e. prefixed with a package name you own, so that
2292      * different developers will not create conflicting commands.
2293      * @param data Any data to include with the command.
2294      */
sendAppPrivateCommand(View view, String action, Bundle data)2295     public void sendAppPrivateCommand(View view, String action, Bundle data) {
2296         // Re-dispatch if there is a context mismatch.
2297         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2298         if (fallbackImm != null) {
2299             fallbackImm.sendAppPrivateCommand(view, action, data);
2300             return;
2301         }
2302 
2303         checkFocus();
2304         synchronized (mH) {
2305             if ((mServedView != view && (mServedView == null
2306                         || !mServedView.checkInputConnectionProxy(view)))
2307                     || mCurrentTextBoxAttribute == null || mCurMethod == null) {
2308                 return;
2309             }
2310             try {
2311                 if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
2312                 mCurMethod.appPrivateCommand(action, data);
2313             } catch (RemoteException e) {
2314                 Log.w(TAG, "IME died: " + mCurId, e);
2315             }
2316         }
2317     }
2318 
2319     /**
2320      * Force switch to a new input method component. This can only be called
2321      * from an application or a service which has a token of the currently active input method.
2322      *
2323      * <p>On Android {@link Build.VERSION_CODES#Q} and later devices, the undocumented behavior that
2324      * token can be {@code null} when the caller has
2325      * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} is deprecated. Instead, update
2326      * {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and
2327      * {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p>
2328      *
2329      * @param token Supplies the identifying token given to an input method
2330      * when it was started, which allows it to perform this operation on
2331      * itself.
2332      * @param id The unique identifier for the new input method to be switched to.
2333      * @deprecated Use {@link InputMethodService#switchInputMethod(String)}
2334      * instead. This method was intended for IME developers who should be accessing APIs through
2335      * the service. APIs in this class are intended for app developers interacting with the IME.
2336      */
2337     @Deprecated
setInputMethod(IBinder token, String id)2338     public void setInputMethod(IBinder token, String id) {
2339         if (token == null) {
2340             // There are still some system components that rely on this undocumented behavior
2341             // regarding null IME token with WRITE_SECURE_SETTINGS.  Provide a fallback logic as a
2342             // temporary remedy.
2343             if (id == null) {
2344                 return;
2345             }
2346             if (Process.myUid() == Process.SYSTEM_UID) {
2347                 Log.w(TAG, "System process should not be calling setInputMethod() because almost "
2348                         + "always it is a bug under multi-user / multi-profile environment. "
2349                         + "Consider interacting with InputMethodManagerService directly via "
2350                         + "LocalServices.");
2351                 return;
2352             }
2353             final Context fallbackContext = ActivityThread.currentApplication();
2354             if (fallbackContext == null) {
2355                 return;
2356             }
2357             if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS)
2358                     != PackageManager.PERMISSION_GRANTED) {
2359                 return;
2360             }
2361             final List<InputMethodInfo> imis = getEnabledInputMethodList();
2362             final int numImis = imis.size();
2363             boolean found = false;
2364             for (int i = 0; i < numImis; ++i) {
2365                 final InputMethodInfo imi = imis.get(i);
2366                 if (id.equals(imi.getId())) {
2367                     found = true;
2368                     break;
2369                 }
2370             }
2371             if (!found) {
2372                 Log.e(TAG, "Ignoring setInputMethod(null, " + id + ") because the specified "
2373                         + "id not found in enabled IMEs.");
2374                 return;
2375             }
2376             Log.w(TAG, "The undocumented behavior that setInputMethod() accepts null token "
2377                     + "when the caller has WRITE_SECURE_SETTINGS is deprecated. This behavior may "
2378                     + "be completely removed in a future version.  Update secure settings directly "
2379                     + "instead.");
2380             final ContentResolver resolver = fallbackContext.getContentResolver();
2381             Settings.Secure.putInt(resolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
2382                     NOT_A_SUBTYPE_ID);
2383             Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD, id);
2384             return;
2385         }
2386         InputMethodPrivilegedOperationsRegistry.get(token).setInputMethod(id);
2387     }
2388 
2389     /**
2390      * Force switch to a new input method and subtype. This can only be called
2391      * from an application or a service which has a token of the currently active input method.
2392      *
2393      * <p>On Android {@link Build.VERSION_CODES#Q} and later devices, {@code token} cannot be
2394      * {@code null} even with {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}. Instead,
2395      * update {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and
2396      * {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p>
2397      *
2398      * @param token Supplies the identifying token given to an input method
2399      * when it was started, which allows it to perform this operation on
2400      * itself.
2401      * @param id The unique identifier for the new input method to be switched to.
2402      * @param subtype The new subtype of the new input method to be switched to.
2403      * @deprecated Use
2404      * {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)}
2405      * instead. This method was intended for IME developers who should be accessing APIs through
2406      * the service. APIs in this class are intended for app developers interacting with the IME.
2407      */
2408     @Deprecated
setInputMethodAndSubtype(@onNull IBinder token, String id, InputMethodSubtype subtype)2409     public void setInputMethodAndSubtype(@NonNull IBinder token, String id,
2410             InputMethodSubtype subtype) {
2411         if (token == null) {
2412             Log.e(TAG, "setInputMethodAndSubtype() does not accept null token on Android Q "
2413                     + "and later.");
2414             return;
2415         }
2416         InputMethodPrivilegedOperationsRegistry.get(token).setInputMethodAndSubtype(id, subtype);
2417     }
2418 
2419     /**
2420      * Close/hide the input method's soft input area, so the user no longer
2421      * sees it or can interact with it.  This can only be called
2422      * from the currently active input method, as validated by the given token.
2423      *
2424      * @param token Supplies the identifying token given to an input method
2425      * when it was started, which allows it to perform this operation on
2426      * itself.
2427      * @param flags Provides additional operating flags.  Currently may be
2428      * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
2429      * {@link #HIDE_NOT_ALWAYS} bit set.
2430      * @deprecated Use {@link InputMethodService#requestHideSelf(int)} instead. This method was
2431      * intended for IME developers who should be accessing APIs through the service. APIs in this
2432      * class are intended for app developers interacting with the IME.
2433      */
2434     @Deprecated
hideSoftInputFromInputMethod(IBinder token, int flags)2435     public void hideSoftInputFromInputMethod(IBinder token, int flags) {
2436         InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(flags);
2437     }
2438 
2439     /**
2440      * Show the input method's soft input area, so the user
2441      * sees the input method window and can interact with it.
2442      * This can only be called from the currently active input method,
2443      * as validated by the given token.
2444      *
2445      * @param token Supplies the identifying token given to an input method
2446      * when it was started, which allows it to perform this operation on
2447      * itself.
2448      * @param flags Provides additional operating flags.  Currently may be
2449      * 0 or have the {@link #SHOW_IMPLICIT} or
2450      * {@link #SHOW_FORCED} bit set.
2451      * @deprecated Use {@link InputMethodService#requestShowSelf(int)} instead. This method was
2452      * intended for IME developers who should be accessing APIs through the service. APIs in this
2453      * class are intended for app developers interacting with the IME.
2454      */
2455     @Deprecated
showSoftInputFromInputMethod(IBinder token, int flags)2456     public void showSoftInputFromInputMethod(IBinder token, int flags) {
2457         InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(flags);
2458     }
2459 
2460     /**
2461      * Dispatches an input event to the IME.
2462      *
2463      * Returns {@link #DISPATCH_HANDLED} if the event was handled.
2464      * Returns {@link #DISPATCH_NOT_HANDLED} if the event was not handled.
2465      * Returns {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the
2466      * callback will be invoked later.
2467      *
2468      * @hide
2469      */
dispatchInputEvent(InputEvent event, Object token, FinishedInputEventCallback callback, Handler handler)2470     public int dispatchInputEvent(InputEvent event, Object token,
2471             FinishedInputEventCallback callback, Handler handler) {
2472         synchronized (mH) {
2473             if (mCurMethod != null) {
2474                 if (event instanceof KeyEvent) {
2475                     KeyEvent keyEvent = (KeyEvent)event;
2476                     if (keyEvent.getAction() == KeyEvent.ACTION_DOWN
2477                             && keyEvent.getKeyCode() == KeyEvent.KEYCODE_SYM
2478                             && keyEvent.getRepeatCount() == 0) {
2479                         showInputMethodPickerLocked();
2480                         return DISPATCH_HANDLED;
2481                     }
2482                 }
2483 
2484                 if (DEBUG) Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurMethod);
2485 
2486                 PendingEvent p = obtainPendingEventLocked(
2487                         event, token, mCurId, callback, handler);
2488                 if (mMainLooper.isCurrentThread()) {
2489                     // Already running on the IMM thread so we can send the event immediately.
2490                     return sendInputEventOnMainLooperLocked(p);
2491                 }
2492 
2493                 // Post the event to the IMM thread.
2494                 Message msg = mH.obtainMessage(MSG_SEND_INPUT_EVENT, p);
2495                 msg.setAsynchronous(true);
2496                 mH.sendMessage(msg);
2497                 return DISPATCH_IN_PROGRESS;
2498             }
2499         }
2500         return DISPATCH_NOT_HANDLED;
2501     }
2502 
2503     /**
2504      * Provides the default implementation of {@link InputConnection#sendKeyEvent(KeyEvent)}, which
2505      * is expected to dispatch an keyboard event sent from the IME to an appropriate event target
2506      * depending on the given {@link View} and the current focus state.
2507      *
2508      * <p>CAUTION: This method is provided only for the situation where
2509      * {@link InputConnection#sendKeyEvent(KeyEvent)} needs to be implemented without relying on
2510      * {@link BaseInputConnection}. Do not use this API for anything else.</p>
2511      *
2512      * @param targetView the default target view. If {@code null} is specified, then this method
2513      * tries to find a good event target based on the current focus state.
2514      * @param event the key event to be dispatched.
2515      */
dispatchKeyEventFromInputMethod(@ullable View targetView, @NonNull KeyEvent event)2516     public void dispatchKeyEventFromInputMethod(@Nullable View targetView,
2517             @NonNull KeyEvent event) {
2518         // Re-dispatch if there is a context mismatch.
2519         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(targetView);
2520         if (fallbackImm != null) {
2521             fallbackImm.dispatchKeyEventFromInputMethod(targetView, event);
2522             return;
2523         }
2524 
2525         synchronized (mH) {
2526             ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
2527             if (viewRootImpl == null) {
2528                 if (mServedView != null) {
2529                     viewRootImpl = mServedView.getViewRootImpl();
2530                 }
2531             }
2532             if (viewRootImpl != null) {
2533                 viewRootImpl.dispatchKeyFromIme(event);
2534             }
2535         }
2536     }
2537 
2538     // Must be called on the main looper
sendInputEventAndReportResultOnMainLooper(PendingEvent p)2539     void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
2540         final boolean handled;
2541         synchronized (mH) {
2542             int result = sendInputEventOnMainLooperLocked(p);
2543             if (result == DISPATCH_IN_PROGRESS) {
2544                 return;
2545             }
2546 
2547             handled = (result == DISPATCH_HANDLED);
2548         }
2549 
2550         invokeFinishedInputEventCallback(p, handled);
2551     }
2552 
2553     // Must be called on the main looper
sendInputEventOnMainLooperLocked(PendingEvent p)2554     int sendInputEventOnMainLooperLocked(PendingEvent p) {
2555         if (mCurChannel != null) {
2556             if (mCurSender == null) {
2557                 mCurSender = new ImeInputEventSender(mCurChannel, mH.getLooper());
2558             }
2559 
2560             final InputEvent event = p.mEvent;
2561             final int seq = event.getSequenceNumber();
2562             if (mCurSender.sendInputEvent(seq, event)) {
2563                 mPendingEvents.put(seq, p);
2564                 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER,
2565                         mPendingEvents.size());
2566 
2567                 Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, seq, 0, p);
2568                 msg.setAsynchronous(true);
2569                 mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);
2570                 return DISPATCH_IN_PROGRESS;
2571             }
2572 
2573             Log.w(TAG, "Unable to send input event to IME: "
2574                     + mCurId + " dropping: " + event);
2575         }
2576         return DISPATCH_NOT_HANDLED;
2577     }
2578 
finishedInputEvent(int seq, boolean handled, boolean timeout)2579     void finishedInputEvent(int seq, boolean handled, boolean timeout) {
2580         final PendingEvent p;
2581         synchronized (mH) {
2582             int index = mPendingEvents.indexOfKey(seq);
2583             if (index < 0) {
2584                 return; // spurious, event already finished or timed out
2585             }
2586 
2587             p = mPendingEvents.valueAt(index);
2588             mPendingEvents.removeAt(index);
2589             Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, mPendingEvents.size());
2590 
2591             if (timeout) {
2592                 Log.w(TAG, "Timeout waiting for IME to handle input event after "
2593                         + INPUT_METHOD_NOT_RESPONDING_TIMEOUT + " ms: " + p.mInputMethodId);
2594             } else {
2595                 mH.removeMessages(MSG_TIMEOUT_INPUT_EVENT, p);
2596             }
2597         }
2598 
2599         invokeFinishedInputEventCallback(p, handled);
2600     }
2601 
2602     // Assumes the event has already been removed from the queue.
invokeFinishedInputEventCallback(PendingEvent p, boolean handled)2603     void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
2604         p.mHandled = handled;
2605         if (p.mHandler.getLooper().isCurrentThread()) {
2606             // Already running on the callback handler thread so we can send the
2607             // callback immediately.
2608             p.run();
2609         } else {
2610             // Post the event to the callback handler thread.
2611             // In this case, the callback will be responsible for recycling the event.
2612             Message msg = Message.obtain(p.mHandler, p);
2613             msg.setAsynchronous(true);
2614             msg.sendToTarget();
2615         }
2616     }
2617 
flushPendingEventsLocked()2618     private void flushPendingEventsLocked() {
2619         mH.removeMessages(MSG_FLUSH_INPUT_EVENT);
2620 
2621         final int count = mPendingEvents.size();
2622         for (int i = 0; i < count; i++) {
2623             int seq = mPendingEvents.keyAt(i);
2624             Message msg = mH.obtainMessage(MSG_FLUSH_INPUT_EVENT, seq, 0);
2625             msg.setAsynchronous(true);
2626             msg.sendToTarget();
2627         }
2628     }
2629 
obtainPendingEventLocked(InputEvent event, Object token, String inputMethodId, FinishedInputEventCallback callback, Handler handler)2630     private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
2631             String inputMethodId, FinishedInputEventCallback callback, Handler handler) {
2632         PendingEvent p = mPendingEventPool.acquire();
2633         if (p == null) {
2634             p = new PendingEvent();
2635         }
2636         p.mEvent = event;
2637         p.mToken = token;
2638         p.mInputMethodId = inputMethodId;
2639         p.mCallback = callback;
2640         p.mHandler = handler;
2641         return p;
2642     }
2643 
recyclePendingEventLocked(PendingEvent p)2644     private void recyclePendingEventLocked(PendingEvent p) {
2645         p.recycle();
2646         mPendingEventPool.release(p);
2647     }
2648 
2649     /**
2650      * Show IME picker popup window.
2651      *
2652      * <p>Requires the {@link PackageManager#FEATURE_INPUT_METHODS} feature which can be detected
2653      * using {@link PackageManager#hasSystemFeature(String)}.
2654      */
showInputMethodPicker()2655     public void showInputMethodPicker() {
2656         synchronized (mH) {
2657             showInputMethodPickerLocked();
2658         }
2659     }
2660 
2661     /**
2662      * Shows the input method chooser dialog from system.
2663      *
2664      * @param showAuxiliarySubtypes Set true to show auxiliary input methods.
2665      * @param displayId The ID of the display where the chooser dialog should be shown.
2666      * @hide
2667      */
2668     @RequiresPermission(WRITE_SECURE_SETTINGS)
showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId)2669     public void showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId) {
2670         final int mode = showAuxiliarySubtypes
2671                 ? SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES
2672                 : SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
2673         try {
2674             mService.showInputMethodPickerFromSystem(mClient, mode, displayId);
2675         } catch (RemoteException e) {
2676             throw e.rethrowFromSystemServer();
2677         }
2678     }
2679 
showInputMethodPickerLocked()2680     private void showInputMethodPickerLocked() {
2681         try {
2682             mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
2683         } catch (RemoteException e) {
2684             throw e.rethrowFromSystemServer();
2685         }
2686     }
2687 
2688     /**
2689      * A test API for CTS to make sure that {@link #showInputMethodPicker()} works as expected.
2690      *
2691      * <p>When customizing the implementation of {@link #showInputMethodPicker()} API, make sure
2692      * that this test API returns when and only while and only while
2693      * {@link #showInputMethodPicker()} is showing UI. Otherwise your OS implementation may not
2694      * pass CTS.</p>
2695      *
2696      * @return {@code true} while and only while {@link #showInputMethodPicker()} is showing UI.
2697      * @hide
2698      */
2699     @TestApi
isInputMethodPickerShown()2700     public boolean isInputMethodPickerShown() {
2701         try {
2702             return mService.isInputMethodPickerShownForTest();
2703         } catch (RemoteException e) {
2704             throw e.rethrowFromSystemServer();
2705         }
2706     }
2707 
2708     /**
2709      * Show the settings for enabling subtypes of the specified input method.
2710      * @param imiId An input method, whose subtypes settings will be shown. If imiId is null,
2711      * subtypes of all input methods will be shown.
2712      */
showInputMethodAndSubtypeEnabler(String imiId)2713     public void showInputMethodAndSubtypeEnabler(String imiId) {
2714         try {
2715             mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
2716         } catch (RemoteException e) {
2717             throw e.rethrowFromSystemServer();
2718         }
2719     }
2720 
2721     /**
2722      * Returns the current input method subtype. This subtype is one of the subtypes in
2723      * the current input method. This method returns null when the current input method doesn't
2724      * have any input method subtype.
2725      */
getCurrentInputMethodSubtype()2726     public InputMethodSubtype getCurrentInputMethodSubtype() {
2727         try {
2728             return mService.getCurrentInputMethodSubtype();
2729         } catch (RemoteException e) {
2730             throw e.rethrowFromSystemServer();
2731         }
2732     }
2733 
2734     /**
2735      * Switch to a new input method subtype of the current input method.
2736      * @param subtype A new input method subtype to switch.
2737      * @return true if the current subtype was successfully switched. When the specified subtype is
2738      * null, this method returns false.
2739      * @deprecated If the calling process is an IME, use
2740      *             {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)}, which
2741      *             does not require any permission as long as the caller is the current IME.
2742      *             If the calling process is some privileged app that already has
2743      *             {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission, just
2744      *             directly update {@link Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE}.
2745      */
2746     @Deprecated
2747     @RequiresPermission(WRITE_SECURE_SETTINGS)
setCurrentInputMethodSubtype(InputMethodSubtype subtype)2748     public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
2749         if (Process.myUid() == Process.SYSTEM_UID) {
2750             Log.w(TAG, "System process should not call setCurrentInputMethodSubtype() because "
2751                     + "almost always it is a bug under multi-user / multi-profile environment. "
2752                     + "Consider directly interacting with InputMethodManagerService "
2753                     + "via LocalServices.");
2754             return false;
2755         }
2756         if (subtype == null) {
2757             // See the JavaDoc. This is how this method has worked.
2758             return false;
2759         }
2760         final Context fallbackContext = ActivityThread.currentApplication();
2761         if (fallbackContext == null) {
2762             return false;
2763         }
2764         if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS)
2765                 != PackageManager.PERMISSION_GRANTED) {
2766             return false;
2767         }
2768         final ContentResolver contentResolver = fallbackContext.getContentResolver();
2769         final String imeId = Settings.Secure.getString(contentResolver,
2770                 Settings.Secure.DEFAULT_INPUT_METHOD);
2771         if (ComponentName.unflattenFromString(imeId) == null) {
2772             // Null or invalid IME ID format.
2773             return false;
2774         }
2775         final List<InputMethodSubtype> enabledSubtypes;
2776         try {
2777             enabledSubtypes = mService.getEnabledInputMethodSubtypeList(imeId, true);
2778         } catch (RemoteException e) {
2779             return false;
2780         }
2781         final int numSubtypes = enabledSubtypes.size();
2782         for (int i = 0; i < numSubtypes; ++i) {
2783             final InputMethodSubtype enabledSubtype = enabledSubtypes.get(i);
2784             if (enabledSubtype.equals(subtype)) {
2785                 Settings.Secure.putInt(contentResolver,
2786                         Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, enabledSubtype.hashCode());
2787                 return true;
2788             }
2789         }
2790         return false;
2791     }
2792 
2793     /**
2794      * Notify that a user took some action with this input method.
2795      *
2796      * @deprecated Just kept to avoid possible app compat issue.
2797      * @hide
2798      */
2799     @Deprecated
2800     @UnsupportedAppUsage(trackingBug = 114740982, maxTargetSdk = Build.VERSION_CODES.P)
notifyUserAction()2801     public void notifyUserAction() {
2802         Log.w(TAG, "notifyUserAction() is a hidden method, which is now just a stub method"
2803                 + " that does nothing.  Leave comments in b.android.com/114740982 if your "
2804                 + " application still depends on the previous behavior of this method.");
2805     }
2806 
2807     /**
2808      * Returns a map of all shortcut input method info and their subtypes.
2809      */
getShortcutInputMethodsAndSubtypes()2810     public Map<InputMethodInfo, List<InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() {
2811         final List<InputMethodInfo> enabledImes = getEnabledInputMethodList();
2812 
2813         // Ensure we check system IMEs first.
2814         enabledImes.sort(Comparator.comparingInt(imi -> imi.isSystem() ? 0 : 1));
2815 
2816         final int numEnabledImes = enabledImes.size();
2817         for (int imiIndex = 0; imiIndex < numEnabledImes; ++imiIndex) {
2818             final InputMethodInfo imi = enabledImes.get(imiIndex);
2819             final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeList(
2820                     imi, true);
2821             final int subtypeCount = subtypes.size();
2822             for (int subtypeIndex = 0; subtypeIndex < subtypeCount; ++subtypeIndex) {
2823                 final InputMethodSubtype subtype = imi.getSubtypeAt(subtypeIndex);
2824                 if (SUBTYPE_MODE_VOICE.equals(subtype.getMode())) {
2825                     return Collections.singletonMap(imi, Collections.singletonList(subtype));
2826                 }
2827             }
2828         }
2829         return Collections.emptyMap();
2830     }
2831 
2832     /**
2833      * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage}.
2834      *
2835      * <p>TODO(Bug 113914148): Check if we can remove this.  We have accidentally exposed
2836      * WindowManagerInternal#getInputMethodWindowVisibleHeight to app developers and some of them
2837      * started relying on it.</p>
2838      *
2839      * @return Something that is not well-defined.
2840      * @hide
2841      */
2842     @UnsupportedAppUsage
getInputMethodWindowVisibleHeight()2843     public int getInputMethodWindowVisibleHeight() {
2844         try {
2845             return mService.getInputMethodWindowVisibleHeight();
2846         } catch (RemoteException e) {
2847             throw e.rethrowFromSystemServer();
2848         }
2849     }
2850 
2851     /**
2852      * An internal API for {@link android.app.ActivityView} to report where its embedded virtual
2853      * display is placed.
2854      *
2855      * @param childDisplayId Display ID of the embedded virtual display.
2856      * @param matrix {@link Matrix} to convert virtual display screen coordinates to
2857      *               the host screen coordinates. {@code null} to clear the relationship.
2858      * @hide
2859      */
reportActivityView(int childDisplayId, @Nullable Matrix matrix)2860     public void reportActivityView(int childDisplayId, @Nullable Matrix matrix) {
2861         try {
2862             final float[] matrixValues;
2863             if (matrix == null) {
2864                 matrixValues = null;
2865             } else {
2866                 matrixValues = new float[9];
2867                 matrix.getValues(matrixValues);
2868             }
2869             mService.reportActivityView(mClient, childDisplayId, matrixValues);
2870         } catch (RemoteException e) {
2871             throw e.rethrowFromSystemServer();
2872         }
2873     }
2874 
2875     /**
2876      * Force switch to the last used input method and subtype. If the last input method didn't have
2877      * any subtypes, the framework will simply switch to the last input method with no subtype
2878      * specified.
2879      * @param imeToken Supplies the identifying token given to an input method when it was started,
2880      * which allows it to perform this operation on itself.
2881      * @return true if the current input method and subtype was successfully switched to the last
2882      * used input method and subtype.
2883      * @deprecated Use {@link InputMethodService#switchToPreviousInputMethod()} instead. This method
2884      * was intended for IME developers who should be accessing APIs through the service. APIs in
2885      * this class are intended for app developers interacting with the IME.
2886      */
2887     @Deprecated
switchToLastInputMethod(IBinder imeToken)2888     public boolean switchToLastInputMethod(IBinder imeToken) {
2889         return InputMethodPrivilegedOperationsRegistry.get(imeToken).switchToPreviousInputMethod();
2890     }
2891 
2892     /**
2893      * Force switch to the next input method and subtype. If there is no IME enabled except
2894      * current IME and subtype, do nothing.
2895      * @param imeToken Supplies the identifying token given to an input method when it was started,
2896      * which allows it to perform this operation on itself.
2897      * @param onlyCurrentIme if true, the framework will find the next subtype which
2898      * belongs to the current IME
2899      * @return true if the current input method and subtype was successfully switched to the next
2900      * input method and subtype.
2901      * @deprecated Use {@link InputMethodService#switchToNextInputMethod(boolean)} instead. This
2902      * method was intended for IME developers who should be accessing APIs through the service.
2903      * APIs in this class are intended for app developers interacting with the IME.
2904      */
2905     @Deprecated
switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme)2906     public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
2907         return InputMethodPrivilegedOperationsRegistry.get(imeToken)
2908                 .switchToNextInputMethod(onlyCurrentIme);
2909     }
2910 
2911     /**
2912      * Returns true if the current IME needs to offer the users ways to switch to a next input
2913      * method (e.g. a globe key.).
2914      * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
2915      * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
2916      * <p> Note that the system determines the most appropriate next input method
2917      * and subtype in order to provide the consistent user experience in switching
2918      * between IMEs and subtypes.
2919      * @param imeToken Supplies the identifying token given to an input method when it was started,
2920      * which allows it to perform this operation on itself.
2921      * @deprecated Use {@link InputMethodService#shouldOfferSwitchingToNextInputMethod()}
2922      * instead. This method was intended for IME developers who should be accessing APIs through
2923      * the service. APIs in this class are intended for app developers interacting with the IME.
2924      */
2925     @Deprecated
shouldOfferSwitchingToNextInputMethod(IBinder imeToken)2926     public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
2927         return InputMethodPrivilegedOperationsRegistry.get(imeToken)
2928                 .shouldOfferSwitchingToNextInputMethod();
2929     }
2930 
2931     /**
2932      * Set additional input method subtypes. Only a process which shares the same uid with the IME
2933      * can add additional input method subtypes to the IME.
2934      * Please note that a subtype's status is stored in the system.
2935      * For example, enabled subtypes are remembered by the framework even after they are removed
2936      * by using this method. If you re-add the same subtypes again,
2937      * they will just get enabled. If you want to avoid such conflicts, for instance, you may
2938      * want to create a "different" new subtype even with the same locale and mode,
2939      * by changing its extra value. The different subtype won't get affected by the stored past
2940      * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer
2941      * to the current implementation.)
2942      *
2943      * <p>NOTE: If the same subtype exists in both the manifest XML file and additional subtypes
2944      * specified by {@code subtypes}, those multiple instances are automatically merged into one
2945      * instance.</p>
2946      *
2947      * <p>CAVEAT: In API Level 23 and prior, the system may do nothing if an empty
2948      * {@link InputMethodSubtype} is specified in {@code subtypes}, which prevents you from removing
2949      * the last one entry of additional subtypes. If your IME statically defines one or more
2950      * subtypes in the manifest XML file, you may be able to work around this limitation by
2951      * specifying one of those statically defined subtypes in {@code subtypes}.</p>
2952      *
2953      * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
2954      * @param subtypes subtypes will be added as additional subtypes of the current input method.
2955      * @deprecated For IMEs that have already implemented features like customizable/downloadable
2956      *             keyboard layouts/languages, please start migration to other approaches. One idea
2957      *             would be exposing only one unified {@link InputMethodSubtype} then implement
2958      *             IME's own language switching mechanism within that unified subtype. The support
2959      *             of "Additional Subtype" may be completely dropped in a future version of Android.
2960      */
2961     @Deprecated
setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes)2962     public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
2963         try {
2964             mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
2965         } catch (RemoteException e) {
2966             throw e.rethrowFromSystemServer();
2967         }
2968     }
2969 
getLastInputMethodSubtype()2970     public InputMethodSubtype getLastInputMethodSubtype() {
2971         try {
2972             return mService.getLastInputMethodSubtype();
2973         } catch (RemoteException e) {
2974             throw e.rethrowFromSystemServer();
2975         }
2976     }
2977 
maybeCallServedViewChangedLocked(EditorInfo tba)2978     private void maybeCallServedViewChangedLocked(EditorInfo tba) {
2979         if (mImeInsetsConsumer != null) {
2980             mImeInsetsConsumer.onServedEditorChanged(tba);
2981         }
2982     }
2983 
2984     /**
2985      * <p>This is used for CTS test only. Do not use this method outside of CTS package.<p/>
2986      * @return the ID of this display which this {@link InputMethodManager} resides
2987      * @hide
2988      */
2989     @TestApi
getDisplayId()2990     public int getDisplayId() {
2991         return mDisplayId;
2992     }
2993 
doDump(FileDescriptor fd, PrintWriter fout, String[] args)2994     void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
2995         final Printer p = new PrintWriterPrinter(fout);
2996         p.println("Input method client state for " + this + ":");
2997 
2998         p.println("  mService=" + mService);
2999         p.println("  mMainLooper=" + mMainLooper);
3000         p.println("  mIInputContext=" + mIInputContext);
3001         p.println("  mActive=" + mActive
3002                 + " mRestartOnNextWindowFocus=" + mRestartOnNextWindowFocus
3003                 + " mBindSequence=" + mBindSequence
3004                 + " mCurId=" + mCurId);
3005         p.println("  mFullscreenMode=" + mFullscreenMode);
3006         p.println("  mCurMethod=" + mCurMethod);
3007         p.println("  mCurRootView=" + mCurRootView);
3008         p.println("  mServedView=" + mServedView);
3009         p.println("  mNextServedView=" + mNextServedView);
3010         p.println("  mServedConnecting=" + mServedConnecting);
3011         if (mCurrentTextBoxAttribute != null) {
3012             p.println("  mCurrentTextBoxAttribute:");
3013             mCurrentTextBoxAttribute.dump(p, "    ");
3014         } else {
3015             p.println("  mCurrentTextBoxAttribute: null");
3016         }
3017         p.println("  mServedInputConnectionWrapper=" + mServedInputConnectionWrapper);
3018         p.println("  mCompletions=" + Arrays.toString(mCompletions));
3019         p.println("  mCursorRect=" + mCursorRect);
3020         p.println("  mCursorSelStart=" + mCursorSelStart
3021                 + " mCursorSelEnd=" + mCursorSelEnd
3022                 + " mCursorCandStart=" + mCursorCandStart
3023                 + " mCursorCandEnd=" + mCursorCandEnd);
3024     }
3025 
3026     /**
3027      * Callback that is invoked when an input event that was dispatched to
3028      * the IME has been finished.
3029      * @hide
3030      */
3031     public interface FinishedInputEventCallback {
onFinishedInputEvent(Object token, boolean handled)3032         public void onFinishedInputEvent(Object token, boolean handled);
3033     }
3034 
3035     private final class ImeInputEventSender extends InputEventSender {
ImeInputEventSender(InputChannel inputChannel, Looper looper)3036         public ImeInputEventSender(InputChannel inputChannel, Looper looper) {
3037             super(inputChannel, looper);
3038         }
3039 
3040         @Override
onInputEventFinished(int seq, boolean handled)3041         public void onInputEventFinished(int seq, boolean handled) {
3042             finishedInputEvent(seq, handled, false);
3043         }
3044     }
3045 
3046     private final class PendingEvent implements Runnable {
3047         public InputEvent mEvent;
3048         public Object mToken;
3049         public String mInputMethodId;
3050         public FinishedInputEventCallback mCallback;
3051         public Handler mHandler;
3052         public boolean mHandled;
3053 
recycle()3054         public void recycle() {
3055             mEvent = null;
3056             mToken = null;
3057             mInputMethodId = null;
3058             mCallback = null;
3059             mHandler = null;
3060             mHandled = false;
3061         }
3062 
3063         @Override
run()3064         public void run() {
3065             mCallback.onFinishedInputEvent(mToken, mHandled);
3066 
3067             synchronized (mH) {
3068                 recyclePendingEventLocked(this);
3069             }
3070         }
3071     }
3072 
dumpViewInfo(@ullable final View view)3073     private static String dumpViewInfo(@Nullable final View view) {
3074         if (view == null) {
3075             return "null";
3076         }
3077         final StringBuilder sb = new StringBuilder();
3078         sb.append(view);
3079         sb.append(",focus=" + view.hasFocus());
3080         sb.append(",windowFocus=" + view.hasWindowFocus());
3081         sb.append(",autofillUiShowing=" + isAutofillUIShowing(view));
3082         sb.append(",window=" + view.getWindowToken());
3083         sb.append(",displayId=" + view.getContext().getDisplayId());
3084         sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
3085         return sb.toString();
3086     }
3087 }
3088