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