InputMethodManager.java revision 67ddf9cbd5d7133c7f443cd3c55841ed1109c3a0
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 android.content.Context;
20import android.graphics.Rect;
21import android.os.Bundle;
22import android.os.Handler;
23import android.os.IBinder;
24import android.os.Looper;
25import android.os.Message;
26import android.os.RemoteException;
27import android.os.ResultReceiver;
28import android.os.ServiceManager;
29import android.util.Log;
30import android.util.Pair;
31import android.util.PrintWriterPrinter;
32import android.util.Printer;
33import android.view.KeyEvent;
34import android.view.MotionEvent;
35import android.view.View;
36import android.view.ViewRoot;
37import android.view.inputmethod.InputMethodSubtype;
38
39import com.android.internal.os.HandlerCaller;
40import com.android.internal.view.IInputConnectionWrapper;
41import com.android.internal.view.IInputContext;
42import com.android.internal.view.IInputMethodCallback;
43import com.android.internal.view.IInputMethodClient;
44import com.android.internal.view.IInputMethodManager;
45import com.android.internal.view.IInputMethodSession;
46import com.android.internal.view.InputBindResult;
47
48import java.io.FileDescriptor;
49import java.io.PrintWriter;
50import java.util.List;
51import java.util.concurrent.CountDownLatch;
52import java.util.concurrent.TimeUnit;
53
54/**
55 * Central system API to the overall input method framework (IMF) architecture,
56 * which arbitrates interaction between applications and the current input method.
57 * You can retrieve an instance of this interface with
58 * {@link Context#getSystemService(String) Context.getSystemService()}.
59 *
60 * <p>Topics covered here:
61 * <ol>
62 * <li><a href="#ArchitectureOverview">Architecture Overview</a>
63 * </ol>
64 *
65 * <a name="ArchitectureOverview"></a>
66 * <h3>Architecture Overview</h3>
67 *
68 * <p>There are three primary parties involved in the input method
69 * framework (IMF) architecture:</p>
70 *
71 * <ul>
72 * <li> The <strong>input method manager</strong> as expressed by this class
73 * is the central point of the system that manages interaction between all
74 * other parts.  It is expressed as the client-side API here which exists
75 * in each application context and communicates with a global system service
76 * that manages the interaction across all processes.
77 * <li> An <strong>input method (IME)</strong> implements a particular
78 * interaction model allowing the user to generate text.  The system binds
79 * to the current input method that is use, causing it to be created and run,
80 * and tells it when to hide and show its UI.  Only one IME is running at a time.
81 * <li> Multiple <strong>client applications</strong> arbitrate with the input
82 * method manager for input focus and control over the state of the IME.  Only
83 * one such client is ever active (working with the IME) at a time.
84 * </ul>
85 *
86 *
87 * <a name="Applications"></a>
88 * <h3>Applications</h3>
89 *
90 * <p>In most cases, applications that are using the standard
91 * {@link android.widget.TextView} or its subclasses will have little they need
92 * to do to work well with soft input methods.  The main things you need to
93 * be aware of are:</p>
94 *
95 * <ul>
96 * <li> Properly set the {@link android.R.attr#inputType} if your editable
97 * text views, so that the input method will have enough context to help the
98 * user in entering text into them.
99 * <li> Deal well with losing screen space when the input method is
100 * displayed.  Ideally an application should handle its window being resized
101 * smaller, but it can rely on the system performing panning of the window
102 * if needed.  You should set the {@link android.R.attr#windowSoftInputMode}
103 * attribute on your activity or the corresponding values on windows you
104 * create to help the system determine whether to pan or resize (it will
105 * try to determine this automatically but may get it wrong).
106 * <li> You can also control the preferred soft input state (open, closed, etc)
107 * for your window using the same {@link android.R.attr#windowSoftInputMode}
108 * attribute.
109 * </ul>
110 *
111 * <p>More finer-grained control is available through the APIs here to directly
112 * interact with the IMF and its IME -- either showing or hiding the input
113 * area, letting the user pick an input method, etc.</p>
114 *
115 * <p>For the rare people amongst us writing their own text editors, you
116 * will need to implement {@link android.view.View#onCreateInputConnection}
117 * to return a new instance of your own {@link InputConnection} interface
118 * allowing the IME to interact with your editor.</p>
119 *
120 *
121 * <a name="InputMethods"></a>
122 * <h3>Input Methods</h3>
123 *
124 * <p>An input method (IME) is implemented
125 * as a {@link android.app.Service}, typically deriving from
126 * {@link android.inputmethodservice.InputMethodService}.  It must provide
127 * the core {@link InputMethod} interface, though this is normally handled by
128 * {@link android.inputmethodservice.InputMethodService} and implementors will
129 * only need to deal with the higher-level API there.</p>
130 *
131 * See the {@link android.inputmethodservice.InputMethodService} class for
132 * more information on implementing IMEs.
133 *
134 *
135 * <a name="Security"></a>
136 * <h3>Security</h3>
137 *
138 * <p>There are a lot of security issues associated with input methods,
139 * since they essentially have freedom to completely drive the UI and monitor
140 * everything the user enters.  The Android input method framework also allows
141 * arbitrary third party IMEs, so care must be taken to restrict their
142 * selection and interactions.</p>
143 *
144 * <p>Here are some key points about the security architecture behind the
145 * IMF:</p>
146 *
147 * <ul>
148 * <li> <p>Only the system is allowed to directly access an IME's
149 * {@link InputMethod} interface, via the
150 * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission.  This is
151 * enforced in the system by not binding to an input method service that does
152 * not require this permission, so the system can guarantee no other untrusted
153 * clients are accessing the current input method outside of its control.</p>
154 *
155 * <li> <p>There may be many client processes of the IMF, but only one may
156 * be active at a time.  The inactive clients can not interact with key
157 * parts of the IMF through the mechanisms described below.</p>
158 *
159 * <li> <p>Clients of an input method are only given access to its
160 * {@link InputMethodSession} interface.  One instance of this interface is
161 * created for each client, and only calls from the session associated with
162 * the active client will be processed by the current IME.  This is enforced
163 * by {@link android.inputmethodservice.AbstractInputMethodService} for normal
164 * IMEs, but must be explicitly handled by an IME that is customizing the
165 * raw {@link InputMethodSession} implementation.</p>
166 *
167 * <li> <p>Only the active client's {@link InputConnection} will accept
168 * operations.  The IMF tells each client process whether it is active, and
169 * the framework enforces that in inactive processes calls on to the current
170 * InputConnection will be ignored.  This ensures that the current IME can
171 * only deliver events and text edits to the UI that the user sees as
172 * being in focus.</p>
173 *
174 * <li> <p>An IME can never interact with an {@link InputConnection} while
175 * the screen is off.  This is enforced by making all clients inactive while
176 * the screen is off, and prevents bad IMEs from driving the UI when the user
177 * can not be aware of its behavior.</p>
178 *
179 * <li> <p>A client application can ask that the system let the user pick a
180 * new IME, but can not programmatically switch to one itself.  This avoids
181 * malicious applications from switching the user to their own IME, which
182 * remains running when the user navigates away to another application.  An
183 * IME, on the other hand, <em>is</em> allowed to programmatically switch
184 * the system to another IME, since it already has full control of user
185 * input.</p>
186 *
187 * <li> <p>The user must explicitly enable a new IME in settings before
188 * they can switch to it, to confirm with the system that they know about it
189 * and want to make it available for use.</p>
190 * </ul>
191 */
192public final class InputMethodManager {
193    static final boolean DEBUG = false;
194    static final String TAG = "InputMethodManager";
195
196    static final Object mInstanceSync = new Object();
197    static InputMethodManager mInstance;
198
199    final IInputMethodManager mService;
200    final Looper mMainLooper;
201
202    // For scheduling work on the main thread.  This also serves as our
203    // global lock.
204    final H mH;
205
206    // Our generic input connection if the current target does not have its own.
207    final IInputContext mIInputContext;
208
209    /**
210     * True if this input method client is active, initially false.
211     */
212    boolean mActive = false;
213
214    /**
215     * Set whenever this client becomes inactive, to know we need to reset
216     * state with the IME then next time we receive focus.
217     */
218    boolean mHasBeenInactive = true;
219
220    /**
221     * As reported by IME through InputConnection.
222     */
223    boolean mFullscreenMode;
224
225    // -----------------------------------------------------------
226
227    /**
228     * This is the root view of the overall window that currently has input
229     * method focus.
230     */
231    View mCurRootView;
232    /**
233     * This is the view that should currently be served by an input method,
234     * regardless of the state of setting that up.
235     */
236    View mServedView;
237    /**
238     * This is then next view that will be served by the input method, when
239     * we get around to updating things.
240     */
241    View mNextServedView;
242    /**
243     * True if we should restart input in the next served view, even if the
244     * view hasn't actually changed from the current serve view.
245     */
246    boolean mNextServedNeedsStart;
247    /**
248     * This is set when we are in the process of connecting, to determine
249     * when we have actually finished.
250     */
251    boolean mServedConnecting;
252    /**
253     * This is non-null when we have connected the served view; it holds
254     * the attributes that were last retrieved from the served view and given
255     * to the input connection.
256     */
257    EditorInfo mCurrentTextBoxAttribute;
258    /**
259     * The InputConnection that was last retrieved from the served view.
260     */
261    InputConnection mServedInputConnection;
262    /**
263     * The completions that were last provided by the served view.
264     */
265    CompletionInfo[] mCompletions;
266
267    // Cursor position on the screen.
268    Rect mTmpCursorRect = new Rect();
269    Rect mCursorRect = new Rect();
270    int mCursorSelStart;
271    int mCursorSelEnd;
272    int mCursorCandStart;
273    int mCursorCandEnd;
274
275    // -----------------------------------------------------------
276
277    /**
278     * Sequence number of this binding, as returned by the server.
279     */
280    int mBindSequence = -1;
281    /**
282     * ID of the method we are bound to.
283     */
284    String mCurId;
285    /**
286     * The actual instance of the method to make calls on it.
287     */
288    IInputMethodSession mCurMethod;
289
290    // -----------------------------------------------------------
291
292    static final int MSG_DUMP = 1;
293    static final int MSG_BIND = 2;
294    static final int MSG_UNBIND = 3;
295    static final int MSG_SET_ACTIVE = 4;
296
297    class H extends Handler {
298        H(Looper looper) {
299            super(looper);
300        }
301
302        @Override
303        public void handleMessage(Message msg) {
304            switch (msg.what) {
305                case MSG_DUMP: {
306                    HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
307                    try {
308                        doDump((FileDescriptor)args.arg1,
309                                (PrintWriter)args.arg2, (String[])args.arg3);
310                    } catch (RuntimeException e) {
311                        ((PrintWriter)args.arg2).println("Exception: " + e);
312                    }
313                    synchronized (args.arg4) {
314                        ((CountDownLatch)args.arg4).countDown();
315                    }
316                    return;
317                }
318                case MSG_BIND: {
319                    final InputBindResult res = (InputBindResult)msg.obj;
320                    synchronized (mH) {
321                        if (mBindSequence < 0 || mBindSequence != res.sequence) {
322                            Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
323                                    + ", given seq=" + res.sequence);
324                            return;
325                        }
326
327                        mCurMethod = res.method;
328                        mCurId = res.id;
329                        mBindSequence = res.sequence;
330                    }
331                    startInputInner();
332                    return;
333                }
334                case MSG_UNBIND: {
335                    final int sequence = msg.arg1;
336                    synchronized (mH) {
337                        if (mBindSequence == sequence) {
338                            if (false) {
339                                // XXX the server has already unbound!
340                                if (mCurMethod != null && mCurrentTextBoxAttribute != null) {
341                                    try {
342                                        mCurMethod.finishInput();
343                                    } catch (RemoteException e) {
344                                        Log.w(TAG, "IME died: " + mCurId, e);
345                                    }
346                                }
347                            }
348                            clearBindingLocked();
349
350                            // If we were actively using the last input method, then
351                            // we would like to re-connect to the next input method.
352                            if (mServedView != null && mServedView.isFocused()) {
353                                mServedConnecting = true;
354                            }
355                        }
356                        startInputInner();
357                    }
358                    return;
359                }
360                case MSG_SET_ACTIVE: {
361                    final boolean active = msg.arg1 != 0;
362                    synchronized (mH) {
363                        mActive = active;
364                        mFullscreenMode = false;
365                        if (!active) {
366                            // Some other client has starting using the IME, so note
367                            // that this happened and make sure our own editor's
368                            // state is reset.
369                            mHasBeenInactive = true;
370                            try {
371                                // Note that finishComposingText() is allowed to run
372                                // even when we are not active.
373                                mIInputContext.finishComposingText();
374                            } catch (RemoteException e) {
375                            }
376                        }
377                    }
378                    return;
379                }
380            }
381        }
382    }
383
384    class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
385        public ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
386            super(mainLooper, conn);
387        }
388
389        public boolean isActive() {
390            return mActive;
391        }
392    }
393
394    final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
395        @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
396            // No need to check for dump permission, since we only give this
397            // interface to the system.
398
399            CountDownLatch latch = new CountDownLatch(1);
400            HandlerCaller.SomeArgs sargs = new HandlerCaller.SomeArgs();
401            sargs.arg1 = fd;
402            sargs.arg2 = fout;
403            sargs.arg3 = args;
404            sargs.arg4 = latch;
405            mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs));
406            try {
407                if (!latch.await(5, TimeUnit.SECONDS)) {
408                    fout.println("Timeout waiting for dump");
409                }
410            } catch (InterruptedException e) {
411                fout.println("Interrupted waiting for dump");
412            }
413        }
414
415        public void setUsingInputMethod(boolean state) {
416        }
417
418        public void onBindMethod(InputBindResult res) {
419            mH.sendMessage(mH.obtainMessage(MSG_BIND, res));
420        }
421
422        public void onUnbindMethod(int sequence) {
423            mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, 0));
424        }
425
426        public void setActive(boolean active) {
427            mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0));
428        }
429    };
430
431    final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
432
433    InputMethodManager(IInputMethodManager service, Looper looper) {
434        mService = service;
435        mMainLooper = looper;
436        mH = new H(looper);
437        mIInputContext = new ControlledInputConnectionWrapper(looper,
438                mDummyInputConnection);
439
440        if (mInstance == null) {
441            mInstance = this;
442        }
443    }
444
445    /**
446     * Retrieve the global InputMethodManager instance, creating it if it
447     * doesn't already exist.
448     * @hide
449     */
450    static public InputMethodManager getInstance(Context context) {
451        return getInstance(context.getMainLooper());
452    }
453
454    /**
455     * Internally, the input method manager can't be context-dependent, so
456     * we have this here for the places that need it.
457     * @hide
458     */
459    static public InputMethodManager getInstance(Looper mainLooper) {
460        synchronized (mInstanceSync) {
461            if (mInstance != null) {
462                return mInstance;
463            }
464            IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
465            IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
466            mInstance = new InputMethodManager(service, mainLooper);
467        }
468        return mInstance;
469    }
470
471    /**
472     * Private optimization: retrieve the global InputMethodManager instance,
473     * if it exists.
474     * @hide
475     */
476    static public InputMethodManager peekInstance() {
477        return mInstance;
478    }
479
480    /** @hide */
481    public IInputMethodClient getClient() {
482        return mClient;
483    }
484
485    /** @hide */
486    public IInputContext getInputContext() {
487        return mIInputContext;
488    }
489
490    public List<InputMethodInfo> getInputMethodList() {
491        try {
492            return mService.getInputMethodList();
493        } catch (RemoteException e) {
494            throw new RuntimeException(e);
495        }
496    }
497
498    public List<InputMethodInfo> getEnabledInputMethodList() {
499        try {
500            return mService.getEnabledInputMethodList();
501        } catch (RemoteException e) {
502            throw new RuntimeException(e);
503        }
504    }
505
506    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi) {
507        try {
508            return mService.getEnabledInputMethodSubtypeList(imi);
509        } catch (RemoteException e) {
510            throw new RuntimeException(e);
511        }
512    }
513
514    public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
515        try {
516            mService.updateStatusIcon(imeToken, packageName, iconId);
517        } catch (RemoteException e) {
518            throw new RuntimeException(e);
519        }
520    }
521
522    public void hideStatusIcon(IBinder imeToken) {
523        try {
524            mService.updateStatusIcon(imeToken, null, 0);
525        } catch (RemoteException e) {
526            throw new RuntimeException(e);
527        }
528    }
529
530    /** @hide */
531    public void setIMEButtonVisible(IBinder imeToken, boolean visible) {
532        try {
533            mService.setIMEButtonVisible(imeToken, visible);
534        } catch (RemoteException e) {
535            throw new RuntimeException(e);
536        }
537    }
538
539    /** @hide */
540    public void setFullscreenMode(boolean fullScreen) {
541        mFullscreenMode = fullScreen;
542    }
543
544    /**
545     * Allows you to discover whether the attached input method is running
546     * in fullscreen mode.  Return true if it is fullscreen, entirely covering
547     * your UI, else returns false.
548     */
549    public boolean isFullscreenMode() {
550        return mFullscreenMode;
551    }
552
553    /**
554     * Return true if the given view is the currently active view for the
555     * input method.
556     */
557    public boolean isActive(View view) {
558        checkFocus();
559        synchronized (mH) {
560            return (mServedView == view
561                    || (mServedView != null
562                            && mServedView.checkInputConnectionProxy(view)))
563                    && mCurrentTextBoxAttribute != null;
564        }
565    }
566
567    /**
568     * Return true if any view is currently active in the input method.
569     */
570    public boolean isActive() {
571        checkFocus();
572        synchronized (mH) {
573            return mServedView != null && mCurrentTextBoxAttribute != null;
574        }
575    }
576
577    /**
578     * Return true if the currently served view is accepting full text edits.
579     * If false, it has no input connection, so can only handle raw key events.
580     */
581    public boolean isAcceptingText() {
582        checkFocus();
583        return mServedInputConnection != null;
584    }
585
586    /**
587     * Reset all of the state associated with being bound to an input method.
588     */
589    void clearBindingLocked() {
590        clearConnectionLocked();
591        mBindSequence = -1;
592        mCurId = null;
593        mCurMethod = null;
594    }
595
596    /**
597     * Reset all of the state associated with a served view being connected
598     * to an input method
599     */
600    void clearConnectionLocked() {
601        mCurrentTextBoxAttribute = null;
602        mServedInputConnection = null;
603    }
604
605    /**
606     * Disconnect any existing input connection, clearing the served view.
607     */
608    void finishInputLocked() {
609        mNextServedView = null;
610        if (mServedView != null) {
611            if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView);
612
613            if (mCurrentTextBoxAttribute != null) {
614                try {
615                    mService.finishInput(mClient);
616                } catch (RemoteException e) {
617                }
618            }
619
620            if (mServedInputConnection != null) {
621                // We need to tell the previously served view that it is no
622                // longer the input target, so it can reset its state.  Schedule
623                // this call on its window's Handler so it will be on the correct
624                // thread and outside of our lock.
625                Handler vh = mServedView.getHandler();
626                if (vh != null) {
627                    // This will result in a call to reportFinishInputConnection()
628                    // below.
629                    vh.sendMessage(vh.obtainMessage(ViewRoot.FINISH_INPUT_CONNECTION,
630                            mServedInputConnection));
631                }
632            }
633
634            mServedView = null;
635            mCompletions = null;
636            mServedConnecting = false;
637            clearConnectionLocked();
638        }
639    }
640
641    /**
642     * Called from the FINISH_INPUT_CONNECTION message above.
643     * @hide
644     */
645    public void reportFinishInputConnection(InputConnection ic) {
646        if (mServedInputConnection != ic) {
647            ic.finishComposingText();
648        }
649    }
650
651    public void displayCompletions(View view, CompletionInfo[] completions) {
652        checkFocus();
653        synchronized (mH) {
654            if (mServedView != view && (mServedView == null
655                            || !mServedView.checkInputConnectionProxy(view))) {
656                return;
657            }
658
659            mCompletions = completions;
660            if (mCurMethod != null) {
661                try {
662                    mCurMethod.displayCompletions(mCompletions);
663                } catch (RemoteException e) {
664                }
665            }
666        }
667    }
668
669    public void updateExtractedText(View view, int token, ExtractedText text) {
670        checkFocus();
671        synchronized (mH) {
672            if (mServedView != view && (mServedView == null
673                    || !mServedView.checkInputConnectionProxy(view))) {
674                return;
675            }
676
677            if (mCurMethod != null) {
678                try {
679                    mCurMethod.updateExtractedText(token, text);
680                } catch (RemoteException e) {
681                }
682            }
683        }
684    }
685
686    /**
687     * Flag for {@link #showSoftInput} to indicate that this is an implicit
688     * request to show the input window, not as the result of a direct request
689     * by the user.  The window may not be shown in this case.
690     */
691    public static final int SHOW_IMPLICIT = 0x0001;
692
693    /**
694     * Flag for {@link #showSoftInput} to indicate that the user has forced
695     * the input method open (such as by long-pressing menu) so it should
696     * not be closed until they explicitly do so.
697     */
698    public static final int SHOW_FORCED = 0x0002;
699
700    /**
701     * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
702     * a result receiver: explicitly request that the current input method's
703     * soft input area be shown to the user, if needed.
704     *
705     * @param view The currently focused view, which would like to receive
706     * soft keyboard input.
707     * @param flags Provides additional operating flags.  Currently may be
708     * 0 or have the {@link #SHOW_IMPLICIT} bit set.
709     */
710    public boolean showSoftInput(View view, int flags) {
711        return showSoftInput(view, flags, null);
712    }
713
714    /**
715     * Flag for the {@link ResultReceiver} result code from
716     * {@link #showSoftInput(View, int, ResultReceiver)} and
717     * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
718     * state of the soft input window was unchanged and remains shown.
719     */
720    public static final int RESULT_UNCHANGED_SHOWN = 0;
721
722    /**
723     * Flag for the {@link ResultReceiver} result code from
724     * {@link #showSoftInput(View, int, ResultReceiver)} and
725     * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
726     * state of the soft input window was unchanged and remains hidden.
727     */
728    public static final int RESULT_UNCHANGED_HIDDEN = 1;
729
730    /**
731     * Flag for the {@link ResultReceiver} result code from
732     * {@link #showSoftInput(View, int, ResultReceiver)} and
733     * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
734     * state of the soft input window changed from hidden to shown.
735     */
736    public static final int RESULT_SHOWN = 2;
737
738    /**
739     * Flag for the {@link ResultReceiver} result code from
740     * {@link #showSoftInput(View, int, ResultReceiver)} and
741     * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
742     * state of the soft input window changed from shown to hidden.
743     */
744    public static final int RESULT_HIDDEN = 3;
745
746    /**
747     * Explicitly request that the current input method's soft input area be
748     * shown to the user, if needed.  Call this if the user interacts with
749     * your view in such a way that they have expressed they would like to
750     * start performing input into it.
751     *
752     * @param view The currently focused view, which would like to receive
753     * soft keyboard input.
754     * @param flags Provides additional operating flags.  Currently may be
755     * 0 or have the {@link #SHOW_IMPLICIT} bit set.
756     * @param resultReceiver If non-null, this will be called by the IME when
757     * it has processed your request to tell you what it has done.  The result
758     * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
759     * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
760     * {@link #RESULT_HIDDEN}.
761     */
762    public boolean showSoftInput(View view, int flags,
763            ResultReceiver resultReceiver) {
764        checkFocus();
765        synchronized (mH) {
766            if (mServedView != view && (mServedView == null
767                    || !mServedView.checkInputConnectionProxy(view))) {
768                return false;
769            }
770
771            try {
772                return mService.showSoftInput(mClient, flags, resultReceiver);
773            } catch (RemoteException e) {
774            }
775
776            return false;
777        }
778    }
779
780    /** @hide */
781    public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
782        try {
783            mService.showSoftInput(mClient, flags, resultReceiver);
784        } catch (RemoteException e) {
785        }
786    }
787
788    /**
789     * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
790     * input window should only be hidden if it was not explicitly shown
791     * by the user.
792     */
793    public static final int HIDE_IMPLICIT_ONLY = 0x0001;
794
795    /**
796     * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
797     * input window should normally be hidden, unless it was originally
798     * shown with {@link #SHOW_FORCED}.
799     */
800    public static final int HIDE_NOT_ALWAYS = 0x0002;
801
802    /**
803     * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)
804     * without a result: request to hide the soft input window from the
805     * context of the window that is currently accepting input.
806     *
807     * @param windowToken The token of the window that is making the request,
808     * as returned by {@link View#getWindowToken() View.getWindowToken()}.
809     * @param flags Provides additional operating flags.  Currently may be
810     * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
811     */
812    public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) {
813        return hideSoftInputFromWindow(windowToken, flags, null);
814    }
815
816    /**
817     * Request to hide the soft input window from the context of the window
818     * that is currently accepting input.  This should be called as a result
819     * of the user doing some actually than fairly explicitly requests to
820     * have the input window hidden.
821     *
822     * @param windowToken The token of the window that is making the request,
823     * as returned by {@link View#getWindowToken() View.getWindowToken()}.
824     * @param flags Provides additional operating flags.  Currently may be
825     * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
826     * @param resultReceiver If non-null, this will be called by the IME when
827     * it has processed your request to tell you what it has done.  The result
828     * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
829     * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
830     * {@link #RESULT_HIDDEN}.
831     */
832    public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
833            ResultReceiver resultReceiver) {
834        checkFocus();
835        synchronized (mH) {
836            if (mServedView == null || mServedView.getWindowToken() != windowToken) {
837                return false;
838            }
839
840            try {
841                return mService.hideSoftInput(mClient, flags, resultReceiver);
842            } catch (RemoteException e) {
843            }
844            return false;
845        }
846    }
847
848
849    /**
850     * This method toggles the input method window display.
851     * If the input window is already displayed, it gets hidden.
852     * If not the input window will be displayed.
853     * @param windowToken The token of the window that is making the request,
854     * as returned by {@link View#getWindowToken() View.getWindowToken()}.
855     * @param showFlags Provides additional operating flags.  May be
856     * 0 or have the {@link #SHOW_IMPLICIT},
857     * {@link #SHOW_FORCED} bit set.
858     * @param hideFlags Provides additional operating flags.  May be
859     * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
860     * {@link #HIDE_NOT_ALWAYS} bit set.
861     **/
862    public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
863        synchronized (mH) {
864            if (mServedView == null || mServedView.getWindowToken() != windowToken) {
865                return;
866            }
867            if (mCurMethod != null) {
868                try {
869                    mCurMethod.toggleSoftInput(showFlags, hideFlags);
870                } catch (RemoteException e) {
871                }
872            }
873        }
874    }
875
876    /*
877     * This method toggles the input method window display.
878     * If the input window is already displayed, it gets hidden.
879     * If not the input window will be displayed.
880     * @param showFlags Provides additional operating flags.  May be
881     * 0 or have the {@link #SHOW_IMPLICIT},
882     * {@link #SHOW_FORCED} bit set.
883     * @param hideFlags Provides additional operating flags.  May be
884     * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
885     * {@link #HIDE_NOT_ALWAYS} bit set.
886     * @hide
887     */
888    public void toggleSoftInput(int showFlags, int hideFlags) {
889        if (mCurMethod != null) {
890            try {
891                mCurMethod.toggleSoftInput(showFlags, hideFlags);
892            } catch (RemoteException e) {
893            }
894        }
895    }
896
897    /**
898     * If the input method is currently connected to the given view,
899     * restart it with its new contents.  You should call this when the text
900     * within your view changes outside of the normal input method or key
901     * input flow, such as when an application calls TextView.setText().
902     *
903     * @param view The view whose text has changed.
904     */
905    public void restartInput(View view) {
906        checkFocus();
907        synchronized (mH) {
908            if (mServedView != view && (mServedView == null
909                    || !mServedView.checkInputConnectionProxy(view))) {
910                return;
911            }
912
913            mServedConnecting = true;
914        }
915
916        startInputInner();
917    }
918
919    void startInputInner() {
920        final View view;
921        synchronized (mH) {
922            view = mServedView;
923
924            // Make sure we have a window token for the served view.
925            if (DEBUG) Log.v(TAG, "Starting input: view=" + view);
926            if (view == null) {
927                if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
928                return;
929            }
930        }
931
932        // Now we need to get an input connection from the served view.
933        // This is complicated in a couple ways: we can't be holding our lock
934        // when calling out to the view, and we need to make sure we call into
935        // the view on the same thread that is driving its view hierarchy.
936        Handler vh = view.getHandler();
937        if (vh == null) {
938            // If the view doesn't have a handler, something has changed out
939            // from under us, so just bail.
940            if (DEBUG) Log.v(TAG, "ABORT input: no handler for view!");
941            return;
942        }
943        if (vh.getLooper() != Looper.myLooper()) {
944            // The view is running on a different thread than our own, so
945            // we need to reschedule our work for over there.
946            if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
947            vh.post(new Runnable() {
948                public void run() {
949                    startInputInner();
950                }
951            });
952            return;
953        }
954
955        // Okay we are now ready to call into the served view and have it
956        // do its stuff.
957        // Life is good: let's hook everything up!
958        EditorInfo tba = new EditorInfo();
959        tba.packageName = view.getContext().getPackageName();
960        tba.fieldId = view.getId();
961        InputConnection ic = view.onCreateInputConnection(tba);
962        if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
963
964        synchronized (mH) {
965            // Now that we are locked again, validate that our state hasn't
966            // changed.
967            if (mServedView != view || !mServedConnecting) {
968                // Something else happened, so abort.
969                if (DEBUG) Log.v(TAG,
970                        "Starting input: finished by someone else (view="
971                        + mServedView + " conn=" + mServedConnecting + ")");
972                return;
973            }
974
975            // If we already have a text box, then this view is already
976            // connected so we want to restart it.
977            final boolean initial = mCurrentTextBoxAttribute == null;
978
979            // Hook 'em up and let 'er rip.
980            mCurrentTextBoxAttribute = tba;
981            mServedConnecting = false;
982            mServedInputConnection = ic;
983            IInputContext servedContext;
984            if (ic != null) {
985                mCursorSelStart = tba.initialSelStart;
986                mCursorSelEnd = tba.initialSelEnd;
987                mCursorCandStart = -1;
988                mCursorCandEnd = -1;
989                mCursorRect.setEmpty();
990                servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic);
991            } else {
992                servedContext = null;
993            }
994
995            try {
996                if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
997                        + ic + " tba=" + tba + " initial=" + initial);
998                InputBindResult res = mService.startInput(mClient,
999                        servedContext, tba, initial, mCurMethod == null);
1000                if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
1001                if (res != null) {
1002                    if (res.id != null) {
1003                        mBindSequence = res.sequence;
1004                        mCurMethod = res.method;
1005                    } else {
1006                        // This means there is no input method available.
1007                        if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
1008                        return;
1009                    }
1010                }
1011                if (mCurMethod != null && mCompletions != null) {
1012                    try {
1013                        mCurMethod.displayCompletions(mCompletions);
1014                    } catch (RemoteException e) {
1015                    }
1016                }
1017            } catch (RemoteException e) {
1018                Log.w(TAG, "IME died: " + mCurId, e);
1019            }
1020        }
1021    }
1022
1023    /**
1024     * When the focused window is dismissed, this method is called to finish the
1025     * input method started before.
1026     * @hide
1027     */
1028    public void windowDismissed(IBinder appWindowToken) {
1029        checkFocus();
1030        synchronized (mH) {
1031            if (mServedView != null &&
1032                    mServedView.getWindowToken() == appWindowToken) {
1033                finishInputLocked();
1034            }
1035        }
1036    }
1037
1038    /**
1039     * Call this when a view receives focus.
1040     * @hide
1041     */
1042    public void focusIn(View view) {
1043        synchronized (mH) {
1044            focusInLocked(view);
1045        }
1046    }
1047
1048    void focusInLocked(View view) {
1049        if (DEBUG) Log.v(TAG, "focusIn: " + view);
1050
1051        if (mCurRootView != view.getRootView()) {
1052            // This is a request from a window that isn't in the window with
1053            // IME focus, so ignore it.
1054            if (DEBUG) Log.v(TAG, "Not IME target window, ignoring");
1055            return;
1056        }
1057
1058        mNextServedView = view;
1059        scheduleCheckFocusLocked(view);
1060    }
1061
1062    /**
1063     * Call this when a view loses focus.
1064     * @hide
1065     */
1066    public void focusOut(View view) {
1067        synchronized (mH) {
1068            if (DEBUG) Log.v(TAG, "focusOut: " + view
1069                    + " mServedView=" + mServedView
1070                    + " winFocus=" + view.hasWindowFocus());
1071            if (mServedView != view) {
1072                // The following code would auto-hide the IME if we end up
1073                // with no more views with focus.  This can happen, however,
1074                // whenever we go into touch mode, so it ends up hiding
1075                // at times when we don't really want it to.  For now it
1076                // seems better to just turn it all off.
1077                if (false && view.hasWindowFocus()) {
1078                    mNextServedView = null;
1079                    scheduleCheckFocusLocked(view);
1080                }
1081            }
1082        }
1083    }
1084
1085    void scheduleCheckFocusLocked(View view) {
1086        Handler vh = view.getHandler();
1087        if (vh != null && !vh.hasMessages(ViewRoot.CHECK_FOCUS)) {
1088            // This will result in a call to checkFocus() below.
1089            vh.sendMessage(vh.obtainMessage(ViewRoot.CHECK_FOCUS));
1090        }
1091    }
1092
1093    /**
1094     * @hide
1095     */
1096    public void checkFocus() {
1097        // This is called a lot, so short-circuit before locking.
1098        if (mServedView == mNextServedView && !mNextServedNeedsStart) {
1099            return;
1100        }
1101
1102        InputConnection ic = null;
1103        synchronized (mH) {
1104            if (mServedView == mNextServedView && !mNextServedNeedsStart) {
1105                return;
1106            }
1107            if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
1108                    + " next=" + mNextServedView
1109                    + " restart=" + mNextServedNeedsStart);
1110
1111            mNextServedNeedsStart = false;
1112            if (mNextServedView == null) {
1113                finishInputLocked();
1114                // In this case, we used to have a focused view on the window,
1115                // but no longer do.  We should make sure the input method is
1116                // no longer shown, since it serves no purpose.
1117                closeCurrentInput();
1118                return;
1119            }
1120
1121            ic = mServedInputConnection;
1122
1123            mServedView = mNextServedView;
1124            mCurrentTextBoxAttribute = null;
1125            mCompletions = null;
1126            mServedConnecting = true;
1127        }
1128
1129        if (ic != null) {
1130            ic.finishComposingText();
1131        }
1132
1133        startInputInner();
1134    }
1135
1136    void closeCurrentInput() {
1137        try {
1138            mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
1139        } catch (RemoteException e) {
1140        }
1141    }
1142
1143    /**
1144     * Called by ViewRoot when its window gets input focus.
1145     * @hide
1146     */
1147    public void onWindowFocus(View rootView, View focusedView, int softInputMode,
1148            boolean first, int windowFlags) {
1149        synchronized (mH) {
1150            if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
1151                    + " softInputMode=" + softInputMode
1152                    + " first=" + first + " flags=#"
1153                    + Integer.toHexString(windowFlags));
1154            if (mHasBeenInactive) {
1155                if (DEBUG) Log.v(TAG, "Has been inactive!  Starting fresh");
1156                mHasBeenInactive = false;
1157                mNextServedNeedsStart = true;
1158            }
1159            focusInLocked(focusedView != null ? focusedView : rootView);
1160        }
1161
1162        checkFocus();
1163
1164        synchronized (mH) {
1165            try {
1166                final boolean isTextEditor = focusedView != null &&
1167                        focusedView.onCheckIsTextEditor();
1168                mService.windowGainedFocus(mClient, rootView.getWindowToken(),
1169                        focusedView != null, isTextEditor, softInputMode, first,
1170                        windowFlags);
1171            } catch (RemoteException e) {
1172            }
1173        }
1174    }
1175
1176    /** @hide */
1177    public void startGettingWindowFocus(View rootView) {
1178        synchronized (mH) {
1179            mCurRootView = rootView;
1180        }
1181    }
1182
1183    /**
1184     * Report the current selection range.
1185     */
1186    public void updateSelection(View view, int selStart, int selEnd,
1187            int candidatesStart, int candidatesEnd) {
1188        checkFocus();
1189        synchronized (mH) {
1190            if ((mServedView != view && (mServedView == null
1191                        || !mServedView.checkInputConnectionProxy(view)))
1192                    || mCurrentTextBoxAttribute == null || mCurMethod == null) {
1193                return;
1194            }
1195
1196            if (mCursorSelStart != selStart || mCursorSelEnd != selEnd
1197                    || mCursorCandStart != candidatesStart
1198                    || mCursorCandEnd != candidatesEnd) {
1199                if (DEBUG) Log.d(TAG, "updateSelection");
1200
1201                try {
1202                    if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
1203                    mCurMethod.updateSelection(mCursorSelStart, mCursorSelEnd,
1204                            selStart, selEnd, candidatesStart, candidatesEnd);
1205                    mCursorSelStart = selStart;
1206                    mCursorSelEnd = selEnd;
1207                    mCursorCandStart = candidatesStart;
1208                    mCursorCandEnd = candidatesEnd;
1209                } catch (RemoteException e) {
1210                    Log.w(TAG, "IME died: " + mCurId, e);
1211                }
1212            }
1213        }
1214    }
1215
1216    /**
1217     * Returns true if the current input method wants to watch the location
1218     * of the input editor's cursor in its window.
1219     */
1220    public boolean isWatchingCursor(View view) {
1221        return false;
1222    }
1223
1224    /**
1225     * Report the current cursor location in its window.
1226     */
1227    public void updateCursor(View view, int left, int top, int right, int bottom) {
1228        checkFocus();
1229        synchronized (mH) {
1230            if ((mServedView != view && (mServedView == null
1231                        || !mServedView.checkInputConnectionProxy(view)))
1232                    || mCurrentTextBoxAttribute == null || mCurMethod == null) {
1233                return;
1234            }
1235
1236            mTmpCursorRect.set(left, top, right, bottom);
1237            if (!mCursorRect.equals(mTmpCursorRect)) {
1238                if (DEBUG) Log.d(TAG, "updateCursor");
1239
1240                try {
1241                    if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
1242                    mCurMethod.updateCursor(mTmpCursorRect);
1243                    mCursorRect.set(mTmpCursorRect);
1244                } catch (RemoteException e) {
1245                    Log.w(TAG, "IME died: " + mCurId, e);
1246                }
1247            }
1248        }
1249    }
1250
1251    /**
1252     * Call {@link InputMethodSession#appPrivateCommand(String, Bundle)
1253     * InputMethodSession.appPrivateCommand()} on the current Input Method.
1254     * @param view Optional View that is sending the command, or null if
1255     * you want to send the command regardless of the view that is attached
1256     * to the input method.
1257     * @param action Name of the command to be performed.  This <em>must</em>
1258     * be a scoped name, i.e. prefixed with a package name you own, so that
1259     * different developers will not create conflicting commands.
1260     * @param data Any data to include with the command.
1261     */
1262    public void sendAppPrivateCommand(View view, String action, Bundle data) {
1263        checkFocus();
1264        synchronized (mH) {
1265            if ((mServedView != view && (mServedView == null
1266                        || !mServedView.checkInputConnectionProxy(view)))
1267                    || mCurrentTextBoxAttribute == null || mCurMethod == null) {
1268                return;
1269            }
1270            try {
1271                if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
1272                mCurMethod.appPrivateCommand(action, data);
1273            } catch (RemoteException e) {
1274                Log.w(TAG, "IME died: " + mCurId, e);
1275            }
1276        }
1277    }
1278
1279    /**
1280     * Force switch to a new input method component.  This can only be called
1281     * from the currently active input method, as validated by the given token.
1282     * @param token Supplies the identifying token given to an input method
1283     * when it was started, which allows it to perform this operation on
1284     * itself.
1285     * @param id The unique identifier for the new input method to be switched to.
1286     */
1287    public void setInputMethod(IBinder token, String id) {
1288        try {
1289            mService.setInputMethod(token, id);
1290        } catch (RemoteException e) {
1291            throw new RuntimeException(e);
1292        }
1293    }
1294
1295    /**
1296     * Close/hide the input method's soft input area, so the user no longer
1297     * sees it or can interact with it.  This can only be called
1298     * from the currently active input method, as validated by the given token.
1299     *
1300     * @param token Supplies the identifying token given to an input method
1301     * when it was started, which allows it to perform this operation on
1302     * itself.
1303     * @param flags Provides additional operating flags.  Currently may be
1304     * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1305     * {@link #HIDE_NOT_ALWAYS} bit set.
1306     */
1307    public void hideSoftInputFromInputMethod(IBinder token, int flags) {
1308        try {
1309            mService.hideMySoftInput(token, flags);
1310        } catch (RemoteException e) {
1311            throw new RuntimeException(e);
1312        }
1313    }
1314
1315    /**
1316     * Show the input method's soft input area, so the user
1317     * sees the input method window and can interact with it.
1318     * This can only be called from the currently active input method,
1319     * as validated by the given token.
1320     *
1321     * @param token Supplies the identifying token given to an input method
1322     * when it was started, which allows it to perform this operation on
1323     * itself.
1324     * @param flags Provides additional operating flags.  Currently may be
1325     * 0 or have the {@link #SHOW_IMPLICIT} or
1326     * {@link #SHOW_FORCED} bit set.
1327     */
1328    public void showSoftInputFromInputMethod(IBinder token, int flags) {
1329        try {
1330            mService.showMySoftInput(token, flags);
1331        } catch (RemoteException e) {
1332            throw new RuntimeException(e);
1333        }
1334    }
1335
1336    /**
1337     * @hide
1338     */
1339    public void dispatchKeyEvent(Context context, int seq, KeyEvent key,
1340            IInputMethodCallback callback) {
1341        synchronized (mH) {
1342            if (DEBUG) Log.d(TAG, "dispatchKeyEvent");
1343
1344            if (mCurMethod == null) {
1345                try {
1346                    callback.finishedEvent(seq, false);
1347                } catch (RemoteException e) {
1348                }
1349                return;
1350            }
1351
1352            if (key.getAction() == KeyEvent.ACTION_DOWN
1353                    && key.getKeyCode() == KeyEvent.KEYCODE_SYM) {
1354                showInputMethodPicker();
1355                try {
1356                    callback.finishedEvent(seq, true);
1357                } catch (RemoteException e) {
1358                }
1359                return;
1360            }
1361            try {
1362                if (DEBUG) Log.v(TAG, "DISPATCH KEY: " + mCurMethod);
1363                mCurMethod.dispatchKeyEvent(seq, key, callback);
1364            } catch (RemoteException e) {
1365                Log.w(TAG, "IME died: " + mCurId + " dropping: " + key, e);
1366                try {
1367                    callback.finishedEvent(seq, false);
1368                } catch (RemoteException ex) {
1369                }
1370            }
1371        }
1372    }
1373
1374    /**
1375     * @hide
1376     */
1377    void dispatchTrackballEvent(Context context, int seq, MotionEvent motion,
1378            IInputMethodCallback callback) {
1379        synchronized (mH) {
1380            if (DEBUG) Log.d(TAG, "dispatchTrackballEvent");
1381
1382            if (mCurMethod == null || mCurrentTextBoxAttribute == null) {
1383                try {
1384                    callback.finishedEvent(seq, false);
1385                } catch (RemoteException e) {
1386                }
1387                return;
1388            }
1389
1390            try {
1391                if (DEBUG) Log.v(TAG, "DISPATCH TRACKBALL: " + mCurMethod);
1392                mCurMethod.dispatchTrackballEvent(seq, motion, callback);
1393            } catch (RemoteException e) {
1394                Log.w(TAG, "IME died: " + mCurId + " dropping trackball: " + motion, e);
1395                try {
1396                    callback.finishedEvent(seq, false);
1397                } catch (RemoteException ex) {
1398                }
1399            }
1400        }
1401    }
1402
1403    public void showInputMethodPicker() {
1404        synchronized (mH) {
1405            try {
1406                mService.showInputMethodPickerFromClient(mClient);
1407            } catch (RemoteException e) {
1408                Log.w(TAG, "IME died: " + mCurId, e);
1409            }
1410        }
1411    }
1412
1413    public void showInputMethodSubtypePicker() {
1414        synchronized (mH) {
1415            try {
1416                mService.showInputMethodSubtypePickerFromClient(mClient);
1417            } catch (RemoteException e) {
1418                Log.w(TAG, "IME died: " + mCurId, e);
1419            }
1420        }
1421    }
1422
1423    public void showInputMethodAndSubtypeEnabler(String topId) {
1424        synchronized (mH) {
1425            try {
1426                mService.showInputMethodAndSubtypeEnablerFromClient(mClient, topId);
1427            } catch (RemoteException e) {
1428                Log.w(TAG, "IME died: " + mCurId, e);
1429            }
1430        }
1431    }
1432
1433    public InputMethodSubtype getCurrentInputMethodSubtype() {
1434        synchronized (mH) {
1435            try {
1436                return mService.getCurrentInputMethodSubtype();
1437            } catch (RemoteException e) {
1438                Log.w(TAG, "IME died: " + mCurId, e);
1439                return null;
1440            }
1441        }
1442    }
1443
1444    public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
1445        synchronized (mH) {
1446            try {
1447                return mService.setCurrentInputMethodSubtype(subtype);
1448            } catch (RemoteException e) {
1449                Log.w(TAG, "IME died: " + mCurId, e);
1450                return false;
1451            }
1452        }
1453    }
1454
1455    public boolean switchToLastInputMethod(IBinder imeToken) {
1456        synchronized (mH) {
1457            try {
1458                return mService.switchToLastInputMethod(imeToken);
1459            } catch (RemoteException e) {
1460                Log.w(TAG, "IME died: " + mCurId, e);
1461                return false;
1462            }
1463        }
1464    }
1465
1466    void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
1467        final Printer p = new PrintWriterPrinter(fout);
1468        p.println("Input method client state for " + this + ":");
1469
1470        p.println("  mService=" + mService);
1471        p.println("  mMainLooper=" + mMainLooper);
1472        p.println("  mIInputContext=" + mIInputContext);
1473        p.println("  mActive=" + mActive
1474                + " mHasBeenInactive=" + mHasBeenInactive
1475                + " mBindSequence=" + mBindSequence
1476                + " mCurId=" + mCurId);
1477        p.println("  mCurMethod=" + mCurMethod);
1478        p.println("  mCurRootView=" + mCurRootView);
1479        p.println("  mServedView=" + mServedView);
1480        p.println("  mNextServedNeedsStart=" + mNextServedNeedsStart
1481                + " mNextServedView=" + mNextServedView);
1482        p.println("  mServedConnecting=" + mServedConnecting);
1483        if (mCurrentTextBoxAttribute != null) {
1484            p.println("  mCurrentTextBoxAttribute:");
1485            mCurrentTextBoxAttribute.dump(p, "    ");
1486        } else {
1487            p.println("  mCurrentTextBoxAttribute: null");
1488        }
1489        p.println("  mServedInputConnection=" + mServedInputConnection);
1490        p.println("  mCompletions=" + mCompletions);
1491        p.println("  mCursorRect=" + mCursorRect);
1492        p.println("  mCursorSelStart=" + mCursorSelStart
1493                + " mCursorSelEnd=" + mCursorSelEnd
1494                + " mCursorCandStart=" + mCursorCandStart
1495                + " mCursorCandEnd=" + mCursorCandEnd);
1496    }
1497}
1498