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