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