OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.content.browser.input; | |
6 | |
7 import android.os.Bundle; | |
8 import android.os.Handler; | |
9 import android.os.Looper; | |
10 import android.view.KeyCharacterMap; | |
11 import android.view.KeyEvent; | |
12 import android.view.inputmethod.CompletionInfo; | |
13 import android.view.inputmethod.CorrectionInfo; | |
14 import android.view.inputmethod.EditorInfo; | |
15 import android.view.inputmethod.ExtractedText; | |
16 import android.view.inputmethod.ExtractedTextRequest; | |
17 import android.view.inputmethod.InputConnection; | |
18 | |
19 import org.chromium.base.Log; | |
20 import org.chromium.base.ThreadUtils; | |
21 import org.chromium.base.VisibleForTesting; | |
22 | |
23 import java.util.concurrent.BlockingQueue; | |
24 import java.util.concurrent.LinkedBlockingQueue; | |
25 | |
26 /** | |
27 * An implementation of {@link InputConnection} to communicate with external inp ut method | |
28 * apps. Note that it is running on IME thread (except for constructor and calls from ImeAdapter) | |
29 * such that it does not block UI thread and returns text values immediately aft er any change | |
30 * to them. | |
31 */ | |
32 public class ThreadedInputConnection implements ChromiumBaseInputConnection { | |
33 private static final String TAG = "cr_Ime"; | |
34 private static final boolean DEBUG_LOGS = false; | |
35 | |
36 private static final TextInputState UNBLOCKER = new TextInputState( | |
37 "", new Range(0, 0), new Range(-1, -1), false, false /* notFromIme * /) { | |
38 | |
39 @Override | |
40 public boolean shouldUnblock() { | |
41 return true; | |
42 } | |
43 }; | |
44 | |
45 private final ImeAdapter mImeAdapter; | |
46 private final Handler mHandler; | |
47 private int mNumNestedBatchEdits; | |
48 | |
49 // TODO(changwan): check if we can keep a pool of TextInputState to avoid cr eating | |
50 // a bunch of new objects for each key stroke. | |
51 private final BlockingQueue<TextInputState> mQueue = new LinkedBlockingQueue <>(); | |
52 private int mPendingAccent; | |
53 // This should be accessed on UI thread. | |
54 private TextInputState mLastUpdatedTextInputState; | |
55 | |
56 ThreadedInputConnection(ImeAdapter imeAdapter, Handler handler) { | |
57 if (DEBUG_LOGS) Log.w(TAG, "constructor"); | |
58 ImeUtils.checkOnUiThread(); | |
59 mImeAdapter = imeAdapter; | |
60 mHandler = handler; | |
Ted C
2016/02/17 19:09:34
should we add an assert that handler.getLooper() !
Changwan Ryu
2016/02/18 06:03:27
Done.
Changwan Ryu
2016/02/18 10:38:42
Hmmm.. Actually ThreadedInputConnectionTest is usi
| |
61 } | |
62 | |
63 void initializeOutAttrsOnUiThread(int inputType, int inputFlags, EditorInfo outAttrs) { | |
64 if (DEBUG_LOGS) Log.w(TAG, "initializeOutAttrs"); | |
65 ImeUtils.checkOnUiThread(); | |
66 int initialSelStart = 0; | |
67 int initialSelEnd = 0; | |
68 mNumNestedBatchEdits = 0; | |
69 mPendingAccent = 0; | |
70 if (mLastUpdatedTextInputState != null) { | |
71 initialSelStart = mLastUpdatedTextInputState.selection().start(); | |
72 initialSelEnd = mLastUpdatedTextInputState.selection().end(); | |
73 } | |
74 ImeUtils.computeEditorInfo(inputType, inputFlags, initialSelStart, initi alSelEnd, outAttrs); | |
75 } | |
76 | |
77 @Override | |
78 public void updateStateOnUiThread(final String text, final int selectionStar t, | |
79 final int selectionEnd, final int compositionStart, final int compos itionEnd, | |
80 boolean singleLine, final boolean isNonImeChange) { | |
81 ImeUtils.checkOnUiThread(); | |
82 | |
83 final TextInputState newState = | |
84 new TextInputState(text, new Range(selectionStart, selectionEnd) , | |
85 new Range(compositionStart, compositionEnd), singleLine, !isNonImeChange); | |
86 if (DEBUG_LOGS) Log.w(TAG, "updateState: %s", newState); | |
87 mLastUpdatedTextInputState = newState; | |
88 | |
89 addToQueueOnUiThread(newState); | |
90 if (isNonImeChange) { | |
91 mHandler.post(new Runnable() { | |
Ted C
2016/02/17 19:09:34
You can probably keep a single one of these runnab
Changwan Ryu
2016/02/18 06:03:26
Done.
| |
92 @Override | |
93 public void run() { | |
94 checkQueue(); | |
95 } | |
96 }); | |
97 } | |
98 } | |
99 | |
100 /** | |
101 * @see ChromiumBaseInputConnection#getHandler() | |
102 */ | |
103 @Override | |
104 public Handler getHandler() { | |
105 return mHandler; | |
106 } | |
107 | |
108 /** | |
109 * @see ChromiumBaseInputConnection#onRestartInputOnUiThread() | |
110 */ | |
111 @Override | |
112 public void onRestartInputOnUiThread() {} | |
113 | |
114 /** | |
115 * @see ChromiumBaseInputConnection#sendKeyEventOnUiThread(KeyEvent) | |
116 */ | |
117 @Override | |
118 public boolean sendKeyEventOnUiThread(final KeyEvent event) { | |
119 ImeUtils.checkOnUiThread(); | |
120 mHandler.post(new Runnable() { | |
121 @Override | |
122 public void run() { | |
123 sendKeyEvent(event); | |
124 } | |
125 }); | |
126 return true; | |
127 } | |
128 | |
129 /** | |
130 * @see ChromiumBaseInputConnection#moveCursorToSelectionEndOnUiThread() | |
131 */ | |
132 @Override | |
133 public void moveCursorToSelectionEndOnUiThread() { | |
134 mHandler.post(new Runnable() { | |
135 @Override | |
136 public void run() { | |
137 TextInputState textInputState = requestTextInputState(); | |
138 if (textInputState == null) return; | |
139 Range selection = textInputState.selection(); | |
140 setSelection(selection.end(), selection.end()); | |
141 } | |
142 }); | |
143 } | |
144 | |
145 @Override | |
146 @VisibleForTesting | |
147 public void unblockOnUiThread() { | |
148 if (DEBUG_LOGS) Log.w(TAG, "unblockOnUiThread"); | |
149 ImeUtils.checkOnUiThread(); | |
150 addToQueueOnUiThread(UNBLOCKER); | |
151 mHandler.post(new Runnable() { | |
152 @Override | |
153 public void run() { | |
154 checkQueue(); | |
155 } | |
156 }); | |
157 } | |
158 | |
159 private void checkQueue() { | |
Ted C
2016/02/17 19:09:34
this is more about emptying the queue than checkin
Changwan Ryu
2016/02/18 06:03:27
Done.
| |
160 if (DEBUG_LOGS) Log.w(TAG, "checkQueue"); | |
161 assertOnImeThread(); | |
162 // Handle all the remaining states in the queue. | |
163 while (true) { | |
164 TextInputState state = mQueue.peek(); | |
Ted C
2016/02/17 19:09:34
just use poll() here and delete the line below. p
Changwan Ryu
2016/02/18 06:03:26
Done.
| |
165 if (state == null) { | |
166 if (DEBUG_LOGS) Log.w(TAG, "checkQueue - finished"); | |
167 return; | |
168 } | |
169 mQueue.poll(); | |
170 if (DEBUG_LOGS) Log.w(TAG, "checkQueue: " + state); | |
171 // Unblocker was not used. Ignore. | |
172 if (state.shouldUnblock()) { | |
173 if (DEBUG_LOGS) Log.w(TAG, "checkQueue - ignoring one unblocker" ); | |
174 continue; | |
175 } | |
176 ImeUtils.checkCondition(!state.fromIme()); | |
177 updateSelection(state); | |
178 } | |
179 } | |
180 | |
181 private void updateSelection(TextInputState textInputState) { | |
182 if (textInputState == null) return; | |
183 assertOnImeThread(); | |
184 if (mNumNestedBatchEdits != 0) return; | |
185 ImeUtils.checkCondition(textInputState != null); | |
Ted C
2016/02/17 19:09:34
this seems unnecessary w/ regards to line 182
Changwan Ryu
2016/02/18 06:03:26
Done.
| |
186 Range selection = textInputState.selection(); | |
187 Range composition = textInputState.composition(); | |
188 mImeAdapter.updateSelection( | |
189 selection.start(), selection.end(), composition.start(), composi tion.end()); | |
190 } | |
191 | |
192 private TextInputState requestTextInputState() { | |
Ted C
2016/02/17 19:09:34
I "might" suffix this with Blocking as it will wai
Changwan Ryu
2016/02/18 06:03:26
Changed name as requestAndWaitForTextInputState.
| |
193 if (DEBUG_LOGS) Log.w(TAG, "requestTextInputState"); | |
194 ThreadUtils.postOnUiThread(new Runnable() { | |
195 @Override | |
196 public void run() { | |
197 boolean result = mImeAdapter.requestTextInputStateUpdate(); | |
198 if (!result) unblockOnUiThread(); | |
199 } | |
200 }); | |
201 return blockAndGetStateUpdate(); | |
202 } | |
203 | |
204 private void addToQueueOnUiThread(TextInputState textInputState) { | |
205 ImeUtils.checkOnUiThread(); | |
206 try { | |
207 mQueue.put(textInputState); | |
208 } catch (InterruptedException e) { | |
209 Log.e(TAG, "addToQueueOnUiThread interrupted", e); | |
210 } | |
211 if (DEBUG_LOGS) Log.w(TAG, "addToQueueOnUiThread finished: %d", mQueue.s ize()); | |
212 } | |
213 | |
214 /** | |
215 * @return BlockingQueue for white box unit testing. | |
216 */ | |
217 BlockingQueue<TextInputState> getQueueForTest() { | |
218 return mQueue; | |
219 } | |
220 | |
221 private void assertOnImeThread() { | |
222 ImeUtils.checkCondition(mHandler.getLooper() == Looper.myLooper()); | |
223 } | |
224 | |
225 /** | |
226 * Block until we get the expected state update. | |
227 * @return TextInputState if we get it successfully. null otherwise. | |
228 */ | |
229 private TextInputState blockAndGetStateUpdate() { | |
230 if (DEBUG_LOGS) Log.w(TAG, "blockAndGetStateUpdate"); | |
231 assertOnImeThread(); | |
232 boolean shouldUpdateSelection = false; | |
233 while (true) { | |
234 TextInputState state; | |
235 try { | |
236 state = mQueue.take(); | |
237 } catch (InterruptedException e) { | |
238 e.printStackTrace(); | |
239 return null; | |
Ted C
2016/02/17 19:09:34
I don't think you should quietly ignore this. If
Changwan Ryu
2016/02/18 06:03:26
Hmmm... IME thread is an artificial thread and cur
| |
240 } | |
241 if (state == null) return null; | |
Ted C
2016/02/17 19:09:34
can this be null? "seems" like take take() doesn'
Changwan Ryu
2016/02/18 06:03:26
No, it can't. Removed the line.
| |
242 if (state.shouldUnblock()) { | |
243 if (DEBUG_LOGS) Log.w(TAG, "blockAndGetStateUpdate: unblocked"); | |
244 return null; | |
245 } else if (state.fromIme()) { | |
246 if (shouldUpdateSelection) updateSelection(state); | |
247 if (DEBUG_LOGS) Log.w(TAG, "blockAndGetStateUpdate done: %d", mQ ueue.size()); | |
248 return state; | |
249 } | |
250 // Ignore when state is not from IME, but make sure to update state when we handle | |
251 // state from IME. | |
252 shouldUpdateSelection = true; | |
Ted C
2016/02/17 19:09:34
What happens if there are no pending events from t
Changwan Ryu
2016/02/18 06:03:27
This should never happen in theory, but when it ha
| |
253 } | |
254 } | |
255 | |
256 private void notifyUserAction() { | |
257 ThreadUtils.postOnUiThread(new Runnable() { | |
258 @Override | |
259 public void run() { | |
260 mImeAdapter.notifyUserAction(); | |
261 } | |
262 }); | |
263 } | |
264 | |
265 /** | |
266 * @see InputConnection#setComposingText(java.lang.CharSequence, int) | |
267 */ | |
268 @Override | |
269 public boolean setComposingText(final CharSequence text, final int newCursor Position) { | |
270 if (DEBUG_LOGS) Log.w(TAG, "setComposingText [%s] [%d]", text, newCursor Position); | |
271 assertOnImeThread(); | |
272 cancelCombiningAccent(); | |
273 ThreadUtils.postOnUiThread(new Runnable() { | |
274 @Override | |
275 public void run() { | |
276 mImeAdapter.sendCompositionToNative(text, newCursorPosition, fal se); | |
277 } | |
278 }); | |
279 notifyUserAction(); | |
280 return true; | |
281 } | |
282 | |
283 /** | |
284 * @see InputConnection#commitText(java.lang.CharSequence, int) | |
285 */ | |
286 @Override | |
287 public boolean commitText(final CharSequence text, final int newCursorPositi on) { | |
288 if (DEBUG_LOGS) Log.w(TAG, "commitText [%s] [%d]", text, newCursorPositi on); | |
289 assertOnImeThread(); | |
290 cancelCombiningAccent(); | |
291 ThreadUtils.postOnUiThread(new Runnable() { | |
292 @Override | |
293 public void run() { | |
294 mImeAdapter.sendCompositionToNative(text, newCursorPosition, tex t.length() > 0); | |
295 } | |
296 }); | |
297 notifyUserAction(); | |
298 return true; | |
299 } | |
300 | |
301 /** | |
302 * @see InputConnection#performEditorAction(int) | |
303 */ | |
304 @Override | |
305 public boolean performEditorAction(final int actionCode) { | |
306 if (DEBUG_LOGS) Log.w(TAG, "performEditorAction [%d]", actionCode); | |
307 assertOnImeThread(); | |
308 ThreadUtils.postOnUiThread(new Runnable() { | |
309 @Override | |
310 public void run() { | |
311 mImeAdapter.performEditorAction(actionCode); | |
312 } | |
313 }); | |
314 return true; | |
315 } | |
316 | |
317 /** | |
318 * @see InputConnection#performContextMenuAction(int) | |
319 */ | |
320 @Override | |
321 public boolean performContextMenuAction(final int id) { | |
322 if (DEBUG_LOGS) Log.w(TAG, "performContextMenuAction [%d]", id); | |
323 assertOnImeThread(); | |
324 ThreadUtils.postOnUiThread(new Runnable() { | |
325 @Override | |
326 public void run() { | |
327 mImeAdapter.performContextMenuAction(id); | |
328 } | |
329 }); | |
330 return true; | |
331 } | |
332 | |
333 /** | |
334 * @see InputConnection#getExtractedText(android.view.inputmethod.ExtractedT extRequest, | |
335 * int) | |
Ted C
2016/02/17 19:09:34
this indenting looks wonky
Changwan Ryu
2016/02/18 06:03:27
Fixed
| |
336 */ | |
337 @Override | |
338 public ExtractedText getExtractedText(ExtractedTextRequest request, int flag s) { | |
339 if (DEBUG_LOGS) Log.w(TAG, "getExtractedText"); | |
340 assertOnImeThread(); | |
341 TextInputState textInputState = requestTextInputState(); | |
342 if (textInputState == null) return null; | |
343 ExtractedText extractedText = new ExtractedText(); | |
344 extractedText.text = textInputState.text(); | |
345 extractedText.partialEndOffset = textInputState.text().length(); | |
346 extractedText.selectionStart = textInputState.selection().start(); | |
347 extractedText.selectionEnd = textInputState.selection().end(); | |
348 extractedText.flags = textInputState.singleLine() ? ExtractedText.FLAG_S INGLE_LINE : 0; | |
349 return extractedText; | |
350 } | |
351 | |
352 /** | |
353 * @see InputConnection#beginBatchEdit() | |
354 */ | |
355 @Override | |
356 public boolean beginBatchEdit() { | |
357 if (DEBUG_LOGS) Log.w(TAG, "beginBatchEdit [%b]", (mNumNestedBatchEdits == 0)); | |
358 assertOnImeThread(); | |
359 mNumNestedBatchEdits++; | |
360 return true; | |
361 } | |
362 | |
363 /** | |
364 * @see InputConnection#endBatchEdit() | |
365 */ | |
366 @Override | |
367 public boolean endBatchEdit() { | |
368 assertOnImeThread(); | |
369 if (mNumNestedBatchEdits == 0) return false; | |
370 --mNumNestedBatchEdits; | |
371 if (DEBUG_LOGS) Log.w(TAG, "endBatchEdit [%b]", (mNumNestedBatchEdits == 0)); | |
372 if (mNumNestedBatchEdits == 0) { | |
373 updateSelection(requestTextInputState()); | |
374 } | |
375 return mNumNestedBatchEdits != 0; | |
376 } | |
377 | |
378 /** | |
379 * @see InputConnection#deleteSurroundingText(int, int) | |
380 */ | |
381 @Override | |
382 public boolean deleteSurroundingText(final int beforeLength, final int after Length) { | |
383 if (DEBUG_LOGS) Log.w(TAG, "deleteSurroundingText [%d %d]", beforeLength , afterLength); | |
384 assertOnImeThread(); | |
385 if (mPendingAccent != 0) { | |
386 finishComposingText(); | |
387 } | |
388 ThreadUtils.postOnUiThread(new Runnable() { | |
389 @Override | |
390 public void run() { | |
391 mImeAdapter.deleteSurroundingText(beforeLength, afterLength); | |
392 } | |
393 }); | |
394 return true; | |
395 } | |
396 | |
397 /** | |
398 * @see InputConnection#sendKeyEvent(android.view.KeyEvent) | |
399 */ | |
400 @Override | |
401 public boolean sendKeyEvent(final KeyEvent event) { | |
402 if (DEBUG_LOGS) Log.w(TAG, "sendKeyEvent [%d %d]", event.getAction(), ev ent.getKeyCode()); | |
403 assertOnImeThread(); | |
404 | |
405 if (handleCombiningAccent(event)) return true; | |
406 | |
407 ThreadUtils.postOnUiThread(new Runnable() { | |
408 @Override | |
409 public void run() { | |
410 mImeAdapter.sendKeyEvent(event); | |
411 } | |
412 }); | |
413 notifyUserAction(); | |
414 return true; | |
415 } | |
416 | |
417 private boolean handleCombiningAccent(final KeyEvent event) { | |
418 // TODO(changwan): this will break the current composition. check if we can | |
419 // implement it in the renderer instead. | |
420 int action = event.getAction(); | |
421 int unicodeChar = event.getUnicodeChar(); | |
422 | |
423 if (action != KeyEvent.ACTION_DOWN) return false; | |
424 if ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) != 0) { | |
425 int pendingAccent = unicodeChar & KeyCharacterMap.COMBINING_ACCENT_M ASK; | |
426 StringBuilder builder = new StringBuilder(); | |
427 builder.appendCodePoint(pendingAccent); | |
428 setComposingText(builder.toString(), 1); | |
429 mPendingAccent = pendingAccent; | |
430 return true; | |
431 } else if (mPendingAccent != 0 && unicodeChar != 0) { | |
432 int combined = KeyEvent.getDeadChar(mPendingAccent, unicodeChar); | |
433 if (combined != 0) { | |
434 StringBuilder builder = new StringBuilder(); | |
435 builder.appendCodePoint(combined); | |
436 commitText(builder.toString(), 1); | |
437 return true; | |
438 } | |
439 // Noncombinable character; commit the accent character and fall thr ough to sending | |
440 // the key event for the character afterwards. | |
441 finishComposingText(); | |
442 } | |
443 return false; | |
444 } | |
445 | |
446 private void cancelCombiningAccent() { | |
447 mPendingAccent = 0; | |
448 } | |
449 | |
450 /** | |
451 * Call finishComposingText on UI thread. | |
452 */ | |
453 public void finishComposingTextOnUiThread() { | |
454 if (DEBUG_LOGS) Log.w(TAG, "finishComposingTextOnUiThread"); | |
455 ThreadUtils.postOnUiThread(new Runnable() { | |
456 @Override | |
457 public void run() { | |
458 finishComposingText(); | |
459 } | |
460 }); | |
461 } | |
462 | |
463 /** | |
464 * @see InputConnection#finishComposingText() | |
465 */ | |
466 @Override | |
467 public boolean finishComposingText() { | |
468 if (DEBUG_LOGS) Log.w(TAG, "finishComposingText"); | |
469 Log.w(TAG, "called from: " + Thread.currentThread().getStackTrace()[3].g etMethodName()); | |
Ted C
2016/02/17 19:09:34
remove?
Changwan Ryu
2016/02/18 06:03:27
Done.
| |
470 cancelCombiningAccent(); | |
471 // This is the only function that may be called on UI thread because | |
472 // of direct calls from InputMethodManager. | |
473 ThreadUtils.postOnUiThread(new Runnable() { | |
474 @Override | |
475 public void run() { | |
476 mImeAdapter.finishComposingText(); | |
477 } | |
478 }); | |
479 return true; | |
480 } | |
481 | |
482 /** | |
483 * @see InputConnection#setSelection(int, int) | |
484 */ | |
485 @Override | |
486 public boolean setSelection(final int start, final int end) { | |
487 if (DEBUG_LOGS) Log.w(TAG, "setSelection [%d %d]", start, end); | |
488 assertOnImeThread(); | |
489 ThreadUtils.postOnUiThread(new Runnable() { | |
490 @Override | |
491 public void run() { | |
492 mImeAdapter.setEditableSelectionOffsets(start, end); | |
493 } | |
494 }); | |
495 return true; | |
496 } | |
497 | |
498 /** | |
499 * @see InputConnection#setComposingRegion(int, int) | |
500 */ | |
501 @Override | |
502 public boolean setComposingRegion(final int start, final int end) { | |
503 if (DEBUG_LOGS) Log.w(TAG, "setComposingRegion [%d %d]", start, end); | |
504 assertOnImeThread(); | |
505 ThreadUtils.postOnUiThread(new Runnable() { | |
506 @Override | |
507 public void run() { | |
508 mImeAdapter.setComposingRegion(start, end); | |
509 } | |
510 }); | |
511 return true; | |
512 } | |
513 | |
514 /** | |
515 * @see InputConnection#getTextBeforeCursor(int, int) | |
516 */ | |
517 @Override | |
518 public CharSequence getTextBeforeCursor(int maxChars, int flags) { | |
519 if (DEBUG_LOGS) Log.w(TAG, "getTextBeforeCursor [%d %x]", maxChars, flag s); | |
520 assertOnImeThread(); | |
521 TextInputState textInputState = requestTextInputState(); | |
522 if (textInputState == null) return null; | |
523 return textInputState.getTextBeforeSelection(maxChars); | |
524 } | |
525 | |
526 /** | |
527 * @see InputConnection#getTextAfterCursor(int, int) | |
528 */ | |
529 @Override | |
530 public CharSequence getTextAfterCursor(int maxChars, int flags) { | |
531 if (DEBUG_LOGS) Log.w(TAG, "getTextAfterCursor [%d %x]", maxChars, flags ); | |
532 assertOnImeThread(); | |
533 TextInputState textInputState = requestTextInputState(); | |
534 if (textInputState == null) return null; | |
535 return textInputState.getTextAfterSelection(maxChars); | |
536 } | |
537 | |
538 /** | |
539 * @see InputConnection#getSelectedText(int) | |
540 */ | |
541 @Override | |
542 public CharSequence getSelectedText(int flags) { | |
543 if (DEBUG_LOGS) Log.w(TAG, "getSelectedText [%x]", flags); | |
544 assertOnImeThread(); | |
545 TextInputState textInputState = requestTextInputState(); | |
546 if (textInputState == null) return null; | |
547 return textInputState.getSelectedText(); | |
548 } | |
549 | |
550 /** | |
551 * @see InputConnection#getCursorCapsMode(int) | |
552 */ | |
553 @Override | |
554 public int getCursorCapsMode(int reqModes) { | |
555 if (DEBUG_LOGS) Log.w(TAG, "getCursorCapsMode [%x]", reqModes); | |
556 assertOnImeThread(); | |
557 // TODO(changwan): Auto-generated method stub | |
Ted C
2016/02/17 19:09:34
remvoe these TODOs
Changwan Ryu
2016/02/18 06:03:26
Removed them and added a real TODO for getCursorCa
| |
558 return 0; | |
559 } | |
560 | |
561 /** | |
562 * @see InputConnection#commitCompletion(android.view.inputmethod.Completion Info) | |
563 */ | |
564 @Override | |
565 public boolean commitCompletion(CompletionInfo text) { | |
566 if (DEBUG_LOGS) Log.w(TAG, "commitCompletion [%s]", text); | |
567 assertOnImeThread(); | |
568 // TODO(changwan): Auto-generated method stub | |
569 return false; | |
570 } | |
571 | |
572 /** | |
573 * @see InputConnection#commitCorrection(android.view.inputmethod.Correction Info) | |
574 */ | |
575 @Override | |
576 public boolean commitCorrection(CorrectionInfo correctionInfo) { | |
577 if (DEBUG_LOGS) { | |
578 Log.w(TAG, "commitCorrection [%s]", ImeUtils.getCorrectInfoDebugStri ng(correctionInfo)); | |
579 } | |
580 assertOnImeThread(); | |
581 // TODO(changwan): Auto-generated method stub | |
582 return false; | |
583 } | |
584 | |
585 /** | |
586 * @see InputConnection#clearMetaKeyStates(int) | |
587 */ | |
588 @Override | |
589 public boolean clearMetaKeyStates(int states) { | |
590 if (DEBUG_LOGS) Log.w(TAG, "clearMetaKeyStates [%x]", states); | |
591 assertOnImeThread(); | |
592 // TODO(changwan): Auto-generated method stub | |
593 return false; | |
594 } | |
595 | |
596 /** | |
597 * @see InputConnection#reportFullscreenMode(boolean) | |
598 */ | |
599 @Override | |
600 public boolean reportFullscreenMode(boolean enabled) { | |
601 if (DEBUG_LOGS) Log.w(TAG, "reportFullscreenMode [%b]", enabled); | |
602 // We ignore fullscreen mode for now. That's why we set | |
603 // EditorInfo.IME_FLAG_NO_FULLSCREEN in constructor. | |
604 // Note that this may be called on UI thread. | |
605 return false; | |
606 } | |
607 | |
608 /** | |
609 * @see InputConnection#performPrivateCommand(java.lang.String, android.os.B undle) | |
610 */ | |
611 @Override | |
612 public boolean performPrivateCommand(String action, Bundle data) { | |
613 if (DEBUG_LOGS) Log.w(TAG, "performPrivateCommand [%s]", action); | |
614 assertOnImeThread(); | |
615 // TODO(changwan): Auto-generated method stub | |
616 return false; | |
617 } | |
618 | |
619 /** | |
620 * @see InputConnection#requestCursorUpdates(int) | |
621 */ | |
622 @Override | |
623 public boolean requestCursorUpdates(int cursorUpdateMode) { | |
624 if (DEBUG_LOGS) Log.w(TAG, "requestCursorUpdates [%x]", cursorUpdateMode ); | |
625 assertOnImeThread(); | |
626 // TODO(changwan): Auto-generated method stub | |
627 return false; | |
628 } | |
629 } | |
OLD | NEW |