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