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