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