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