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