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