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