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