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