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