blob: c792d78405ddaf1628306a669aaa4a257b730587 [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;
21import android.os.Looper;
22import android.os.Message;
23import android.os.RemoteException;
24import android.util.Log;
25import android.view.KeyEvent;
26import android.view.inputmethod.CompletionInfo;
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -080027import android.view.inputmethod.CorrectionInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.view.inputmethod.ExtractedTextRequest;
29import android.view.inputmethod.InputConnection;
30
31import java.lang.ref.WeakReference;
32
33public class IInputConnectionWrapper extends IInputContext.Stub {
34 static final String TAG = "IInputConnectionWrapper";
Amith Yamasania90b7f02010-08-25 18:27:20 -070035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
37 private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
Amith Yamasania90b7f02010-08-25 18:27:20 -070038 private static final int DO_GET_SELECTED_TEXT = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 private static final int DO_GET_CURSOR_CAPS_MODE = 30;
40 private static final int DO_GET_EXTRACTED_TEXT = 40;
41 private static final int DO_COMMIT_TEXT = 50;
42 private static final int DO_COMMIT_COMPLETION = 55;
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -080043 private static final int DO_COMMIT_CORRECTION = 56;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 private static final int DO_SET_SELECTION = 57;
45 private static final int DO_PERFORM_EDITOR_ACTION = 58;
46 private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
47 private static final int DO_SET_COMPOSING_TEXT = 60;
Amith Yamasania90b7f02010-08-25 18:27:20 -070048 private static final int DO_SET_COMPOSING_REGION = 63;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 private static final int DO_FINISH_COMPOSING_TEXT = 65;
50 private static final int DO_SEND_KEY_EVENT = 70;
51 private static final int DO_DELETE_SURROUNDING_TEXT = 80;
52 private static final int DO_BEGIN_BATCH_EDIT = 90;
53 private static final int DO_END_BATCH_EDIT = 95;
54 private static final int DO_REPORT_FULLSCREEN_MODE = 100;
55 private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
56 private static final int DO_CLEAR_META_KEY_STATES = 130;
Amith Yamasania90b7f02010-08-25 18:27:20 -070057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 private WeakReference<InputConnection> mInputConnection;
59
60 private Looper mMainLooper;
61 private Handler mH;
62
63 static class SomeArgs {
64 Object arg1;
65 Object arg2;
66 IInputContextCallback callback;
67 int seq;
68 }
69
70 class MyHandler extends Handler {
71 MyHandler(Looper looper) {
72 super(looper);
73 }
74
75 @Override
76 public void handleMessage(Message msg) {
77 executeMessage(msg);
78 }
79 }
80
81 public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
82 mInputConnection = new WeakReference<InputConnection>(conn);
83 mMainLooper = mainLooper;
84 mH = new MyHandler(mMainLooper);
85 }
86
87 public boolean isActive() {
88 return true;
89 }
90
91 public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
92 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
93 }
94
95 public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) {
96 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
97 }
98
Amith Yamasania90b7f02010-08-25 18:27:20 -070099 public void getSelectedText(int flags, int seq, IInputContextCallback callback) {
100 dispatchMessage(obtainMessageISC(DO_GET_SELECTED_TEXT, flags, seq, callback));
101 }
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
104 dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
105 }
106
107 public void getExtractedText(ExtractedTextRequest request,
108 int flags, int seq, IInputContextCallback callback) {
109 dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags,
110 request, seq, callback));
111 }
112
113 public void commitText(CharSequence text, int newCursorPosition) {
114 dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
115 }
116
117 public void commitCompletion(CompletionInfo text) {
118 dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
119 }
120
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -0800121 public void commitCorrection(CorrectionInfo info) {
122 dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
123 }
124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 public void setSelection(int start, int end) {
126 dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
127 }
128
129 public void performEditorAction(int id) {
130 dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
131 }
132
133 public void performContextMenuAction(int id) {
134 dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
135 }
136
Amith Yamasania90b7f02010-08-25 18:27:20 -0700137 public void setComposingRegion(int start, int end) {
138 dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
139 }
140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 public void setComposingText(CharSequence text, int newCursorPosition) {
142 dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
143 }
144
145 public void finishComposingText() {
146 dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
147 }
148
149 public void sendKeyEvent(KeyEvent event) {
150 dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
151 }
152
153 public void clearMetaKeyStates(int states) {
154 dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
155 }
156
157 public void deleteSurroundingText(int leftLength, int rightLength) {
158 dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
159 leftLength, rightLength));
160 }
161
162 public void beginBatchEdit() {
163 dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
164 }
165
166 public void endBatchEdit() {
167 dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
168 }
169
170 public void reportFullscreenMode(boolean enabled) {
171 dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
172 }
173
174 public void performPrivateCommand(String action, Bundle data) {
175 dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
176 }
satokadb43582011-03-09 10:08:47 +0900177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 void dispatchMessage(Message msg) {
179 // If we are calling this from the main thread, then we can call
180 // right through. Otherwise, we need to send the message to the
181 // main thread.
182 if (Looper.myLooper() == mMainLooper) {
183 executeMessage(msg);
184 msg.recycle();
185 return;
186 }
187
188 mH.sendMessage(msg);
189 }
190
191 void executeMessage(Message msg) {
192 switch (msg.what) {
193 case DO_GET_TEXT_AFTER_CURSOR: {
194 SomeArgs args = (SomeArgs)msg.obj;
195 try {
196 InputConnection ic = mInputConnection.get();
197 if (ic == null || !isActive()) {
198 Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
199 args.callback.setTextAfterCursor(null, args.seq);
200 return;
201 }
202 args.callback.setTextAfterCursor(ic.getTextAfterCursor(
203 msg.arg1, msg.arg2), args.seq);
204 } catch (RemoteException e) {
205 Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e);
206 }
207 return;
208 }
209 case DO_GET_TEXT_BEFORE_CURSOR: {
210 SomeArgs args = (SomeArgs)msg.obj;
211 try {
212 InputConnection ic = mInputConnection.get();
213 if (ic == null || !isActive()) {
214 Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
215 args.callback.setTextBeforeCursor(null, args.seq);
216 return;
217 }
218 args.callback.setTextBeforeCursor(ic.getTextBeforeCursor(
219 msg.arg1, msg.arg2), args.seq);
220 } catch (RemoteException e) {
221 Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e);
222 }
223 return;
224 }
Amith Yamasania90b7f02010-08-25 18:27:20 -0700225 case DO_GET_SELECTED_TEXT: {
226 SomeArgs args = (SomeArgs)msg.obj;
227 try {
228 InputConnection ic = mInputConnection.get();
229 if (ic == null || !isActive()) {
230 Log.w(TAG, "getSelectedText on inactive InputConnection");
231 args.callback.setSelectedText(null, args.seq);
232 return;
233 }
234 args.callback.setSelectedText(ic.getSelectedText(
235 msg.arg1), args.seq);
236 } catch (RemoteException e) {
237 Log.w(TAG, "Got RemoteException calling setSelectedText", e);
238 }
239 return;
240 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 case DO_GET_CURSOR_CAPS_MODE: {
242 SomeArgs args = (SomeArgs)msg.obj;
243 try {
244 InputConnection ic = mInputConnection.get();
245 if (ic == null || !isActive()) {
246 Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
247 args.callback.setCursorCapsMode(0, args.seq);
248 return;
249 }
250 args.callback.setCursorCapsMode(ic.getCursorCapsMode(msg.arg1),
251 args.seq);
252 } catch (RemoteException e) {
253 Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e);
254 }
255 return;
256 }
257 case DO_GET_EXTRACTED_TEXT: {
258 SomeArgs args = (SomeArgs)msg.obj;
259 try {
260 InputConnection ic = mInputConnection.get();
261 if (ic == null || !isActive()) {
262 Log.w(TAG, "getExtractedText on inactive InputConnection");
263 args.callback.setExtractedText(null, args.seq);
264 return;
265 }
266 args.callback.setExtractedText(ic.getExtractedText(
267 (ExtractedTextRequest)args.arg1, msg.arg1), args.seq);
268 } catch (RemoteException e) {
269 Log.w(TAG, "Got RemoteException calling setExtractedText", e);
270 }
271 return;
272 }
273 case DO_COMMIT_TEXT: {
274 InputConnection ic = mInputConnection.get();
275 if (ic == null || !isActive()) {
276 Log.w(TAG, "commitText on inactive InputConnection");
277 return;
278 }
279 ic.commitText((CharSequence)msg.obj, msg.arg1);
280 return;
281 }
282 case DO_SET_SELECTION: {
283 InputConnection ic = mInputConnection.get();
284 if (ic == null || !isActive()) {
285 Log.w(TAG, "setSelection on inactive InputConnection");
286 return;
287 }
288 ic.setSelection(msg.arg1, msg.arg2);
289 return;
290 }
291 case DO_PERFORM_EDITOR_ACTION: {
292 InputConnection ic = mInputConnection.get();
293 if (ic == null || !isActive()) {
294 Log.w(TAG, "performEditorAction on inactive InputConnection");
295 return;
296 }
297 ic.performEditorAction(msg.arg1);
298 return;
299 }
300 case DO_PERFORM_CONTEXT_MENU_ACTION: {
301 InputConnection ic = mInputConnection.get();
302 if (ic == null || !isActive()) {
303 Log.w(TAG, "performContextMenuAction on inactive InputConnection");
304 return;
305 }
306 ic.performContextMenuAction(msg.arg1);
307 return;
308 }
309 case DO_COMMIT_COMPLETION: {
310 InputConnection ic = mInputConnection.get();
311 if (ic == null || !isActive()) {
312 Log.w(TAG, "commitCompletion on inactive InputConnection");
313 return;
314 }
315 ic.commitCompletion((CompletionInfo)msg.obj);
316 return;
317 }
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -0800318 case DO_COMMIT_CORRECTION: {
319 InputConnection ic = mInputConnection.get();
320 if (ic == null || !isActive()) {
321 Log.w(TAG, "commitCorrection on inactive InputConnection");
322 return;
323 }
324 ic.commitCorrection((CorrectionInfo)msg.obj);
325 return;
326 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 case DO_SET_COMPOSING_TEXT: {
328 InputConnection ic = mInputConnection.get();
329 if (ic == null || !isActive()) {
330 Log.w(TAG, "setComposingText on inactive InputConnection");
331 return;
332 }
333 ic.setComposingText((CharSequence)msg.obj, msg.arg1);
334 return;
335 }
Amith Yamasania90b7f02010-08-25 18:27:20 -0700336 case DO_SET_COMPOSING_REGION: {
337 InputConnection ic = mInputConnection.get();
338 if (ic == null || !isActive()) {
339 Log.w(TAG, "setComposingRegion on inactive InputConnection");
340 return;
341 }
342 ic.setComposingRegion(msg.arg1, msg.arg2);
343 return;
344 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 case DO_FINISH_COMPOSING_TEXT: {
346 InputConnection ic = mInputConnection.get();
347 // Note we do NOT check isActive() here, because this is safe
348 // for an IME to call at any time, and we need to allow it
349 // through to clean up our state after the IME has switched to
350 // another client.
351 if (ic == null) {
352 Log.w(TAG, "finishComposingText on inactive InputConnection");
353 return;
354 }
355 ic.finishComposingText();
356 return;
357 }
358 case DO_SEND_KEY_EVENT: {
359 InputConnection ic = mInputConnection.get();
360 if (ic == null || !isActive()) {
361 Log.w(TAG, "sendKeyEvent on inactive InputConnection");
362 return;
363 }
364 ic.sendKeyEvent((KeyEvent)msg.obj);
365 return;
366 }
367 case DO_CLEAR_META_KEY_STATES: {
368 InputConnection ic = mInputConnection.get();
369 if (ic == null || !isActive()) {
370 Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
371 return;
372 }
373 ic.clearMetaKeyStates(msg.arg1);
374 return;
375 }
376 case DO_DELETE_SURROUNDING_TEXT: {
377 InputConnection ic = mInputConnection.get();
378 if (ic == null || !isActive()) {
379 Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
380 return;
381 }
382 ic.deleteSurroundingText(msg.arg1, msg.arg2);
383 return;
384 }
385 case DO_BEGIN_BATCH_EDIT: {
386 InputConnection ic = mInputConnection.get();
387 if (ic == null || !isActive()) {
388 Log.w(TAG, "beginBatchEdit on inactive InputConnection");
389 return;
390 }
391 ic.beginBatchEdit();
392 return;
393 }
394 case DO_END_BATCH_EDIT: {
395 InputConnection ic = mInputConnection.get();
396 if (ic == null || !isActive()) {
397 Log.w(TAG, "endBatchEdit on inactive InputConnection");
398 return;
399 }
400 ic.endBatchEdit();
401 return;
402 }
403 case DO_REPORT_FULLSCREEN_MODE: {
404 InputConnection ic = mInputConnection.get();
405 if (ic == null || !isActive()) {
406 Log.w(TAG, "showStatusIcon on inactive InputConnection");
407 return;
408 }
409 ic.reportFullscreenMode(msg.arg1 == 1);
410 return;
411 }
412 case DO_PERFORM_PRIVATE_COMMAND: {
413 InputConnection ic = mInputConnection.get();
414 if (ic == null || !isActive()) {
415 Log.w(TAG, "performPrivateCommand on inactive InputConnection");
416 return;
417 }
418 SomeArgs args = (SomeArgs)msg.obj;
419 ic.performPrivateCommand((String)args.arg1,
420 (Bundle)args.arg2);
421 return;
422 }
423 }
424 Log.w(TAG, "Unhandled message code: " + msg.what);
425 }
426
427 Message obtainMessage(int what) {
428 return mH.obtainMessage(what);
429 }
430
431 Message obtainMessageII(int what, int arg1, int arg2) {
432 return mH.obtainMessage(what, arg1, arg2);
433 }
434
435 Message obtainMessageO(int what, Object arg1) {
436 return mH.obtainMessage(what, 0, 0, arg1);
437 }
438
439 Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) {
440 SomeArgs args = new SomeArgs();
441 args.callback = callback;
442 args.seq = seq;
443 return mH.obtainMessage(what, arg1, 0, args);
444 }
445
446 Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) {
447 SomeArgs args = new SomeArgs();
448 args.callback = callback;
449 args.seq = seq;
450 return mH.obtainMessage(what, arg1, arg2, args);
451 }
452
453 Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
454 IInputContextCallback callback) {
455 SomeArgs args = new SomeArgs();
456 args.arg1 = arg2;
457 args.callback = callback;
458 args.seq = seq;
459 return mH.obtainMessage(what, arg1, 0, args);
460 }
461
462 Message obtainMessageIO(int what, int arg1, Object arg2) {
463 return mH.obtainMessage(what, arg1, 0, arg2);
464 }
465
466 Message obtainMessageOO(int what, Object arg1, Object arg2) {
467 SomeArgs args = new SomeArgs();
468 args.arg1 = arg1;
469 args.arg2 = arg2;
470 return mH.obtainMessage(what, 0, 0, args);
471 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472}