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