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.IInputMethodClient;
     23 import com.android.internal.view.IInputMethodManager;
     24 import com.android.internal.view.IInputMethodSession;
     25 import com.android.internal.view.InputBindResult;
     26 
     27 import android.content.Context;
     28 import android.graphics.Rect;
     29 import android.os.Bundle;
     30 import android.os.Handler;
     31 import android.os.IBinder;
     32 import android.os.Looper;
     33 import android.os.Message;
     34 import android.os.RemoteException;
     35 import android.os.ResultReceiver;
     36 import android.os.ServiceManager;
     37 import android.os.Trace;
     38 import android.text.style.SuggestionSpan;
     39 import android.util.Log;
     40 import android.util.Pools.Pool;
     41 import android.util.Pools.SimplePool;
     42 import android.util.PrintWriterPrinter;
     43 import android.util.Printer;
     44 import android.view.InputChannel;
     45 import android.view.InputEvent;
     46 import android.view.InputEventSender;
     47 import android.view.KeyEvent;
     48 import android.view.View;
     49 import android.view.ViewRootImpl;
     50 import android.util.SparseArray;
     51 
     52 import java.io.FileDescriptor;
     53 import java.io.PrintWriter;
     54 import java.util.ArrayList;
     55 import java.util.HashMap;
     56 import java.util.List;
     57 import java.util.Map;
     58 import java.util.concurrent.CountDownLatch;
     59 import 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  */
    202 public 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