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