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.os.Trace.TRACE_TAG_WINDOW_MANAGER;
20 import static android.view.inputmethod.InputConnection.CURSOR_UPDATE_IMMEDIATE;
21 import static android.view.inputmethod.InputConnection.CURSOR_UPDATE_MONITOR;
22 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.DISPLAY_ID;
23 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.EDITOR_INFO;
24 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER;
25 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION;
26 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION_CALL;
27 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_METHOD_MANAGER;
28 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.VIEW_ROOT_IMPL;
29 import static android.view.inputmethod.InputMethodManagerProto.ACTIVE;
30 import static android.view.inputmethod.InputMethodManagerProto.CUR_ID;
31 import static android.view.inputmethod.InputMethodManagerProto.FULLSCREEN_MODE;
32 import static android.view.inputmethod.InputMethodManagerProto.NEXT_SERVED_VIEW;
33 import static android.view.inputmethod.InputMethodManagerProto.SERVED_CONNECTING;
34 import static android.view.inputmethod.InputMethodManagerProto.SERVED_VIEW;
35 
36 import static com.android.internal.inputmethod.StartInputReason.BOUND_TO_IMMS;
37 
38 import android.Manifest;
39 import android.annotation.DisplayContext;
40 import android.annotation.DrawableRes;
41 import android.annotation.DurationMillisLong;
42 import android.annotation.IntDef;
43 import android.annotation.NonNull;
44 import android.annotation.Nullable;
45 import android.annotation.RequiresFeature;
46 import android.annotation.RequiresPermission;
47 import android.annotation.SuppressLint;
48 import android.annotation.SystemApi;
49 import android.annotation.SystemService;
50 import android.annotation.TestApi;
51 import android.annotation.UiThread;
52 import android.annotation.UserIdInt;
53 import android.app.ActivityThread;
54 import android.app.PropertyInvalidatedCache;
55 import android.compat.annotation.ChangeId;
56 import android.compat.annotation.EnabledSince;
57 import android.compat.annotation.UnsupportedAppUsage;
58 import android.content.ComponentName;
59 import android.content.ContentResolver;
60 import android.content.Context;
61 import android.content.Intent;
62 import android.content.pm.PackageManager;
63 import android.graphics.Matrix;
64 import android.graphics.Rect;
65 import android.hardware.display.DisplayManager;
66 import android.inputmethodservice.InputMethodService;
67 import android.os.Binder;
68 import android.os.Build;
69 import android.os.Bundle;
70 import android.os.Handler;
71 import android.os.IBinder;
72 import android.os.Looper;
73 import android.os.Message;
74 import android.os.Process;
75 import android.os.ResultReceiver;
76 import android.os.SystemProperties;
77 import android.os.Trace;
78 import android.os.UserHandle;
79 import android.provider.Settings;
80 import android.text.TextUtils;
81 import android.text.style.SuggestionSpan;
82 import android.util.Log;
83 import android.util.Pair;
84 import android.util.Pools.Pool;
85 import android.util.Pools.SimplePool;
86 import android.util.PrintWriterPrinter;
87 import android.util.Printer;
88 import android.util.SparseArray;
89 import android.util.proto.ProtoOutputStream;
90 import android.view.Display;
91 import android.view.ImeFocusController;
92 import android.view.ImeInsetsSourceConsumer;
93 import android.view.InputChannel;
94 import android.view.InputEvent;
95 import android.view.InputEventSender;
96 import android.view.KeyEvent;
97 import android.view.View;
98 import android.view.ViewRootImpl;
99 import android.view.WindowInsets;
100 import android.view.WindowManager;
101 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
102 import android.view.autofill.AutofillId;
103 import android.view.autofill.AutofillManager;
104 import android.widget.Editor;
105 import android.window.ImeOnBackInvokedDispatcher;
106 import android.window.WindowOnBackInvokedDispatcher;
107 
108 import com.android.internal.annotations.GuardedBy;
109 import com.android.internal.inputmethod.DirectBootAwareness;
110 import com.android.internal.inputmethod.IInputMethodClient;
111 import com.android.internal.inputmethod.IInputMethodSession;
112 import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
113 import com.android.internal.inputmethod.ImeTracing;
114 import com.android.internal.inputmethod.InputBindResult;
115 import com.android.internal.inputmethod.InputMethodDebug;
116 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
117 import com.android.internal.inputmethod.SoftInputShowHideReason;
118 import com.android.internal.inputmethod.StartInputFlags;
119 import com.android.internal.inputmethod.StartInputReason;
120 import com.android.internal.inputmethod.UnbindReason;
121 import com.android.internal.os.SomeArgs;
122 import com.android.internal.view.IInputMethodManager;
123 
124 import java.io.FileDescriptor;
125 import java.io.PrintWriter;
126 import java.lang.annotation.Retention;
127 import java.lang.annotation.RetentionPolicy;
128 import java.lang.reflect.Proxy;
129 import java.util.Arrays;
130 import java.util.Collections;
131 import java.util.Comparator;
132 import java.util.List;
133 import java.util.Map;
134 import java.util.Objects;
135 import java.util.concurrent.CountDownLatch;
136 import java.util.concurrent.TimeUnit;
137 import java.util.concurrent.atomic.AtomicBoolean;
138 import java.util.function.Consumer;
139 
140 /**
141  * Central system API to the overall input method framework (IMF) architecture,
142  * which arbitrates interaction between applications and the current input method.
143  *
144  * <p>Topics covered here:
145  * <ol>
146  * <li><a href="#ArchitectureOverview">Architecture Overview</a>
147  * <li><a href="#Applications">Applications</a>
148  * <li><a href="#InputMethods">Input Methods</a>
149  * <li><a href="#Security">Security</a>
150  * </ol>
151  *
152  * <a name="ArchitectureOverview"></a>
153  * <h3>Architecture Overview</h3>
154  *
155  * <p>There are three primary parties involved in the input method
156  * framework (IMF) architecture:</p>
157  *
158  * <ul>
159  * <li> The <strong>input method manager</strong> as expressed by this class
160  * is the central point of the system that manages interaction between all
161  * other parts.  It is expressed as the client-side API here which exists
162  * in each application context and communicates with a global system service
163  * that manages the interaction across all processes.
164  * <li> An <strong>input method (IME)</strong> implements a particular
165  * interaction model allowing the user to generate text.  The system binds
166  * to the current input method that is in use, causing it to be created and run,
167  * and tells it when to hide and show its UI.  Only one IME is running at a time.
168  * <li> Multiple <strong>client applications</strong> arbitrate with the input
169  * method manager for input focus and control over the state of the IME.  Only
170  * one such client is ever active (working with the IME) at a time.
171  * </ul>
172  *
173  *
174  * <a name="Applications"></a>
175  * <h3>Applications</h3>
176  *
177  * <p>In most cases, applications that are using the standard
178  * {@link android.widget.TextView} or its subclasses will have little they need
179  * to do to work well with soft input methods.  The main things you need to
180  * be aware of are:</p>
181  *
182  * <ul>
183  * <li> Properly set the {@link android.R.attr#inputType} in your editable
184  * text views, so that the input method will have enough context to help the
185  * user in entering text into them.
186  * <li> Deal well with losing screen space when the input method is
187  * displayed.  Ideally an application should handle its window being resized
188  * smaller, but it can rely on the system performing panning of the window
189  * if needed.  You should set the {@link android.R.attr#windowSoftInputMode}
190  * attribute on your activity or the corresponding values on windows you
191  * create to help the system determine whether to pan or resize (it will
192  * try to determine this automatically but may get it wrong).
193  * <li> You can also control the preferred soft input state (open, closed, etc)
194  * for your window using the same {@link android.R.attr#windowSoftInputMode}
195  * attribute.
196  * </ul>
197  *
198  * <p>More finer-grained control is available through the APIs here to directly
199  * interact with the IMF and its IME -- either showing or hiding the input
200  * area, letting the user pick an input method, etc.</p>
201  *
202  * <p>For the rare people amongst us writing their own text editors, you
203  * will need to implement {@link android.view.View#onCreateInputConnection}
204  * to return a new instance of your own {@link InputConnection} interface
205  * allowing the IME to interact with your editor.</p>
206  *
207  *
208  * <a name="InputMethods"></a>
209  * <h3>Input Methods</h3>
210  *
211  * <p>An input method (IME) is implemented
212  * as a {@link android.app.Service}, typically deriving from
213  * {@link android.inputmethodservice.InputMethodService}.  It must provide
214  * the core {@link InputMethod} interface, though this is normally handled by
215  * {@link android.inputmethodservice.InputMethodService} and implementors will
216  * only need to deal with the higher-level API there.</p>
217  *
218  * See the {@link android.inputmethodservice.InputMethodService} class for
219  * more information on implementing IMEs.
220  *
221  *
222  * <a name="Security"></a>
223  * <h3>Security</h3>
224  *
225  * <p>There are a lot of security issues associated with input methods,
226  * since they essentially have freedom to completely drive the UI and monitor
227  * everything the user enters.  The Android input method framework also allows
228  * arbitrary third party IMEs, so care must be taken to restrict their
229  * selection and interactions.</p>
230  *
231  * <p>Here are some key points about the security architecture behind the
232  * IMF:</p>
233  *
234  * <ul>
235  * <li> <p>Only the system is allowed to directly access an IME's
236  * {@link InputMethod} interface, via the
237  * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission.  This is
238  * enforced in the system by not binding to an input method service that does
239  * not require this permission, so the system can guarantee no other untrusted
240  * clients are accessing the current input method outside of its control.</p>
241  *
242  * <li> <p>There may be many client processes of the IMF, but only one may
243  * be active at a time.  The inactive clients can not interact with key
244  * parts of the IMF through the mechanisms described below.</p>
245  *
246  * <li> <p>Clients of an input method are only given access to its
247  * {@link InputMethodSession} interface.  One instance of this interface is
248  * created for each client, and only calls from the session associated with
249  * the active client will be processed by the current IME.  This is enforced
250  * by {@link android.inputmethodservice.AbstractInputMethodService} for normal
251  * IMEs, but must be explicitly handled by an IME that is customizing the
252  * raw {@link InputMethodSession} implementation.</p>
253  *
254  * <li> <p>Only the active client's {@link InputConnection} will accept
255  * operations.  The IMF tells each client process whether it is active, and
256  * the framework enforces that in inactive processes calls on to the current
257  * InputConnection will be ignored.  This ensures that the current IME can
258  * only deliver events and text edits to the UI that the user sees as
259  * being in focus.</p>
260  *
261  * <li> <p>An IME can never interact with an {@link InputConnection} while
262  * the screen is off.  This is enforced by making all clients inactive while
263  * the screen is off, and prevents bad IMEs from driving the UI when the user
264  * can not be aware of its behavior.</p>
265  *
266  * <li> <p>A client application can ask that the system let the user pick a
267  * new IME, but can not programmatically switch to one itself.  This avoids
268  * malicious applications from switching the user to their own IME, which
269  * remains running when the user navigates away to another application.  An
270  * IME, on the other hand, <em>is</em> allowed to programmatically switch
271  * the system to another IME, since it already has full control of user
272  * input.</p>
273  *
274  * <li> <p>The user must explicitly enable a new IME in settings before
275  * they can switch to it, to confirm with the system that they know about it
276  * and want to make it available for use.</p>
277  * </ul>
278  *
279  * <p>If your app targets Android 11 (API level 30) or higher, the methods in
280  * this class each return a filtered result by the rules of
281  * <a href="/training/basics/intents/package-visibility">package visibility</a>,
282  * except for the currently connected IME. Apps having a query for the
283  * {@link InputMethod#SERVICE_INTERFACE} see all IMEs.</p>
284  */
285 @SystemService(Context.INPUT_METHOD_SERVICE)
286 @RequiresFeature(PackageManager.FEATURE_INPUT_METHODS)
287 public final class InputMethodManager {
288     private static final boolean DEBUG = false;
289     private static final String TAG = "InputMethodManager";
290 
291     private static final String PENDING_EVENT_COUNTER = "aq:imm";
292 
293     private static final int NOT_A_SUBTYPE_ID = -1;
294 
295     /**
296      * A constant that represents Voice IME.
297      *
298      * @see InputMethodSubtype#getMode()
299      */
300     private static final String SUBTYPE_MODE_VOICE = "voice";
301 
302     /**
303      * Provide this to {@link IInputMethodManagerGlobalInvoker#startInputOrWindowGainedFocus(int,
304      * IInputMethodClient, IBinder, int, int, int, EditorInfo,
305      * com.android.internal.inputmethod.IRemoteInputConnection, IRemoteAccessibilityInputConnection,
306      * int, int, ImeOnBackInvokedDispatcher)} to receive
307      * {@link android.window.OnBackInvokedCallback} registrations from IME.
308      */
309     private final ImeOnBackInvokedDispatcher mImeDispatcher =
310             new ImeOnBackInvokedDispatcher(Handler.getMain()) {
311         @Override
312         public WindowOnBackInvokedDispatcher getReceivingDispatcher() {
313             synchronized (mH) {
314                 return mCurRootView != null ? mCurRootView.getOnBackInvokedDispatcher() : null;
315             }
316         }
317     };
318 
319     /**
320      * Ensures that {@link #sInstance} becomes non-{@code null} for application that have directly
321      * or indirectly relied on {@link #sInstance} via reflection or something like that.
322      *
323      * <p>Here are scenarios we know and there could be more scenarios we are not
324      * aware of right know.</p>
325      *
326      * <ul>
327      *     <li>Apps that directly access {@link #sInstance} via reflection, which is currently
328      *     allowed because of {@link UnsupportedAppUsage} annotation.  Currently
329      *     {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that
330      *     {@link #sInstance} is not {@code null} when such an app is accessing it, but removing
331      *     that code from {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal
332      *     untested code paths in their apps, which probably happen in an early startup time of that
333      *     app.</li>
334      *     <li>Apps that directly access {@link #peekInstance()} via reflection, which is currently
335      *     allowed because of {@link UnsupportedAppUsage} annotation.  Currently
336      *     {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that
337      *     {@link #peekInstance()} returns non-{@code null} object when such an app is calling
338      *     {@link #peekInstance()}, but removing that code from
339      *     {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal untested code
340      *     paths in their apps, which probably happen in an early startup time of that app. The good
341      *     news is that unlike {@link #sInstance}'s case we can at least work around this scenario
342      *     by changing the semantics of {@link #peekInstance()}, which is currently defined as
343      *     "retrieve the global {@link InputMethodManager} instance, if it exists" to something that
344      *     always returns non-{@code null} {@link InputMethodManager}.  However, introducing such an
345      *     workaround can also trigger different compatibility issues if {@link #peekInstance()} was
346      *     called before {@link android.view.WindowManagerGlobal#getWindowSession()} and it expected
347      *     {@link #peekInstance()} to return {@code null} as written in the JavaDoc.</li>
348      * </ul>
349      *
350      * <p>Since this is purely a compatibility hack, this method must be used only from
351      * {@link android.view.WindowManagerGlobal#getWindowSession()} and {@link #getInstance()}.</p>
352      *
353      * <p>TODO(Bug 116157766): Remove this method once we clean up {@link UnsupportedAppUsage}.</p>
354      * @hide
355      */
ensureDefaultInstanceForDefaultDisplayIfNecessary()356     public static void ensureDefaultInstanceForDefaultDisplayIfNecessary() {
357         forContextInternal(Display.DEFAULT_DISPLAY, Looper.getMainLooper());
358     }
359 
360     private static final Object sLock = new Object();
361 
362     /**
363      * @deprecated This cannot be compatible with multi-display. Please do not use this.
364      */
365     @Deprecated
366     @GuardedBy("sLock")
367     @UnsupportedAppUsage
368     static InputMethodManager sInstance;
369 
370     /**
371      * Global map between display to {@link InputMethodManager}.
372      *
373      * <p>Currently this map works like a so-called leaky singleton.  Once an instance is registered
374      * for the associated display ID, that instance will never be garbage collected.</p>
375      *
376      * <p>TODO(Bug 116699479): Implement instance clean up mechanism.</p>
377      */
378     @GuardedBy("sLock")
379     private static final SparseArray<InputMethodManager> sInstanceMap = new SparseArray<>();
380 
381     /**
382      * Timeout in milliseconds for delivering a key to an IME.
383      */
384     private static final long INPUT_METHOD_NOT_RESPONDING_TIMEOUT = 2500;
385 
386     /** @hide */
387     public static final int DISPATCH_IN_PROGRESS = -1;
388 
389     /** @hide */
390     public static final int DISPATCH_NOT_HANDLED = 0;
391 
392     /** @hide */
393     public static final int DISPATCH_HANDLED = 1;
394 
395     /** @hide */
396     public static final int SHOW_IM_PICKER_MODE_AUTO = 0;
397     /** @hide */
398     public static final int SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES = 1;
399     /** @hide */
400     public static final int SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES = 2;
401 
402     /**
403      * Clear {@link #SHOW_FORCED} flag when the next IME focused application changed.
404      *
405      * <p>
406      * Note that when this flag enabled in server side, {@link #SHOW_FORCED} will no longer
407      * affect the next focused application to keep showing IME, in case of unexpected IME visible
408      * when the next focused app isn't be the IME requester. </p>
409      *
410      * @hide
411      */
412     @TestApi
413     @ChangeId
414     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
415     public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // This is a bug id.
416 
417     /**
418      * If {@code true}, avoid calling the
419      * {@link com.android.server.inputmethod.InputMethodManagerService InputMethodManagerService}
420      * by skipping the call to {@link IInputMethodManager#startInputOrWindowGainedFocus}
421      * when we are switching focus between two non-editable views. This saves the cost of a binder
422      * call into the system server.
423      * <p><b>Note:</b>
424      * The default value is {@code true}.
425      */
426     private static final boolean OPTIMIZE_NONEDITABLE_VIEWS =
427             SystemProperties.getBoolean("debug.imm.optimize_noneditable_views", true);
428 
429     /**
430      * @deprecated Use {@link IInputMethodManagerGlobalInvoker} instead.
431      */
432     @Deprecated
433     @UnsupportedAppUsage
434     final IInputMethodManager mService;
435     private final Looper mMainLooper;
436 
437     // For scheduling work on the main thread.  This also serves as our
438     // global lock.
439     // Remark on @UnsupportedAppUsage: there were context leaks on old versions
440     // of android (b/37043700), so developers used this field to perform manual clean up.
441     // Leaks were fixed, hacks were backported to AppCompatActivity,
442     // so an access to the field is closed.
443     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
444     final H mH;
445 
446     // Our generic input connection if the current target does not have its own.
447     private final RemoteInputConnectionImpl mFallbackInputConnection;
448 
449     private final int mDisplayId;
450 
451     /**
452      * True if this input method client is active, initially false.
453      */
454     @GuardedBy("mH")
455     private boolean mActive = false;
456 
457     /**
458      * {@code true} if next {@link ImeFocusController#onPostWindowFocus} needs to
459      * restart input.
460      */
461     @GuardedBy("mH")
462     private boolean mRestartOnNextWindowFocus = true;
463 
464     /**
465      * As reported by IME through InputConnection.
466      */
467     @GuardedBy("mH")
468     private boolean mFullscreenMode;
469 
470     // -----------------------------------------------------------
471 
472     /**
473      * This is the view that should currently be served by an input method,
474      * regardless of the state of setting that up.
475      */
476     @Nullable
477     @GuardedBy("mH")
478     private View mServedView;
479 
480     /**
481      * This is the next view that will be served by the input method, when
482      * we get around to updating things.
483      */
484     @Nullable
485     @GuardedBy("mH")
486     private View mNextServedView;
487 
488     /**
489      * The latest {@link ViewRootImpl} that has, or most recently had, input method focus.
490      *
491      * <p>This value will be cleared when it becomes inactive and no longer has window focus.
492      */
493     @Nullable
494     @GuardedBy("mH")
495     ViewRootImpl mCurRootView;
496 
497     /**
498      * Whether the {@link #mCurRootView} currently has window focus.
499      */
500     @GuardedBy("mH")
501     boolean mCurRootViewWindowFocused;
502 
503     /**
504      * This is set when we are in the process of connecting, to determine
505      * when we have actually finished.
506      */
507     @GuardedBy("mH")
508     private boolean mServedConnecting;
509 
510     /**
511      * This is non-null when we have connected the served view; it holds
512      * the attributes that were last retrieved from the served view and given
513      * to the input connection.
514      */
515     @GuardedBy("mH")
516     private EditorInfo mCurrentEditorInfo;
517 
518     @GuardedBy("mH")
519     @Nullable
520     private ViewFocusParameterInfo mPreviousViewFocusParameters;
521 
522     /**
523      * The InputConnection that was last retrieved from the served view.
524      */
525     @GuardedBy("mH")
526     private RemoteInputConnectionImpl mServedInputConnection;
527 
528     /**
529      * The completions that were last provided by the served view.
530      */
531     @GuardedBy("mH")
532     private CompletionInfo[] mCompletions;
533 
534     // Cursor position on the screen.
535     @GuardedBy("mH")
536     @UnsupportedAppUsage
537     Rect mTmpCursorRect = new Rect();
538 
539     @GuardedBy("mH")
540     @UnsupportedAppUsage
541     Rect mCursorRect = new Rect();
542 
543     /** Cached value for {@link #isStylusHandwritingAvailable} for userId. */
544     @GuardedBy("mH")
545     private PropertyInvalidatedCache<Integer, Boolean> mStylusHandwritingAvailableCache;
546 
547     private static final String CACHE_KEY_STYLUS_HANDWRITING_PROPERTY =
548             "cache_key.system_server.stylus_handwriting";
549 
550     @GuardedBy("mH")
551     private int mCursorSelStart;
552     @GuardedBy("mH")
553     private int mCursorSelEnd;
554     @GuardedBy("mH")
555     private int mCursorCandStart;
556     @GuardedBy("mH")
557     private int mCursorCandEnd;
558     @GuardedBy("mH")
559     private int mInitialSelStart;
560     @GuardedBy("mH")
561     private int mInitialSelEnd;
562 
563     /**
564      * Handler for {@link RemoteInputConnectionImpl#getInputConnection()}.
565      */
566     @GuardedBy("mH")
567     private Handler mServedInputConnectionHandler;
568 
569     /**
570      * The instance that has previously been sent to the input method.
571      */
572     @GuardedBy("mH")
573     private CursorAnchorInfo mCursorAnchorInfo = null;
574 
575     /**
576      * A special {@link Matrix} that can be provided by the system when this instance is running
577      * inside a virtual display.
578      *
579      * <p>If this is non-{@code null}, {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}
580      * should be adjusted with this {@link Matrix}.</p>
581      *
582      * <p>{@code null} when not used.</p>
583      */
584     @GuardedBy("mH")
585     private Matrix mVirtualDisplayToScreenMatrix = null;
586 
587     // -----------------------------------------------------------
588 
589     /**
590      * ID of the method we are bound to.
591      *
592      * @deprecated New code should use {@code mCurBindState.mImeId}.
593      */
594     @Deprecated
595     @GuardedBy("mH")
596     @UnsupportedAppUsage(trackingBug = 236937383,
597             maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
598             publicAlternatives = "Apps should not change behavior based on the currently connected"
599                     + " IME. If absolutely needed, use {@link InputMethodInfo#getId()} instead.")
600     String mCurId;
601 
602     /**
603      * Kept for {@link UnsupportedAppUsage}.  Not officially maintained.
604      *
605      * @deprecated New code should use {@code mCurBindState.mImeSession}.
606      */
607     @Deprecated
608     @GuardedBy("mH")
609     @Nullable
610     @UnsupportedAppUsage(trackingBug = 236937383,
611             maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
612             publicAlternatives = "Use methods on {@link InputMethodManager} instead.")
613     IInputMethodSession mCurMethod;
614 
615     /**
616      * Encapsulates per-binding state from {@link InputBindResult}.
617      */
618     @GuardedBy("mH")
619     @Nullable
620     private BindState mCurBindState;
621 
622     /**
623      * Encapsulates IPCs to the currently connected AccessibilityServices.
624      */
625     @Nullable
626     @GuardedBy("mH")
627     private final SparseArray<IAccessibilityInputMethodSessionInvoker>
628             mAccessibilityInputMethodSession = new SparseArray<>();
629 
630     @GuardedBy("mH")
631     private InputChannel mCurChannel;
632     @GuardedBy("mH")
633     private ImeInputEventSender mCurSender;
634 
635     private static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE = 0x0;
636 
637     /**
638      * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
639      * @deprecated This is kept for {@link UnsupportedAppUsage}.  Must not be used.
640      */
641     @Deprecated
642     @GuardedBy("mH")
643     private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
644 
645     /**
646      * Applies the IME visibility and listens for other state changes.
647      */
648     @GuardedBy("mH")
649     private ImeInsetsSourceConsumer mImeInsetsConsumer;
650 
651     @GuardedBy("mH")
652     private final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
653     @GuardedBy("mH")
654     private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
655 
656     private final DelegateImpl mDelegate = new DelegateImpl();
657 
658     private static boolean sPreventImeStartupUnlessTextEditor;
659 
660     // -----------------------------------------------------------
661 
662     private static final int MSG_DUMP = 1;
663     private static final int MSG_BIND = 2;
664     private static final int MSG_UNBIND = 3;
665     private static final int MSG_SET_ACTIVE = 4;
666     private static final int MSG_SEND_INPUT_EVENT = 5;
667     private static final int MSG_TIMEOUT_INPUT_EVENT = 6;
668     private static final int MSG_FLUSH_INPUT_EVENT = 7;
669     private static final int MSG_REPORT_FULLSCREEN_MODE = 10;
670     private static final int MSG_BIND_ACCESSIBILITY_SERVICE = 11;
671     private static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 12;
672     private static final int MSG_SET_INTERACTIVE = 13;
673     private static final int MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX = 30;
674     private static final int MSG_ON_SHOW_REQUESTED = 31;
675 
676     /**
677      * Calling this will invalidate Local stylus handwriting availability Cache which
678      * forces the next query in any process to recompute the cache.
679      * @hide
680      */
invalidateLocalStylusHandwritingAvailabilityCaches()681     public static void invalidateLocalStylusHandwritingAvailabilityCaches() {
682         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_STYLUS_HANDWRITING_PROPERTY);
683     }
684 
isAutofillUIShowing(View servedView)685     private static boolean isAutofillUIShowing(View servedView) {
686         AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
687         return afm != null && afm.isAutofillUiShowing();
688     }
689 
690     /**
691      * Returns fallback {@link InputMethodManager} if the called one is not likely to be compatible
692      * with the given {@code view}.
693      *
694      * @param view {@link View} to be checked.
695      * @return {@code null} when it is unnecessary (or impossible) to use fallback
696      *         {@link InputMethodManager} to which IME API calls need to be re-dispatched.
697      *          Non-{@code null} {@link InputMethodManager} if this method believes it'd be safer to
698      *          re-dispatch IME APIs calls on it.
699      */
700     @Nullable
getFallbackInputMethodManagerIfNecessary(@ullable View view)701     private InputMethodManager getFallbackInputMethodManagerIfNecessary(@Nullable View view) {
702         if (view == null) {
703             return null;
704         }
705         // As evidenced in Bug 118341760, view.getViewRootImpl().getDisplayId() is supposed to be
706         // more reliable to determine with which display the given view is interacting than
707         // view.getContext().getDisplayId() / view.getContext().getSystemService(), which can be
708         // easily messed up by app developers (or library authors) by creating inconsistent
709         // ContextWrapper objects that re-dispatch those methods to other Context such as
710         // ApplicationContext.
711         final ViewRootImpl viewRootImpl = view.getViewRootImpl();
712         if (viewRootImpl == null) {
713             return null;
714         }
715         final int viewRootDisplayId = viewRootImpl.getDisplayId();
716         if (viewRootDisplayId == mDisplayId) {
717             // Expected case.  Good to go.
718             return null;
719         }
720         final InputMethodManager fallbackImm =
721                 viewRootImpl.mContext.getSystemService(InputMethodManager.class);
722         if (fallbackImm == null) {
723             Log.v(TAG, "b/117267690: Failed to get non-null fallback IMM. view=" + view);
724             return null;
725         }
726         if (fallbackImm.mDisplayId != viewRootDisplayId) {
727             Log.v(TAG, "b/117267690: Failed to get fallback IMM with expected displayId="
728                     + viewRootDisplayId + " actual IMM#displayId=" + fallbackImm.mDisplayId
729                     + " view=" + view);
730             return null;
731         }
732         Log.v(TAG, "b/117267690: Display ID mismatch found."
733                 + " ViewRootImpl displayId=" + viewRootDisplayId
734                 + " InputMethodManager displayId=" + mDisplayId
735                 + ". Use the right InputMethodManager instance to avoid performance overhead.",
736                 new Throwable());
737         return fallbackImm;
738     }
739 
740     /**
741      * An internal API that returns the {@link Context} of the current served view connected to
742      * an input method.
743      * @hide
744      */
getFallbackContextFromServedView()745     Context getFallbackContextFromServedView() {
746         synchronized (mH) {
747             if (mCurRootView == null) {
748                 return null;
749             }
750             return mServedView != null ? mServedView.getContext() : null;
751         }
752     }
753 
canStartInput(View servedView)754     private static boolean canStartInput(View servedView) {
755         // We can start input ether the servedView has window focus
756         // or the activity is showing autofill ui.
757         return servedView.hasWindowFocus() || isAutofillUIShowing(servedView);
758     }
759 
760     /**
761      * Reports whether the IME is currently perceptible or not, according to the leash applied by
762      * {@link android.view.WindowInsetsController}.
763      * @hide
764      */
reportPerceptible(@onNull IBinder windowToken, boolean perceptible)765     public void reportPerceptible(@NonNull IBinder windowToken, boolean perceptible) {
766         IInputMethodManagerGlobalInvoker.reportPerceptibleAsync(windowToken, perceptible);
767     }
768 
769     private final class DelegateImpl implements
770             ImeFocusController.InputMethodManagerDelegate {
771 
772         @Override
onPreWindowGainedFocus(ViewRootImpl viewRootImpl)773         public void onPreWindowGainedFocus(ViewRootImpl viewRootImpl) {
774             synchronized (mH) {
775                 setCurrentRootViewLocked(viewRootImpl);
776                 mCurRootViewWindowFocused = true;
777             }
778         }
779 
780         @Override
onPostWindowGainedFocus(View viewForWindowFocus, @NonNull WindowManager.LayoutParams windowAttribute)781         public void onPostWindowGainedFocus(View viewForWindowFocus,
782                 @NonNull WindowManager.LayoutParams windowAttribute) {
783             boolean forceFocus = false;
784             synchronized (mH) {
785                 // Update mNextServedView when focusedView changed.
786                 onViewFocusChangedInternal(viewForWindowFocus, true);
787 
788                 // Starting new input when the next focused view is same as served view but the
789                 // currently active connection (if any) is not associated with it.
790                 final boolean nextFocusIsServedView = mServedView == viewForWindowFocus;
791 
792                 if (nextFocusIsServedView
793                         && !hasActiveInputConnectionInternal(viewForWindowFocus)) {
794                     forceFocus = true;
795                 }
796             }
797 
798             final int softInputMode = windowAttribute.softInputMode;
799             final int windowFlags = windowAttribute.flags;
800 
801             int startInputFlags = getStartInputFlags(viewForWindowFocus, 0);
802             startInputFlags |= StartInputFlags.WINDOW_GAINED_FOCUS;
803 
804             ImeTracing.getInstance().triggerClientDump(
805                     "InputMethodManager.DelegateImpl#startInputAsyncOnWindowFocusGain",
806                     InputMethodManager.this, null /* icProto */);
807 
808             boolean checkFocusResult;
809             synchronized (mH) {
810                 if (mCurRootView == null) {
811                     return;
812                 }
813                 if (mRestartOnNextWindowFocus) {
814                     if (DEBUG) Log.v(TAG, "Restarting due to mRestartOnNextWindowFocus as true");
815                     mRestartOnNextWindowFocus = false;
816                     forceFocus = true;
817                 }
818                 checkFocusResult = checkFocusInternalLocked(forceFocus, mCurRootView);
819             }
820 
821             if (checkFocusResult) {
822                 // We need to restart input on the current focus view.  This
823                 // should be done in conjunction with telling the system service
824                 // about the window gaining focus, to help make the transition
825                 // smooth.
826                 if (startInputOnWindowFocusGainInternal(StartInputReason.WINDOW_FOCUS_GAIN,
827                         viewForWindowFocus, startInputFlags, softInputMode, windowFlags)) {
828                     return;
829                 }
830             }
831 
832             synchronized (mH) {
833                 // For some reason we didn't do a startInput + windowFocusGain, so
834                 // we'll just do a window focus gain and call it a day.
835                 if (DEBUG) {
836                     Log.v(TAG, "Reporting focus gain, without startInput");
837                 }
838 
839                 // ignore the result
840                 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMM.startInputOrWindowGainedFocus");
841                 IInputMethodManagerGlobalInvoker.startInputOrWindowGainedFocus(
842                         StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
843                         viewForWindowFocus.getWindowToken(), startInputFlags, softInputMode,
844                         windowFlags,
845                         null,
846                         null, null,
847                         mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
848                         UserHandle.myUserId(), mImeDispatcher);
849                 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
850             }
851         }
852 
853         @Override
onWindowLostFocus(@onNull ViewRootImpl viewRootImpl)854         public void onWindowLostFocus(@NonNull ViewRootImpl viewRootImpl) {
855             synchronized (mH) {
856                 if (mCurRootView == viewRootImpl) {
857                     mCurRootViewWindowFocused = false;
858 
859                     clearCurRootViewIfNeeded();
860                 }
861             }
862         }
863 
864         @Override
onViewFocusChanged(@ullable View view, boolean hasFocus)865         public void onViewFocusChanged(@Nullable View view, boolean hasFocus) {
866             onViewFocusChangedInternal(view, hasFocus);
867         }
868 
869         @Override
onScheduledCheckFocus(ViewRootImpl viewRootImpl)870         public void onScheduledCheckFocus(ViewRootImpl viewRootImpl) {
871             synchronized (mH) {
872                 if (!checkFocusInternalLocked(false, viewRootImpl)) {
873                     return;
874                 }
875             }
876             startInputOnWindowFocusGainInternal(StartInputReason.SCHEDULED_CHECK_FOCUS,
877                     null /* focusedView */, 0 /* startInputFlags */, 0 /* softInputMode */,
878                     0 /* windowFlags */);
879         }
880 
881         @Override
onViewDetachedFromWindow(View view, ViewRootImpl viewRootImpl)882         public void onViewDetachedFromWindow(View view, ViewRootImpl viewRootImpl) {
883             synchronized (mH) {
884                 if (mCurRootView != view.getViewRootImpl()) {
885                     return;
886                 }
887                 if (mNextServedView == view) {
888                     mNextServedView = null;
889                 }
890                 if (mServedView == view) {
891                     viewRootImpl.dispatchCheckFocus();
892                 }
893             }
894         }
895 
896         @Override
onWindowDismissed(ViewRootImpl viewRootImpl)897         public void onWindowDismissed(ViewRootImpl viewRootImpl) {
898             synchronized (mH) {
899                 if (mCurRootView != viewRootImpl) {
900                     return;
901                 }
902                 if (mServedView != null) {
903                     finishInputLocked();
904                 }
905                 setCurrentRootViewLocked(null);
906             }
907         }
908 
909         @GuardedBy("mH")
setCurrentRootViewLocked(ViewRootImpl rootView)910         private void setCurrentRootViewLocked(ViewRootImpl rootView) {
911             mImeDispatcher.switchRootView(mCurRootView, rootView);
912             mCurRootView = rootView;
913         }
914     }
915 
916     /** @hide */
getDelegate()917     public DelegateImpl getDelegate() {
918         return mDelegate;
919     }
920 
921     /**
922      * Checks whether the active input connection (if any) is for the given view.
923      *
924      * <p>Note that {@code view} parameter does not take
925      * {@link View#checkInputConnectionProxy(View)} into account. This method returns {@code true}
926      * when and only when the specified {@code view} is the actual {@link View} instance that is
927      * connected to the IME.</p>
928      *
929      * @param view {@link View} to be checked.
930      * @return {@code true} if {@code view} is currently interacting with IME.
931      * @hide
932      */
933     @TestApi
hasActiveInputConnection(@ullable View view)934     public boolean hasActiveInputConnection(@Nullable View view) {
935         synchronized (mH) {
936             return mCurRootView != null
937                     && view != null
938                     && mServedView == view
939                     && mServedInputConnection != null
940                     && mServedInputConnection.isAssociatedWith(view)
941                     && isImeSessionAvailableLocked();
942         }
943     }
944 
945     /**
946      * Checks whether the active input connection (if any) is for the given view.
947      *
948      * Note that this method is only intended for restarting input after focus gain
949      * (e.g. b/160391516), DO NOT leverage this method to do another check.
950      */
hasActiveInputConnectionInternal(@ullable View view)951     private boolean hasActiveInputConnectionInternal(@Nullable View view) {
952         synchronized (mH) {
953             if (!hasServedByInputMethodLocked(view) || !isImeSessionAvailableLocked()) {
954                 return false;
955             }
956 
957             return mServedInputConnection != null
958                     && mServedInputConnection.isAssociatedWith(view);
959         }
960     }
961 
startInputOnWindowFocusGainInternal(@tartInputReason int startInputReason, View focusedView, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags)962     private boolean startInputOnWindowFocusGainInternal(@StartInputReason int startInputReason,
963             View focusedView, @StartInputFlags int startInputFlags,
964             @SoftInputModeFlags int softInputMode, int windowFlags) {
965         synchronized (mH) {
966             mCurrentEditorInfo = null;
967             mCompletions = null;
968             mServedConnecting = true;
969         }
970         return startInputInner(startInputReason,
971                 focusedView != null ? focusedView.getWindowToken() : null, startInputFlags,
972                 softInputMode, windowFlags);
973     }
974 
975     @GuardedBy("mH")
getServedViewLocked()976     private View getServedViewLocked() {
977         return mCurRootView != null ? mServedView : null;
978     }
979 
980     @GuardedBy("mH")
getNextServedViewLocked()981     private View getNextServedViewLocked() {
982         return mCurRootView != null ? mNextServedView : null;
983     }
984 
985     /**
986      * Returns {@code true} when the given view has been served by Input Method.
987      */
988     @GuardedBy("mH")
hasServedByInputMethodLocked(View view)989     private boolean hasServedByInputMethodLocked(View view) {
990         final View servedView = getServedViewLocked();
991         return (servedView == view
992                 || (servedView != null && servedView.checkInputConnectionProxy(view)));
993     }
994 
995     class H extends Handler {
H(Looper looper)996         H(Looper looper) {
997             super(looper, null, true);
998         }
999 
1000         @Override
handleMessage(Message msg)1001         public void handleMessage(Message msg) {
1002             switch (msg.what) {
1003                 case MSG_DUMP: {
1004                     SomeArgs args = (SomeArgs)msg.obj;
1005                     try {
1006                         doDump((FileDescriptor)args.arg1,
1007                                 (PrintWriter)args.arg2, (String[])args.arg3);
1008                     } catch (RuntimeException e) {
1009                         ((PrintWriter)args.arg2).println("Exception: " + e);
1010                     }
1011                     synchronized (args.arg4) {
1012                         ((CountDownLatch)args.arg4).countDown();
1013                     }
1014                     args.recycle();
1015                     return;
1016                 }
1017                 case MSG_BIND: {
1018                     final InputBindResult res = (InputBindResult)msg.obj;
1019                     if (DEBUG) {
1020                         Log.i(TAG, "handleMessage: MSG_BIND " + res.sequence + "," + res.id);
1021                     }
1022                     synchronized (mH) {
1023                         final int curBindSequence = getBindSequenceLocked();
1024                         if (curBindSequence < 0 || curBindSequence != res.sequence) {
1025                             Log.w(TAG, "Ignoring onBind: cur seq=" + curBindSequence
1026                                     + ", given seq=" + res.sequence);
1027                             if (res.channel != null && res.channel != mCurChannel) {
1028                                 res.channel.dispose();
1029                             }
1030                             return;
1031                         }
1032 
1033                         mRequestUpdateCursorAnchorInfoMonitorMode =
1034                                 REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
1035 
1036                         updateInputChannelLocked(res.channel);
1037                         mCurMethod = res.method; // for @UnsupportedAppUsage
1038                         mCurBindState = new BindState(res);
1039                         mCurId = res.id; // for @UnsupportedAppUsage
1040                         mVirtualDisplayToScreenMatrix = res.getVirtualDisplayToScreenMatrix();
1041                     }
1042                     startInputInner(StartInputReason.BOUND_TO_IMMS, null, 0, 0, 0);
1043                     return;
1044                 }
1045                 case MSG_UNBIND: {
1046                     final int sequence = msg.arg1;
1047                     @UnbindReason
1048                     final int reason = msg.arg2;
1049                     if (DEBUG) {
1050                         Log.i(TAG, "handleMessage: MSG_UNBIND " + sequence +
1051                                 " reason=" + InputMethodDebug.unbindReasonToString(reason));
1052                     }
1053                     final boolean startInput;
1054                     synchronized (mH) {
1055                         if (getBindSequenceLocked() != sequence) {
1056                             return;
1057                         }
1058                         clearAllAccessibilityBindingLocked();
1059                         clearBindingLocked();
1060                         // If we were actively using the last input method, then
1061                         // we would like to re-connect to the next input method.
1062                         final View servedView = getServedViewLocked();
1063                         if (servedView != null && servedView.isFocused()) {
1064                             mServedConnecting = true;
1065                         }
1066                         startInput = mActive;
1067                     }
1068                     if (startInput) {
1069                         startInputInner(
1070                                 StartInputReason.UNBOUND_FROM_IMMS, null, 0, 0, 0);
1071                     }
1072                     return;
1073                 }
1074                 case MSG_BIND_ACCESSIBILITY_SERVICE: {
1075                     final int id = msg.arg1;
1076                     final InputBindResult res = (InputBindResult) msg.obj;
1077                     if (DEBUG) {
1078                         Log.i(TAG, "handleMessage: MSG_BIND_ACCESSIBILITY " + res.sequence
1079                                 + "," + res.id);
1080                     }
1081                     synchronized (mH) {
1082                         final int curBindSequence = getBindSequenceLocked();
1083                         if (curBindSequence < 0 || curBindSequence != res.sequence) {
1084                             Log.w(TAG, "Ignoring onBind: cur seq=" + curBindSequence
1085                                     + ", given seq=" + res.sequence);
1086                             if (res.channel != null && res.channel != mCurChannel) {
1087                                 res.channel.dispose();
1088                             }
1089                             return;
1090                         }
1091 
1092                         // Since IMM can start inputting text before a11y sessions are back,
1093                         // we send a notification so that the a11y service knows the session is
1094                         // registered and update the a11y service with the current cursor positions.
1095                         if (res.accessibilitySessions != null) {
1096                             IAccessibilityInputMethodSessionInvoker invoker =
1097                                     IAccessibilityInputMethodSessionInvoker.createOrNull(
1098                                             res.accessibilitySessions.get(id));
1099                             if (invoker != null) {
1100                                 mAccessibilityInputMethodSession.put(id, invoker);
1101                                 if (mServedInputConnection != null) {
1102                                     invoker.updateSelection(mInitialSelStart, mInitialSelEnd,
1103                                             mCursorSelStart, mCursorSelEnd, mCursorCandStart,
1104                                             mCursorCandEnd);
1105                                 } else {
1106                                     // If an a11y service binds before input starts, we should still
1107                                     // send a notification because the a11y service doesn't know it
1108                                     // binds before or after input starts, it may wonder if it binds
1109                                     // after input starts, why it doesn't receive a notification of
1110                                     // the current cursor positions.
1111                                     invoker.updateSelection(-1, -1, -1, -1, -1, -1);
1112                                 }
1113                             }
1114                         }
1115                     }
1116                     startInputInner(StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS, null,
1117                             0, 0, 0);
1118                     return;
1119                 }
1120                 case MSG_UNBIND_ACCESSIBILITY_SERVICE: {
1121                     final int sequence = msg.arg1;
1122                     final int id = msg.arg2;
1123                     if (DEBUG) {
1124                         Log.i(TAG, "handleMessage: MSG_UNBIND_ACCESSIBILITY_SERVICE "
1125                                 + sequence + " id=" + id);
1126                     }
1127                     synchronized (mH) {
1128                         if (getBindSequenceLocked() != sequence) {
1129                             if (DEBUG) {
1130                                 Log.i(TAG, "current BindSequence =" + getBindSequenceLocked()
1131                                         + " sequence =" + sequence + " id=" + id);
1132                             }
1133                             return;
1134                         }
1135                         clearAccessibilityBindingLocked(id);
1136                     }
1137                     return;
1138                 }
1139                 case MSG_SET_ACTIVE: {
1140                     final boolean active = msg.arg1 != 0;
1141                     final boolean fullscreen = msg.arg2 != 0;
1142                     if (DEBUG) {
1143                         Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
1144                     }
1145                     synchronized (mH) {
1146                         mActive = active;
1147                         mFullscreenMode = fullscreen;
1148 
1149                         if (!active) {
1150                             // Some other client has starting using the IME, so note
1151                             // that this happened and make sure our own editor's
1152                             // state is reset.
1153                             mRestartOnNextWindowFocus = true;
1154                             // Note that finishComposingText() is allowed to run
1155                             // even when we are not active.
1156                             mFallbackInputConnection.finishComposingTextFromImm();
1157 
1158                             if (clearCurRootViewIfNeeded()) {
1159                                 return;
1160                             }
1161                         }
1162                         // Check focus again in case that "onWindowFocus" is called before
1163                         // handling this message.
1164                         final View servedView = getServedViewLocked();
1165                         if (servedView == null || !canStartInput(servedView)) {
1166                             return;
1167                         }
1168                         if (mCurRootView == null) {
1169                             return;
1170                         }
1171                         if (!checkFocusInternalLocked(mRestartOnNextWindowFocus, mCurRootView)) {
1172                             return;
1173                         }
1174                         mCurrentEditorInfo = null;
1175                         mCompletions = null;
1176                         mServedConnecting = true;
1177                     }
1178                     final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS
1179                             : StartInputReason.DEACTIVATED_BY_IMMS;
1180                     startInputInner(reason, null, 0, 0, 0);
1181                     return;
1182                 }
1183                 case MSG_SET_INTERACTIVE: {
1184                     final boolean interactive = msg.arg1 != 0;
1185                     final boolean fullscreen = msg.arg2 != 0;
1186                     if (DEBUG) {
1187                         Log.i(TAG, "handleMessage: MSG_SET_INTERACTIVE " + interactive
1188                                 + ", was " + mActive);
1189                     }
1190                     synchronized (mH) {
1191                         mActive = interactive;
1192                         mFullscreenMode = fullscreen;
1193                         if (interactive) {
1194                             final View rootView =
1195                                     mCurRootView != null ? mCurRootView.getView() : null;
1196                             if (rootView == null) {
1197                                 return;
1198                             }
1199                             // Find the next view focus to start the input connection when the
1200                             // device was interactive.
1201                             final ViewRootImpl currentViewRootImpl = mCurRootView;
1202                             rootView.post(() -> {
1203                                 synchronized (mH) {
1204                                     if (mCurRootView != currentViewRootImpl) {
1205                                         return;
1206                                     }
1207                                 }
1208                                 final View focusedView = currentViewRootImpl.getView().findFocus();
1209                                 onViewFocusChangedInternal(focusedView, focusedView != null);
1210                             });
1211                         } else {
1212                             finishInputLocked();
1213                             if (isImeSessionAvailableLocked()) {
1214                                 mCurBindState.mImeSession.finishInput();
1215                             }
1216                             forAccessibilitySessionsLocked(
1217                                     IAccessibilityInputMethodSessionInvoker::finishInput);
1218                         }
1219                     }
1220                     return;
1221                 }
1222                 case MSG_SEND_INPUT_EVENT: {
1223                     sendInputEventAndReportResultOnMainLooper((PendingEvent)msg.obj);
1224                     return;
1225                 }
1226                 case MSG_TIMEOUT_INPUT_EVENT: {
1227                     finishedInputEvent(msg.arg1, false, true);
1228                     return;
1229                 }
1230                 case MSG_FLUSH_INPUT_EVENT: {
1231                     finishedInputEvent(msg.arg1, false, false);
1232                     return;
1233                 }
1234                 case MSG_REPORT_FULLSCREEN_MODE: {
1235                     final boolean fullscreen = msg.arg1 != 0;
1236                     RemoteInputConnectionImpl ic = null;
1237                     synchronized (mH) {
1238                         if (mFullscreenMode != fullscreen && mServedInputConnection != null) {
1239                             ic = mServedInputConnection;
1240                             mFullscreenMode = fullscreen;
1241                         }
1242                     }
1243                     if (ic != null) {
1244                         ic.dispatchReportFullscreenMode(fullscreen);
1245                     }
1246                     return;
1247                 }
1248                 case MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX: {
1249                     final float[] matrixValues = (float[]) msg.obj;
1250                     final int bindSequence = msg.arg1;
1251                     synchronized (mH) {
1252                         if (getBindSequenceLocked() != bindSequence) {
1253                             return;
1254                         }
1255                         if (matrixValues == null || mVirtualDisplayToScreenMatrix == null) {
1256                             // Either InputBoundResult#mVirtualDisplayToScreenMatrixValues is null
1257                             // OR this app is unbound from the parent VirtualDisplay. In this case,
1258                             // calling updateCursorAnchorInfo() isn't safe. Only clear the matrix.
1259                             mVirtualDisplayToScreenMatrix = null;
1260                             return;
1261                         }
1262 
1263                         final float[] currentValues = new float[9];
1264                         mVirtualDisplayToScreenMatrix.getValues(currentValues);
1265                         if (Arrays.equals(currentValues, matrixValues)) {
1266                             return;
1267                         }
1268                         mVirtualDisplayToScreenMatrix.setValues(matrixValues);
1269 
1270                         if (mCursorAnchorInfo == null || !isImeSessionAvailableLocked()
1271                                 || mServedInputConnection == null) {
1272                             return;
1273                         }
1274                         if (!mServedInputConnection.isCursorAnchorInfoMonitoring()) {
1275                             return;
1276                         }
1277                         // Since the host VirtualDisplay is moved, we need to issue
1278                         // IMS#updateCursorAnchorInfo() again.
1279                         mCurBindState.mImeSession.updateCursorAnchorInfo(
1280                                 CursorAnchorInfo.createForAdditionalParentMatrix(
1281                                         mCursorAnchorInfo, mVirtualDisplayToScreenMatrix));
1282                     }
1283                     return;
1284                 }
1285                 case MSG_ON_SHOW_REQUESTED: {
1286                     synchronized (mH) {
1287                         if (mImeInsetsConsumer != null) {
1288                             mImeInsetsConsumer.onShowRequested();
1289                         }
1290                     }
1291                     return;
1292                 }
1293             }
1294         }
1295     }
1296 
1297     private final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
1298         @Override
1299         protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
1300             // No need to check for dump permission, since we only give this
1301             // interface to the system.
1302             CountDownLatch latch = new CountDownLatch(1);
1303             SomeArgs sargs = SomeArgs.obtain();
1304             sargs.arg1 = fd;
1305             sargs.arg2 = fout;
1306             sargs.arg3 = args;
1307             sargs.arg4 = latch;
1308             mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs));
1309             try {
1310                 if (!latch.await(5, TimeUnit.SECONDS)) {
1311                     fout.println("Timeout waiting for dump");
1312                 }
1313             } catch (InterruptedException e) {
1314                 fout.println("Interrupted waiting for dump");
1315             }
1316         }
1317 
1318         @Override
1319         public void onBindMethod(InputBindResult res) {
1320             mH.obtainMessage(MSG_BIND, res).sendToTarget();
1321         }
1322 
1323         @Override
1324         public void onBindAccessibilityService(InputBindResult res, int id) {
1325             mH.obtainMessage(MSG_BIND_ACCESSIBILITY_SERVICE, id, 0, res).sendToTarget();
1326         }
1327 
1328         @Override
1329         public void onUnbindMethod(int sequence, @UnbindReason int unbindReason) {
1330             mH.obtainMessage(MSG_UNBIND, sequence, unbindReason).sendToTarget();
1331         }
1332 
1333         @Override
1334         public void onUnbindAccessibilityService(int sequence, int id) {
1335             mH.obtainMessage(MSG_UNBIND_ACCESSIBILITY_SERVICE, sequence, id).sendToTarget();
1336         }
1337 
1338         @Override
1339         public void setActive(boolean active, boolean fullscreen) {
1340             mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0).sendToTarget();
1341         }
1342 
1343         @Override
1344         public void setInteractive(boolean interactive, boolean fullscreen) {
1345             mH.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, fullscreen ? 1 : 0)
1346                     .sendToTarget();
1347         }
1348 
1349         @Override
1350         public void scheduleStartInputIfNecessary(boolean fullscreen) {
1351             // TODO(b/149859205): See if we can optimize this by having a fused dedicated operation.
1352             mH.obtainMessage(MSG_SET_ACTIVE, 0 /* active */, fullscreen ? 1 : 0).sendToTarget();
1353             mH.obtainMessage(MSG_SET_ACTIVE, 1 /* active */, fullscreen ? 1 : 0).sendToTarget();
1354         }
1355 
1356         @Override
1357         public void reportFullscreenMode(boolean fullscreen) {
1358             mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0)
1359                     .sendToTarget();
1360         }
1361 
1362         @Override
1363         public void updateVirtualDisplayToScreenMatrix(int bindSequence, float[] matrixValues) {
1364             mH.obtainMessage(MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX, bindSequence, 0,
1365                     matrixValues).sendToTarget();
1366         }
1367 
1368         @Override
1369         public void setImeTraceEnabled(boolean enabled) {
1370             ImeTracing.getInstance().setEnabled(enabled);
1371         }
1372 
1373         @Override
1374         public void throwExceptionFromSystem(String message) {
1375             throw new RuntimeException(message);
1376         }
1377     };
1378 
1379     /**
1380      * For layoutlib to clean up static objects inside {@link InputMethodManager}.
1381      */
tearDownEditMode()1382     static void tearDownEditMode() {
1383         if (!isInEditMode()) {
1384             throw new UnsupportedOperationException(
1385                     "This method must be called only from layoutlib");
1386         }
1387         synchronized (sLock) {
1388             sInstance = null;
1389         }
1390     }
1391 
1392     /**
1393      * For layoutlib to override this method to return {@code true}.
1394      *
1395      * @return {@code true} if the process is running for developer tools
1396      * @see View#isInEditMode()
1397      */
isInEditMode()1398     private static boolean isInEditMode() {
1399         return false;
1400     }
1401 
isInEditModeInternal()1402     static boolean isInEditModeInternal() {
1403         return isInEditMode();
1404     }
1405 
1406     @NonNull
createInstance(int displayId, Looper looper)1407     private static InputMethodManager createInstance(int displayId, Looper looper) {
1408         return isInEditMode() ? createStubInstance(displayId, looper)
1409                 : createRealInstance(displayId, looper);
1410     }
1411 
1412     @NonNull
createRealInstance(int displayId, Looper looper)1413     private static InputMethodManager createRealInstance(int displayId, Looper looper) {
1414         final IInputMethodManager service = IInputMethodManagerGlobalInvoker.getService();
1415         if (service == null) {
1416             throw new IllegalStateException("IInputMethodManager is not available");
1417         }
1418         final InputMethodManager imm = new InputMethodManager(service, displayId, looper);
1419         // InputMethodManagerService#addClient() relies on Binder.getCalling{Pid, Uid}() to
1420         // associate PID/UID with each IME client. This means:
1421         //  A. if this method call will be handled as an IPC, there is no problem.
1422         //  B. if this method call will be handled as an in-proc method call, we need to
1423         //     ensure that Binder.getCalling{Pid, Uid}() return Process.my{Pid, Uid}()
1424         // Either ways we can always call Binder.{clear, restore}CallingIdentity() because
1425         // 1) doing so has no effect for A and 2) doing so is sufficient for B.
1426         final long identity = Binder.clearCallingIdentity();
1427         try {
1428             IInputMethodManagerGlobalInvoker.addClient(imm.mClient, imm.mFallbackInputConnection,
1429                     displayId);
1430         } finally {
1431             Binder.restoreCallingIdentity(identity);
1432         }
1433         return imm;
1434     }
1435 
1436     @NonNull
createStubInstance(int displayId, Looper looper)1437     private static InputMethodManager createStubInstance(int displayId, Looper looper) {
1438         // If InputMethodManager is running for layoutlib, stub out IPCs into IMMS.
1439         final Class<IInputMethodManager> c = IInputMethodManager.class;
1440         final IInputMethodManager stubInterface =
1441                 (IInputMethodManager) Proxy.newProxyInstance(c.getClassLoader(),
1442                         new Class[]{c}, (proxy, method, args) -> {
1443                             final Class<?> returnType = method.getReturnType();
1444                             if (returnType == boolean.class) {
1445                                 return false;
1446                             } else if (returnType == int.class) {
1447                                 return 0;
1448                             } else if (returnType == long.class) {
1449                                 return 0L;
1450                             } else if (returnType == short.class) {
1451                                 return 0;
1452                             } else if (returnType == char.class) {
1453                                 return 0;
1454                             } else if (returnType == byte.class) {
1455                                 return 0;
1456                             } else if (returnType == float.class) {
1457                                 return 0f;
1458                             } else if (returnType == double.class) {
1459                                 return 0.0;
1460                             } else {
1461                                 return null;
1462                             }
1463                         });
1464         return new InputMethodManager(stubInterface, displayId, looper);
1465     }
1466 
InputMethodManager(@onNull IInputMethodManager service, int displayId, Looper looper)1467     private InputMethodManager(@NonNull IInputMethodManager service, int displayId, Looper looper) {
1468         mService = service;  // For @UnsupportedAppUsage
1469         mMainLooper = looper;
1470         mH = new H(looper);
1471         mDisplayId = displayId;
1472         mFallbackInputConnection = new RemoteInputConnectionImpl(looper,
1473                 new BaseInputConnection(this, false), this, null);
1474     }
1475 
1476     /**
1477      * Retrieve an instance for the given {@link Context}, creating it if it doesn't already exist.
1478      *
1479      * @param context {@link Context} for which IME APIs need to work
1480      * @return {@link InputMethodManager} instance
1481      * @hide
1482      */
1483     @NonNull
forContext(@isplayContext Context context)1484     public static InputMethodManager forContext(@DisplayContext Context context) {
1485         final int displayId = context.getDisplayId();
1486         // For better backward compatibility, we always use Looper.getMainLooper() for the default
1487         // display case.
1488         final Looper looper = displayId == Display.DEFAULT_DISPLAY
1489                 ? Looper.getMainLooper() : context.getMainLooper();
1490         // Keep track of whether to expect the IME to be unavailable so as to avoid log spam in
1491         // sendInputEventOnMainLooperLocked() by not logging a verbose message on every DPAD event
1492         sPreventImeStartupUnlessTextEditor = context.getResources().getBoolean(
1493                 com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
1494         return forContextInternal(displayId, looper);
1495     }
1496 
1497     @NonNull
forContextInternal(int displayId, Looper looper)1498     private static InputMethodManager forContextInternal(int displayId, Looper looper) {
1499         final boolean isDefaultDisplay = displayId == Display.DEFAULT_DISPLAY;
1500         synchronized (sLock) {
1501             InputMethodManager instance = sInstanceMap.get(displayId);
1502             if (instance != null) {
1503                 return instance;
1504             }
1505             instance = createInstance(displayId, looper);
1506             // For backward compatibility, store the instance also to sInstance for default display.
1507             if (sInstance == null && isDefaultDisplay) {
1508                 sInstance = instance;
1509             }
1510             sInstanceMap.put(displayId, instance);
1511             return instance;
1512         }
1513     }
1514 
1515     /**
1516      * Deprecated. Do not use.
1517      *
1518      * @return global {@link InputMethodManager} instance
1519      * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully
1520      *             support multi-display scenario.
1521      * @hide
1522      */
1523     @Deprecated
1524     @UnsupportedAppUsage
getInstance()1525     public static InputMethodManager getInstance() {
1526         Log.w(TAG, "InputMethodManager.getInstance() is deprecated because it cannot be"
1527                         + " compatible with multi-display."
1528                         + " Use context.getSystemService(InputMethodManager.class) instead.",
1529                 new Throwable());
1530         ensureDefaultInstanceForDefaultDisplayIfNecessary();
1531         return peekInstance();
1532     }
1533 
1534     /**
1535      * Deprecated. Do not use.
1536      *
1537      * @return {@link #sInstance}
1538      * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully
1539      *             support multi-display scenario.
1540      * @hide
1541      */
1542     @Deprecated
1543     @UnsupportedAppUsage
peekInstance()1544     public static InputMethodManager peekInstance() {
1545         Log.w(TAG, "InputMethodManager.peekInstance() is deprecated because it cannot be"
1546                         + " compatible with multi-display."
1547                         + " Use context.getSystemService(InputMethodManager.class) instead.",
1548                 new Throwable());
1549         synchronized (sLock) {
1550             return sInstance;
1551         }
1552     }
1553 
1554     /**
1555      * Returns the list of installed input methods.
1556      *
1557      * <p>On multi user environment, this API returns a result for the calling process user.</p>
1558      *
1559      * @return {@link List} of {@link InputMethodInfo}.
1560      */
1561     @NonNull
getInputMethodList()1562     public List<InputMethodInfo> getInputMethodList() {
1563         // We intentionally do not use UserHandle.getCallingUserId() here because for system
1564         // services InputMethodManagerInternal.getInputMethodListAsUser() should be used
1565         // instead.
1566         return IInputMethodManagerGlobalInvoker.getInputMethodList(UserHandle.myUserId(),
1567                 DirectBootAwareness.AUTO);
1568     }
1569 
1570     /**
1571      * Returns {@code true} if currently selected IME supports Stylus handwriting & is enabled.
1572      * If the method returns {@code false}, {@link #startStylusHandwriting(View)} shouldn't be
1573      * called and Stylus touch should continue as normal touch input.
1574      * @see #startStylusHandwriting(View)
1575      */
isStylusHandwritingAvailable()1576     public boolean isStylusHandwritingAvailable() {
1577         return isStylusHandwritingAvailableAsUser(UserHandle.myUserId());
1578     }
1579 
1580     /**
1581      * Returns {@code true} if currently selected IME supports Stylus handwriting & is enabled for
1582      * the given userId.
1583      *
1584      * <p>If the method returns {@code false}, {@link #startStylusHandwriting(View)} shouldn't be
1585      * called and Stylus touch should continue as normal touch input.</p>
1586      *
1587      * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
1588      * {@code userId} is different from the user id of the current process.</p>
1589      *
1590      * @see #startStylusHandwriting(View)
1591      * @param userId user ID to query.
1592      * @hide
1593      */
1594     @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
isStylusHandwritingAvailableAsUser(@serIdInt int userId)1595     public boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId) {
1596         final Context fallbackContext = ActivityThread.currentApplication();
1597         if (fallbackContext == null) {
1598             return false;
1599         }
1600         boolean isAvailable;
1601         synchronized (mH) {
1602             if (mStylusHandwritingAvailableCache == null) {
1603                 mStylusHandwritingAvailableCache = new PropertyInvalidatedCache<>(
1604                         4 /* maxEntries */, CACHE_KEY_STYLUS_HANDWRITING_PROPERTY) {
1605                     @Override
1606                     public Boolean recompute(Integer userId) {
1607                         return IInputMethodManagerGlobalInvoker.isStylusHandwritingAvailableAsUser(
1608                                 userId);
1609                     }
1610                 };
1611             }
1612             isAvailable = mStylusHandwritingAvailableCache.query(userId);
1613         }
1614         return isAvailable;
1615     }
1616 
1617     /**
1618      * Returns the list of installed input methods for the specified user.
1619      *
1620      * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
1621      * {@code userId} is different from the user id of the current process.</p>
1622      *
1623      * @param userId user ID to query
1624      * @return {@link List} of {@link InputMethodInfo}.
1625      * @hide
1626      */
1627     @TestApi
1628     @NonNull
1629     @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
getInputMethodListAsUser(@serIdInt int userId)1630     public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
1631         return IInputMethodManagerGlobalInvoker.getInputMethodList(userId,
1632                 DirectBootAwareness.AUTO);
1633     }
1634 
1635     /**
1636      * Returns the list of installed input methods for the specified user.
1637      *
1638      * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
1639      * {@code userId} is different from the user id of the current process.</p>
1640      *
1641      * @param userId user ID to query
1642      * @param directBootAwareness {@code true} if caller want to query installed input methods list
1643      * on user locked state.
1644      * @return {@link List} of {@link InputMethodInfo}.
1645      * @hide
1646      */
1647     @NonNull
1648     @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
getInputMethodListAsUser(@serIdInt int userId, @DirectBootAwareness int directBootAwareness)1649     public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId,
1650             @DirectBootAwareness int directBootAwareness) {
1651         return IInputMethodManagerGlobalInvoker.getInputMethodList(userId, directBootAwareness);
1652     }
1653 
1654     /**
1655      * Returns the {@link InputMethodInfo} of the currently selected input method (for the process's
1656      * user).
1657      *
1658      * <p>On multi user environment, this API returns a result for the calling process user.</p>
1659      */
1660     @Nullable
getCurrentInputMethodInfo()1661     public InputMethodInfo getCurrentInputMethodInfo() {
1662         // We intentionally do not use UserHandle.getCallingUserId() here because for system
1663         // services InputMethodManagerInternal.getCurrentInputMethodInfoForUser() should be used
1664         // instead.
1665         return IInputMethodManagerGlobalInvoker.getCurrentInputMethodInfoAsUser(
1666                 UserHandle.myUserId());
1667     }
1668 
1669     /**
1670      * Returns the {@link InputMethodInfo} for currently selected input method for the given user.
1671      *
1672      * @param user user to query.
1673      * @hide
1674      */
1675     @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1676     @Nullable
1677     @SystemApi
1678     @SuppressLint("UserHandle")
getCurrentInputMethodInfoAsUser(@onNull UserHandle user)1679     public InputMethodInfo getCurrentInputMethodInfoAsUser(@NonNull UserHandle user) {
1680         Objects.requireNonNull(user);
1681         return IInputMethodManagerGlobalInvoker.getCurrentInputMethodInfoAsUser(
1682                 user.getIdentifier());
1683     }
1684 
1685     /**
1686      * Returns the list of enabled input methods.
1687      *
1688      * <p>On multi user environment, this API returns a result for the calling process user.</p>
1689      *
1690      * @return {@link List} of {@link InputMethodInfo}.
1691      */
1692     @NonNull
getEnabledInputMethodList()1693     public List<InputMethodInfo> getEnabledInputMethodList() {
1694         // We intentionally do not use UserHandle.getCallingUserId() here because for system
1695         // services InputMethodManagerInternal.getEnabledInputMethodListAsUser() should be used
1696         // instead.
1697         return IInputMethodManagerGlobalInvoker.getEnabledInputMethodList(UserHandle.myUserId());
1698     }
1699 
1700     /**
1701      * Returns the list of enabled input methods for the specified user.
1702      *
1703      * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
1704      * {@code userId} is different from the user id of the current process.</p>
1705      *
1706      * @param userId user ID to query
1707      * @return {@link List} of {@link InputMethodInfo}.
1708      * @see #getEnabledInputMethodSubtypeListAsUser(String, boolean, int)
1709      * @hide
1710      */
1711     @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
getEnabledInputMethodListAsUser(@serIdInt int userId)1712     public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
1713         return IInputMethodManagerGlobalInvoker.getEnabledInputMethodList(userId);
1714     }
1715 
1716     /**
1717      * Returns a list of enabled input method subtypes for the specified input method info.
1718      *
1719      * <p>On multi user environment, this API returns a result for the calling process user.</p>
1720      *
1721      * @param imi The {@link InputMethodInfo} whose subtypes list will be returned. If {@code null},
1722      * returns enabled subtypes for the currently selected {@link InputMethodInfo}.
1723      * @param allowsImplicitlyEnabledSubtypes A boolean flag to allow to return the implicitly
1724      * enabled subtypes. If an input method info doesn't have enabled subtypes, the framework
1725      * will implicitly enable subtypes according to the current system language.
1726      */
1727     @NonNull
getEnabledInputMethodSubtypeList(@ullable InputMethodInfo imi, boolean allowsImplicitlyEnabledSubtypes)1728     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(@Nullable InputMethodInfo imi,
1729             boolean allowsImplicitlyEnabledSubtypes) {
1730         return IInputMethodManagerGlobalInvoker.getEnabledInputMethodSubtypeList(
1731                 imi == null ? null : imi.getId(),
1732                 allowsImplicitlyEnabledSubtypes,
1733                 UserHandle.myUserId());
1734     }
1735 
1736     /**
1737      * Returns a list of enabled input method subtypes for the specified input method info for the
1738      * specified user.
1739      *
1740      * @param imeId IME ID to be queried about.
1741      * @param allowsImplicitlyEnabledSubtypes {@code true} to include implicitly enabled subtypes.
1742      * @param userId user ID to be queried about.
1743      *               {@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required if this is
1744      *               different from the calling process user ID.
1745      * @return {@link List} of {@link InputMethodSubtype}.
1746      * @see #getEnabledInputMethodListAsUser(int)
1747      * @hide
1748      */
1749     @NonNull
1750     @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
getEnabledInputMethodSubtypeListAsUser( @onNull String imeId, boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId)1751     public List<InputMethodSubtype> getEnabledInputMethodSubtypeListAsUser(
1752             @NonNull String imeId, boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId) {
1753         return IInputMethodManagerGlobalInvoker.getEnabledInputMethodSubtypeList(
1754                 Objects.requireNonNull(imeId), allowsImplicitlyEnabledSubtypes, userId);
1755     }
1756 
1757     /**
1758      * @deprecated Use {@link InputMethodService#showStatusIcon(int)} instead. This method was
1759      * intended for IME developers who should be accessing APIs through the service. APIs in this
1760      * class are intended for app developers interacting with the IME.
1761      */
1762     @Deprecated
showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId)1763     public void showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId) {
1764         InputMethodPrivilegedOperationsRegistry.get(
1765                 imeToken).updateStatusIconAsync(packageName, iconId);
1766     }
1767 
1768     /**
1769      * @deprecated Use {@link InputMethodService#hideStatusIcon()} instead. This method was
1770      * intended for IME developers who should be accessing APIs through the service. APIs in
1771      * this class are intended for app developers interacting with the IME.
1772      */
1773     @Deprecated
hideStatusIcon(IBinder imeToken)1774     public void hideStatusIcon(IBinder imeToken) {
1775         InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIconAsync(null, 0);
1776     }
1777 
1778     /**
1779      * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing.
1780      *
1781      * @param spans will be ignored.
1782      *
1783      * @deprecated Do not use.
1784      * @hide
1785      */
1786     @Deprecated
1787     @UnsupportedAppUsage
registerSuggestionSpansForNotification(SuggestionSpan[] spans)1788     public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
1789         Log.w(TAG, "registerSuggestionSpansForNotification() is deprecated.  Does nothing.");
1790     }
1791 
1792     /**
1793      * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing.
1794      *
1795      * @deprecated Do not use.
1796      * @hide
1797      */
1798     @Deprecated
1799     @UnsupportedAppUsage
notifySuggestionPicked(SuggestionSpan span, String originalString, int index)1800     public void notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
1801         Log.w(TAG, "notifySuggestionPicked() is deprecated.  Does nothing.");
1802     }
1803 
1804     /**
1805      * Allows you to discover whether the attached input method is running
1806      * in fullscreen mode.  Return true if it is fullscreen, entirely covering
1807      * your UI, else returns false.
1808      */
isFullscreenMode()1809     public boolean isFullscreenMode() {
1810         synchronized (mH) {
1811             return mFullscreenMode;
1812         }
1813     }
1814 
1815     /**
1816      * Return {@code true} if the given view is the currently active view for the input method.
1817      */
isActive(View view)1818     public boolean isActive(View view) {
1819         // Re-dispatch if there is a context mismatch.
1820         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
1821         if (fallbackImm != null) {
1822             return fallbackImm.isActive(view);
1823         }
1824 
1825         checkFocus();
1826         synchronized (mH) {
1827             return hasServedByInputMethodLocked(view) && mCurrentEditorInfo != null;
1828         }
1829     }
1830 
1831     /**
1832      * Return {@code true} if any view is currently active for the input method.
1833      */
isActive()1834     public boolean isActive() {
1835         checkFocus();
1836         synchronized (mH) {
1837             return getServedViewLocked() != null && mCurrentEditorInfo != null;
1838         }
1839     }
1840 
1841     /**
1842      * Returns {@code true} if the given view's {@link ViewRootImpl} is the currently active one
1843      * for the {@code InputMethodManager}.
1844      *
1845      * @hide
1846      */
1847     @TestApi
1848     @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
isCurrentRootView(@onNull View attachedView)1849     public boolean isCurrentRootView(@NonNull View attachedView) {
1850         synchronized (mH) {
1851             return mCurRootView == attachedView.getViewRootImpl();
1852         }
1853     }
1854 
1855     /**
1856      * Return {@code true} if the currently served view is accepting full text edits.
1857      * If {@code false}, it has no input connection, so it can only handle raw key events.
1858      */
isAcceptingText()1859     public boolean isAcceptingText() {
1860         checkFocus();
1861         synchronized (mH) {
1862             return mServedInputConnection != null;
1863         }
1864     }
1865 
1866     /**
1867      * Return {@code true} if the input method is suppressing system spell checker.
1868      */
isInputMethodSuppressingSpellChecker()1869     public boolean isInputMethodSuppressingSpellChecker() {
1870         synchronized (mH) {
1871             return mCurBindState != null
1872                     && mCurBindState.mIsInputMethodSuppressingSpellChecker;
1873         }
1874     }
1875 
1876     /**
1877      * Reset all of the state associated with being bound to an input method.
1878      */
1879     @GuardedBy("mH")
clearBindingLocked()1880     private void clearBindingLocked() {
1881         if (DEBUG) Log.v(TAG, "Clearing binding!");
1882         clearConnectionLocked();
1883         updateInputChannelLocked(null);
1884         mCurId = null; // for @UnsupportedAppUsage
1885         mCurMethod = null; // for @UnsupportedAppUsage
1886         // We only reset sequence number for input method, but not accessibility.
1887         mCurBindState = null;
1888     }
1889 
1890     /**
1891      * Reset all of the state associated with being bound to an accessibility service.
1892      */
1893     @GuardedBy("mH")
clearAccessibilityBindingLocked(int id)1894     private void clearAccessibilityBindingLocked(int id) {
1895         if (DEBUG) Log.v(TAG, "Clearing accessibility binding " + id);
1896         mAccessibilityInputMethodSession.remove(id);
1897     }
1898 
1899     /**
1900      * Reset all of the state associated with being bound to all accessibility services.
1901      */
1902     @GuardedBy("mH")
clearAllAccessibilityBindingLocked()1903     private void clearAllAccessibilityBindingLocked() {
1904         if (DEBUG) Log.v(TAG, "Clearing all accessibility bindings");
1905         mAccessibilityInputMethodSession.clear();
1906     }
1907 
1908     @GuardedBy("mH")
updateInputChannelLocked(InputChannel channel)1909     private void updateInputChannelLocked(InputChannel channel) {
1910         if (areSameInputChannel(mCurChannel, channel)) {
1911             return;
1912         }
1913         // TODO(b/238720598) : Requirements when design a new protocol for InputChannel
1914         // channel is a dupe of 'mCurChannel', because they have the same token, and represent
1915         // the same connection. Ignore the incoming channel and keep using 'mCurChannel' to
1916         // avoid confusing the InputEventReceiver.
1917         if (mCurSender != null) {
1918             flushPendingEventsLocked();
1919             mCurSender.dispose();
1920             mCurSender = null;
1921         }
1922 
1923         if (mCurChannel != null) {
1924             mCurChannel.dispose();
1925         }
1926         mCurChannel = channel;
1927     }
1928 
areSameInputChannel(@ullable InputChannel lhs, @Nullable InputChannel rhs)1929     private static boolean areSameInputChannel(@Nullable InputChannel lhs,
1930             @Nullable InputChannel rhs) {
1931         if (lhs == rhs) {
1932             return true;
1933         }
1934         if (lhs == null || rhs == null) {
1935             return false;
1936         }
1937         return lhs.getToken() == rhs.getToken();
1938     }
1939 
1940     /**
1941      * Reset all of the state associated with a served view being connected
1942      * to an input method
1943      */
1944     @GuardedBy("mH")
clearConnectionLocked()1945     private void clearConnectionLocked() {
1946         mCurrentEditorInfo = null;
1947         mPreviousViewFocusParameters = null;
1948         if (mServedInputConnection != null) {
1949             mServedInputConnection.deactivate();
1950             mServedInputConnection = null;
1951             mServedInputConnectionHandler = null;
1952         }
1953     }
1954 
1955     /**
1956      * Disconnect any existing input connection, clearing the served view.
1957      */
1958     @UnsupportedAppUsage
1959     @GuardedBy("mH")
finishInputLocked()1960     void finishInputLocked() {
1961         mVirtualDisplayToScreenMatrix = null;
1962         View clearedView = null;
1963         mNextServedView = null;
1964         if (mServedView != null) {
1965             clearedView = mServedView;
1966             mServedView = null;
1967         }
1968         if (clearedView != null) {
1969             if (DEBUG) {
1970                 Log.v(TAG, "FINISH INPUT: mServedView="
1971                         + InputMethodDebug.dumpViewInfo(clearedView));
1972             }
1973             mCompletions = null;
1974             mServedConnecting = false;
1975             clearConnectionLocked();
1976         }
1977         // Clear the back callbacks held by the ime dispatcher to avoid memory leaks.
1978         mImeDispatcher.clear();
1979     }
1980 
1981     /**
1982      * Clears the {@link #mCurRootView} if it's no longer window focused and the connection is
1983      * no longer active.
1984      *
1985      * @return {@code} true iff it was cleared.
1986      */
1987     @GuardedBy("mH")
clearCurRootViewIfNeeded()1988     private boolean clearCurRootViewIfNeeded() {
1989         if (!mActive && !mCurRootViewWindowFocused) {
1990             finishInputLocked();
1991             mDelegate.setCurrentRootViewLocked(null);
1992 
1993             return true;
1994         }
1995 
1996         return false;
1997     }
1998 
displayCompletions(View view, CompletionInfo[] completions)1999     public void displayCompletions(View view, CompletionInfo[] completions) {
2000         // Re-dispatch if there is a context mismatch.
2001         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2002         if (fallbackImm != null) {
2003             fallbackImm.displayCompletions(view, completions);
2004             return;
2005         }
2006 
2007         checkFocus();
2008         synchronized (mH) {
2009             if (!hasServedByInputMethodLocked(view)) {
2010                 return;
2011             }
2012 
2013             mCompletions = completions;
2014             if (isImeSessionAvailableLocked()) {
2015                 mCurBindState.mImeSession.displayCompletions(mCompletions);
2016             }
2017         }
2018     }
2019 
updateExtractedText(View view, int token, ExtractedText text)2020     public void updateExtractedText(View view, int token, ExtractedText text) {
2021         // Re-dispatch if there is a context mismatch.
2022         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2023         if (fallbackImm != null) {
2024             fallbackImm.updateExtractedText(view, token, text);
2025             return;
2026         }
2027 
2028         checkFocus();
2029         synchronized (mH) {
2030             if (!hasServedByInputMethodLocked(view)) {
2031                 return;
2032             }
2033 
2034             if (isImeSessionAvailableLocked()) {
2035                 mCurBindState.mImeSession.updateExtractedText(token, text);
2036             }
2037         }
2038     }
2039 
2040     /** @hide */
2041     @IntDef(flag = true, prefix = { "SHOW_" }, value = {
2042             SHOW_IMPLICIT,
2043             SHOW_FORCED,
2044     })
2045     @Retention(RetentionPolicy.SOURCE)
2046     public @interface ShowFlags {}
2047 
2048     /**
2049      * Flag for {@link #showSoftInput} to indicate that this is an implicit
2050      * request to show the input window, not as the result of a direct request
2051      * by the user.  The window may not be shown in this case.
2052      */
2053     public static final int SHOW_IMPLICIT = 0x0001;
2054 
2055     /**
2056      * Flag for {@link #showSoftInput} to indicate that the user has forced
2057      * the input method open (such as by long-pressing menu) so it should
2058      * not be closed until they explicitly do so.
2059      *
2060      * @deprecated Use {@link #showSoftInput} without this flag instead. Using this flag can lead
2061      * to the soft input remaining visible even when the calling application is closed. The
2062      * use of this flag can make the soft input remains visible globally. Starting in
2063      * {@link Build.VERSION_CODES#TIRAMISU Android T}, this flag only has an effect while the
2064      * caller is currently focused.
2065      */
2066     @Deprecated
2067     public static final int SHOW_FORCED = 0x0002;
2068 
2069     /**
2070      * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
2071      * a result receiver: explicitly request that the current input method's
2072      * soft input area be shown to the user, if needed.
2073      *
2074      * @param view The currently focused view, which would like to receive soft keyboard input.
2075      *             Note that this view is only considered focused here if both it itself has
2076      *             {@link View#isFocused view focus}, and its containing window has
2077      *             {@link View#hasWindowFocus window focus}. Otherwise the call fails and
2078      *             returns {@code false}.
2079      */
showSoftInput(View view, @ShowFlags int flags)2080     public boolean showSoftInput(View view, @ShowFlags int flags) {
2081         // Re-dispatch if there is a context mismatch.
2082         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2083         if (fallbackImm != null) {
2084             return fallbackImm.showSoftInput(view, flags);
2085         }
2086 
2087         return showSoftInput(view, flags, null);
2088     }
2089 
2090     /**
2091      * Flag for the {@link ResultReceiver} result code from
2092      * {@link #showSoftInput(View, int, ResultReceiver)} and
2093      * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
2094      * state of the soft input window was unchanged and remains shown.
2095      */
2096     public static final int RESULT_UNCHANGED_SHOWN = 0;
2097 
2098     /**
2099      * Flag for the {@link ResultReceiver} result code from
2100      * {@link #showSoftInput(View, int, ResultReceiver)} and
2101      * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
2102      * state of the soft input window was unchanged and remains hidden.
2103      */
2104     public static final int RESULT_UNCHANGED_HIDDEN = 1;
2105 
2106     /**
2107      * Flag for the {@link ResultReceiver} result code from
2108      * {@link #showSoftInput(View, int, ResultReceiver)} and
2109      * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
2110      * state of the soft input window changed from hidden to shown.
2111      */
2112     public static final int RESULT_SHOWN = 2;
2113 
2114     /**
2115      * Flag for the {@link ResultReceiver} result code from
2116      * {@link #showSoftInput(View, int, ResultReceiver)} and
2117      * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
2118      * state of the soft input window changed from shown to hidden.
2119      */
2120     public static final int RESULT_HIDDEN = 3;
2121 
2122     /**
2123      * Explicitly request that the current input method's soft input area be
2124      * shown to the user, if needed.  Call this if the user interacts with
2125      * your view in such a way that they have expressed they would like to
2126      * start performing input into it.
2127      *
2128      * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
2129      * this method can be a long-lived object, because it may not be
2130      * garbage-collected until all the corresponding {@link ResultReceiver}
2131      * objects transferred to different processes get garbage-collected.
2132      * Follow the general patterns to avoid memory leaks in Android.
2133      * Consider to use {@link java.lang.ref.WeakReference} so that application
2134      * logic objects such as {@link android.app.Activity} and {@link Context}
2135      * can be garbage collected regardless of the lifetime of
2136      * {@link ResultReceiver}.
2137      *
2138      * @param view The currently focused view, which would like to receive soft keyboard input.
2139      *             Note that this view is only considered focused here if both it itself has
2140      *             {@link View#isFocused view focus}, and its containing window has
2141      *             {@link View#hasWindowFocus window focus}. Otherwise the call fails and
2142      *             returns {@code false}.
2143      * @param resultReceiver If non-null, this will be called by the IME when
2144      * it has processed your request to tell you what it has done.  The result
2145      * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
2146      * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
2147      * {@link #RESULT_HIDDEN}.
2148      */
showSoftInput(View view, @ShowFlags int flags, ResultReceiver resultReceiver)2149     public boolean showSoftInput(View view, @ShowFlags int flags, ResultReceiver resultReceiver) {
2150         return showSoftInput(view, null /* statsToken */, flags, resultReceiver,
2151                 SoftInputShowHideReason.SHOW_SOFT_INPUT);
2152     }
2153 
showSoftInput(View view, @Nullable ImeTracker.Token statsToken, @ShowFlags int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason)2154     private boolean showSoftInput(View view, @Nullable ImeTracker.Token statsToken,
2155             @ShowFlags int flags, ResultReceiver resultReceiver,
2156             @SoftInputShowHideReason int reason) {
2157         if (statsToken == null) {
2158             statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
2159                     Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, reason);
2160         }
2161         ImeTracker.forLatency().onRequestShow(statsToken, ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
2162                 reason, ActivityThread::currentApplication);
2163         ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this,
2164                 null /* icProto */);
2165         // Re-dispatch if there is a context mismatch.
2166         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2167         if (fallbackImm != null) {
2168             return fallbackImm.showSoftInput(view, statsToken, flags, resultReceiver, reason);
2169         }
2170 
2171         checkFocus();
2172         synchronized (mH) {
2173             if (!hasServedByInputMethodLocked(view)) {
2174                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
2175                 ImeTracker.forLatency().onShowFailed(
2176                         statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED,
2177                         ActivityThread::currentApplication);
2178                 Log.w(TAG, "Ignoring showSoftInput() as view=" + view + " is not served.");
2179                 return false;
2180             }
2181 
2182             ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
2183 
2184             // Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
2185             // TODO(b/229426865): call WindowInsetsController#show instead.
2186             mH.executeOrSendMessage(Message.obtain(mH, MSG_ON_SHOW_REQUESTED));
2187             Log.d(TAG, "showSoftInput() view=" + view + " flags=" + flags + " reason="
2188                     + InputMethodDebug.softInputDisplayReasonToString(reason));
2189             return IInputMethodManagerGlobalInvoker.showSoftInput(
2190                     mClient,
2191                     view.getWindowToken(),
2192                     statsToken,
2193                     flags,
2194                     mCurRootView.getLastClickToolType(),
2195                     resultReceiver,
2196                     reason);
2197         }
2198     }
2199 
2200     /**
2201      * This method is still kept for a while until androidx.appcompat.widget.SearchView ver. 26.0
2202      * is publicly released because previous implementations of that class had relied on this method
2203      * via reflection.
2204      *
2205      * @deprecated This is a hidden API. You should never use this.
2206      * @hide
2207      */
2208     @Deprecated
2209     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
showSoftInputUnchecked(@howFlags int flags, ResultReceiver resultReceiver)2210     public void showSoftInputUnchecked(@ShowFlags int flags, ResultReceiver resultReceiver) {
2211         synchronized (mH) {
2212             final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestShow(
2213                     null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
2214                     SoftInputShowHideReason.SHOW_SOFT_INPUT);
2215 
2216             Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be"
2217                     + " removed soon. If you are using androidx.appcompat.widget.SearchView,"
2218                     + " please update to version 26.0 or newer version.");
2219             if (mCurRootView == null || mCurRootView.getView() == null) {
2220                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
2221                 Log.w(TAG, "No current root view, ignoring showSoftInputUnchecked()");
2222                 return;
2223             }
2224 
2225             ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
2226 
2227             // Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
2228             // TODO(b/229426865): call WindowInsetsController#show instead.
2229             mH.executeOrSendMessage(Message.obtain(mH, MSG_ON_SHOW_REQUESTED));
2230             IInputMethodManagerGlobalInvoker.showSoftInput(
2231                     mClient,
2232                     mCurRootView.getView().getWindowToken(),
2233                     statsToken,
2234                     flags,
2235                     mCurRootView.getLastClickToolType(),
2236                     resultReceiver,
2237                     SoftInputShowHideReason.SHOW_SOFT_INPUT);
2238         }
2239     }
2240 
2241     /** @hide */
2242     @IntDef(flag = true, prefix = { "HIDE_" }, value = {
2243             HIDE_IMPLICIT_ONLY,
2244             HIDE_NOT_ALWAYS,
2245     })
2246     @Retention(RetentionPolicy.SOURCE)
2247     public @interface HideFlags {}
2248 
2249     /**
2250      * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestHideSelf(int)}
2251      * to indicate that the soft input window should only be hidden if it was not explicitly shown
2252      * by the user.
2253      */
2254     public static final int HIDE_IMPLICIT_ONLY = 0x0001;
2255 
2256     /**
2257      * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestShowSelf(int)}
2258      * to indicate that the soft input window should normally be hidden, unless it was originally
2259      * shown with {@link #SHOW_FORCED}.
2260      */
2261     public static final int HIDE_NOT_ALWAYS = 0x0002;
2262 
2263     /**
2264      * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}
2265      * without a result: request to hide the soft input window from the
2266      * context of the window that is currently accepting input.
2267      *
2268      * @param windowToken The token of the window that is making the request,
2269      * as returned by {@link View#getWindowToken() View.getWindowToken()}.
2270      */
hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags)2271     public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags) {
2272         return hideSoftInputFromWindow(windowToken, flags, null);
2273     }
2274 
2275     /**
2276      * Request to hide the soft input window from the context of the window
2277      * that is currently accepting input.  This should be called as a result
2278      * of the user doing some actually than fairly explicitly requests to
2279      * have the input window hidden.
2280      *
2281      * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
2282      * this method can be a long-lived object, because it may not be
2283      * garbage-collected until all the corresponding {@link ResultReceiver}
2284      * objects transferred to different processes get garbage-collected.
2285      * Follow the general patterns to avoid memory leaks in Android.
2286      * Consider to use {@link java.lang.ref.WeakReference} so that application
2287      * logic objects such as {@link android.app.Activity} and {@link Context}
2288      * can be garbage collected regardless of the lifetime of
2289      * {@link ResultReceiver}.
2290      *
2291      * @param windowToken The token of the window that is making the request,
2292      * as returned by {@link View#getWindowToken() View.getWindowToken()}.
2293      * @param resultReceiver If non-null, this will be called by the IME when
2294      * it has processed your request to tell you what it has done.  The result
2295      * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
2296      * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
2297      * {@link #RESULT_HIDDEN}.
2298      */
hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags, ResultReceiver resultReceiver)2299     public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags,
2300             ResultReceiver resultReceiver) {
2301         return hideSoftInputFromWindow(windowToken, flags, resultReceiver,
2302                 SoftInputShowHideReason.HIDE_SOFT_INPUT);
2303     }
2304 
hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason)2305     private boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags,
2306             ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
2307         final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
2308                 null /* component */, Process.myUid(),
2309                 ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, reason);
2310         ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
2311                 reason, ActivityThread::currentApplication);
2312         ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
2313                 this, null /* icProto */);
2314         checkFocus();
2315         synchronized (mH) {
2316             final View servedView = getServedViewLocked();
2317             if (servedView == null || servedView.getWindowToken() != windowToken) {
2318                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
2319                 ImeTracker.forLatency().onHideFailed(statsToken,
2320                         ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
2321                 return false;
2322             }
2323 
2324             ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
2325 
2326             return IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, windowToken, statsToken,
2327                     flags, resultReceiver, reason);
2328         }
2329     }
2330 
2331     /**
2332      * Start stylus handwriting session.
2333      *
2334      * If supported by the current input method, a stylus handwriting session is started on the
2335      * given View, capturing all stylus input and converting it to InputConnection commands.
2336      *
2337      * If handwriting mode is started successfully by the IME, any currently dispatched stylus
2338      * pointers will be {@code android.view.MotionEvent#FLAG_CANCELED} cancelled.
2339      *
2340      * If Stylus handwriting mode is not supported or cannot be fulfilled for any reason by IME,
2341      * request will be ignored and Stylus touch will continue as normal touch input. Ideally,
2342      * {@link #isStylusHandwritingAvailable()} should be called first to determine if stylus
2343      * handwriting is supported by IME.
2344      *
2345      * @param view the View for which stylus handwriting is requested. It and
2346      * {@link View#hasWindowFocus its window} must be {@link View#hasFocus focused}.
2347      * @see #isStylusHandwritingAvailable()
2348      */
startStylusHandwriting(@onNull View view)2349     public void startStylusHandwriting(@NonNull View view) {
2350         startStylusHandwritingInternal(view, null /* delegatorPackageName */);
2351     }
2352 
startStylusHandwritingInternal( @onNull View view, @Nullable String delegatorPackageName)2353     private boolean startStylusHandwritingInternal(
2354             @NonNull View view, @Nullable String delegatorPackageName) {
2355         Objects.requireNonNull(view);
2356 
2357         // Re-dispatch if there is a context mismatch.
2358         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2359         if (fallbackImm != null) {
2360             fallbackImm.startStylusHandwritingInternal(view, delegatorPackageName);
2361         }
2362 
2363         boolean useDelegation = !TextUtils.isEmpty(delegatorPackageName);
2364 
2365         checkFocus();
2366         synchronized (mH) {
2367             if (!hasServedByInputMethodLocked(view)) {
2368                 Log.w(TAG,
2369                         "Ignoring startStylusHandwriting as view=" + view + " is not served.");
2370                 return false;
2371             }
2372             if (view.getViewRootImpl() != mCurRootView) {
2373                 Log.w(TAG,
2374                         "Ignoring startStylusHandwriting: View's window does not have focus.");
2375                 return false;
2376             }
2377             if (useDelegation) {
2378                 return IInputMethodManagerGlobalInvoker.acceptStylusHandwritingDelegation(
2379                         mClient, UserHandle.myUserId(), view.getContext().getOpPackageName(),
2380                         delegatorPackageName);
2381             } else {
2382                 IInputMethodManagerGlobalInvoker.startStylusHandwriting(mClient);
2383             }
2384             return false;
2385         }
2386     }
2387 
2388     /**
2389      * Prepares delegation of starting stylus handwriting session to a different editor in same
2390      * or different window than the view on which initial handwriting stroke was detected.
2391      *
2392      * Delegation can be used to start stylus handwriting session before the {@link Editor} view or
2393      * its {@link InputConnection} is started. Calling this method starts buffering of stylus
2394      * motion events until {@link #acceptStylusHandwritingDelegation(View)} is called, at which
2395      * point the handwriting session can be started and the buffered stylus motion events will be
2396      * delivered to the IME.
2397      * e.g. Delegation can be used when initial handwriting stroke is
2398      * on a pseudo {@link Editor} like widget (with no {@link InputConnection}) but actual
2399      * {@link Editor} is on a different window.
2400      *
2401      * <p> Note: If an actual {@link Editor} capable of {@link InputConnection} is being scribbled
2402      * upon using stylus, use {@link #startStylusHandwriting(View)} instead.</p>
2403      *
2404      * @param delegatorView the view that receives initial stylus stroke and delegates it to the
2405      *  actual editor. Its window must {@link View#hasWindowFocus have focus}.
2406      * @see #prepareStylusHandwritingDelegation(View, String)
2407      * @see #acceptStylusHandwritingDelegation(View)
2408      * @see #startStylusHandwriting(View)
2409      */
prepareStylusHandwritingDelegation(@onNull View delegatorView)2410     public void prepareStylusHandwritingDelegation(@NonNull View delegatorView) {
2411         prepareStylusHandwritingDelegation(
2412                 delegatorView, delegatorView.getContext().getOpPackageName());
2413     }
2414 
2415     /**
2416      * Prepares delegation of starting stylus handwriting session to a different editor in same or a
2417      * different window in a different package than the view on which initial handwriting stroke
2418      * was detected.
2419      *
2420      * Delegation can be used to start stylus handwriting session before the {@link Editor} view or
2421      * its {@link InputConnection} is started. Calling this method starts buffering of stylus
2422      * motion events until {@link #acceptStylusHandwritingDelegation(View, String)} is called, at
2423      * which point the handwriting session can be started and the buffered stylus motion events will
2424      * be delivered to the IME.
2425      * e.g. Delegation can be used when initial handwriting stroke is
2426      * on a pseudo {@link Editor} like widget (with no {@link InputConnection}) but actual
2427      * {@link Editor} is on a different window in the given package.
2428      *
2429      * <p>Note: If delegator and delegate are in same package use
2430      * {@link #prepareStylusHandwritingDelegation(View)} instead.</p>
2431      *
2432      * @param delegatorView  the view that receives initial stylus stroke and delegates it to the
2433      * actual editor. Its window must {@link View#hasWindowFocus have focus}.
2434      * @param delegatePackageName package name that contains actual {@link Editor} which should
2435      *  start stylus handwriting session by calling {@link #acceptStylusHandwritingDelegation}.
2436      * @see #prepareStylusHandwritingDelegation(View)
2437      * @see #acceptStylusHandwritingDelegation(View, String)
2438      */
prepareStylusHandwritingDelegation( @onNull View delegatorView, @NonNull String delegatePackageName)2439     public void prepareStylusHandwritingDelegation(
2440             @NonNull View delegatorView, @NonNull String delegatePackageName) {
2441         Objects.requireNonNull(delegatorView);
2442         Objects.requireNonNull(delegatePackageName);
2443 
2444         // Re-dispatch if there is a context mismatch.
2445         final InputMethodManager fallbackImm =
2446                 getFallbackInputMethodManagerIfNecessary(delegatorView);
2447         if (fallbackImm != null) {
2448             fallbackImm.prepareStylusHandwritingDelegation(delegatorView, delegatePackageName);
2449         }
2450 
2451         IInputMethodManagerGlobalInvoker.prepareStylusHandwritingDelegation(
2452                 mClient,
2453                 UserHandle.myUserId(),
2454                 delegatePackageName,
2455                 delegatorView.getContext().getOpPackageName());
2456     }
2457 
2458     /**
2459      * Accepts and starts a stylus handwriting session on the delegate view, if handwriting
2460      * initiation delegation was previously requested using
2461      * {@link #prepareStylusHandwritingDelegation(View)} from the delegator.
2462      *
2463      * <p>Note: If delegator and delegate are in different application packages, use
2464      * {@link #acceptStylusHandwritingDelegation(View, String)} instead.</p>
2465      *
2466      * @param delegateView delegate view capable of receiving input via {@link InputConnection}
2467      *  on which {@link #startStylusHandwriting(View)} will be called.
2468      * @return {@code true} if view belongs to same application package as used in
2469      *  {@link #prepareStylusHandwritingDelegation(View)} and handwriting session can start.
2470      * @see #acceptStylusHandwritingDelegation(View, String)
2471      * @see #prepareStylusHandwritingDelegation(View)
2472      */
acceptStylusHandwritingDelegation(@onNull View delegateView)2473     public boolean acceptStylusHandwritingDelegation(@NonNull View delegateView) {
2474         return startStylusHandwritingInternal(
2475                 delegateView, delegateView.getContext().getOpPackageName());
2476     }
2477 
2478     /**
2479      * Accepts and starts a stylus handwriting session on the delegate view, if handwriting
2480      * initiation delegation was previously requested using
2481      * {@link #prepareStylusHandwritingDelegation(View, String)} from te delegator and the view
2482      * belongs to a specified delegate package.
2483      *
2484      * <p>Note: If delegator and delegate are in same application package use
2485      * {@link #acceptStylusHandwritingDelegation(View)} instead.</p>
2486      *
2487      * @param delegateView delegate view capable of receiving input via {@link InputConnection}
2488      *  on which {@link #startStylusHandwriting(View)} will be called.
2489      * @param delegatorPackageName package name of the delegator that handled initial stylus stroke.
2490      * @return {@code true} if view belongs to allowed delegate package declared in
2491      *  {@link #prepareStylusHandwritingDelegation(View, String)} and handwriting session can start.
2492      * @see #prepareStylusHandwritingDelegation(View, String)
2493      * @see #acceptStylusHandwritingDelegation(View)
2494      */
acceptStylusHandwritingDelegation( @onNull View delegateView, @NonNull String delegatorPackageName)2495     public boolean acceptStylusHandwritingDelegation(
2496             @NonNull View delegateView, @NonNull String delegatorPackageName) {
2497         Objects.requireNonNull(delegatorPackageName);
2498 
2499         return startStylusHandwritingInternal(delegateView, delegatorPackageName);
2500     }
2501 
2502     /**
2503      * This method toggles the input method window display.
2504      * If the input window is already displayed, it gets hidden.
2505      * If not the input window will be displayed.
2506      * @param windowToken The token of the window that is making the request,
2507      * as returned by {@link View#getWindowToken() View.getWindowToken()}.
2508      *
2509      * @deprecated Use {@link #showSoftInput(View, int)} or
2510      * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead.
2511      * In particular during focus changes, the current visibility of the IME is not
2512      * well defined. Starting in {@link Build.VERSION_CODES#S Android S}, this only
2513      * has an effect if the calling app is the current IME focus.
2514      */
2515     @Deprecated
toggleSoftInputFromWindow(IBinder windowToken, @ShowFlags int showFlags, @HideFlags int hideFlags)2516     public void toggleSoftInputFromWindow(IBinder windowToken, @ShowFlags int showFlags,
2517             @HideFlags int hideFlags) {
2518         ImeTracing.getInstance().triggerClientDump(
2519                 "InputMethodManager#toggleSoftInputFromWindow", InputMethodManager.this,
2520                 null /* icProto */);
2521         synchronized (mH) {
2522             final View servedView = getServedViewLocked();
2523             if (servedView == null || servedView.getWindowToken() != windowToken) {
2524                 return;
2525             }
2526             toggleSoftInput(showFlags, hideFlags);
2527         }
2528     }
2529 
2530     /**
2531      * This method toggles the input method window display.
2532      *
2533      * If the input window is already displayed, it gets hidden.
2534      * If not the input window will be displayed.
2535      *
2536      * @deprecated Use {@link #showSoftInput(View, int)} or
2537      * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead.
2538      * In particular during focus changes, the current visibility of the IME is not
2539      * well defined. Starting in {@link Build.VERSION_CODES#S Android S}, this only
2540      * has an effect if the calling app is the current IME focus.
2541      */
2542     @Deprecated
toggleSoftInput(@howFlags int showFlags, @HideFlags int hideFlags)2543     public void toggleSoftInput(@ShowFlags int showFlags, @HideFlags int hideFlags) {
2544         ImeTracing.getInstance().triggerClientDump(
2545                 "InputMethodManager#toggleSoftInput", InputMethodManager.this,
2546                 null /* icProto */);
2547         synchronized (mH) {
2548             final View view = getServedViewLocked();
2549             if (view != null) {
2550                 final WindowInsets rootInsets = view.getRootWindowInsets();
2551                 if (rootInsets != null && rootInsets.isVisible(WindowInsets.Type.ime())) {
2552                     hideSoftInputFromWindow(view.getWindowToken(), hideFlags, null,
2553                             SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT);
2554                 } else {
2555                     showSoftInput(view, null /* statsToken */, showFlags, null /* resultReceiver */,
2556                             SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT);
2557                 }
2558             }
2559         }
2560     }
2561 
2562     /**
2563      * If the input method is currently connected to the given view,
2564      * restart it with its new contents.  You should call this when the text
2565      * within your view changes outside of the normal input method or key
2566      * input flow, such as when an application calls TextView.setText().
2567      *
2568      * @param view The view whose text has changed.
2569      */
restartInput(View view)2570     public void restartInput(View view) {
2571         // Re-dispatch if there is a context mismatch.
2572         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2573         if (fallbackImm != null) {
2574             fallbackImm.restartInput(view);
2575             return;
2576         }
2577 
2578         checkFocus();
2579         synchronized (mH) {
2580             if (!hasServedByInputMethodLocked(view)) {
2581                 return;
2582             }
2583 
2584             mServedConnecting = true;
2585         }
2586 
2587         startInputInner(StartInputReason.APP_CALLED_RESTART_INPUT_API, null, 0, 0, 0);
2588     }
2589 
2590     /**
2591      * Sends an async signal to the IME to reset the currently served {@link InputConnection}.
2592      *
2593      * @param inputConnection the connection to be invalidated.
2594      * @param textSnapshot {@link TextSnapshot} to be used to update {@link EditorInfo}.
2595      * @param sessionId the session ID to be sent.
2596      * @return {@code true} if the operation is done. {@code false} if the caller needs to fall back
2597      *         to {@link InputMethodManager#restartInput(View)}.
2598      * @hide
2599      */
doInvalidateInput(@onNull RemoteInputConnectionImpl inputConnection, @NonNull TextSnapshot textSnapshot, int sessionId)2600     public boolean doInvalidateInput(@NonNull RemoteInputConnectionImpl inputConnection,
2601             @NonNull TextSnapshot textSnapshot, int sessionId) {
2602         synchronized (mH) {
2603             if (mServedInputConnection != inputConnection || mCurrentEditorInfo == null) {
2604                 // OK to ignore because the calling InputConnection is already abandoned.
2605                 return true;
2606             }
2607             if (!isImeSessionAvailableLocked()) {
2608                 // IME is not yet bound to the client.  Need to fall back to the restartInput().
2609                 return false;
2610             }
2611             final EditorInfo editorInfo = mCurrentEditorInfo.createCopyInternal();
2612             editorInfo.initialSelStart = mCursorSelStart = textSnapshot.getSelectionStart();
2613             editorInfo.initialSelEnd = mCursorSelEnd = textSnapshot.getSelectionEnd();
2614             mCursorCandStart = textSnapshot.getCompositionStart();
2615             mCursorCandEnd = textSnapshot.getCompositionEnd();
2616             editorInfo.initialCapsMode = textSnapshot.getCursorCapsMode();
2617             editorInfo.setInitialSurroundingTextInternal(textSnapshot.getSurroundingText());
2618             mCurBindState.mImeSession.invalidateInput(editorInfo, mServedInputConnection,
2619                     sessionId);
2620             final IRemoteAccessibilityInputConnection accessibilityInputConnection =
2621                     mServedInputConnection.asIRemoteAccessibilityInputConnection();
2622             forAccessibilitySessionsLocked(wrapper -> wrapper.invalidateInput(editorInfo,
2623                     accessibilityInputConnection, sessionId));
2624             return true;
2625         }
2626     }
2627 
2628     /**
2629      * Gives a hint to the system that the text associated with {@code view} is updated by something
2630      * that is not an input method editor (IME), so that the system can cancel any pending text
2631      * editing requests from the IME until it receives the new editing context such as surrounding
2632      * text provided by {@link InputConnection#takeSnapshot()}.
2633      *
2634      * <p>When {@code view} does not support {@link InputConnection#takeSnapshot()} protocol,
2635      * calling this method may trigger {@link View#onCreateInputConnection(EditorInfo)}.</p>
2636      *
2637      * <p>Unlike {@link #restartInput(View)}, this API does not immediately interact with
2638      * {@link InputConnection}.  Instead, the application may later receive
2639      * {@link InputConnection#takeSnapshot()} as needed so that the system can capture new editing
2640      * context for the IME.  For instance, successive invocations of this API can be coerced into a
2641      * single (or zero) callback of {@link InputConnection#takeSnapshot()}.</p>
2642      *
2643      * @param view The view whose text has changed.
2644      * @see #restartInput(View)
2645      */
invalidateInput(@onNull View view)2646     public void invalidateInput(@NonNull View view) {
2647         Objects.requireNonNull(view);
2648 
2649         // Re-dispatch if there is a context mismatch.
2650         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
2651         if (fallbackImm != null) {
2652             fallbackImm.invalidateInput(view);
2653             return;
2654         }
2655 
2656         synchronized (mH) {
2657             if (mServedInputConnection == null || getServedViewLocked() != view) {
2658                 return;
2659             }
2660             mServedInputConnection.scheduleInvalidateInput();
2661         }
2662     }
2663 
2664     /**
2665      * Starts an input connection from the served view that gains the window focus.
2666      * Note that this method should *NOT* be called inside of {@code mH} lock to prevent start input
2667      * background thread may blocked by other methods which already inside {@code mH} lock.
2668      *
2669      * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
2670      * {@code userId} is different from the user id of the current process.</p>
2671      */
2672     @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
startInputInner(@tartInputReason int startInputReason, @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags)2673     private boolean startInputInner(@StartInputReason int startInputReason,
2674             @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags,
2675             @SoftInputModeFlags int softInputMode, int windowFlags) {
2676         final View view;
2677         synchronized (mH) {
2678             view = getServedViewLocked();
2679 
2680             // Make sure we have a window token for the served view.
2681             if (DEBUG) {
2682                 Log.v(TAG, "Starting input: view=" + InputMethodDebug.dumpViewInfo(view) +
2683                         " reason=" + InputMethodDebug.startInputReasonToString(startInputReason));
2684             }
2685             if (view == null) {
2686                 if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
2687                 return false;
2688             }
2689         }
2690 
2691         // Now we need to get an input connection from the served view.
2692         // This is complicated in a couple ways: we can't be holding our lock
2693         // when calling out to the view, and we need to make sure we call into
2694         // the view on the same thread that is driving its view hierarchy.
2695         Handler vh = view.getHandler();
2696         if (vh == null) {
2697             // If the view doesn't have a handler, something has changed out
2698             // from under us, so just close the current input.
2699             // If we don't close the current input, the current input method can remain on the
2700             // screen without a connection.
2701             if (DEBUG) Log.v(TAG, "ABORT input: no handler for view! Close current input.");
2702             closeCurrentInput();
2703             return false;
2704         }
2705         if (vh.getLooper() != Looper.myLooper()) {
2706             // The view is running on a different thread than our own, so
2707             // we need to reschedule our work for over there.
2708             if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
2709             vh.post(() -> startInputOnWindowFocusGainInternal(startInputReason, null, 0, 0, 0));
2710             return false;
2711         }
2712 
2713         if (windowGainingFocus == null) {
2714             windowGainingFocus = view.getWindowToken();
2715             if (windowGainingFocus == null) {
2716                 Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
2717                 return false;
2718             }
2719             startInputFlags = getStartInputFlags(view, startInputFlags);
2720             softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
2721             windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
2722         }
2723 
2724         // Okay we are now ready to call into the served view and have it
2725         // do its stuff.
2726         // Life is good: let's hook everything up!
2727         final Pair<InputConnection, EditorInfo> connectionPair = createInputConnection(view);
2728         final InputConnection ic = connectionPair.first;
2729         final EditorInfo editorInfo = connectionPair.second;
2730         final Handler icHandler;
2731         InputBindResult res = null;
2732         final boolean hasServedView;
2733         synchronized (mH) {
2734             // Now that we are locked again, validate that our state hasn't
2735             // changed.
2736             final View servedView = getServedViewLocked();
2737             if (servedView != view || !mServedConnecting) {
2738                 // Something else happened, so abort.
2739                 if (DEBUG) Log.v(TAG, "Starting input: finished by someone else."
2740                         + " view=" + InputMethodDebug.dumpViewInfo(view)
2741                         + " servedView=" + InputMethodDebug.dumpViewInfo(servedView)
2742                         + " mServedConnecting=" + mServedConnecting);
2743                 if (mServedInputConnection != null && startInputReason == BOUND_TO_IMMS) {
2744                     // This is not an error. Once IME binds (MSG_BIND), InputConnection is fully
2745                     // established. So we report this to interested recipients.
2746                     reportInputConnectionOpened(
2747                             mServedInputConnection.getInputConnection(), mCurrentEditorInfo,
2748                             mServedInputConnectionHandler, view);
2749                 }
2750                 return false;
2751             }
2752 
2753             // If we already have a text box, then this view is already
2754             // connected so we want to restart it.
2755             if (mCurrentEditorInfo == null) {
2756                 startInputFlags |= StartInputFlags.INITIAL_CONNECTION;
2757             }
2758 
2759             editorInfo.setInitialToolType(mCurRootView.getLastClickToolType());
2760 
2761             // Hook 'em up and let 'er rip.
2762             mCurrentEditorInfo = editorInfo.createCopyInternal();
2763             // Store the previously served connection so that we can determine whether it is safe
2764             // to skip the call to startInputOrWindowGainedFocus in the IMMS
2765             final RemoteInputConnectionImpl previouslyServedConnection = mServedInputConnection;
2766 
2767             mServedConnecting = false;
2768             if (mServedInputConnection != null) {
2769                 mServedInputConnection.deactivate();
2770                 mServedInputConnection = null;
2771                 mServedInputConnectionHandler = null;
2772             }
2773             final RemoteInputConnectionImpl servedInputConnection;
2774             if (ic != null) {
2775                 mCursorSelStart = editorInfo.initialSelStart;
2776                 mCursorSelEnd = editorInfo.initialSelEnd;
2777                 mInitialSelStart = mCursorSelStart;
2778                 mInitialSelEnd = mCursorSelEnd;
2779                 mCursorCandStart = -1;
2780                 mCursorCandEnd = -1;
2781                 mCursorRect.setEmpty();
2782                 mCursorAnchorInfo = null;
2783                 Handler handler = null;
2784                 try {
2785                     handler = ic.getHandler();
2786                 } catch (AbstractMethodError ignored) {
2787                     // TODO(b/199934664): See if we can remove this by providing a default impl.
2788                 }
2789                 icHandler = handler;
2790                 mServedInputConnectionHandler = icHandler;
2791                 servedInputConnection = new RemoteInputConnectionImpl(
2792                         icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
2793             } else {
2794                 servedInputConnection = null;
2795                 icHandler = null;
2796                 mServedInputConnectionHandler = null;
2797             }
2798             mServedInputConnection = servedInputConnection;
2799 
2800             if (DEBUG) {
2801                 Log.v(TAG, "START INPUT: view=" + InputMethodDebug.dumpViewInfo(view)
2802                         + " ic=" + ic + " editorInfo=" + editorInfo + " startInputFlags="
2803                         + InputMethodDebug.startInputFlagsToString(startInputFlags));
2804             }
2805 
2806             // When we switch between non-editable views, do not call into the IMMS.
2807             final boolean canSkip = OPTIMIZE_NONEDITABLE_VIEWS
2808                     && previouslyServedConnection == null
2809                     && ic == null
2810                     && isSwitchingBetweenEquivalentNonEditableViews(
2811                             mPreviousViewFocusParameters, startInputFlags,
2812                             startInputReason, softInputMode, windowFlags);
2813             mPreviousViewFocusParameters = new ViewFocusParameterInfo(mCurrentEditorInfo,
2814                     startInputFlags, startInputReason, softInputMode, windowFlags);
2815             if (canSkip) {
2816                 if (DEBUG) {
2817                     Log.d(TAG, "Not calling IMMS due to switching between non-editable views.");
2818                 }
2819                 return false;
2820             }
2821             final int targetUserId = editorInfo.targetInputMethodUser != null
2822                     ? editorInfo.targetInputMethodUser.getIdentifier() : UserHandle.myUserId();
2823             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMM.startInputOrWindowGainedFocus");
2824             res = IInputMethodManagerGlobalInvoker.startInputOrWindowGainedFocus(
2825                     startInputReason, mClient, windowGainingFocus, startInputFlags,
2826                     softInputMode, windowFlags, editorInfo, servedInputConnection,
2827                     servedInputConnection == null ? null
2828                             : servedInputConnection.asIRemoteAccessibilityInputConnection(),
2829                     view.getContext().getApplicationInfo().targetSdkVersion, targetUserId,
2830                     mImeDispatcher);
2831             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
2832             if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
2833             if (res == null) {
2834                 Log.wtf(TAG, "startInputOrWindowGainedFocus must not return"
2835                         + " null. startInputReason="
2836                         + InputMethodDebug.startInputReasonToString(startInputReason)
2837                         + " editorInfo=" + editorInfo
2838                         + " startInputFlags="
2839                         + InputMethodDebug.startInputFlagsToString(startInputFlags));
2840                 return false;
2841             }
2842             mVirtualDisplayToScreenMatrix = res.getVirtualDisplayToScreenMatrix();
2843             if (res.id != null) {
2844                 updateInputChannelLocked(res.channel);
2845                 mCurMethod = res.method; // for @UnsupportedAppUsage
2846                 mCurBindState = new BindState(res);
2847                 mAccessibilityInputMethodSession.clear();
2848                 if (res.accessibilitySessions != null) {
2849                     for (int i = 0; i < res.accessibilitySessions.size(); i++) {
2850                         IAccessibilityInputMethodSessionInvoker wrapper =
2851                                 IAccessibilityInputMethodSessionInvoker.createOrNull(
2852                                         res.accessibilitySessions.valueAt(i));
2853                         if (wrapper != null) {
2854                             mAccessibilityInputMethodSession.append(
2855                                     res.accessibilitySessions.keyAt(i), wrapper);
2856                         }
2857                     }
2858                 }
2859                 mCurId = res.id; // for @UnsupportedAppUsage
2860             } else if (res.channel != null && res.channel != mCurChannel) {
2861                 res.channel.dispose();
2862             }
2863             switch (res.result) {
2864                 case InputBindResult.ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
2865                     mRestartOnNextWindowFocus = true;
2866                     mServedView = null;
2867                     break;
2868             }
2869             if (mCompletions != null) {
2870                 if (isImeSessionAvailableLocked()) {
2871                     mCurBindState.mImeSession.displayCompletions(mCompletions);
2872                 }
2873             }
2874             hasServedView = mServedView != null;
2875         }
2876 
2877         // Notify the app that the InputConnection is initialized and ready for use.
2878         if (ic != null && res != null && res.method != null && hasServedView) {
2879             if (DEBUG) {
2880                 Log.v(TAG, "Calling View.onInputConnectionOpened: view= " + view
2881                         + ", ic=" + ic + ", editorInfo=" + editorInfo + ", handler=" + icHandler);
2882             }
2883             reportInputConnectionOpened(ic, editorInfo, icHandler, view);
2884         }
2885 
2886         return true;
2887     }
2888 
2889     /**
2890      * @return {@code true} when we are switching focus between two non-editable views
2891      * so that we can avoid calling {@link IInputMethodManager#startInputOrWindowGainedFocus}.
2892      */
2893     @GuardedBy("mH")
isSwitchingBetweenEquivalentNonEditableViews( @ullable ViewFocusParameterInfo previousViewFocusParameters, @StartInputFlags int startInputFlags, @StartInputReason int startInputReason, @SoftInputModeFlags int softInputMode, int windowFlags)2894     private boolean isSwitchingBetweenEquivalentNonEditableViews(
2895             @Nullable ViewFocusParameterInfo previousViewFocusParameters,
2896             @StartInputFlags int startInputFlags,
2897             @StartInputReason int startInputReason,
2898             @SoftInputModeFlags int softInputMode,
2899             int windowFlags) {
2900         return (startInputFlags & StartInputFlags.WINDOW_GAINED_FOCUS) == 0
2901                 && (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) == 0
2902                 && previousViewFocusParameters != null
2903                 && previousViewFocusParameters.sameAs(mCurrentEditorInfo,
2904                     startInputFlags, startInputReason, softInputMode, windowFlags);
2905     }
2906 
reportInputConnectionOpened( InputConnection ic, EditorInfo editorInfo, Handler icHandler, View view)2907     private void reportInputConnectionOpened(
2908             InputConnection ic, EditorInfo editorInfo, Handler icHandler, View view) {
2909         view.onInputConnectionOpenedInternal(ic, editorInfo, icHandler);
2910         final ViewRootImpl viewRoot = view.getViewRootImpl();
2911         if (viewRoot != null) {
2912             viewRoot.getHandwritingInitiator().onInputConnectionCreated(view);
2913         }
2914     }
2915 
2916     /**
2917      *
2918      * @hide
2919      */
2920     @TestApi
2921     @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
addVirtualStylusIdForTestSession()2922     public void addVirtualStylusIdForTestSession() {
2923         synchronized (mH) {
2924             IInputMethodManagerGlobalInvoker.addVirtualStylusIdForTestSession(mClient);
2925         }
2926     }
2927 
2928     /**
2929      * Set a stylus idle-timeout after which handwriting {@code InkWindow} will be removed.
2930      * <p> This API is for tests only.</p>
2931      * @param timeout to set in milliseconds. To reset to default, use a value <= zero.
2932      * @hide
2933      */
2934     @TestApi
2935     @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
setStylusWindowIdleTimeoutForTest(@urationMillisLong long timeout)2936     public void setStylusWindowIdleTimeoutForTest(@DurationMillisLong long timeout) {
2937         synchronized (mH) {
2938             IInputMethodManagerGlobalInvoker.setStylusWindowIdleTimeoutForTest(mClient, timeout);
2939         }
2940     }
2941 
2942     /**
2943      * An empty method only to avoid crashes of apps that call this method via reflection and do not
2944      * handle {@link NoSuchMethodException} in a graceful manner.
2945      *
2946      * @deprecated This is an empty method.  No framework method must call this method.
2947      * @hide
2948      */
2949     @Deprecated
2950     @UnsupportedAppUsage(trackingBug = 37122102, maxTargetSdk = Build.VERSION_CODES.Q,
2951             publicAlternatives = "{@code androidx.activity.ComponentActivity}")
windowDismissed(IBinder appWindowToken)2952     public void windowDismissed(IBinder appWindowToken) {
2953         // Intentionally empty.
2954         //
2955         // It seems that some applications call this method via reflection to null clear the
2956         // following fields that used to exist in InputMethodManager:
2957         //  * InputMethodManager#mCurRootView
2958         //  * InputMethodManager#mServedView
2959         //  * InputMethodManager#mNextServedView
2960         // so that these objects can be garbage-collected when an Activity gets dismissed.
2961         //
2962         // It is indeed true that older versions of InputMethodManager had issues that prevented
2963         // these fields from being null-cleared when it should have been, but the understanding of
2964         // the engineering team is that all known issues have already been fixed as of Android 10.
2965         //
2966         // For older devices, developers can work around the object leaks by using
2967         // androidx.activity.ComponentActivity.
2968         // See https://issuetracker.google.com/u/1/issues/37122102 for details.
2969         //
2970         // If you believe InputMethodManager is leaking objects in API 24 or any later version,
2971         // please file a bug at https://issuetracker.google.com/issues/new?component=192705.
2972     }
2973 
getStartInputFlags(View focusedView, int startInputFlags)2974     private int getStartInputFlags(View focusedView, int startInputFlags) {
2975         startInputFlags |= StartInputFlags.VIEW_HAS_FOCUS;
2976         if (focusedView.onCheckIsTextEditor()) {
2977             startInputFlags |= StartInputFlags.IS_TEXT_EDITOR;
2978         }
2979         return startInputFlags;
2980     }
2981 
2982     /**
2983      * Note that this method should *NOT* be called inside of {@code mH} lock to prevent start input
2984      * background thread may blocked by other methods which already inside {@code mH} lock.
2985      * @hide
2986      */
2987     @UnsupportedAppUsage
checkFocus()2988     public void checkFocus() {
2989         synchronized (mH) {
2990             if (mCurRootView == null) {
2991                 return;
2992             }
2993             if (!checkFocusInternalLocked(false /* forceNewFocus */, mCurRootView)) {
2994                 return;
2995             }
2996         }
2997         startInputOnWindowFocusGainInternal(StartInputReason.CHECK_FOCUS,
2998                 null /* focusedView */,
2999                 0 /* startInputFlags */, 0 /* softInputMode */, 0 /* windowFlags */);
3000     }
3001 
3002     /**
3003      * Check the next served view if needs to start input.
3004      */
3005     @GuardedBy("mH")
checkFocusInternalLocked(boolean forceNewFocus, ViewRootImpl viewRootImpl)3006     private boolean checkFocusInternalLocked(boolean forceNewFocus, ViewRootImpl viewRootImpl) {
3007         if (mCurRootView != viewRootImpl) {
3008             return false;
3009         }
3010         if (mServedView == mNextServedView && !forceNewFocus) {
3011             return false;
3012         }
3013         if (DEBUG) {
3014             Log.v(TAG, "checkFocus: view=" + mServedView
3015                     + " next=" + mNextServedView
3016                     + " force=" + forceNewFocus
3017                     + " package="
3018                     + (mServedView != null ? mServedView.getContext().getPackageName()
3019                     : "<none>"));
3020         }
3021         // Close the connection when no next served view coming.
3022         if (mNextServedView == null) {
3023             finishInputLocked();
3024             closeCurrentInput();
3025             return false;
3026         }
3027         mServedView = mNextServedView;
3028         if (mServedInputConnection != null) {
3029             mServedInputConnection.finishComposingTextFromImm();
3030         }
3031         return true;
3032     }
3033 
3034     @UiThread
onViewFocusChangedInternal(@ullable View view, boolean hasFocus)3035     private void onViewFocusChangedInternal(@Nullable View view, boolean hasFocus) {
3036         if (view == null || view.isTemporarilyDetached()) {
3037             return;
3038         }
3039         final ViewRootImpl viewRootImpl = view.getViewRootImpl();
3040         synchronized (mH) {
3041             if (mCurRootView != viewRootImpl) {
3042                 return;
3043             }
3044             if (!view.hasImeFocus() || !view.hasWindowFocus()) {
3045                 return;
3046             }
3047             if (DEBUG) {
3048                 Log.d(TAG, "onViewFocusChangedInternal, view="
3049                         + InputMethodDebug.dumpViewInfo(view));
3050             }
3051 
3052             // We don't need to track the next served view when the view lost focus here
3053             // because:
3054             // 1) The current view focus may be cleared temporary when in touch mode, closing
3055             //    input at this moment isn't the right way.
3056             // 2) We only care about the served view change when it focused, since changing
3057             //    input connection when the focus target changed is reasonable.
3058             // 3) Setting the next served view as null when no more served view should be
3059             //    handled in other special events (e.g. view detached from window or the window
3060             //    dismissed).
3061             if (hasFocus) {
3062                 mNextServedView = view;
3063             }
3064         }
3065         viewRootImpl.dispatchCheckFocus();
3066     }
3067 
3068     @UnsupportedAppUsage
closeCurrentInput()3069     void closeCurrentInput() {
3070         final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
3071                 null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
3072                 SoftInputShowHideReason.HIDE_SOFT_INPUT);
3073         ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
3074                 SoftInputShowHideReason.HIDE_SOFT_INPUT, ActivityThread::currentApplication);
3075 
3076         synchronized (mH) {
3077             if (mCurRootView == null || mCurRootView.getView() == null) {
3078                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
3079                 ImeTracker.forLatency().onHideFailed(statsToken,
3080                         ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
3081                 Log.w(TAG, "No current root view, ignoring closeCurrentInput()");
3082                 return;
3083             }
3084 
3085             ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
3086 
3087             IInputMethodManagerGlobalInvoker.hideSoftInput(
3088                     mClient,
3089                     mCurRootView.getView().getWindowToken(),
3090                     statsToken,
3091                     HIDE_NOT_ALWAYS,
3092                     null,
3093                     SoftInputShowHideReason.HIDE_SOFT_INPUT);
3094         }
3095     }
3096 
3097     /**
3098      * Register for IME state callbacks and applying visibility in
3099      * {@link android.view.ImeInsetsSourceConsumer}.
3100      * @hide
3101      */
registerImeConsumer(@onNull ImeInsetsSourceConsumer imeInsetsConsumer)3102     public void registerImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) {
3103         if (imeInsetsConsumer == null) {
3104             throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null.");
3105         }
3106 
3107         synchronized (mH) {
3108             mImeInsetsConsumer = imeInsetsConsumer;
3109         }
3110     }
3111 
3112     /**
3113      * Unregister for IME state callbacks and applying visibility in
3114      * {@link android.view.ImeInsetsSourceConsumer}.
3115      * @hide
3116      */
unregisterImeConsumer(@onNull ImeInsetsSourceConsumer imeInsetsConsumer)3117     public void unregisterImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) {
3118         if (imeInsetsConsumer == null) {
3119             throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null.");
3120         }
3121 
3122         synchronized (mH) {
3123             if (mImeInsetsConsumer == imeInsetsConsumer) {
3124                 mImeInsetsConsumer = null;
3125             }
3126         }
3127     }
3128 
3129     /**
3130      * Call showSoftInput with currently focused view.
3131      *
3132      * @param windowToken the window from which this request originates. If this doesn't match the
3133      *                    currently served view, the request is ignored and returns {@code false}.
3134      * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
3135      *
3136      * @return {@code true} if IME can (eventually) be shown, {@code false} otherwise.
3137      * @hide
3138      */
requestImeShow(IBinder windowToken, @Nullable ImeTracker.Token statsToken)3139     public boolean requestImeShow(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
3140         checkFocus();
3141         synchronized (mH) {
3142             final View servedView = getServedViewLocked();
3143             if (servedView == null || servedView.getWindowToken() != windowToken) {
3144                 ImeTracker.forLogging().onFailed(statsToken,
3145                         ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
3146                 return false;
3147             }
3148 
3149             ImeTracker.forLogging().onProgress(statsToken,
3150                     ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
3151 
3152             showSoftInput(servedView, statsToken, 0 /* flags */, null /* resultReceiver */,
3153                     SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API);
3154             return true;
3155         }
3156     }
3157 
3158     /**
3159      * Notify IMMS that IME insets are no longer visible.
3160      *
3161      * @param windowToken the window from which this request originates. If this doesn't match the
3162      *                    currently served view, the request is ignored.
3163      * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
3164      * @hide
3165      */
notifyImeHidden(IBinder windowToken, @Nullable ImeTracker.Token statsToken)3166     public void notifyImeHidden(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
3167         if (statsToken == null) {
3168             statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
3169                     Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
3170                     SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
3171         }
3172         ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
3173                 SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
3174                 ActivityThread::currentApplication);
3175         ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
3176                 null /* icProto */);
3177         synchronized (mH) {
3178             if (!isImeSessionAvailableLocked() || mCurRootView == null
3179                     || mCurRootView.getWindowToken() != windowToken) {
3180                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
3181                 ImeTracker.forLatency().onHideFailed(statsToken,
3182                         ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
3183                 return;
3184             }
3185 
3186             ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
3187 
3188             IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, windowToken, statsToken,
3189                     0 /* flags */, null /* resultReceiver */,
3190                     SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
3191         }
3192     }
3193 
3194     /**
3195      * Notify IME directly to remove surface as it is no longer visible.
3196      * @param windowToken The client window token that requests the IME to remove its surface.
3197      * @hide
3198      */
removeImeSurface(@onNull IBinder windowToken)3199     public void removeImeSurface(@NonNull IBinder windowToken) {
3200         synchronized (mH) {
3201             IInputMethodManagerGlobalInvoker.removeImeSurfaceFromWindowAsync(windowToken);
3202         }
3203     }
3204 
3205     /**
3206      * Report the current selection range.
3207      *
3208      * <p><strong>Editor authors</strong>, you need to call this method whenever
3209      * the cursor moves in your editor. Remember that in addition to doing this, your
3210      * editor needs to always supply current cursor values in
3211      * {@link EditorInfo#initialSelStart} and {@link EditorInfo#initialSelEnd} every
3212      * time {@link android.view.View#onCreateInputConnection(EditorInfo)} is
3213      * called, which happens whenever the keyboard shows up or the focus changes
3214      * to a text field, among other cases.</p>
3215      */
updateSelection(View view, int selStart, int selEnd, int candidatesStart, int candidatesEnd)3216     public void updateSelection(View view, int selStart, int selEnd,
3217             int candidatesStart, int candidatesEnd) {
3218         // Re-dispatch if there is a context mismatch.
3219         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
3220         if (fallbackImm != null) {
3221             fallbackImm.updateSelection(view, selStart, selEnd, candidatesStart, candidatesEnd);
3222             return;
3223         }
3224 
3225         checkFocus();
3226         synchronized (mH) {
3227             if (!hasServedByInputMethodLocked(view) || mCurrentEditorInfo == null
3228                     || !isImeSessionAvailableLocked()) {
3229                 return;
3230             }
3231 
3232             if (mServedInputConnection != null && mServedInputConnection.hasPendingInvalidation()) {
3233                 return;
3234             }
3235 
3236             if (mCursorSelStart != selStart || mCursorSelEnd != selEnd
3237                     || mCursorCandStart != candidatesStart
3238                     || mCursorCandEnd != candidatesEnd) {
3239                 if (DEBUG) Log.d(TAG, "updateSelection");
3240 
3241                 if (DEBUG) {
3242                     Log.v(TAG, "SELECTION CHANGE: " + mCurBindState.mImeSession);
3243                 }
3244                 mCurBindState.mImeSession.updateSelection(mCursorSelStart, mCursorSelEnd, selStart,
3245                         selEnd, candidatesStart, candidatesEnd);
3246                 forAccessibilitySessionsLocked(wrapper -> wrapper.updateSelection(mCursorSelStart,
3247                         mCursorSelEnd, selStart, selEnd, candidatesStart, candidatesEnd));
3248                 mCursorSelStart = selStart;
3249                 mCursorSelEnd = selEnd;
3250                 mCursorCandStart = candidatesStart;
3251                 mCursorCandEnd = candidatesEnd;
3252             }
3253         }
3254     }
3255 
3256     /**
3257      * Notify the event when the user tapped or clicked the text view.
3258      *
3259      * @param view {@link View} which is being clicked.
3260      * @see InputMethodService#onViewClicked(boolean)
3261      * @deprecated The semantics of this method can never be defined well for composite {@link View}
3262      *             that works as a giant "Canvas", which can host its own UI hierarchy and sub focus
3263      *             state. {@link android.webkit.WebView} is a good example. Application / IME
3264      *             developers should not rely on this method.
3265      */
3266     @Deprecated
viewClicked(View view)3267     public void viewClicked(View view) {
3268         // Re-dispatch if there is a context mismatch.
3269         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
3270         if (fallbackImm != null) {
3271             fallbackImm.viewClicked(view);
3272             return;
3273         }
3274 
3275         final View servedView;
3276         final View nextServedView;
3277         synchronized (mH) {
3278             servedView = getServedViewLocked();
3279             nextServedView = getNextServedViewLocked();
3280         }
3281         final boolean focusChanged = servedView != nextServedView;
3282         checkFocus();
3283         synchronized (mH) {
3284             if (!hasServedByInputMethodLocked(view) || mCurrentEditorInfo == null
3285                     || !isImeSessionAvailableLocked()) {
3286                 return;
3287             }
3288             if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
3289             mCurBindState.mImeSession.viewClicked(focusChanged);
3290         }
3291     }
3292 
3293     /**
3294      * Return true if the current input method wants to watch the location
3295      * of the input editor's cursor in its window.
3296      *
3297      * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead.
3298      */
3299     @Deprecated
isWatchingCursor(View view)3300     public boolean isWatchingCursor(View view) {
3301         return false;
3302     }
3303 
3304     /**
3305      * Return true if the current input method wants to be notified when cursor/anchor location
3306      * is changed.
3307      *
3308      * @deprecated This method is kept for {@link UnsupportedAppUsage}.  Must not be used.
3309      * @hide
3310      */
3311     @Deprecated
3312     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isCursorAnchorInfoEnabled()3313     public boolean isCursorAnchorInfoEnabled() {
3314         synchronized (mH) {
3315             final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
3316                     CURSOR_UPDATE_IMMEDIATE) != 0;
3317             final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode &
3318                     CURSOR_UPDATE_MONITOR) != 0;
3319             return isImmediate || isMonitoring;
3320         }
3321     }
3322 
3323     /**
3324      * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
3325      *
3326      * @deprecated This method is kept for {@link UnsupportedAppUsage}.  Must not be used.
3327      * @hide
3328      */
3329     @Deprecated
3330     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setUpdateCursorAnchorInfoMode(int flags)3331     public void setUpdateCursorAnchorInfoMode(int flags) {
3332         synchronized (mH) {
3333             mRequestUpdateCursorAnchorInfoMonitorMode = flags;
3334         }
3335     }
3336 
3337     /**
3338      * Report the current cursor location in its window.
3339      *
3340      * @deprecated Use {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)} instead.
3341      */
3342     @Deprecated
updateCursor(View view, int left, int top, int right, int bottom)3343     public void updateCursor(View view, int left, int top, int right, int bottom) {
3344         // Re-dispatch if there is a context mismatch.
3345         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
3346         if (fallbackImm != null) {
3347             fallbackImm.updateCursor(view, left, top, right, bottom);
3348             return;
3349         }
3350 
3351         checkFocus();
3352         synchronized (mH) {
3353             if (!hasServedByInputMethodLocked(view) || mCurrentEditorInfo == null
3354                     || !isImeSessionAvailableLocked()) {
3355                 return;
3356             }
3357 
3358             mTmpCursorRect.set(left, top, right, bottom);
3359             if (!mCursorRect.equals(mTmpCursorRect)) {
3360                 if (DEBUG) Log.d(TAG, "updateCursor: " + mCurBindState.mImeSession);
3361 
3362                 mCurBindState.mImeSession.updateCursor(mTmpCursorRect);
3363                 mCursorRect.set(mTmpCursorRect);
3364             }
3365         }
3366     }
3367 
3368     /**
3369      * Report positional change of the text insertion point and/or characters in the composition
3370      * string.
3371      */
updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo)3372     public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) {
3373         if (view == null || cursorAnchorInfo == null) {
3374             return;
3375         }
3376         // Re-dispatch if there is a context mismatch.
3377         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
3378         if (fallbackImm != null) {
3379             fallbackImm.updateCursorAnchorInfo(view, cursorAnchorInfo);
3380             return;
3381         }
3382 
3383         checkFocus();
3384         synchronized (mH) {
3385             if (!hasServedByInputMethodLocked(view) || mCurrentEditorInfo == null
3386                     || !isImeSessionAvailableLocked()) {
3387                 return;
3388             }
3389             // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has
3390             // not been changed from the previous call.
3391             final boolean isImmediate = mServedInputConnection != null
3392                     && mServedInputConnection.resetHasPendingImmediateCursorAnchorInfoUpdate();
3393             if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) {
3394                 // TODO: Consider always emitting this message once we have addressed redundant
3395                 // calls of this method from android.widget.Editor.
3396                 if (DEBUG) {
3397                     Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info="
3398                             + cursorAnchorInfo);
3399                 }
3400                 return;
3401             }
3402             if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
3403             if (mVirtualDisplayToScreenMatrix != null) {
3404                 mCurBindState.mImeSession.updateCursorAnchorInfo(
3405                         CursorAnchorInfo.createForAdditionalParentMatrix(
3406                                 cursorAnchorInfo, mVirtualDisplayToScreenMatrix));
3407             } else {
3408                 mCurBindState.mImeSession.updateCursorAnchorInfo(cursorAnchorInfo);
3409             }
3410             mCursorAnchorInfo = cursorAnchorInfo;
3411         }
3412     }
3413 
3414     /**
3415      * Call {@link InputMethodSession#appPrivateCommand(String, Bundle)
3416      * InputMethodSession.appPrivateCommand()} on the current Input Method.
3417      * @param view Optional View that is sending the command, or null if
3418      * you want to send the command regardless of the view that is attached
3419      * to the input method.
3420      * @param action Name of the command to be performed.  This <em>must</em>
3421      * be a scoped name, i.e. prefixed with a package name you own, so that
3422      * different developers will not create conflicting commands.
3423      * @param data Any data to include with the command.
3424      */
sendAppPrivateCommand(View view, String action, Bundle data)3425     public void sendAppPrivateCommand(View view, String action, Bundle data) {
3426         // Re-dispatch if there is a context mismatch.
3427         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
3428         if (fallbackImm != null) {
3429             fallbackImm.sendAppPrivateCommand(view, action, data);
3430             return;
3431         }
3432 
3433         checkFocus();
3434         synchronized (mH) {
3435             if (!hasServedByInputMethodLocked(view) || mCurrentEditorInfo == null
3436                     || !isImeSessionAvailableLocked()) {
3437                 return;
3438             }
3439             if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
3440             mCurBindState.mImeSession.appPrivateCommand(action, data);
3441         }
3442     }
3443 
3444     /**
3445      * Force switch to a new input method component. This can only be called
3446      * from an application or a service which has a token of the currently active input method.
3447      *
3448      * <p>On Android {@link Build.VERSION_CODES#Q} and later devices, the undocumented behavior that
3449      * token can be {@code null} when the caller has
3450      * {@link Manifest.permission#WRITE_SECURE_SETTINGS} is deprecated. Instead, update
3451      * {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and
3452      * {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p>
3453      *
3454      * @param token Supplies the identifying token given to an input method
3455      * when it was started, which allows it to perform this operation on
3456      * itself.
3457      * @param id The unique identifier for the new input method to be switched to.
3458      * @throws IllegalArgumentException if the input method is unknown or filtered by the rules of
3459      * <a href="/training/basics/intents/package-visibility">package visibility</a>.
3460      * @deprecated Use {@link InputMethodService#switchInputMethod(String)}
3461      * instead. This method was intended for IME developers who should be accessing APIs through
3462      * the service. APIs in this class are intended for app developers interacting with the IME.
3463      */
3464     @Deprecated
setInputMethod(IBinder token, String id)3465     public void setInputMethod(IBinder token, String id) {
3466         if (token == null) {
3467             // There are still some system components that rely on this undocumented behavior
3468             // regarding null IME token with WRITE_SECURE_SETTINGS.  Provide a fallback logic as a
3469             // temporary remedy.
3470             if (id == null) {
3471                 return;
3472             }
3473             if (Process.myUid() == Process.SYSTEM_UID) {
3474                 Log.w(TAG, "System process should not be calling setInputMethod() because almost "
3475                         + "always it is a bug under multi-user / multi-profile environment. "
3476                         + "Consider interacting with InputMethodManagerService directly via "
3477                         + "LocalServices.");
3478                 return;
3479             }
3480             final Context fallbackContext = ActivityThread.currentApplication();
3481             if (fallbackContext == null) {
3482                 return;
3483             }
3484             if (fallbackContext.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
3485                     != PackageManager.PERMISSION_GRANTED) {
3486                 return;
3487             }
3488             final List<InputMethodInfo> imis = getEnabledInputMethodList();
3489             final int numImis = imis.size();
3490             boolean found = false;
3491             for (int i = 0; i < numImis; ++i) {
3492                 final InputMethodInfo imi = imis.get(i);
3493                 if (id.equals(imi.getId())) {
3494                     found = true;
3495                     break;
3496                 }
3497             }
3498             if (!found) {
3499                 Log.e(TAG, "Ignoring setInputMethod(null, " + id + ") because the specified "
3500                         + "id not found in enabled IMEs.");
3501                 return;
3502             }
3503             Log.w(TAG, "The undocumented behavior that setInputMethod() accepts null token "
3504                     + "when the caller has WRITE_SECURE_SETTINGS is deprecated. This behavior may "
3505                     + "be completely removed in a future version.  Update secure settings directly "
3506                     + "instead.");
3507             final ContentResolver resolver = fallbackContext.getContentResolver();
3508             Settings.Secure.putInt(resolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
3509                     NOT_A_SUBTYPE_ID);
3510             Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD, id);
3511             return;
3512         }
3513         InputMethodPrivilegedOperationsRegistry.get(token).setInputMethod(id);
3514     }
3515 
3516     /**
3517      * Force switch to a new input method and subtype. This can only be called
3518      * from an application or a service which has a token of the currently active input method.
3519      *
3520      * <p>On Android {@link Build.VERSION_CODES#Q} and later devices, {@code token} cannot be
3521      * {@code null} even with {@link Manifest.permission#WRITE_SECURE_SETTINGS}. Instead,
3522      * update {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and
3523      * {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p>
3524      *
3525      * @param token Supplies the identifying token given to an input method
3526      * when it was started, which allows it to perform this operation on
3527      * itself.
3528      * @param id The unique identifier for the new input method to be switched to.
3529      * @param subtype The new subtype of the new input method to be switched to.
3530      * @throws IllegalArgumentException if the input method is unknown or filtered by the rules of
3531      * <a href="/training/basics/intents/package-visibility">package visibility</a>.
3532      * @deprecated Use
3533      * {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)}
3534      * instead. This method was intended for IME developers who should be accessing APIs through
3535      * the service. APIs in this class are intended for app developers interacting with the IME.
3536      */
3537     @Deprecated
setInputMethodAndSubtype(@onNull IBinder token, String id, InputMethodSubtype subtype)3538     public void setInputMethodAndSubtype(@NonNull IBinder token, String id,
3539             InputMethodSubtype subtype) {
3540         if (token == null) {
3541             Log.e(TAG, "setInputMethodAndSubtype() does not accept null token on Android Q "
3542                     + "and later.");
3543             return;
3544         }
3545         InputMethodPrivilegedOperationsRegistry.get(token).setInputMethodAndSubtype(id, subtype);
3546     }
3547 
3548     /**
3549      * Close/hide the input method's soft input area, so the user no longer
3550      * sees it or can interact with it.  This can only be called
3551      * from the currently active input method, as validated by the given token.
3552      *
3553      * @param token Supplies the identifying token given to an input method
3554      * when it was started, which allows it to perform this operation on
3555      * itself.
3556      * @deprecated Use {@link InputMethodService#requestHideSelf(int)} instead. This method was
3557      * intended for IME developers who should be accessing APIs through the service. APIs in this
3558      * class are intended for app developers interacting with the IME.
3559      */
3560     @Deprecated
hideSoftInputFromInputMethod(IBinder token, @HideFlags int flags)3561     public void hideSoftInputFromInputMethod(IBinder token, @HideFlags int flags) {
3562         InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(
3563                 flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION);
3564     }
3565 
3566     /**
3567      * Show the input method's soft input area, so the user
3568      * sees the input method window and can interact with it.
3569      * This can only be called from the currently active input method,
3570      * as validated by the given token.
3571      *
3572      * @param token Supplies the identifying token given to an input method
3573      * when it was started, which allows it to perform this operation on
3574      * itself.
3575      * @deprecated Use {@link InputMethodService#requestShowSelf(int)} instead. This method was
3576      * intended for IME developers who should be accessing APIs through the service. APIs in this
3577      * class are intended for app developers interacting with the IME.
3578      */
3579     @Deprecated
showSoftInputFromInputMethod(IBinder token, @ShowFlags int flags)3580     public void showSoftInputFromInputMethod(IBinder token, @ShowFlags int flags) {
3581         InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(flags);
3582     }
3583 
3584     /**
3585      * Dispatches an input event to the IME.
3586      *
3587      * Returns {@link #DISPATCH_HANDLED} if the event was handled.
3588      * Returns {@link #DISPATCH_NOT_HANDLED} if the event was not handled.
3589      * Returns {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the
3590      * callback will be invoked later.
3591      *
3592      * @hide
3593      */
dispatchInputEvent(InputEvent event, Object token, FinishedInputEventCallback callback, Handler handler)3594     public int dispatchInputEvent(InputEvent event, Object token,
3595             FinishedInputEventCallback callback, Handler handler) {
3596         synchronized (mH) {
3597             if (isImeSessionAvailableLocked()) {
3598                 if (event instanceof KeyEvent) {
3599                     KeyEvent keyEvent = (KeyEvent)event;
3600                     if (keyEvent.getAction() == KeyEvent.ACTION_DOWN
3601                             && keyEvent.getKeyCode() == KeyEvent.KEYCODE_SYM
3602                             && keyEvent.getRepeatCount() == 0) {
3603                         showInputMethodPickerLocked();
3604                         return DISPATCH_HANDLED;
3605                     }
3606                 }
3607 
3608                 if (DEBUG) {
3609                     Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurBindState.mImeSession);
3610                 }
3611 
3612                 PendingEvent p = obtainPendingEventLocked(
3613                         event, token, mCurBindState.mImeId, callback, handler);
3614                 if (mMainLooper.isCurrentThread()) {
3615                     // Already running on the IMM thread so we can send the event immediately.
3616                     return sendInputEventOnMainLooperLocked(p);
3617                 }
3618 
3619                 // Post the event to the IMM thread.
3620                 Message msg = mH.obtainMessage(MSG_SEND_INPUT_EVENT, p);
3621                 msg.setAsynchronous(true);
3622                 mH.sendMessage(msg);
3623                 return DISPATCH_IN_PROGRESS;
3624             }
3625         }
3626         return DISPATCH_NOT_HANDLED;
3627     }
3628 
3629     /**
3630      * Provides the default implementation of {@link InputConnection#sendKeyEvent(KeyEvent)}, which
3631      * is expected to dispatch an keyboard event sent from the IME to an appropriate event target
3632      * depending on the given {@link View} and the current focus state.
3633      *
3634      * <p>CAUTION: This method is provided only for the situation where
3635      * {@link InputConnection#sendKeyEvent(KeyEvent)} needs to be implemented without relying on
3636      * {@link BaseInputConnection}. Do not use this API for anything else.</p>
3637      *
3638      * @param targetView the default target view. If {@code null} is specified, then this method
3639      * tries to find a good event target based on the current focus state.
3640      * @param event the key event to be dispatched.
3641      */
dispatchKeyEventFromInputMethod(@ullable View targetView, @NonNull KeyEvent event)3642     public void dispatchKeyEventFromInputMethod(@Nullable View targetView,
3643             @NonNull KeyEvent event) {
3644         // Re-dispatch if there is a context mismatch.
3645         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(targetView);
3646         if (fallbackImm != null) {
3647             fallbackImm.dispatchKeyEventFromInputMethod(targetView, event);
3648             return;
3649         }
3650 
3651         synchronized (mH) {
3652             ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
3653             if (viewRootImpl == null) {
3654                 final View servedView = getServedViewLocked();
3655                 if (servedView != null) {
3656                     viewRootImpl = servedView.getViewRootImpl();
3657                 }
3658             }
3659             if (viewRootImpl != null) {
3660                 viewRootImpl.dispatchKeyFromIme(event);
3661             }
3662         }
3663     }
3664 
3665     // Must be called on the main looper
sendInputEventAndReportResultOnMainLooper(PendingEvent p)3666     private void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
3667         final boolean handled;
3668         synchronized (mH) {
3669             int result = sendInputEventOnMainLooperLocked(p);
3670             if (result == DISPATCH_IN_PROGRESS) {
3671                 return;
3672             }
3673 
3674             handled = (result == DISPATCH_HANDLED);
3675         }
3676 
3677         invokeFinishedInputEventCallback(p, handled);
3678     }
3679 
3680     // Must be called on the main looper
3681     @GuardedBy("mH")
sendInputEventOnMainLooperLocked(PendingEvent p)3682     private int sendInputEventOnMainLooperLocked(PendingEvent p) {
3683         if (mCurChannel != null) {
3684             if (mCurSender == null) {
3685                 mCurSender = new ImeInputEventSender(mCurChannel, mH.getLooper());
3686             }
3687 
3688             final InputEvent event = p.mEvent;
3689             final int seq = event.getSequenceNumber();
3690             if (mCurSender.sendInputEvent(seq, event)) {
3691                 mPendingEvents.put(seq, p);
3692                 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER,
3693                         mPendingEvents.size());
3694 
3695                 Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, seq, 0, p);
3696                 msg.setAsynchronous(true);
3697                 mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);
3698                 return DISPATCH_IN_PROGRESS;
3699             }
3700 
3701             if (sPreventImeStartupUnlessTextEditor) {
3702                 Log.d(TAG, "Dropping event because IME is evicted: " + event);
3703             } else {
3704                 Log.w(TAG, "Unable to send input event to IME: " + getImeIdLocked()
3705                         + " dropping: " + event);
3706             }
3707         }
3708         return DISPATCH_NOT_HANDLED;
3709     }
3710 
finishedInputEvent(int seq, boolean handled, boolean timeout)3711     private void finishedInputEvent(int seq, boolean handled, boolean timeout) {
3712         final PendingEvent p;
3713         synchronized (mH) {
3714             int index = mPendingEvents.indexOfKey(seq);
3715             if (index < 0) {
3716                 return; // spurious, event already finished or timed out
3717             }
3718 
3719             p = mPendingEvents.valueAt(index);
3720             mPendingEvents.removeAt(index);
3721             Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, mPendingEvents.size());
3722 
3723             if (timeout) {
3724                 Log.w(TAG, "Timeout waiting for IME to handle input event after "
3725                         + INPUT_METHOD_NOT_RESPONDING_TIMEOUT + " ms: " + p.mInputMethodId);
3726             } else {
3727                 mH.removeMessages(MSG_TIMEOUT_INPUT_EVENT, p);
3728             }
3729         }
3730 
3731         invokeFinishedInputEventCallback(p, handled);
3732     }
3733 
3734     // Assumes the event has already been removed from the queue.
invokeFinishedInputEventCallback(PendingEvent p, boolean handled)3735     private void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
3736         p.mHandled = handled;
3737         if (p.mHandler.getLooper().isCurrentThread()) {
3738             // Already running on the callback handler thread so we can send the
3739             // callback immediately.
3740             p.run();
3741         } else {
3742             // Post the event to the callback handler thread.
3743             // In this case, the callback will be responsible for recycling the event.
3744             Message msg = Message.obtain(p.mHandler, p);
3745             msg.setAsynchronous(true);
3746             msg.sendToTarget();
3747         }
3748     }
3749 
3750     @GuardedBy("mH")
flushPendingEventsLocked()3751     private void flushPendingEventsLocked() {
3752         mH.removeMessages(MSG_FLUSH_INPUT_EVENT);
3753 
3754         final int count = mPendingEvents.size();
3755         for (int i = 0; i < count; i++) {
3756             int seq = mPendingEvents.keyAt(i);
3757             Message msg = mH.obtainMessage(MSG_FLUSH_INPUT_EVENT, seq, 0);
3758             msg.setAsynchronous(true);
3759             msg.sendToTarget();
3760         }
3761     }
3762 
3763     @GuardedBy("mH")
obtainPendingEventLocked(InputEvent event, Object token, String inputMethodId, FinishedInputEventCallback callback, Handler handler)3764     private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
3765             String inputMethodId, FinishedInputEventCallback callback, Handler handler) {
3766         PendingEvent p = mPendingEventPool.acquire();
3767         if (p == null) {
3768             p = new PendingEvent();
3769         }
3770         p.mEvent = event;
3771         p.mToken = token;
3772         p.mInputMethodId = inputMethodId;
3773         p.mCallback = callback;
3774         p.mHandler = handler;
3775         return p;
3776     }
3777 
3778     @GuardedBy("mH")
recyclePendingEventLocked(PendingEvent p)3779     private void recyclePendingEventLocked(PendingEvent p) {
3780         p.recycle();
3781         mPendingEventPool.release(p);
3782     }
3783 
3784     /**
3785      * Show IME picker popup window.
3786      *
3787      * <p>Requires the {@link PackageManager#FEATURE_INPUT_METHODS} feature which can be detected
3788      * using {@link PackageManager#hasSystemFeature(String)}.
3789      */
showInputMethodPicker()3790     public void showInputMethodPicker() {
3791         synchronized (mH) {
3792             showInputMethodPickerLocked();
3793         }
3794     }
3795 
3796     /**
3797      * Shows the input method chooser dialog from system.
3798      *
3799      * @param showAuxiliarySubtypes Set true to show auxiliary input methods.
3800      * @param displayId The ID of the display where the chooser dialog should be shown.
3801      * @hide
3802      */
3803     @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId)3804     public void showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId) {
3805         final int mode = showAuxiliarySubtypes
3806                 ? SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES
3807                 : SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
3808         IInputMethodManagerGlobalInvoker.showInputMethodPickerFromSystem(mode, displayId);
3809     }
3810 
3811     @GuardedBy("mH")
showInputMethodPickerLocked()3812     private void showInputMethodPickerLocked() {
3813         IInputMethodManagerGlobalInvoker.showInputMethodPickerFromClient(mClient,
3814                 SHOW_IM_PICKER_MODE_AUTO);
3815     }
3816 
3817     /**
3818      * A test API for CTS to make sure that {@link #showInputMethodPicker()} works as expected.
3819      *
3820      * <p>When customizing the implementation of {@link #showInputMethodPicker()} API, make sure
3821      * that this test API returns when and only while and only while
3822      * {@link #showInputMethodPicker()} is showing UI. Otherwise your OS implementation may not
3823      * pass CTS.</p>
3824      *
3825      * @return {@code true} while and only while {@link #showInputMethodPicker()} is showing UI.
3826      * @hide
3827      */
3828     @TestApi
3829     @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
isInputMethodPickerShown()3830     public boolean isInputMethodPickerShown() {
3831         return IInputMethodManagerGlobalInvoker.isInputMethodPickerShownForTest();
3832     }
3833 
3834     /**
3835      * A test API for CTS to check whether there are any pending IME visibility requests.
3836      *
3837      * @return {@code true} iff there are pending IME visibility requests.
3838      * @hide
3839      */
3840     @TestApi
3841     @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
hasPendingImeVisibilityRequests()3842     public boolean hasPendingImeVisibilityRequests() {
3843         return IInputMethodManagerGlobalInvoker.hasPendingImeVisibilityRequests();
3844     }
3845 
3846     /**
3847      * Show the settings for enabling subtypes of the specified input method.
3848      *
3849      * @param imiId An input method, whose subtypes settings will be shown. If imiId is null,
3850      * subtypes of all input methods will be shown.
3851      */
showInputMethodAndSubtypeEnabler(@ullable String imiId)3852     public void showInputMethodAndSubtypeEnabler(@Nullable String imiId) {
3853         Context context = null;
3854         synchronized (mH) {
3855             if (mCurRootView != null) {
3856                 context = mCurRootView.mContext;
3857             }
3858         }
3859         if (context == null) {
3860             final Context appContext = ActivityThread.currentApplication();
3861             final DisplayManager displayManager = appContext.getSystemService(DisplayManager.class);
3862             context = appContext.createDisplayContext(displayManager.getDisplay(mDisplayId));
3863         }
3864 
3865         final Intent intent = new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
3866         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
3867                 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
3868                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
3869         if (!TextUtils.isEmpty(imiId)) {
3870             intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, imiId);
3871         }
3872         context.startActivity(intent);
3873     }
3874 
3875     /**
3876      * Returns the current input method subtype. This subtype is one of the subtypes in
3877      * the current input method. This method returns null when the current input method doesn't
3878      * have any input method subtype.
3879      */
3880     @Nullable
getCurrentInputMethodSubtype()3881     public InputMethodSubtype getCurrentInputMethodSubtype() {
3882         return IInputMethodManagerGlobalInvoker.getCurrentInputMethodSubtype(UserHandle.myUserId());
3883     }
3884 
3885     /**
3886      * Switch to a new input method subtype of the current input method.
3887      * @param subtype A new input method subtype to switch.
3888      * @return true if the current subtype was successfully switched. When the specified subtype is
3889      * null, this method returns false.
3890      * @deprecated If the calling process is an IME, use
3891      *             {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)}, which
3892      *             does not require any permission as long as the caller is the current IME.
3893      *             If the calling process is some privileged app that already has
3894      *             {@link Manifest.permission#WRITE_SECURE_SETTINGS} permission, just
3895      *             directly update {@link Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE}.
3896      */
3897     @Deprecated
3898     @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
setCurrentInputMethodSubtype(InputMethodSubtype subtype)3899     public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
3900         if (Process.myUid() == Process.SYSTEM_UID) {
3901             Log.w(TAG, "System process should not call setCurrentInputMethodSubtype() because "
3902                     + "almost always it is a bug under multi-user / multi-profile environment. "
3903                     + "Consider directly interacting with InputMethodManagerService "
3904                     + "via LocalServices.");
3905             return false;
3906         }
3907         if (subtype == null) {
3908             // See the JavaDoc. This is how this method has worked.
3909             return false;
3910         }
3911         final Context fallbackContext = ActivityThread.currentApplication();
3912         if (fallbackContext == null) {
3913             return false;
3914         }
3915         if (fallbackContext.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
3916                 != PackageManager.PERMISSION_GRANTED) {
3917             return false;
3918         }
3919         final ContentResolver contentResolver = fallbackContext.getContentResolver();
3920         final String imeId = Settings.Secure.getString(contentResolver,
3921                 Settings.Secure.DEFAULT_INPUT_METHOD);
3922         if (ComponentName.unflattenFromString(imeId) == null) {
3923             // Null or invalid IME ID format.
3924             return false;
3925         }
3926         final List<InputMethodSubtype> enabledSubtypes =
3927                 IInputMethodManagerGlobalInvoker.getEnabledInputMethodSubtypeList(imeId, true,
3928                         UserHandle.myUserId());
3929         final int numSubtypes = enabledSubtypes.size();
3930         for (int i = 0; i < numSubtypes; ++i) {
3931             final InputMethodSubtype enabledSubtype = enabledSubtypes.get(i);
3932             if (enabledSubtype.equals(subtype)) {
3933                 Settings.Secure.putInt(contentResolver,
3934                         Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, enabledSubtype.hashCode());
3935                 return true;
3936             }
3937         }
3938         return false;
3939     }
3940 
3941     /**
3942      * Notify that a user took some action with this input method.
3943      *
3944      * @deprecated Just kept to avoid possible app compat issue.
3945      * @hide
3946      */
3947     @Deprecated
3948     @UnsupportedAppUsage(trackingBug = 114740982, maxTargetSdk = Build.VERSION_CODES.P)
notifyUserAction()3949     public void notifyUserAction() {
3950         Log.w(TAG, "notifyUserAction() is a hidden method, which is now just a stub method"
3951                 + " that does nothing.  Leave comments in b.android.com/114740982 if your "
3952                 + " application still depends on the previous behavior of this method.");
3953     }
3954 
3955     /**
3956      * Returns a map of all shortcut input method info and their subtypes.
3957      */
getShortcutInputMethodsAndSubtypes()3958     public Map<InputMethodInfo, List<InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() {
3959         final List<InputMethodInfo> enabledImes = getEnabledInputMethodList();
3960 
3961         // Ensure we check system IMEs first.
3962         enabledImes.sort(Comparator.comparingInt(imi -> imi.isSystem() ? 0 : 1));
3963 
3964         final int numEnabledImes = enabledImes.size();
3965         for (int imiIndex = 0; imiIndex < numEnabledImes; ++imiIndex) {
3966             final InputMethodInfo imi = enabledImes.get(imiIndex);
3967             final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeList(
3968                     imi, true);
3969             final int subtypeCount = subtypes.size();
3970             for (int subtypeIndex = 0; subtypeIndex < subtypeCount; ++subtypeIndex) {
3971                 final InputMethodSubtype subtype = imi.getSubtypeAt(subtypeIndex);
3972                 if (SUBTYPE_MODE_VOICE.equals(subtype.getMode())) {
3973                     return Collections.singletonMap(imi, Collections.singletonList(subtype));
3974                 }
3975             }
3976         }
3977         return Collections.emptyMap();
3978     }
3979 
3980     /**
3981      * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage}.
3982      *
3983      * <p>TODO(Bug 113914148): Check if we can remove this.  We have accidentally exposed
3984      * WindowManagerInternal#getInputMethodWindowVisibleHeight to app developers and some of them
3985      * started relying on it.</p>
3986      *
3987      * @return Something that is not well-defined.
3988      * @hide
3989      */
3990     @UnsupportedAppUsage(trackingBug = 204906124, maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
3991             publicAlternatives = "Use {@link android.view.WindowInsets} instead")
getInputMethodWindowVisibleHeight()3992     public int getInputMethodWindowVisibleHeight() {
3993         return IInputMethodManagerGlobalInvoker.getInputMethodWindowVisibleHeight(mClient);
3994     }
3995 
3996     /**
3997      * {@code true} means that
3998      * {@link RemoteInputConnectionImpl#requestCursorUpdatesInternal(int, int, int)} returns
3999      * {@code false} when the IME client and the IME run in different displays.
4000      */
4001     final AtomicBoolean mRequestCursorUpdateDisplayIdCheck = new AtomicBoolean(true);
4002 
4003     /**
4004      * Controls the display ID mismatch validation in
4005      * {@link RemoteInputConnectionImpl#requestCursorUpdatesInternal(int, int, int)}.
4006      *
4007      * <p>{@link #updateCursorAnchorInfo(View, CursorAnchorInfo)} is not guaranteed to work
4008      * correctly when the IME client and the IME run in different displays.  This is why
4009      * {@link RemoteInputConnectionImpl#requestCursorUpdatesInternal(int, int, int)} returns
4010      * {@code false} by default when the display ID does not match. This method allows special apps
4011      * to override this behavior when they are sure that it should work.</p>
4012      *
4013      * <p>By default the validation is enabled.</p>
4014      *
4015      * @param enabled {@code false} to disable the display ID validation.
4016      * @hide
4017      */
setRequestCursorUpdateDisplayIdCheck(boolean enabled)4018     public void setRequestCursorUpdateDisplayIdCheck(boolean enabled) {
4019         mRequestCursorUpdateDisplayIdCheck.set(enabled);
4020     }
4021 
4022     /**
4023      * An internal API for {@link android.hardware.display.VirtualDisplay} to report where its
4024      * embedded virtual display is placed.
4025      *
4026      * @param childDisplayId Display ID of the embedded virtual display.
4027      * @param matrix         {@link Matrix} to convert virtual display screen coordinates to
4028      *                       the host screen coordinates. {@code null} to clear the relationship.
4029      * @hide
4030      */
reportVirtualDisplayGeometry(int childDisplayId, @Nullable Matrix matrix)4031     public void reportVirtualDisplayGeometry(int childDisplayId, @Nullable Matrix matrix) {
4032         final float[] matrixValues;
4033         if (matrix == null) {
4034             matrixValues = null;
4035         } else {
4036             matrixValues = new float[9];
4037             matrix.getValues(matrixValues);
4038         }
4039         IInputMethodManagerGlobalInvoker.reportVirtualDisplayGeometryAsync(mClient, childDisplayId,
4040                 matrixValues);
4041     }
4042 
4043     /**
4044      * An internal API that returns if the current display has a transformation matrix to apply.
4045      *
4046      * @return {@code true} if {@link Matrix} to convert virtual display screen coordinates to
4047      * the host screen coordinates is set.
4048      * @hide
4049      */
hasVirtualDisplayToScreenMatrix()4050     public boolean hasVirtualDisplayToScreenMatrix() {
4051         synchronized (mH) {
4052             return mVirtualDisplayToScreenMatrix != null;
4053         }
4054     }
4055 
4056     /**
4057      * Force switch to the last used input method and subtype. If the last input method didn't have
4058      * any subtypes, the framework will simply switch to the last input method with no subtype
4059      * specified.
4060      * @param imeToken Supplies the identifying token given to an input method when it was started,
4061      * which allows it to perform this operation on itself.
4062      * @return true if the current input method and subtype was successfully switched to the last
4063      * used input method and subtype.
4064      * @deprecated Use {@link InputMethodService#switchToPreviousInputMethod()} instead. This method
4065      * was intended for IME developers who should be accessing APIs through the service. APIs in
4066      * this class are intended for app developers interacting with the IME.
4067      */
4068     @Deprecated
switchToLastInputMethod(IBinder imeToken)4069     public boolean switchToLastInputMethod(IBinder imeToken) {
4070         return InputMethodPrivilegedOperationsRegistry.get(imeToken).switchToPreviousInputMethod();
4071     }
4072 
4073     /**
4074      * Force switch to the next input method and subtype. If there is no IME enabled except
4075      * current IME and subtype, do nothing.
4076      * @param imeToken Supplies the identifying token given to an input method when it was started,
4077      * which allows it to perform this operation on itself.
4078      * @param onlyCurrentIme if true, the framework will find the next subtype which
4079      * belongs to the current IME
4080      * @return true if the current input method and subtype was successfully switched to the next
4081      * input method and subtype.
4082      * @deprecated Use {@link InputMethodService#switchToNextInputMethod(boolean)} instead. This
4083      * method was intended for IME developers who should be accessing APIs through the service.
4084      * APIs in this class are intended for app developers interacting with the IME.
4085      */
4086     @Deprecated
switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme)4087     public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
4088         return InputMethodPrivilegedOperationsRegistry.get(imeToken)
4089                 .switchToNextInputMethod(onlyCurrentIme);
4090     }
4091 
4092     /**
4093      * Returns true if the current IME needs to offer the users ways to switch to a next input
4094      * method (e.g. a globe key.).
4095      * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
4096      * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
4097      * <p> Note that the system determines the most appropriate next input method
4098      * and subtype in order to provide the consistent user experience in switching
4099      * between IMEs and subtypes.
4100      * @param imeToken Supplies the identifying token given to an input method when it was started,
4101      * which allows it to perform this operation on itself.
4102      * @deprecated Use {@link InputMethodService#shouldOfferSwitchingToNextInputMethod()}
4103      * instead. This method was intended for IME developers who should be accessing APIs through
4104      * the service. APIs in this class are intended for app developers interacting with the IME.
4105      */
4106     @Deprecated
shouldOfferSwitchingToNextInputMethod(IBinder imeToken)4107     public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
4108         return InputMethodPrivilegedOperationsRegistry.get(imeToken)
4109                 .shouldOfferSwitchingToNextInputMethod();
4110     }
4111 
4112     /**
4113      * Set additional input method subtypes. Only a process which shares the same uid with the IME
4114      * can add additional input method subtypes to the IME.
4115      * Please note that a subtype's status is stored in the system.
4116      * For example, enabled subtypes are remembered by the framework even after they are removed
4117      * by using this method. If you re-add the same subtypes again,
4118      * they will just get enabled. If you want to avoid such conflicts, for instance, you may
4119      * want to create a "different" new subtype even with the same locale and mode,
4120      * by changing its extra value. The different subtype won't get affected by the stored past
4121      * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer
4122      * to the current implementation.)
4123      *
4124      * <p>NOTE: If the same subtype exists in both the manifest XML file and additional subtypes
4125      * specified by {@code subtypes}, those multiple instances are automatically merged into one
4126      * instance.</p>
4127      *
4128      * <p>CAVEAT: In API Level 23 and prior, the system may do nothing if an empty
4129      * {@link InputMethodSubtype} is specified in {@code subtypes}, which prevents you from removing
4130      * the last one entry of additional subtypes. If your IME statically defines one or more
4131      * subtypes in the manifest XML file, you may be able to work around this limitation by
4132      * specifying one of those statically defined subtypes in {@code subtypes}.</p>
4133      *
4134      * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
4135      * If the imiId is {@code null}, system would do nothing for this operation.
4136      * @param subtypes subtypes will be added as additional subtypes of the current input method.
4137      * If the subtypes is {@code null}, system would do nothing for this operation.
4138      * @deprecated For IMEs that have already implemented features like customizable/downloadable
4139      *             keyboard layouts/languages, please start migration to other approaches. One idea
4140      *             would be exposing only one unified {@link InputMethodSubtype} then implement
4141      *             IME's own language switching mechanism within that unified subtype. The support
4142      *             of "Additional Subtype" may be completely dropped in a future version of Android.
4143      */
4144     @Deprecated
setAdditionalInputMethodSubtypes(@onNull String imiId, @NonNull InputMethodSubtype[] subtypes)4145     public void setAdditionalInputMethodSubtypes(@NonNull String imiId,
4146             @NonNull InputMethodSubtype[] subtypes) {
4147         IInputMethodManagerGlobalInvoker.setAdditionalInputMethodSubtypes(imiId, subtypes,
4148                 UserHandle.myUserId());
4149     }
4150 
4151     /**
4152      * Updates the list of explicitly enabled {@link InputMethodSubtype} for a given IME owned by
4153      * the calling process.
4154      *
4155      * <p>By default each IME has no explicitly enabled {@link InputMethodSubtype}.  In this state
4156      * the system will decide what {@link InputMethodSubtype} should be enabled by using information
4157      * available at runtime as per-user language settings.  Users can, however, manually pick up one
4158      * or more {@link InputMethodSubtype} to be enabled on an Activity shown by
4159      * {@link #showInputMethodAndSubtypeEnabler(String)}. Such a manual change is stored in
4160      * {@link Settings.Secure#ENABLED_INPUT_METHODS} so that the change can persist across reboots.
4161      * {@link Settings.Secure#ENABLED_INPUT_METHODS} stores {@link InputMethodSubtype#hashCode()} as
4162      * the identifier of {@link InputMethodSubtype} for historical reasons.</p>
4163      *
4164      * <p>This API provides a safe and managed way for IME developers to modify what
4165      * {@link InputMethodSubtype} are referenced in {@link Settings.Secure#ENABLED_INPUT_METHODS}
4166      * for their own IME.  One use case is when IME developers want to use their own Activity for
4167      * users to pick up {@link InputMethodSubtype}. Another use case is for IME developers to fix up
4168      * any stale and/or invalid value stored in {@link Settings.Secure#ENABLED_INPUT_METHODS}
4169      * without bothering users. Passing an empty {@code subtypeHashCodes} is guaranteed to reset
4170      * the state to default.</p>
4171      *
4172      * <h3>To control the return value of {@link InputMethodSubtype#hashCode()}</h3>
4173      * <p>{@link android.R.attr#subtypeId} and {@link
4174      * android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder#setSubtypeId(int)} are
4175      * available for IME developers to control the return value of
4176      * {@link InputMethodSubtype#hashCode()}. Beware that {@code -1} is not a valid value of
4177      * {@link InputMethodSubtype#hashCode()} for historical reasons.</p>
4178      *
4179      * <h3>Note for Direct Boot support</h3>
4180      * <p>While IME developers can call this API even before
4181      * {@link android.os.UserManager#isUserUnlocked()} becomes {@code true}, such a change is
4182      * volatile thus remains effective only until {@link android.os.UserManager#isUserUnlocked()}
4183      * becomes {@code true} or the device is rebooted. To make the change persistent IME developers
4184      * need to call this API again after receiving {@link Intent#ACTION_USER_UNLOCKED}.</p>
4185      *
4186      * @param imiId IME ID. The specified IME and the calling process need to belong to the same
4187      *              package.  Otherwise {@link SecurityException} will be thrown.
4188      * @param subtypeHashCodes An arrays of {@link InputMethodSubtype#hashCode()} to be explicitly
4189      *                         enabled. Entries that are found in the specified IME will be silently
4190      *                         ignored. Pass an empty array to reset the state to default.
4191      * @throws NullPointerException if {@code subtypeHashCodes} is {@code null}.
4192      * @throws SecurityException if the specified IME and the calling process do not belong to the
4193      *                           same package.
4194      */
setExplicitlyEnabledInputMethodSubtypes(@onNull String imiId, @NonNull int[] subtypeHashCodes)4195     public void setExplicitlyEnabledInputMethodSubtypes(@NonNull String imiId,
4196             @NonNull int[] subtypeHashCodes) {
4197         IInputMethodManagerGlobalInvoker.setExplicitlyEnabledInputMethodSubtypes(imiId,
4198                 subtypeHashCodes, UserHandle.myUserId());
4199     }
4200 
4201     /**
4202      * Returns the last used {@link InputMethodSubtype} in system history.
4203      *
4204      * @return the last {@link InputMethodSubtype}, {@code null} if last IME have no subtype.
4205      */
4206     @Nullable
getLastInputMethodSubtype()4207     public InputMethodSubtype getLastInputMethodSubtype() {
4208         return IInputMethodManagerGlobalInvoker.getLastInputMethodSubtype(UserHandle.myUserId());
4209     }
4210 
4211     /**
4212      * <p>This is used for CTS test only. Do not use this method outside of CTS package.<p/>
4213      * @return the ID of this display which this {@link InputMethodManager} resides
4214      * @hide
4215      */
4216     @TestApi
getDisplayId()4217     public int getDisplayId() {
4218         return mDisplayId;
4219     }
4220 
doDump(FileDescriptor fd, PrintWriter fout, String[] args)4221     private void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
4222         if (processDump(fd, args)) {
4223             return;
4224         }
4225 
4226         final Printer p = new PrintWriterPrinter(fout);
4227         p.println("Input method client state for " + this + ":");
4228         p.println("  mFallbackInputConnection=" + mFallbackInputConnection);
4229         p.println("  mActive=" + mActive
4230                 + " mRestartOnNextWindowFocus=" + mRestartOnNextWindowFocus
4231                 + " mBindSequence=" + getBindSequenceLocked()
4232                 + " mCurImeId=" + getImeIdLocked());
4233         p.println("  mFullscreenMode=" + mFullscreenMode);
4234         if (isImeSessionAvailableLocked()) {
4235             p.println("  mCurMethod=" + mCurBindState.mImeSession);
4236         } else {
4237             p.println("  mCurMethod= null");
4238         }
4239         for (int i = 0; i < mAccessibilityInputMethodSession.size(); i++) {
4240             p.println("  mAccessibilityInputMethodSession("
4241                     + mAccessibilityInputMethodSession.keyAt(i) + ")="
4242                     + mAccessibilityInputMethodSession.valueAt(i));
4243         }
4244         p.println("  mCurRootView=" + mCurRootView);
4245         p.println("  mServedView=" + getServedViewLocked());
4246         p.println("  mNextServedView=" + getNextServedViewLocked());
4247         p.println("  mServedConnecting=" + mServedConnecting);
4248         if (mCurrentEditorInfo != null) {
4249             p.println("  mCurrentEditorInfo:");
4250             mCurrentEditorInfo.dump(p, "    ", false /* dumpExtras */);
4251         } else {
4252             p.println("  mCurrentEditorInfo: null");
4253         }
4254         p.println("  mServedInputConnection=" + mServedInputConnection);
4255         p.println("  mServedInputConnectionHandler=" + mServedInputConnectionHandler);
4256         p.println("  mCompletions=" + Arrays.toString(mCompletions));
4257         p.println("  mCursorRect=" + mCursorRect);
4258         p.println("  mCursorSelStart=" + mCursorSelStart
4259                 + " mCursorSelEnd=" + mCursorSelEnd
4260                 + " mCursorCandStart=" + mCursorCandStart
4261                 + " mCursorCandEnd=" + mCursorCandEnd);
4262     }
4263 
4264     /**
4265      * Callback that is invoked when an input event that was dispatched to
4266      * the IME has been finished.
4267      * @hide
4268      */
4269     public interface FinishedInputEventCallback {
onFinishedInputEvent(Object token, boolean handled)4270         public void onFinishedInputEvent(Object token, boolean handled);
4271     }
4272 
4273     private final class ImeInputEventSender extends InputEventSender {
ImeInputEventSender(InputChannel inputChannel, Looper looper)4274         public ImeInputEventSender(InputChannel inputChannel, Looper looper) {
4275             super(inputChannel, looper);
4276         }
4277 
4278         @Override
onInputEventFinished(int seq, boolean handled)4279         public void onInputEventFinished(int seq, boolean handled) {
4280             finishedInputEvent(seq, handled, false);
4281         }
4282     }
4283 
4284     private final class PendingEvent implements Runnable {
4285         public InputEvent mEvent;
4286         public Object mToken;
4287         public String mInputMethodId;
4288         public FinishedInputEventCallback mCallback;
4289         public Handler mHandler;
4290         public boolean mHandled;
4291 
recycle()4292         public void recycle() {
4293             mEvent = null;
4294             mToken = null;
4295             mInputMethodId = null;
4296             mCallback = null;
4297             mHandler = null;
4298             mHandled = false;
4299         }
4300 
4301         @Override
run()4302         public void run() {
4303             mCallback.onFinishedInputEvent(mToken, mHandled);
4304 
4305             synchronized (mH) {
4306                 recyclePendingEventLocked(this);
4307             }
4308         }
4309     }
4310 
4311     private static final class BindState {
4312         /**
4313          * Encapsulates IPCs to the currently connected InputMethodService.
4314          */
4315         @Nullable
4316         final IInputMethodSessionInvoker mImeSession;
4317 
4318         /**
4319          * As reported by {@link InputBindResult}. This value is determined by
4320          * {@link com.android.internal.R.styleable#InputMethod_suppressesSpellChecker}.
4321          */
4322         final boolean mIsInputMethodSuppressingSpellChecker;
4323 
4324         /**
4325          * As reported by {@link InputBindResult}. This value indicates the bound input method ID.
4326          */
4327         @Nullable
4328         final String mImeId;
4329 
4330         /**
4331          * Sequence number of this binding, as returned by the server.
4332          */
4333         final int mBindSequence;
4334 
BindState(@onNull InputBindResult inputBindResult)4335         BindState(@NonNull InputBindResult inputBindResult) {
4336             mImeSession = IInputMethodSessionInvoker.createOrNull(inputBindResult.method);
4337             mIsInputMethodSuppressingSpellChecker =
4338                     inputBindResult.isInputMethodSuppressingSpellChecker;
4339             mImeId = inputBindResult.id;
4340             mBindSequence = inputBindResult.sequence;
4341         }
4342     }
4343 
4344     @GuardedBy("mH")
isImeSessionAvailableLocked()4345     private boolean isImeSessionAvailableLocked() {
4346         return mCurBindState != null && mCurBindState.mImeSession != null;
4347     }
4348 
4349     @GuardedBy("mH")
getImeIdLocked()4350     private String getImeIdLocked() {
4351         return mCurBindState != null ? mCurBindState.mImeId : null;
4352     }
4353 
4354     @GuardedBy("mH")
getBindSequenceLocked()4355     private int getBindSequenceLocked() {
4356         return mCurBindState != null ? mCurBindState.mBindSequence : -1;
4357     }
4358 
4359     /**
4360      * Checks the args to see if a proto-based ime dump was requested and writes the client side
4361      * ime dump to the given {@link FileDescriptor}.
4362      *
4363      * @return {@code true} if a proto-based ime dump was requested.
4364      */
processDump(final FileDescriptor fd, final String[] args)4365     private boolean processDump(final FileDescriptor fd, final String[] args) {
4366         if (args == null) {
4367             return false;
4368         }
4369 
4370         for (String arg : args) {
4371             if (arg.equals(ImeTracing.PROTO_ARG)) {
4372                 final ProtoOutputStream proto = new ProtoOutputStream(fd);
4373                 dumpDebug(proto, null /* icProto */);
4374                 proto.flush();
4375                 return true;
4376             }
4377         }
4378         return false;
4379     }
4380 
4381     /**
4382      * Write the proto dump of various client side components to the provided
4383      * {@link ProtoOutputStream}.
4384      *
4385      * @param proto The proto stream to which the dumps are written.
4386      * @param icProto {@link InputConnection} call data in proto format.
4387      * @hide
4388      */
dumpDebug(ProtoOutputStream proto, @Nullable byte[] icProto)4389     public void dumpDebug(ProtoOutputStream proto, @Nullable byte[] icProto) {
4390         synchronized (mH) {
4391             if (!isImeSessionAvailableLocked()) {
4392                 return;
4393             }
4394 
4395             proto.write(DISPLAY_ID, mDisplayId);
4396             final long token = proto.start(INPUT_METHOD_MANAGER);
4397             proto.write(CUR_ID, mCurBindState.mImeId);
4398             proto.write(FULLSCREEN_MODE, mFullscreenMode);
4399             proto.write(ACTIVE, mActive);
4400             proto.write(SERVED_CONNECTING, mServedConnecting);
4401             proto.write(SERVED_VIEW, Objects.toString(mServedView));
4402             proto.write(NEXT_SERVED_VIEW, Objects.toString(mNextServedView));
4403             proto.end(token);
4404             if (mCurRootView != null) {
4405                 mCurRootView.dumpDebug(proto, VIEW_ROOT_IMPL);
4406             }
4407             if (mCurrentEditorInfo != null) {
4408                 mCurrentEditorInfo.dumpDebug(proto, EDITOR_INFO);
4409             }
4410             if (mImeInsetsConsumer != null) {
4411                 mImeInsetsConsumer.dumpDebug(proto, IME_INSETS_SOURCE_CONSUMER);
4412             }
4413             if (mServedInputConnection != null) {
4414                 mServedInputConnection.dumpDebug(proto, INPUT_CONNECTION);
4415             }
4416             if (icProto != null) {
4417                 proto.write(INPUT_CONNECTION_CALL, icProto);
4418             }
4419         }
4420     }
4421 
4422     @GuardedBy("mH")
forAccessibilitySessionsLocked( Consumer<IAccessibilityInputMethodSessionInvoker> consumer)4423     private void forAccessibilitySessionsLocked(
4424             Consumer<IAccessibilityInputMethodSessionInvoker> consumer) {
4425         for (int i = 0; i < mAccessibilityInputMethodSession.size(); i++) {
4426             consumer.accept(mAccessibilityInputMethodSession.valueAt(i));
4427         }
4428     }
4429 
4430     @UiThread
createInputConnection( @onNull View servedView)4431     private static Pair<InputConnection, EditorInfo> createInputConnection(
4432             @NonNull View servedView) {
4433         final EditorInfo editorInfo = new EditorInfo();
4434         // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the
4435         // system can verify the consistency between the uid of this process and package name passed
4436         // from here. See comment of Context#getOpPackageName() for details.
4437         editorInfo.packageName = servedView.getContext().getOpPackageName();
4438         editorInfo.autofillId = servedView.getAutofillId();
4439         editorInfo.fieldId = servedView.getId();
4440         final InputConnection ic = servedView.onCreateInputConnection(editorInfo);
4441         if (DEBUG) Log.v(TAG, "Starting input: editorInfo=" + editorInfo + " ic=" + ic);
4442 
4443         // Clear autofill and field ids if a connection could not be established.
4444         // This ensures that even disconnected EditorInfos have well-defined attributes,
4445         // making them consistently and straightforwardly comparable.
4446         if (ic == null) {
4447             editorInfo.autofillId = AutofillId.NO_AUTOFILL_ID;
4448             editorInfo.fieldId = 0;
4449         }
4450         return new Pair<>(ic, editorInfo);
4451     }
4452 }
4453