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