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