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