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