Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of 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,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.view;
     18 
     19 import com.android.internal.annotations.GuardedBy;
     20 import com.android.internal.os.SomeArgs;
     21 
     22 import android.annotation.NonNull;
     23 import android.annotation.Nullable;
     24 import android.os.Bundle;
     25 import android.os.Handler;
     26 import android.os.Looper;
     27 import android.os.Message;
     28 import android.os.RemoteException;
     29 import android.util.Log;
     30 import android.view.KeyEvent;
     31 import android.view.inputmethod.CompletionInfo;
     32 import android.view.inputmethod.CorrectionInfo;
     33 import android.view.inputmethod.ExtractedTextRequest;
     34 import android.view.inputmethod.InputConnection;
     35 import android.view.inputmethod.InputConnectionInspector;
     36 import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
     37 import android.view.inputmethod.InputContentInfo;
     38 
     39 public abstract class IInputConnectionWrapper extends IInputContext.Stub {
     40     private static final String TAG = "IInputConnectionWrapper";
     41     private static final boolean DEBUG = false;
     42 
     43     private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
     44     private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
     45     private static final int DO_GET_SELECTED_TEXT = 25;
     46     private static final int DO_GET_CURSOR_CAPS_MODE = 30;
     47     private static final int DO_GET_EXTRACTED_TEXT = 40;
     48     private static final int DO_COMMIT_TEXT = 50;
     49     private static final int DO_COMMIT_COMPLETION = 55;
     50     private static final int DO_COMMIT_CORRECTION = 56;
     51     private static final int DO_SET_SELECTION = 57;
     52     private static final int DO_PERFORM_EDITOR_ACTION = 58;
     53     private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
     54     private static final int DO_SET_COMPOSING_TEXT = 60;
     55     private static final int DO_SET_COMPOSING_REGION = 63;
     56     private static final int DO_FINISH_COMPOSING_TEXT = 65;
     57     private static final int DO_SEND_KEY_EVENT = 70;
     58     private static final int DO_DELETE_SURROUNDING_TEXT = 80;
     59     private static final int DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 81;
     60     private static final int DO_BEGIN_BATCH_EDIT = 90;
     61     private static final int DO_END_BATCH_EDIT = 95;
     62     private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
     63     private static final int DO_CLEAR_META_KEY_STATES = 130;
     64     private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
     65     private static final int DO_CLOSE_CONNECTION = 150;
     66     private static final int DO_COMMIT_CONTENT = 160;
     67 
     68     @GuardedBy("mLock")
     69     @Nullable
     70     private InputConnection mInputConnection;
     71 
     72     private Looper mMainLooper;
     73     private Handler mH;
     74     private Object mLock = new Object();
     75     @GuardedBy("mLock")
     76     private boolean mFinished = false;
     77 
     78     class MyHandler extends Handler {
     79         MyHandler(Looper looper) {
     80             super(looper);
     81         }
     82 
     83         @Override
     84         public void handleMessage(Message msg) {
     85             executeMessage(msg);
     86         }
     87     }
     88 
     89     public IInputConnectionWrapper(Looper mainLooper, @NonNull InputConnection inputConnection) {
     90         mInputConnection = inputConnection;
     91         mMainLooper = mainLooper;
     92         mH = new MyHandler(mMainLooper);
     93     }
     94 
     95     @Nullable
     96     public InputConnection getInputConnection() {
     97         synchronized (mLock) {
     98             return mInputConnection;
     99         }
    100     }
    101 
    102     protected boolean isFinished() {
    103         synchronized (mLock) {
    104             return mFinished;
    105         }
    106     }
    107 
    108     abstract protected boolean isActive();
    109 
    110     /**
    111      * Called when the user took some actions that should be taken into consideration to update the
    112      * LRU list for input method rotation.
    113      */
    114     abstract protected void onUserAction();
    115 
    116     public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
    117         dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
    118     }
    119 
    120     public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) {
    121         dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
    122     }
    123 
    124     public void getSelectedText(int flags, int seq, IInputContextCallback callback) {
    125         dispatchMessage(obtainMessageISC(DO_GET_SELECTED_TEXT, flags, seq, callback));
    126     }
    127 
    128     public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
    129         dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
    130     }
    131 
    132     public void getExtractedText(ExtractedTextRequest request,
    133             int flags, int seq, IInputContextCallback callback) {
    134         dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags,
    135                 request, seq, callback));
    136     }
    137 
    138     public void commitText(CharSequence text, int newCursorPosition) {
    139         dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
    140     }
    141 
    142     public void commitCompletion(CompletionInfo text) {
    143         dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
    144     }
    145 
    146     public void commitCorrection(CorrectionInfo info) {
    147         dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
    148     }
    149 
    150     public void setSelection(int start, int end) {
    151         dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
    152     }
    153 
    154     public void performEditorAction(int id) {
    155         dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
    156     }
    157 
    158     public void performContextMenuAction(int id) {
    159         dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
    160     }
    161 
    162     public void setComposingRegion(int start, int end) {
    163         dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
    164     }
    165 
    166     public void setComposingText(CharSequence text, int newCursorPosition) {
    167         dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
    168     }
    169 
    170     public void finishComposingText() {
    171         dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
    172     }
    173 
    174     public void sendKeyEvent(KeyEvent event) {
    175         dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
    176     }
    177 
    178     public void clearMetaKeyStates(int states) {
    179         dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
    180     }
    181 
    182     public void deleteSurroundingText(int beforeLength, int afterLength) {
    183         dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
    184                 beforeLength, afterLength));
    185     }
    186 
    187     public void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
    188         dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
    189                 beforeLength, afterLength));
    190     }
    191 
    192     public void beginBatchEdit() {
    193         dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
    194     }
    195 
    196     public void endBatchEdit() {
    197         dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
    198     }
    199 
    200     public void performPrivateCommand(String action, Bundle data) {
    201         dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
    202     }
    203 
    204     public void requestUpdateCursorAnchorInfo(int cursorUpdateMode, int seq,
    205             IInputContextCallback callback) {
    206         dispatchMessage(obtainMessageISC(DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO, cursorUpdateMode,
    207                 seq, callback));
    208     }
    209 
    210     public void closeConnection() {
    211         dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
    212     }
    213 
    214     public void commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts,
    215             int seq, IInputContextCallback callback) {
    216         dispatchMessage(obtainMessageIOOSC(DO_COMMIT_CONTENT, flags, inputContentInfo, opts, seq,
    217                 callback));
    218     }
    219 
    220     void dispatchMessage(Message msg) {
    221         // If we are calling this from the main thread, then we can call
    222         // right through.  Otherwise, we need to send the message to the
    223         // main thread.
    224         if (Looper.myLooper() == mMainLooper) {
    225             executeMessage(msg);
    226             msg.recycle();
    227             return;
    228         }
    229 
    230         mH.sendMessage(msg);
    231     }
    232 
    233     void executeMessage(Message msg) {
    234         switch (msg.what) {
    235             case DO_GET_TEXT_AFTER_CURSOR: {
    236                 SomeArgs args = (SomeArgs)msg.obj;
    237                 try {
    238                     final IInputContextCallback callback = (IInputContextCallback) args.arg6;
    239                     final int callbackSeq = args.argi6;
    240                     InputConnection ic = getInputConnection();
    241                     if (ic == null || !isActive()) {
    242                         Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
    243                         callback.setTextAfterCursor(null, callbackSeq);
    244                         return;
    245                     }
    246                     callback.setTextAfterCursor(ic.getTextAfterCursor(
    247                             msg.arg1, msg.arg2), callbackSeq);
    248                 } catch (RemoteException e) {
    249                     Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e);
    250                 } finally {
    251                     args.recycle();
    252                 }
    253                 return;
    254             }
    255             case DO_GET_TEXT_BEFORE_CURSOR: {
    256                 SomeArgs args = (SomeArgs)msg.obj;
    257                 try {
    258                     final IInputContextCallback callback = (IInputContextCallback) args.arg6;
    259                     final int callbackSeq = args.argi6;
    260                     InputConnection ic = getInputConnection();
    261                     if (ic == null || !isActive()) {
    262                         Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
    263                         callback.setTextBeforeCursor(null, callbackSeq);
    264                         return;
    265                     }
    266                     callback.setTextBeforeCursor(ic.getTextBeforeCursor(
    267                             msg.arg1, msg.arg2), callbackSeq);
    268                 } catch (RemoteException e) {
    269                     Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e);
    270                 } finally {
    271                     args.recycle();
    272                 }
    273                 return;
    274             }
    275             case DO_GET_SELECTED_TEXT: {
    276                 SomeArgs args = (SomeArgs)msg.obj;
    277                 try {
    278                     final IInputContextCallback callback = (IInputContextCallback) args.arg6;
    279                     final int callbackSeq = args.argi6;
    280                     InputConnection ic = getInputConnection();
    281                     if (ic == null || !isActive()) {
    282                         Log.w(TAG, "getSelectedText on inactive InputConnection");
    283                         callback.setSelectedText(null, callbackSeq);
    284                         return;
    285                     }
    286                     callback.setSelectedText(ic.getSelectedText(
    287                             msg.arg1), callbackSeq);
    288                 } catch (RemoteException e) {
    289                     Log.w(TAG, "Got RemoteException calling setSelectedText", e);
    290                 } finally {
    291                     args.recycle();
    292                 }
    293                 return;
    294             }
    295             case DO_GET_CURSOR_CAPS_MODE: {
    296                 SomeArgs args = (SomeArgs)msg.obj;
    297                 try {
    298                     final IInputContextCallback callback = (IInputContextCallback) args.arg6;
    299                     final int callbackSeq = args.argi6;
    300                     InputConnection ic = getInputConnection();
    301                     if (ic == null || !isActive()) {
    302                         Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
    303                         callback.setCursorCapsMode(0, callbackSeq);
    304                         return;
    305                     }
    306                     callback.setCursorCapsMode(ic.getCursorCapsMode(msg.arg1),
    307                             callbackSeq);
    308                 } catch (RemoteException e) {
    309                     Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e);
    310                 } finally {
    311                     args.recycle();
    312                 }
    313                 return;
    314             }
    315             case DO_GET_EXTRACTED_TEXT: {
    316                 SomeArgs args = (SomeArgs)msg.obj;
    317                 try {
    318                     final IInputContextCallback callback = (IInputContextCallback) args.arg6;
    319                     final int callbackSeq = args.argi6;
    320                     InputConnection ic = getInputConnection();
    321                     if (ic == null || !isActive()) {
    322                         Log.w(TAG, "getExtractedText on inactive InputConnection");
    323                         callback.setExtractedText(null, callbackSeq);
    324                         return;
    325                     }
    326                     callback.setExtractedText(ic.getExtractedText(
    327                             (ExtractedTextRequest)args.arg1, msg.arg1), callbackSeq);
    328                 } catch (RemoteException e) {
    329                     Log.w(TAG, "Got RemoteException calling setExtractedText", e);
    330                 } finally {
    331                     args.recycle();
    332                 }
    333                 return;
    334             }
    335             case DO_COMMIT_TEXT: {
    336                 InputConnection ic = getInputConnection();
    337                 if (ic == null || !isActive()) {
    338                     Log.w(TAG, "commitText on inactive InputConnection");
    339                     return;
    340                 }
    341                 ic.commitText((CharSequence)msg.obj, msg.arg1);
    342                 onUserAction();
    343                 return;
    344             }
    345             case DO_SET_SELECTION: {
    346                 InputConnection ic = getInputConnection();
    347                 if (ic == null || !isActive()) {
    348                     Log.w(TAG, "setSelection on inactive InputConnection");
    349                     return;
    350                 }
    351                 ic.setSelection(msg.arg1, msg.arg2);
    352                 return;
    353             }
    354             case DO_PERFORM_EDITOR_ACTION: {
    355                 InputConnection ic = getInputConnection();
    356                 if (ic == null || !isActive()) {
    357                     Log.w(TAG, "performEditorAction on inactive InputConnection");
    358                     return;
    359                 }
    360                 ic.performEditorAction(msg.arg1);
    361                 return;
    362             }
    363             case DO_PERFORM_CONTEXT_MENU_ACTION: {
    364                 InputConnection ic = getInputConnection();
    365                 if (ic == null || !isActive()) {
    366                     Log.w(TAG, "performContextMenuAction on inactive InputConnection");
    367                     return;
    368                 }
    369                 ic.performContextMenuAction(msg.arg1);
    370                 return;
    371             }
    372             case DO_COMMIT_COMPLETION: {
    373                 InputConnection ic = getInputConnection();
    374                 if (ic == null || !isActive()) {
    375                     Log.w(TAG, "commitCompletion on inactive InputConnection");
    376                     return;
    377                 }
    378                 ic.commitCompletion((CompletionInfo)msg.obj);
    379                 return;
    380             }
    381             case DO_COMMIT_CORRECTION: {
    382                 InputConnection ic = getInputConnection();
    383                 if (ic == null || !isActive()) {
    384                     Log.w(TAG, "commitCorrection on inactive InputConnection");
    385                     return;
    386                 }
    387                 ic.commitCorrection((CorrectionInfo)msg.obj);
    388                 return;
    389             }
    390             case DO_SET_COMPOSING_TEXT: {
    391                 InputConnection ic = getInputConnection();
    392                 if (ic == null || !isActive()) {
    393                     Log.w(TAG, "setComposingText on inactive InputConnection");
    394                     return;
    395                 }
    396                 ic.setComposingText((CharSequence)msg.obj, msg.arg1);
    397                 onUserAction();
    398                 return;
    399             }
    400             case DO_SET_COMPOSING_REGION: {
    401                 InputConnection ic = getInputConnection();
    402                 if (ic == null || !isActive()) {
    403                     Log.w(TAG, "setComposingRegion on inactive InputConnection");
    404                     return;
    405                 }
    406                 ic.setComposingRegion(msg.arg1, msg.arg2);
    407                 return;
    408             }
    409             case DO_FINISH_COMPOSING_TEXT: {
    410                 if (isFinished()) {
    411                     // In this case, #finishComposingText() is guaranteed to be called already.
    412                     // There should be no negative impact if we ignore this call silently.
    413                     if (DEBUG) {
    414                         Log.w(TAG, "Bug 35301295: Redundant finishComposingText.");
    415                     }
    416                     return;
    417                 }
    418                 InputConnection ic = getInputConnection();
    419                 // Note we do NOT check isActive() here, because this is safe
    420                 // for an IME to call at any time, and we need to allow it
    421                 // through to clean up our state after the IME has switched to
    422                 // another client.
    423                 if (ic == null) {
    424                     Log.w(TAG, "finishComposingText on inactive InputConnection");
    425                     return;
    426                 }
    427                 ic.finishComposingText();
    428                 return;
    429             }
    430             case DO_SEND_KEY_EVENT: {
    431                 InputConnection ic = getInputConnection();
    432                 if (ic == null || !isActive()) {
    433                     Log.w(TAG, "sendKeyEvent on inactive InputConnection");
    434                     return;
    435                 }
    436                 ic.sendKeyEvent((KeyEvent)msg.obj);
    437                 onUserAction();
    438                 return;
    439             }
    440             case DO_CLEAR_META_KEY_STATES: {
    441                 InputConnection ic = getInputConnection();
    442                 if (ic == null || !isActive()) {
    443                     Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
    444                     return;
    445                 }
    446                 ic.clearMetaKeyStates(msg.arg1);
    447                 return;
    448             }
    449             case DO_DELETE_SURROUNDING_TEXT: {
    450                 InputConnection ic = getInputConnection();
    451                 if (ic == null || !isActive()) {
    452                     Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
    453                     return;
    454                 }
    455                 ic.deleteSurroundingText(msg.arg1, msg.arg2);
    456                 return;
    457             }
    458             case DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
    459                 InputConnection ic = getInputConnection();
    460                 if (ic == null || !isActive()) {
    461                     Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
    462                     return;
    463                 }
    464                 ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
    465                 return;
    466             }
    467             case DO_BEGIN_BATCH_EDIT: {
    468                 InputConnection ic = getInputConnection();
    469                 if (ic == null || !isActive()) {
    470                     Log.w(TAG, "beginBatchEdit on inactive InputConnection");
    471                     return;
    472                 }
    473                 ic.beginBatchEdit();
    474                 return;
    475             }
    476             case DO_END_BATCH_EDIT: {
    477                 InputConnection ic = getInputConnection();
    478                 if (ic == null || !isActive()) {
    479                     Log.w(TAG, "endBatchEdit on inactive InputConnection");
    480                     return;
    481                 }
    482                 ic.endBatchEdit();
    483                 return;
    484             }
    485             case DO_PERFORM_PRIVATE_COMMAND: {
    486                 final SomeArgs args = (SomeArgs) msg.obj;
    487                 try {
    488                     final String action = (String) args.arg1;
    489                     final Bundle data = (Bundle) args.arg2;
    490                     InputConnection ic = getInputConnection();
    491                     if (ic == null || !isActive()) {
    492                         Log.w(TAG, "performPrivateCommand on inactive InputConnection");
    493                         return;
    494                     }
    495                     ic.performPrivateCommand(action, data);
    496                 } finally {
    497                     args.recycle();
    498                 }
    499                 return;
    500             }
    501             case DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO: {
    502                 SomeArgs args = (SomeArgs)msg.obj;
    503                 try {
    504                     final IInputContextCallback callback = (IInputContextCallback) args.arg6;
    505                     final int callbackSeq = args.argi6;
    506                     InputConnection ic = getInputConnection();
    507                     if (ic == null || !isActive()) {
    508                         Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
    509                         callback.setRequestUpdateCursorAnchorInfoResult(false, callbackSeq);
    510                         return;
    511                     }
    512                     callback.setRequestUpdateCursorAnchorInfoResult(
    513                             ic.requestCursorUpdates(msg.arg1), callbackSeq);
    514                 } catch (RemoteException e) {
    515                     Log.w(TAG, "Got RemoteException calling requestCursorAnchorInfo", e);
    516                 } finally {
    517                     args.recycle();
    518                 }
    519                 return;
    520             }
    521             case DO_CLOSE_CONNECTION: {
    522                 // Note that we do not need to worry about race condition here, because 1) mFinished
    523                 // is updated only inside this block, and 2) the code here is running on a Handler
    524                 // hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
    525                 // same time.
    526                 if (isFinished()) {
    527                     return;
    528                 }
    529                 try {
    530                     InputConnection ic = getInputConnection();
    531                     // Note we do NOT check isActive() here, because this is safe
    532                     // for an IME to call at any time, and we need to allow it
    533                     // through to clean up our state after the IME has switched to
    534                     // another client.
    535                     if (ic == null) {
    536                         return;
    537                     }
    538                     @MissingMethodFlags
    539                     final int missingMethods = InputConnectionInspector.getMissingMethodFlags(ic);
    540                     if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
    541                         ic.closeConnection();
    542                     }
    543                 } finally {
    544                     synchronized (mLock) {
    545                         mInputConnection = null;
    546                         mFinished = true;
    547                     }
    548                 }
    549                 return;
    550             }
    551             case DO_COMMIT_CONTENT: {
    552                 final int flags = msg.arg1;
    553                 SomeArgs args = (SomeArgs) msg.obj;
    554                 try {
    555                     final IInputContextCallback callback = (IInputContextCallback) args.arg6;
    556                     final int callbackSeq = args.argi6;
    557                     InputConnection ic = getInputConnection();
    558                     if (ic == null || !isActive()) {
    559                         Log.w(TAG, "commitContent on inactive InputConnection");
    560                         callback.setCommitContentResult(false, callbackSeq);
    561                         return;
    562                     }
    563                     final InputContentInfo inputContentInfo = (InputContentInfo) args.arg1;
    564                     if (inputContentInfo == null || !inputContentInfo.validate()) {
    565                         Log.w(TAG, "commitContent with invalid inputContentInfo="
    566                                 + inputContentInfo);
    567                         callback.setCommitContentResult(false, callbackSeq);
    568                         return;
    569                     }
    570                     final boolean result =
    571                             ic.commitContent(inputContentInfo, flags, (Bundle) args.arg2);
    572                     callback.setCommitContentResult(result, callbackSeq);
    573                 } catch (RemoteException e) {
    574                     Log.w(TAG, "Got RemoteException calling commitContent", e);
    575                 } finally {
    576                     args.recycle();
    577                 }
    578                 return;
    579             }
    580         }
    581         Log.w(TAG, "Unhandled message code: " + msg.what);
    582     }
    583 
    584     Message obtainMessage(int what) {
    585         return mH.obtainMessage(what);
    586     }
    587 
    588     Message obtainMessageII(int what, int arg1, int arg2) {
    589         return mH.obtainMessage(what, arg1, arg2);
    590     }
    591 
    592     Message obtainMessageO(int what, Object arg1) {
    593         return mH.obtainMessage(what, 0, 0, arg1);
    594     }
    595 
    596     Message obtainMessageISC(int what, int arg1, int callbackSeq, IInputContextCallback callback) {
    597         final SomeArgs args = SomeArgs.obtain();
    598         args.arg6 = callback;
    599         args.argi6 = callbackSeq;
    600         return mH.obtainMessage(what, arg1, 0, args);
    601     }
    602 
    603     Message obtainMessageIISC(int what, int arg1, int arg2, int callbackSeq,
    604             IInputContextCallback callback) {
    605         final SomeArgs args = SomeArgs.obtain();
    606         args.arg6 = callback;
    607         args.argi6 = callbackSeq;
    608         return mH.obtainMessage(what, arg1, arg2, args);
    609     }
    610 
    611     Message obtainMessageIOOSC(int what, int arg1, Object objArg1, Object objArg2, int callbackSeq,
    612             IInputContextCallback callback) {
    613         final SomeArgs args = SomeArgs.obtain();
    614         args.arg1 = objArg1;
    615         args.arg2 = objArg2;
    616         args.arg6 = callback;
    617         args.argi6 = callbackSeq;
    618         return mH.obtainMessage(what, arg1, 0, args);
    619     }
    620 
    621     Message obtainMessageIOSC(int what, int arg1, Object arg2, int callbackSeq,
    622             IInputContextCallback callback) {
    623         final SomeArgs args = SomeArgs.obtain();
    624         args.arg1 = arg2;
    625         args.arg6 = callback;
    626         args.argi6 = callbackSeq;
    627         return mH.obtainMessage(what, arg1, 0, args);
    628     }
    629 
    630     Message obtainMessageIO(int what, int arg1, Object arg2) {
    631         return mH.obtainMessage(what, arg1, 0, arg2);
    632     }
    633 
    634     Message obtainMessageOO(int what, Object arg1, Object arg2) {
    635         final SomeArgs args = SomeArgs.obtain();
    636         args.arg1 = arg1;
    637         args.arg2 = arg2;
    638         return mH.obtainMessage(what, 0, 0, args);
    639     }
    640 }
    641