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 {
MyHandler(Looper looper)79         MyHandler(Looper looper) {
80             super(looper);
81         }
82 
83         @Override
handleMessage(Message msg)84         public void handleMessage(Message msg) {
85             executeMessage(msg);
86         }
87     }
88 
IInputConnectionWrapper(Looper mainLooper, @NonNull InputConnection inputConnection)89     public IInputConnectionWrapper(Looper mainLooper, @NonNull InputConnection inputConnection) {
90         mInputConnection = inputConnection;
91         mMainLooper = mainLooper;
92         mH = new MyHandler(mMainLooper);
93     }
94 
95     @Nullable
getInputConnection()96     public InputConnection getInputConnection() {
97         synchronized (mLock) {
98             return mInputConnection;
99         }
100     }
101 
isFinished()102     protected boolean isFinished() {
103         synchronized (mLock) {
104             return mFinished;
105         }
106     }
107 
isActive()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      */
onUserAction()114     abstract protected void onUserAction();
115 
getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback)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 
getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback)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 
getSelectedText(int flags, int seq, IInputContextCallback callback)124     public void getSelectedText(int flags, int seq, IInputContextCallback callback) {
125         dispatchMessage(obtainMessageISC(DO_GET_SELECTED_TEXT, flags, seq, callback));
126     }
127 
getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback)128     public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
129         dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
130     }
131 
getExtractedText(ExtractedTextRequest request, int flags, int seq, IInputContextCallback callback)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 
commitText(CharSequence text, int newCursorPosition)138     public void commitText(CharSequence text, int newCursorPosition) {
139         dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
140     }
141 
commitCompletion(CompletionInfo text)142     public void commitCompletion(CompletionInfo text) {
143         dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
144     }
145 
commitCorrection(CorrectionInfo info)146     public void commitCorrection(CorrectionInfo info) {
147         dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
148     }
149 
setSelection(int start, int end)150     public void setSelection(int start, int end) {
151         dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
152     }
153 
performEditorAction(int id)154     public void performEditorAction(int id) {
155         dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
156     }
157 
performContextMenuAction(int id)158     public void performContextMenuAction(int id) {
159         dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
160     }
161 
setComposingRegion(int start, int end)162     public void setComposingRegion(int start, int end) {
163         dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
164     }
165 
setComposingText(CharSequence text, int newCursorPosition)166     public void setComposingText(CharSequence text, int newCursorPosition) {
167         dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
168     }
169 
finishComposingText()170     public void finishComposingText() {
171         dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
172     }
173 
sendKeyEvent(KeyEvent event)174     public void sendKeyEvent(KeyEvent event) {
175         dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
176     }
177 
clearMetaKeyStates(int states)178     public void clearMetaKeyStates(int states) {
179         dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
180     }
181 
deleteSurroundingText(int beforeLength, int afterLength)182     public void deleteSurroundingText(int beforeLength, int afterLength) {
183         dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
184                 beforeLength, afterLength));
185     }
186 
deleteSurroundingTextInCodePoints(int beforeLength, int afterLength)187     public void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
188         dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
189                 beforeLength, afterLength));
190     }
191 
beginBatchEdit()192     public void beginBatchEdit() {
193         dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
194     }
195 
endBatchEdit()196     public void endBatchEdit() {
197         dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
198     }
199 
performPrivateCommand(String action, Bundle data)200     public void performPrivateCommand(String action, Bundle data) {
201         dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
202     }
203 
requestUpdateCursorAnchorInfo(int cursorUpdateMode, int seq, IInputContextCallback callback)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 
closeConnection()210     public void closeConnection() {
211         dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
212     }
213 
commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts, int seq, IInputContextCallback callback)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 
dispatchMessage(Message msg)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 
executeMessage(Message msg)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 
obtainMessage(int what)584     Message obtainMessage(int what) {
585         return mH.obtainMessage(what);
586     }
587 
obtainMessageII(int what, int arg1, int arg2)588     Message obtainMessageII(int what, int arg1, int arg2) {
589         return mH.obtainMessage(what, arg1, arg2);
590     }
591 
obtainMessageO(int what, Object arg1)592     Message obtainMessageO(int what, Object arg1) {
593         return mH.obtainMessage(what, 0, 0, arg1);
594     }
595 
obtainMessageISC(int what, int arg1, int callbackSeq, IInputContextCallback callback)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 
obtainMessageIISC(int what, int arg1, int arg2, int callbackSeq, IInputContextCallback callback)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 
obtainMessageIOOSC(int what, int arg1, Object objArg1, Object objArg2, int callbackSeq, IInputContextCallback callback)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 
obtainMessageIOSC(int what, int arg1, Object arg2, int callbackSeq, IInputContextCallback callback)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 
obtainMessageIO(int what, int arg1, Object arg2)630     Message obtainMessageIO(int what, int arg1, Object arg2) {
631         return mH.obtainMessage(what, arg1, 0, arg2);
632     }
633 
obtainMessageOO(int what, Object arg1, Object arg2)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