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