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