blob: 106392d35a6a5aec50765813946854df03938f6f [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001package 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 // Note we do NOT check isActive() here, because this is safe
282 // for an IME to call at any time, and we need to allow it
283 // through to clean up our state after the IME has switched to
284 // another client.
285 if (ic == null) {
286 Log.w(TAG, "finishComposingText on inactive InputConnection");
287 return;
288 }
289 ic.finishComposingText();
290 return;
291 }
292 case DO_SEND_KEY_EVENT: {
293 InputConnection ic = mInputConnection.get();
294 if (ic == null || !isActive()) {
295 Log.w(TAG, "sendKeyEvent on inactive InputConnection");
296 return;
297 }
298 ic.sendKeyEvent((KeyEvent)msg.obj);
299 return;
300 }
301 case DO_CLEAR_META_KEY_STATES: {
302 InputConnection ic = mInputConnection.get();
303 if (ic == null || !isActive()) {
304 Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
305 return;
306 }
307 ic.clearMetaKeyStates(msg.arg1);
308 return;
309 }
310 case DO_DELETE_SURROUNDING_TEXT: {
311 InputConnection ic = mInputConnection.get();
312 if (ic == null || !isActive()) {
313 Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
314 return;
315 }
316 ic.deleteSurroundingText(msg.arg1, msg.arg2);
317 return;
318 }
319 case DO_BEGIN_BATCH_EDIT: {
320 InputConnection ic = mInputConnection.get();
321 if (ic == null || !isActive()) {
322 Log.w(TAG, "beginBatchEdit on inactive InputConnection");
323 return;
324 }
325 ic.beginBatchEdit();
326 return;
327 }
328 case DO_END_BATCH_EDIT: {
329 InputConnection ic = mInputConnection.get();
330 if (ic == null || !isActive()) {
331 Log.w(TAG, "endBatchEdit on inactive InputConnection");
332 return;
333 }
334 ic.endBatchEdit();
335 return;
336 }
337 case DO_REPORT_FULLSCREEN_MODE: {
338 InputConnection ic = mInputConnection.get();
339 if (ic == null || !isActive()) {
340 Log.w(TAG, "showStatusIcon on inactive InputConnection");
341 return;
342 }
343 ic.reportFullscreenMode(msg.arg1 == 1);
344 return;
345 }
346 case DO_PERFORM_PRIVATE_COMMAND: {
347 InputConnection ic = mInputConnection.get();
348 if (ic == null || !isActive()) {
349 Log.w(TAG, "performPrivateCommand on inactive InputConnection");
350 return;
351 }
352 SomeArgs args = (SomeArgs)msg.obj;
353 ic.performPrivateCommand((String)args.arg1,
354 (Bundle)args.arg2);
355 return;
356 }
357 }
358 Log.w(TAG, "Unhandled message code: " + msg.what);
359 }
360
361 Message obtainMessage(int what) {
362 return mH.obtainMessage(what);
363 }
364
365 Message obtainMessageII(int what, int arg1, int arg2) {
366 return mH.obtainMessage(what, arg1, arg2);
367 }
368
369 Message obtainMessageO(int what, Object arg1) {
370 return mH.obtainMessage(what, 0, 0, arg1);
371 }
372
373 Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) {
374 SomeArgs args = new SomeArgs();
375 args.callback = callback;
376 args.seq = seq;
377 return mH.obtainMessage(what, arg1, 0, args);
378 }
379
380 Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) {
381 SomeArgs args = new SomeArgs();
382 args.callback = callback;
383 args.seq = seq;
384 return mH.obtainMessage(what, arg1, arg2, args);
385 }
386
387 Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
388 IInputContextCallback callback) {
389 SomeArgs args = new SomeArgs();
390 args.arg1 = arg2;
391 args.callback = callback;
392 args.seq = seq;
393 return mH.obtainMessage(what, arg1, 0, args);
394 }
395
396 Message obtainMessageIO(int what, int arg1, Object arg2) {
397 return mH.obtainMessage(what, arg1, 0, arg2);
398 }
399
400 Message obtainMessageOO(int what, Object arg1, Object arg2) {
401 SomeArgs args = new SomeArgs();
402 args.arg1 = arg1;
403 args.arg2 = arg2;
404 return mH.obtainMessage(what, 0, 0, args);
405 }
406}