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