blob: 8719fdedad784a1a95a1547e491d0782d92538a2 [file] [log] [blame]
Kenny Root15a4d2f2010-03-11 18:20:12 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017package com.android.internal.view;
18
19import android.os.Bundle;
20import android.os.Handler;
satokadb43582011-03-09 10:08:47 +090021import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.os.Looper;
23import android.os.Message;
24import android.os.RemoteException;
satokadb43582011-03-09 10:08:47 +090025import android.text.style.CorrectionSpan;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.util.Log;
27import android.view.KeyEvent;
28import android.view.inputmethod.CompletionInfo;
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -080029import android.view.inputmethod.CorrectionInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.view.inputmethod.ExtractedTextRequest;
31import android.view.inputmethod.InputConnection;
32
33import java.lang.ref.WeakReference;
34
35public class IInputConnectionWrapper extends IInputContext.Stub {
36 static final String TAG = "IInputConnectionWrapper";
Amith Yamasania90b7f02010-08-25 18:27:20 -070037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038 private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
39 private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
Amith Yamasania90b7f02010-08-25 18:27:20 -070040 private static final int DO_GET_SELECTED_TEXT = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041 private static final int DO_GET_CURSOR_CAPS_MODE = 30;
42 private static final int DO_GET_EXTRACTED_TEXT = 40;
43 private static final int DO_COMMIT_TEXT = 50;
44 private static final int DO_COMMIT_COMPLETION = 55;
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -080045 private static final int DO_COMMIT_CORRECTION = 56;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 private static final int DO_SET_SELECTION = 57;
47 private static final int DO_PERFORM_EDITOR_ACTION = 58;
48 private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
49 private static final int DO_SET_COMPOSING_TEXT = 60;
satokadb43582011-03-09 10:08:47 +090050 private static final int DO_SET_SECURE_CORRECTION_SPAN = 61;
Amith Yamasania90b7f02010-08-25 18:27:20 -070051 private static final int DO_SET_COMPOSING_REGION = 63;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 private static final int DO_FINISH_COMPOSING_TEXT = 65;
53 private static final int DO_SEND_KEY_EVENT = 70;
54 private static final int DO_DELETE_SURROUNDING_TEXT = 80;
55 private static final int DO_BEGIN_BATCH_EDIT = 90;
56 private static final int DO_END_BATCH_EDIT = 95;
57 private static final int DO_REPORT_FULLSCREEN_MODE = 100;
58 private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
59 private static final int DO_CLEAR_META_KEY_STATES = 130;
Amith Yamasania90b7f02010-08-25 18:27:20 -070060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 private WeakReference<InputConnection> mInputConnection;
62
63 private Looper mMainLooper;
64 private Handler mH;
65
66 static class SomeArgs {
67 Object arg1;
68 Object arg2;
69 IInputContextCallback callback;
70 int seq;
71 }
72
73 class MyHandler extends Handler {
74 MyHandler(Looper looper) {
75 super(looper);
76 }
77
78 @Override
79 public void handleMessage(Message msg) {
80 executeMessage(msg);
81 }
82 }
83
84 public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
85 mInputConnection = new WeakReference<InputConnection>(conn);
86 mMainLooper = mainLooper;
87 mH = new MyHandler(mMainLooper);
88 }
89
90 public boolean isActive() {
91 return true;
92 }
93
94 public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
95 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
96 }
97
98 public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) {
99 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
100 }
101
Amith Yamasania90b7f02010-08-25 18:27:20 -0700102 public void getSelectedText(int flags, int seq, IInputContextCallback callback) {
103 dispatchMessage(obtainMessageISC(DO_GET_SELECTED_TEXT, flags, seq, callback));
104 }
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
107 dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
108 }
109
110 public void getExtractedText(ExtractedTextRequest request,
111 int flags, int seq, IInputContextCallback callback) {
112 dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags,
113 request, seq, callback));
114 }
115
116 public void commitText(CharSequence text, int newCursorPosition) {
117 dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
118 }
119
120 public void commitCompletion(CompletionInfo text) {
121 dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
122 }
123
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -0800124 public void commitCorrection(CorrectionInfo info) {
125 dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
126 }
127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 public void setSelection(int start, int end) {
129 dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
130 }
131
132 public void performEditorAction(int id) {
133 dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
134 }
135
136 public void performContextMenuAction(int id) {
137 dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
138 }
139
Amith Yamasania90b7f02010-08-25 18:27:20 -0700140 public void setComposingRegion(int start, int end) {
141 dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
142 }
143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 public void setComposingText(CharSequence text, int newCursorPosition) {
145 dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
146 }
147
148 public void finishComposingText() {
149 dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
150 }
151
152 public void sendKeyEvent(KeyEvent event) {
153 dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
154 }
155
156 public void clearMetaKeyStates(int states) {
157 dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
158 }
159
160 public void deleteSurroundingText(int leftLength, int rightLength) {
161 dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
162 leftLength, rightLength));
163 }
164
165 public void beginBatchEdit() {
166 dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
167 }
168
169 public void endBatchEdit() {
170 dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
171 }
172
173 public void reportFullscreenMode(boolean enabled) {
174 dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
175 }
176
177 public void performPrivateCommand(String action, Bundle data) {
178 dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
179 }
satokadb43582011-03-09 10:08:47 +0900180
181 @Override
182 public void setCorrectionSpan(IBinder token, CorrectionSpan correctionSpan, int start,
183 int end, int flags) {
184 dispatchMessage(obtainMessageOOIII(DO_SET_SECURE_CORRECTION_SPAN, token, correctionSpan,
185 start, end, flags));
186 }
187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 void dispatchMessage(Message msg) {
189 // If we are calling this from the main thread, then we can call
190 // right through. Otherwise, we need to send the message to the
191 // main thread.
192 if (Looper.myLooper() == mMainLooper) {
193 executeMessage(msg);
194 msg.recycle();
195 return;
196 }
197
198 mH.sendMessage(msg);
199 }
200
201 void executeMessage(Message msg) {
202 switch (msg.what) {
203 case DO_GET_TEXT_AFTER_CURSOR: {
204 SomeArgs args = (SomeArgs)msg.obj;
205 try {
206 InputConnection ic = mInputConnection.get();
207 if (ic == null || !isActive()) {
208 Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
209 args.callback.setTextAfterCursor(null, args.seq);
210 return;
211 }
212 args.callback.setTextAfterCursor(ic.getTextAfterCursor(
213 msg.arg1, msg.arg2), args.seq);
214 } catch (RemoteException e) {
215 Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e);
216 }
217 return;
218 }
219 case DO_GET_TEXT_BEFORE_CURSOR: {
220 SomeArgs args = (SomeArgs)msg.obj;
221 try {
222 InputConnection ic = mInputConnection.get();
223 if (ic == null || !isActive()) {
224 Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
225 args.callback.setTextBeforeCursor(null, args.seq);
226 return;
227 }
228 args.callback.setTextBeforeCursor(ic.getTextBeforeCursor(
229 msg.arg1, msg.arg2), args.seq);
230 } catch (RemoteException e) {
231 Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e);
232 }
233 return;
234 }
Amith Yamasania90b7f02010-08-25 18:27:20 -0700235 case DO_GET_SELECTED_TEXT: {
236 SomeArgs args = (SomeArgs)msg.obj;
237 try {
238 InputConnection ic = mInputConnection.get();
239 if (ic == null || !isActive()) {
240 Log.w(TAG, "getSelectedText on inactive InputConnection");
241 args.callback.setSelectedText(null, args.seq);
242 return;
243 }
244 args.callback.setSelectedText(ic.getSelectedText(
245 msg.arg1), args.seq);
246 } catch (RemoteException e) {
247 Log.w(TAG, "Got RemoteException calling setSelectedText", e);
248 }
249 return;
250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 case DO_GET_CURSOR_CAPS_MODE: {
252 SomeArgs args = (SomeArgs)msg.obj;
253 try {
254 InputConnection ic = mInputConnection.get();
255 if (ic == null || !isActive()) {
256 Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
257 args.callback.setCursorCapsMode(0, args.seq);
258 return;
259 }
260 args.callback.setCursorCapsMode(ic.getCursorCapsMode(msg.arg1),
261 args.seq);
262 } catch (RemoteException e) {
263 Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e);
264 }
265 return;
266 }
267 case DO_GET_EXTRACTED_TEXT: {
268 SomeArgs args = (SomeArgs)msg.obj;
269 try {
270 InputConnection ic = mInputConnection.get();
271 if (ic == null || !isActive()) {
272 Log.w(TAG, "getExtractedText on inactive InputConnection");
273 args.callback.setExtractedText(null, args.seq);
274 return;
275 }
276 args.callback.setExtractedText(ic.getExtractedText(
277 (ExtractedTextRequest)args.arg1, msg.arg1), args.seq);
278 } catch (RemoteException e) {
279 Log.w(TAG, "Got RemoteException calling setExtractedText", e);
280 }
281 return;
282 }
283 case DO_COMMIT_TEXT: {
284 InputConnection ic = mInputConnection.get();
285 if (ic == null || !isActive()) {
286 Log.w(TAG, "commitText on inactive InputConnection");
287 return;
288 }
289 ic.commitText((CharSequence)msg.obj, msg.arg1);
290 return;
291 }
292 case DO_SET_SELECTION: {
293 InputConnection ic = mInputConnection.get();
294 if (ic == null || !isActive()) {
295 Log.w(TAG, "setSelection on inactive InputConnection");
296 return;
297 }
298 ic.setSelection(msg.arg1, msg.arg2);
299 return;
300 }
301 case DO_PERFORM_EDITOR_ACTION: {
302 InputConnection ic = mInputConnection.get();
303 if (ic == null || !isActive()) {
304 Log.w(TAG, "performEditorAction on inactive InputConnection");
305 return;
306 }
307 ic.performEditorAction(msg.arg1);
308 return;
309 }
310 case DO_PERFORM_CONTEXT_MENU_ACTION: {
311 InputConnection ic = mInputConnection.get();
312 if (ic == null || !isActive()) {
313 Log.w(TAG, "performContextMenuAction on inactive InputConnection");
314 return;
315 }
316 ic.performContextMenuAction(msg.arg1);
317 return;
318 }
319 case DO_COMMIT_COMPLETION: {
320 InputConnection ic = mInputConnection.get();
321 if (ic == null || !isActive()) {
322 Log.w(TAG, "commitCompletion on inactive InputConnection");
323 return;
324 }
325 ic.commitCompletion((CompletionInfo)msg.obj);
326 return;
327 }
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -0800328 case DO_COMMIT_CORRECTION: {
329 InputConnection ic = mInputConnection.get();
330 if (ic == null || !isActive()) {
331 Log.w(TAG, "commitCorrection on inactive InputConnection");
332 return;
333 }
334 ic.commitCorrection((CorrectionInfo)msg.obj);
335 return;
336 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 case DO_SET_COMPOSING_TEXT: {
338 InputConnection ic = mInputConnection.get();
339 if (ic == null || !isActive()) {
340 Log.w(TAG, "setComposingText on inactive InputConnection");
341 return;
342 }
343 ic.setComposingText((CharSequence)msg.obj, msg.arg1);
344 return;
345 }
Amith Yamasania90b7f02010-08-25 18:27:20 -0700346 case DO_SET_COMPOSING_REGION: {
347 InputConnection ic = mInputConnection.get();
348 if (ic == null || !isActive()) {
349 Log.w(TAG, "setComposingRegion on inactive InputConnection");
350 return;
351 }
352 ic.setComposingRegion(msg.arg1, msg.arg2);
353 return;
354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 case DO_FINISH_COMPOSING_TEXT: {
356 InputConnection ic = mInputConnection.get();
357 // Note we do NOT check isActive() here, because this is safe
358 // for an IME to call at any time, and we need to allow it
359 // through to clean up our state after the IME has switched to
360 // another client.
361 if (ic == null) {
362 Log.w(TAG, "finishComposingText on inactive InputConnection");
363 return;
364 }
365 ic.finishComposingText();
366 return;
367 }
368 case DO_SEND_KEY_EVENT: {
369 InputConnection ic = mInputConnection.get();
370 if (ic == null || !isActive()) {
371 Log.w(TAG, "sendKeyEvent on inactive InputConnection");
372 return;
373 }
374 ic.sendKeyEvent((KeyEvent)msg.obj);
375 return;
376 }
377 case DO_CLEAR_META_KEY_STATES: {
378 InputConnection ic = mInputConnection.get();
379 if (ic == null || !isActive()) {
380 Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
381 return;
382 }
383 ic.clearMetaKeyStates(msg.arg1);
384 return;
385 }
386 case DO_DELETE_SURROUNDING_TEXT: {
387 InputConnection ic = mInputConnection.get();
388 if (ic == null || !isActive()) {
389 Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
390 return;
391 }
392 ic.deleteSurroundingText(msg.arg1, msg.arg2);
393 return;
394 }
395 case DO_BEGIN_BATCH_EDIT: {
396 InputConnection ic = mInputConnection.get();
397 if (ic == null || !isActive()) {
398 Log.w(TAG, "beginBatchEdit on inactive InputConnection");
399 return;
400 }
401 ic.beginBatchEdit();
402 return;
403 }
404 case DO_END_BATCH_EDIT: {
405 InputConnection ic = mInputConnection.get();
406 if (ic == null || !isActive()) {
407 Log.w(TAG, "endBatchEdit on inactive InputConnection");
408 return;
409 }
410 ic.endBatchEdit();
411 return;
412 }
413 case DO_REPORT_FULLSCREEN_MODE: {
414 InputConnection ic = mInputConnection.get();
415 if (ic == null || !isActive()) {
416 Log.w(TAG, "showStatusIcon on inactive InputConnection");
417 return;
418 }
419 ic.reportFullscreenMode(msg.arg1 == 1);
420 return;
421 }
422 case DO_PERFORM_PRIVATE_COMMAND: {
423 InputConnection ic = mInputConnection.get();
424 if (ic == null || !isActive()) {
425 Log.w(TAG, "performPrivateCommand on inactive InputConnection");
426 return;
427 }
428 SomeArgs args = (SomeArgs)msg.obj;
429 ic.performPrivateCommand((String)args.arg1,
430 (Bundle)args.arg2);
431 return;
432 }
satokadb43582011-03-09 10:08:47 +0900433 case DO_SET_SECURE_CORRECTION_SPAN: {
434 InputConnection ic = mInputConnection.get();
435 if (ic == null || !isActive()) {
436 Log.w(TAG, "setCorrectionSpan on inactive InputConnection");
437 return;
438 }
439 SomeArgs args = (SomeArgs)msg.obj;
440 ic.setCorrectionSpan((IBinder)args.arg1, (CorrectionSpan)args.arg2, msg.arg1,
441 msg.arg2, args.seq);
442 return;
443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 }
445 Log.w(TAG, "Unhandled message code: " + msg.what);
446 }
447
448 Message obtainMessage(int what) {
449 return mH.obtainMessage(what);
450 }
451
452 Message obtainMessageII(int what, int arg1, int arg2) {
453 return mH.obtainMessage(what, arg1, arg2);
454 }
455
456 Message obtainMessageO(int what, Object arg1) {
457 return mH.obtainMessage(what, 0, 0, arg1);
458 }
459
460 Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) {
461 SomeArgs args = new SomeArgs();
462 args.callback = callback;
463 args.seq = seq;
464 return mH.obtainMessage(what, arg1, 0, args);
465 }
466
467 Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) {
468 SomeArgs args = new SomeArgs();
469 args.callback = callback;
470 args.seq = seq;
471 return mH.obtainMessage(what, arg1, arg2, args);
472 }
473
474 Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
475 IInputContextCallback callback) {
476 SomeArgs args = new SomeArgs();
477 args.arg1 = arg2;
478 args.callback = callback;
479 args.seq = seq;
480 return mH.obtainMessage(what, arg1, 0, args);
481 }
482
483 Message obtainMessageIO(int what, int arg1, Object arg2) {
484 return mH.obtainMessage(what, arg1, 0, arg2);
485 }
486
487 Message obtainMessageOO(int what, Object arg1, Object arg2) {
488 SomeArgs args = new SomeArgs();
489 args.arg1 = arg1;
490 args.arg2 = arg2;
491 return mH.obtainMessage(what, 0, 0, args);
492 }
satokadb43582011-03-09 10:08:47 +0900493
494 Message obtainMessageOOIII(int what, Object arg1, Object arg2, int arg3, int arg4, int arg5) {
495 SomeArgs args = new SomeArgs();
496 args.arg1 = arg1;
497 args.arg2 = arg2;
498 args.seq = arg5;
499 return mH.obtainMessage(what, arg3, arg4, args);
500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501}