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