blob: b77cc6365d8a1a8c83368779d4babc9042dffe0b [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;
Yohei Yukawac89e22a2016-01-13 22:48:14 -080052 private static final int DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 81;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 private static final int DO_BEGIN_BATCH_EDIT = 90;
54 private static final int DO_END_BATCH_EDIT = 95;
55 private static final int DO_REPORT_FULLSCREEN_MODE = 100;
56 private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
57 private static final int DO_CLEAR_META_KEY_STATES = 130;
Yohei Yukawaa277db22014-08-21 18:38:44 -070058 private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
Amith Yamasania90b7f02010-08-25 18:27:20 -070059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 private WeakReference<InputConnection> mInputConnection;
61
62 private Looper mMainLooper;
63 private Handler mH;
64
65 static class SomeArgs {
66 Object arg1;
67 Object arg2;
68 IInputContextCallback callback;
69 int seq;
70 }
71
72 class MyHandler extends Handler {
73 MyHandler(Looper looper) {
74 super(looper);
75 }
76
77 @Override
78 public void handleMessage(Message msg) {
79 executeMessage(msg);
80 }
81 }
82
83 public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
84 mInputConnection = new WeakReference<InputConnection>(conn);
85 mMainLooper = mainLooper;
86 mH = new MyHandler(mMainLooper);
87 }
88
89 public boolean isActive() {
90 return true;
91 }
92
93 public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
94 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
95 }
96
97 public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) {
98 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
99 }
100
Amith Yamasania90b7f02010-08-25 18:27:20 -0700101 public void getSelectedText(int flags, int seq, IInputContextCallback callback) {
102 dispatchMessage(obtainMessageISC(DO_GET_SELECTED_TEXT, flags, seq, callback));
103 }
104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
106 dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
107 }
108
109 public void getExtractedText(ExtractedTextRequest request,
110 int flags, int seq, IInputContextCallback callback) {
111 dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags,
112 request, seq, callback));
113 }
114
115 public void commitText(CharSequence text, int newCursorPosition) {
116 dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
117 }
118
119 public void commitCompletion(CompletionInfo text) {
120 dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
121 }
122
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -0800123 public void commitCorrection(CorrectionInfo info) {
124 dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
125 }
126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 public void setSelection(int start, int end) {
128 dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
129 }
130
131 public void performEditorAction(int id) {
132 dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
133 }
134
135 public void performContextMenuAction(int id) {
136 dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
137 }
138
Amith Yamasania90b7f02010-08-25 18:27:20 -0700139 public void setComposingRegion(int start, int end) {
140 dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
141 }
142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 public void setComposingText(CharSequence text, int newCursorPosition) {
144 dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
145 }
146
147 public void finishComposingText() {
148 dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
149 }
150
151 public void sendKeyEvent(KeyEvent event) {
152 dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
153 }
154
155 public void clearMetaKeyStates(int states) {
156 dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
157 }
158
Yohei Yukawac89e22a2016-01-13 22:48:14 -0800159 public void deleteSurroundingText(int beforeLength, int afterLength) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
Yohei Yukawac89e22a2016-01-13 22:48:14 -0800161 beforeLength, afterLength));
162 }
163
164 public void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
165 dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
166 beforeLength, afterLength));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 }
168
169 public void beginBatchEdit() {
170 dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
171 }
172
173 public void endBatchEdit() {
174 dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
175 }
176
177 public void reportFullscreenMode(boolean enabled) {
178 dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
179 }
180
181 public void performPrivateCommand(String action, Bundle data) {
182 dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
183 }
satokadb43582011-03-09 10:08:47 +0900184
Yohei Yukawaa277db22014-08-21 18:38:44 -0700185 public void requestUpdateCursorAnchorInfo(int cursorUpdateMode, int seq,
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900186 IInputContextCallback callback) {
Yohei Yukawaa277db22014-08-21 18:38:44 -0700187 dispatchMessage(obtainMessageISC(DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO, cursorUpdateMode,
188 seq, callback));
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900189 }
190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 void dispatchMessage(Message msg) {
192 // If we are calling this from the main thread, then we can call
193 // right through. Otherwise, we need to send the message to the
194 // main thread.
195 if (Looper.myLooper() == mMainLooper) {
196 executeMessage(msg);
197 msg.recycle();
198 return;
199 }
200
201 mH.sendMessage(msg);
202 }
203
204 void executeMessage(Message msg) {
205 switch (msg.what) {
206 case DO_GET_TEXT_AFTER_CURSOR: {
207 SomeArgs args = (SomeArgs)msg.obj;
208 try {
209 InputConnection ic = mInputConnection.get();
210 if (ic == null || !isActive()) {
211 Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
212 args.callback.setTextAfterCursor(null, args.seq);
213 return;
214 }
215 args.callback.setTextAfterCursor(ic.getTextAfterCursor(
216 msg.arg1, msg.arg2), args.seq);
217 } catch (RemoteException e) {
218 Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e);
219 }
220 return;
221 }
222 case DO_GET_TEXT_BEFORE_CURSOR: {
223 SomeArgs args = (SomeArgs)msg.obj;
224 try {
225 InputConnection ic = mInputConnection.get();
226 if (ic == null || !isActive()) {
227 Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
228 args.callback.setTextBeforeCursor(null, args.seq);
229 return;
230 }
231 args.callback.setTextBeforeCursor(ic.getTextBeforeCursor(
232 msg.arg1, msg.arg2), args.seq);
233 } catch (RemoteException e) {
234 Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e);
235 }
236 return;
237 }
Amith Yamasania90b7f02010-08-25 18:27:20 -0700238 case DO_GET_SELECTED_TEXT: {
239 SomeArgs args = (SomeArgs)msg.obj;
240 try {
241 InputConnection ic = mInputConnection.get();
242 if (ic == null || !isActive()) {
243 Log.w(TAG, "getSelectedText on inactive InputConnection");
244 args.callback.setSelectedText(null, args.seq);
245 return;
246 }
247 args.callback.setSelectedText(ic.getSelectedText(
248 msg.arg1), args.seq);
249 } catch (RemoteException e) {
250 Log.w(TAG, "Got RemoteException calling setSelectedText", e);
251 }
252 return;
253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 case DO_GET_CURSOR_CAPS_MODE: {
255 SomeArgs args = (SomeArgs)msg.obj;
256 try {
257 InputConnection ic = mInputConnection.get();
258 if (ic == null || !isActive()) {
259 Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
260 args.callback.setCursorCapsMode(0, args.seq);
261 return;
262 }
263 args.callback.setCursorCapsMode(ic.getCursorCapsMode(msg.arg1),
264 args.seq);
265 } catch (RemoteException e) {
266 Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e);
267 }
268 return;
269 }
270 case DO_GET_EXTRACTED_TEXT: {
271 SomeArgs args = (SomeArgs)msg.obj;
272 try {
273 InputConnection ic = mInputConnection.get();
274 if (ic == null || !isActive()) {
275 Log.w(TAG, "getExtractedText on inactive InputConnection");
276 args.callback.setExtractedText(null, args.seq);
277 return;
278 }
279 args.callback.setExtractedText(ic.getExtractedText(
280 (ExtractedTextRequest)args.arg1, msg.arg1), args.seq);
281 } catch (RemoteException e) {
282 Log.w(TAG, "Got RemoteException calling setExtractedText", e);
283 }
284 return;
285 }
286 case DO_COMMIT_TEXT: {
287 InputConnection ic = mInputConnection.get();
288 if (ic == null || !isActive()) {
289 Log.w(TAG, "commitText on inactive InputConnection");
290 return;
291 }
292 ic.commitText((CharSequence)msg.obj, msg.arg1);
293 return;
294 }
295 case DO_SET_SELECTION: {
296 InputConnection ic = mInputConnection.get();
297 if (ic == null || !isActive()) {
298 Log.w(TAG, "setSelection on inactive InputConnection");
299 return;
300 }
301 ic.setSelection(msg.arg1, msg.arg2);
302 return;
303 }
304 case DO_PERFORM_EDITOR_ACTION: {
305 InputConnection ic = mInputConnection.get();
306 if (ic == null || !isActive()) {
307 Log.w(TAG, "performEditorAction on inactive InputConnection");
308 return;
309 }
310 ic.performEditorAction(msg.arg1);
311 return;
312 }
313 case DO_PERFORM_CONTEXT_MENU_ACTION: {
314 InputConnection ic = mInputConnection.get();
315 if (ic == null || !isActive()) {
316 Log.w(TAG, "performContextMenuAction on inactive InputConnection");
317 return;
318 }
319 ic.performContextMenuAction(msg.arg1);
320 return;
321 }
322 case DO_COMMIT_COMPLETION: {
323 InputConnection ic = mInputConnection.get();
324 if (ic == null || !isActive()) {
325 Log.w(TAG, "commitCompletion on inactive InputConnection");
326 return;
327 }
328 ic.commitCompletion((CompletionInfo)msg.obj);
329 return;
330 }
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -0800331 case DO_COMMIT_CORRECTION: {
332 InputConnection ic = mInputConnection.get();
333 if (ic == null || !isActive()) {
334 Log.w(TAG, "commitCorrection on inactive InputConnection");
335 return;
336 }
337 ic.commitCorrection((CorrectionInfo)msg.obj);
338 return;
339 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 case DO_SET_COMPOSING_TEXT: {
341 InputConnection ic = mInputConnection.get();
342 if (ic == null || !isActive()) {
343 Log.w(TAG, "setComposingText on inactive InputConnection");
344 return;
345 }
346 ic.setComposingText((CharSequence)msg.obj, msg.arg1);
347 return;
348 }
Amith Yamasania90b7f02010-08-25 18:27:20 -0700349 case DO_SET_COMPOSING_REGION: {
350 InputConnection ic = mInputConnection.get();
351 if (ic == null || !isActive()) {
352 Log.w(TAG, "setComposingRegion on inactive InputConnection");
353 return;
354 }
355 ic.setComposingRegion(msg.arg1, msg.arg2);
356 return;
357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 case DO_FINISH_COMPOSING_TEXT: {
359 InputConnection ic = mInputConnection.get();
360 // Note we do NOT check isActive() here, because this is safe
361 // for an IME to call at any time, and we need to allow it
362 // through to clean up our state after the IME has switched to
363 // another client.
364 if (ic == null) {
365 Log.w(TAG, "finishComposingText on inactive InputConnection");
366 return;
367 }
368 ic.finishComposingText();
369 return;
370 }
371 case DO_SEND_KEY_EVENT: {
372 InputConnection ic = mInputConnection.get();
373 if (ic == null || !isActive()) {
374 Log.w(TAG, "sendKeyEvent on inactive InputConnection");
375 return;
376 }
377 ic.sendKeyEvent((KeyEvent)msg.obj);
378 return;
379 }
380 case DO_CLEAR_META_KEY_STATES: {
381 InputConnection ic = mInputConnection.get();
382 if (ic == null || !isActive()) {
383 Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
384 return;
385 }
386 ic.clearMetaKeyStates(msg.arg1);
387 return;
388 }
389 case DO_DELETE_SURROUNDING_TEXT: {
390 InputConnection ic = mInputConnection.get();
391 if (ic == null || !isActive()) {
392 Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
393 return;
394 }
395 ic.deleteSurroundingText(msg.arg1, msg.arg2);
396 return;
397 }
Yohei Yukawac89e22a2016-01-13 22:48:14 -0800398 case DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
399 InputConnection ic = mInputConnection.get();
400 if (ic == null || !isActive()) {
401 Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
402 return;
403 }
404 ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
405 return;
406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 case DO_BEGIN_BATCH_EDIT: {
408 InputConnection ic = mInputConnection.get();
409 if (ic == null || !isActive()) {
410 Log.w(TAG, "beginBatchEdit on inactive InputConnection");
411 return;
412 }
413 ic.beginBatchEdit();
414 return;
415 }
416 case DO_END_BATCH_EDIT: {
417 InputConnection ic = mInputConnection.get();
418 if (ic == null || !isActive()) {
419 Log.w(TAG, "endBatchEdit on inactive InputConnection");
420 return;
421 }
422 ic.endBatchEdit();
423 return;
424 }
425 case DO_REPORT_FULLSCREEN_MODE: {
426 InputConnection ic = mInputConnection.get();
Andrei Stingaceanuda589df2015-06-17 10:38:08 +0100427 if (ic == null) {
428 Log.w(TAG, "reportFullscreenMode on inexistent InputConnection");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 return;
430 }
431 ic.reportFullscreenMode(msg.arg1 == 1);
432 return;
433 }
434 case DO_PERFORM_PRIVATE_COMMAND: {
435 InputConnection ic = mInputConnection.get();
436 if (ic == null || !isActive()) {
437 Log.w(TAG, "performPrivateCommand on inactive InputConnection");
438 return;
439 }
440 SomeArgs args = (SomeArgs)msg.obj;
441 ic.performPrivateCommand((String)args.arg1,
442 (Bundle)args.arg2);
443 return;
444 }
Yohei Yukawaa277db22014-08-21 18:38:44 -0700445 case DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO: {
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900446 SomeArgs args = (SomeArgs)msg.obj;
447 try {
448 InputConnection ic = mInputConnection.get();
449 if (ic == null || !isActive()) {
450 Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
Yohei Yukawaa277db22014-08-21 18:38:44 -0700451 args.callback.setRequestUpdateCursorAnchorInfoResult(false, args.seq);
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900452 return;
453 }
Yohei Yukawaa277db22014-08-21 18:38:44 -0700454 args.callback.setRequestUpdateCursorAnchorInfoResult(
Yohei Yukawad8636ea2014-09-02 22:03:30 -0700455 ic.requestCursorUpdates(msg.arg1), args.seq);
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900456 } catch (RemoteException e) {
457 Log.w(TAG, "Got RemoteException calling requestCursorAnchorInfo", e);
458 }
459 return;
460 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 }
462 Log.w(TAG, "Unhandled message code: " + msg.what);
463 }
464
465 Message obtainMessage(int what) {
466 return mH.obtainMessage(what);
467 }
468
469 Message obtainMessageII(int what, int arg1, int arg2) {
470 return mH.obtainMessage(what, arg1, arg2);
471 }
Yohei Yukawac89e22a2016-01-13 22:48:14 -0800472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 Message obtainMessageO(int what, Object arg1) {
474 return mH.obtainMessage(what, 0, 0, arg1);
475 }
476
477 Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) {
478 SomeArgs args = new SomeArgs();
479 args.callback = callback;
480 args.seq = seq;
481 return mH.obtainMessage(what, arg1, 0, args);
482 }
483
484 Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) {
485 SomeArgs args = new SomeArgs();
486 args.callback = callback;
487 args.seq = seq;
488 return mH.obtainMessage(what, arg1, arg2, args);
489 }
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900490
491 Message obtainMessageOSC(int what, Object arg1, int seq, IInputContextCallback callback) {
492 SomeArgs args = new SomeArgs();
493 args.arg1 = arg1;
494 args.callback = callback;
495 args.seq = seq;
496 return mH.obtainMessage(what, 0, 0, args);
497 }
498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
500 IInputContextCallback callback) {
501 SomeArgs args = new SomeArgs();
502 args.arg1 = arg2;
503 args.callback = callback;
504 args.seq = seq;
505 return mH.obtainMessage(what, arg1, 0, args);
506 }
507
508 Message obtainMessageIO(int what, int arg1, Object arg2) {
509 return mH.obtainMessage(what, arg1, 0, arg2);
510 }
511
512 Message obtainMessageOO(int what, Object arg1, Object arg2) {
513 SomeArgs args = new SomeArgs();
514 args.arg1 = arg1;
515 args.arg2 = arg2;
516 return mH.obtainMessage(what, 0, 0, args);
517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518}