IInputConnectionWrapper.java revision d24b8183b93e781080b2c16c487e60d51c12da31
1package com.android.internal.view;
2
3import com.android.internal.view.IInputContext;
4
5import android.os.Bundle;
6import android.os.Handler;
7import android.os.Looper;
8import android.os.Message;
9import android.os.RemoteException;
10import android.util.Log;
11import android.view.KeyEvent;
12import android.view.inputmethod.CompletionInfo;
13import android.view.inputmethod.ExtractedTextRequest;
14import android.view.inputmethod.InputConnection;
15
16import java.lang.ref.WeakReference;
17
18public class IInputConnectionWrapper extends IInputContext.Stub {
19    static final String TAG = "IInputConnectionWrapper";
20
21    private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
22    private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
23    private static final int DO_GET_CURSOR_CAPS_MODE = 30;
24    private static final int DO_GET_EXTRACTED_TEXT = 40;
25    private static final int DO_COMMIT_TEXT = 50;
26    private static final int DO_COMMIT_COMPLETION = 55;
27    private static final int DO_SET_SELECTION = 57;
28    private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 58;
29    private static final int DO_SET_COMPOSING_TEXT = 60;
30    private static final int DO_FINISH_COMPOSING_TEXT = 65;
31    private static final int DO_SEND_KEY_EVENT = 70;
32    private static final int DO_DELETE_SURROUNDING_TEXT = 80;
33    private static final int DO_BEGIN_BATCH_EDIT = 90;
34    private static final int DO_END_BATCH_EDIT = 95;
35    private static final int DO_HIDE_STATUS_ICON = 100;
36    private static final int DO_SHOW_STATUS_ICON = 110;
37    private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
38    private static final int DO_CLEAR_META_KEY_STATES = 130;
39
40    private WeakReference<InputConnection> mInputConnection;
41
42    private Looper mMainLooper;
43    private Handler mH;
44
45    static class SomeArgs {
46        Object arg1;
47        Object arg2;
48        IInputContextCallback callback;
49        int seq;
50    }
51
52    class MyHandler extends Handler {
53        MyHandler(Looper looper) {
54            super(looper);
55        }
56
57        @Override
58        public void handleMessage(Message msg) {
59            executeMessage(msg);
60        }
61    }
62
63    public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
64        mInputConnection = new WeakReference<InputConnection>(conn);
65        mMainLooper = mainLooper;
66        mH = new MyHandler(mMainLooper);
67    }
68
69    public boolean isActive() {
70        return true;
71    }
72
73    public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
74        dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
75    }
76
77    public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) {
78        dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
79    }
80
81    public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
82        dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
83    }
84
85    public void getExtractedText(ExtractedTextRequest request,
86            int flags, int seq, IInputContextCallback callback) {
87        dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags,
88                request, seq, callback));
89    }
90
91    public void commitText(CharSequence text, int newCursorPosition) {
92        dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
93    }
94
95    public void commitCompletion(CompletionInfo text) {
96        dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
97    }
98
99    public void setSelection(int start, int end) {
100        dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
101    }
102
103    public void performContextMenuAction(int id) {
104        dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
105    }
106
107    public void setComposingText(CharSequence text, int newCursorPosition) {
108        dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
109    }
110
111    public void finishComposingText() {
112        dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
113    }
114
115    public void sendKeyEvent(KeyEvent event) {
116        dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
117    }
118
119    public void clearMetaKeyStates(int states) {
120        dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
121    }
122
123    public void deleteSurroundingText(int leftLength, int rightLength) {
124        dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
125            leftLength, rightLength));
126    }
127
128    public void beginBatchEdit() {
129        dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
130    }
131
132    public void endBatchEdit() {
133        dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
134    }
135
136    public void hideStatusIcon() {
137        dispatchMessage(obtainMessage(DO_HIDE_STATUS_ICON));
138    }
139
140    public void showStatusIcon(String packageName, int resId) {
141        dispatchMessage(obtainMessageIO(DO_SHOW_STATUS_ICON, resId, packageName));
142    }
143
144    public void performPrivateCommand(String action, Bundle data) {
145        dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
146    }
147
148    void dispatchMessage(Message msg) {
149        // If we are calling this from the main thread, then we can call
150        // right through.  Otherwise, we need to send the message to the
151        // main thread.
152        if (Looper.myLooper() == mMainLooper) {
153            executeMessage(msg);
154            msg.recycle();
155            return;
156        }
157
158        mH.sendMessage(msg);
159    }
160
161    void executeMessage(Message msg) {
162        switch (msg.what) {
163            case DO_GET_TEXT_AFTER_CURSOR: {
164                SomeArgs args = (SomeArgs)msg.obj;
165                try {
166                    InputConnection ic = mInputConnection.get();
167                    if (ic == null || !isActive()) {
168                        Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
169                        args.callback.setTextAfterCursor(null, args.seq);
170                        return;
171                    }
172                    args.callback.setTextAfterCursor(ic.getTextAfterCursor(
173                            msg.arg1, msg.arg2), args.seq);
174                } catch (RemoteException e) {
175                    Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e);
176                }
177                return;
178            }
179            case DO_GET_TEXT_BEFORE_CURSOR: {
180                SomeArgs args = (SomeArgs)msg.obj;
181                try {
182                    InputConnection ic = mInputConnection.get();
183                    if (ic == null || !isActive()) {
184                        Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
185                        args.callback.setTextBeforeCursor(null, args.seq);
186                        return;
187                    }
188                    args.callback.setTextBeforeCursor(ic.getTextBeforeCursor(
189                            msg.arg1, msg.arg2), args.seq);
190                } catch (RemoteException e) {
191                    Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e);
192                }
193                return;
194            }
195            case DO_GET_CURSOR_CAPS_MODE: {
196                SomeArgs args = (SomeArgs)msg.obj;
197                try {
198                    InputConnection ic = mInputConnection.get();
199                    if (ic == null || !isActive()) {
200                        Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
201                        args.callback.setCursorCapsMode(0, args.seq);
202                        return;
203                    }
204                    args.callback.setCursorCapsMode(ic.getCursorCapsMode(msg.arg1),
205                            args.seq);
206                } catch (RemoteException e) {
207                    Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e);
208                }
209                return;
210            }
211            case DO_GET_EXTRACTED_TEXT: {
212                SomeArgs args = (SomeArgs)msg.obj;
213                try {
214                    InputConnection ic = mInputConnection.get();
215                    if (ic == null || !isActive()) {
216                        Log.w(TAG, "getExtractedText on inactive InputConnection");
217                        args.callback.setExtractedText(null, args.seq);
218                        return;
219                    }
220                    args.callback.setExtractedText(ic.getExtractedText(
221                            (ExtractedTextRequest)args.arg1, msg.arg1), args.seq);
222                } catch (RemoteException e) {
223                    Log.w(TAG, "Got RemoteException calling setExtractedText", e);
224                }
225                return;
226            }
227            case DO_COMMIT_TEXT: {
228                InputConnection ic = mInputConnection.get();
229                if (ic == null || !isActive()) {
230                    Log.w(TAG, "commitText on inactive InputConnection");
231                    return;
232                }
233                ic.commitText((CharSequence)msg.obj, msg.arg1);
234                return;
235            }
236            case DO_SET_SELECTION: {
237                InputConnection ic = mInputConnection.get();
238                if (ic == null || !isActive()) {
239                    Log.w(TAG, "setSelection on inactive InputConnection");
240                    return;
241                }
242                ic.setSelection(msg.arg1, msg.arg2);
243                return;
244            }
245            case DO_PERFORM_CONTEXT_MENU_ACTION: {
246                InputConnection ic = mInputConnection.get();
247                if (ic == null || !isActive()) {
248                    Log.w(TAG, "performContextMenuAction on inactive InputConnection");
249                    return;
250                }
251                ic.performContextMenuAction(msg.arg1);
252                return;
253            }
254            case DO_COMMIT_COMPLETION: {
255                InputConnection ic = mInputConnection.get();
256                if (ic == null || !isActive()) {
257                    Log.w(TAG, "commitCompletion on inactive InputConnection");
258                    return;
259                }
260                ic.commitCompletion((CompletionInfo)msg.obj);
261                return;
262            }
263            case DO_SET_COMPOSING_TEXT: {
264                InputConnection ic = mInputConnection.get();
265                if (ic == null || !isActive()) {
266                    Log.w(TAG, "setComposingText on inactive InputConnection");
267                    return;
268                }
269                ic.setComposingText((CharSequence)msg.obj, msg.arg1);
270                return;
271            }
272            case DO_FINISH_COMPOSING_TEXT: {
273                InputConnection ic = mInputConnection.get();
274                if (ic == null || !isActive()) {
275                    Log.w(TAG, "finishComposingText on inactive InputConnection");
276                    return;
277                }
278                ic.finishComposingText();
279                return;
280            }
281            case DO_SEND_KEY_EVENT: {
282                InputConnection ic = mInputConnection.get();
283                if (ic == null || !isActive()) {
284                    Log.w(TAG, "sendKeyEvent on inactive InputConnection");
285                    return;
286                }
287                ic.sendKeyEvent((KeyEvent)msg.obj);
288                return;
289            }
290            case DO_CLEAR_META_KEY_STATES: {
291                InputConnection ic = mInputConnection.get();
292                if (ic == null || !isActive()) {
293                    Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
294                    return;
295                }
296                ic.clearMetaKeyStates(msg.arg1);
297                return;
298            }
299            case DO_DELETE_SURROUNDING_TEXT: {
300                InputConnection ic = mInputConnection.get();
301                if (ic == null || !isActive()) {
302                    Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
303                    return;
304                }
305                ic.deleteSurroundingText(msg.arg1, msg.arg2);
306                return;
307            }
308            case DO_BEGIN_BATCH_EDIT: {
309                InputConnection ic = mInputConnection.get();
310                if (ic == null || !isActive()) {
311                    Log.w(TAG, "beginBatchEdit on inactive InputConnection");
312                    return;
313                }
314                ic.beginBatchEdit();
315                return;
316            }
317            case DO_END_BATCH_EDIT: {
318                InputConnection ic = mInputConnection.get();
319                if (ic == null || !isActive()) {
320                    Log.w(TAG, "endBatchEdit on inactive InputConnection");
321                    return;
322                }
323                ic.endBatchEdit();
324                return;
325            }
326            case DO_HIDE_STATUS_ICON: {
327                InputConnection ic = mInputConnection.get();
328                if (ic == null || !isActive()) {
329                    Log.w(TAG, "hideStatusIcon on inactive InputConnection");
330                    return;
331                }
332                ic.hideStatusIcon();
333                return;
334            }
335            case DO_SHOW_STATUS_ICON: {
336                InputConnection ic = mInputConnection.get();
337                if (ic == null || !isActive()) {
338                    Log.w(TAG, "showStatusIcon on inactive InputConnection");
339                    return;
340                }
341                ic.showStatusIcon((String)msg.obj, msg.arg1);
342                return;
343            }
344            case DO_PERFORM_PRIVATE_COMMAND: {
345                InputConnection ic = mInputConnection.get();
346                if (ic == null || !isActive()) {
347                    Log.w(TAG, "performPrivateCommand on inactive InputConnection");
348                    return;
349                }
350                SomeArgs args = (SomeArgs)msg.obj;
351                ic.performPrivateCommand((String)args.arg1,
352                        (Bundle)args.arg2);
353                return;
354            }
355        }
356        Log.w(TAG, "Unhandled message code: " + msg.what);
357    }
358
359    Message obtainMessage(int what) {
360        return mH.obtainMessage(what);
361    }
362
363    Message obtainMessageII(int what, int arg1, int arg2) {
364        return mH.obtainMessage(what, arg1, arg2);
365    }
366
367    Message obtainMessageO(int what, Object arg1) {
368        return mH.obtainMessage(what, 0, 0, arg1);
369    }
370
371    Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) {
372        SomeArgs args = new SomeArgs();
373        args.callback = callback;
374        args.seq = seq;
375        return mH.obtainMessage(what, arg1, 0, args);
376    }
377
378    Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) {
379        SomeArgs args = new SomeArgs();
380        args.callback = callback;
381        args.seq = seq;
382        return mH.obtainMessage(what, arg1, arg2, args);
383    }
384
385    Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
386            IInputContextCallback callback) {
387        SomeArgs args = new SomeArgs();
388        args.arg1 = arg2;
389        args.callback = callback;
390        args.seq = seq;
391        return mH.obtainMessage(what, arg1, 0, args);
392    }
393
394    Message obtainMessageIO(int what, int arg1, Object arg2) {
395        return mH.obtainMessage(what, arg1, 0, arg2);
396    }
397
398    Message obtainMessageOO(int what, Object arg1, Object arg2) {
399        SomeArgs args = new SomeArgs();
400        args.arg1 = arg1;
401        args.arg2 = arg2;
402        return mH.obtainMessage(what, 0, 0, args);
403    }
404}
405