OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.content.browser.input; | 5 package org.chromium.content.browser.input; |
6 | 6 |
7 import android.os.SystemClock; | 7 import android.os.SystemClock; |
8 import android.text.Editable; | 8 import android.text.Editable; |
9 import android.text.InputType; | 9 import android.text.InputType; |
10 import android.text.Selection; | 10 import android.text.Selection; |
11 import android.text.TextUtils; | |
12 import android.util.Log; | 11 import android.util.Log; |
13 import android.view.KeyEvent; | 12 import android.view.KeyEvent; |
14 import android.view.View; | 13 import android.view.View; |
15 import android.view.inputmethod.BaseInputConnection; | 14 import android.view.inputmethod.BaseInputConnection; |
16 import android.view.inputmethod.EditorInfo; | 15 import android.view.inputmethod.EditorInfo; |
17 import android.view.inputmethod.ExtractedText; | 16 import android.view.inputmethod.ExtractedText; |
18 import android.view.inputmethod.ExtractedTextRequest; | 17 import android.view.inputmethod.ExtractedTextRequest; |
19 | 18 |
20 import com.google.common.annotations.VisibleForTesting; | 19 import com.google.common.annotations.VisibleForTesting; |
21 | 20 |
(...skipping 17 matching lines...) Expand all Loading... | |
39 | 38 |
40 private boolean mSingleLine; | 39 private boolean mSingleLine; |
41 private int mNumNestedBatchEdits = 0; | 40 private int mNumNestedBatchEdits = 0; |
42 | 41 |
43 private int mLastUpdateSelectionStart = INVALID_SELECTION; | 42 private int mLastUpdateSelectionStart = INVALID_SELECTION; |
44 private int mLastUpdateSelectionEnd = INVALID_SELECTION; | 43 private int mLastUpdateSelectionEnd = INVALID_SELECTION; |
45 private int mLastUpdateCompositionStart = INVALID_COMPOSITION; | 44 private int mLastUpdateCompositionStart = INVALID_COMPOSITION; |
46 private int mLastUpdateCompositionEnd = INVALID_COMPOSITION; | 45 private int mLastUpdateCompositionEnd = INVALID_COMPOSITION; |
47 | 46 |
48 @VisibleForTesting | 47 @VisibleForTesting |
48 public int mUpdateStateCalls = 0; | |
49 | |
50 @VisibleForTesting | |
49 AdapterInputConnection(View view, ImeAdapter imeAdapter, Editable editable, | 51 AdapterInputConnection(View view, ImeAdapter imeAdapter, Editable editable, |
50 EditorInfo outAttrs) { | 52 EditorInfo outAttrs) { |
51 super(view, true); | 53 super(view, true); |
52 mInternalView = view; | 54 mInternalView = view; |
53 mImeAdapter = imeAdapter; | 55 mImeAdapter = imeAdapter; |
54 mImeAdapter.setInputConnection(this); | 56 mImeAdapter.setInputConnection(this); |
55 mEditable = editable; | 57 mEditable = editable; |
56 // The editable passed in might have been in use by a prior keyboard and could have had | 58 // The editable passed in might have been in use by a prior keyboard and could have had |
57 // prior composition spans set. To avoid keyboard conflicts, remove all composing spans | 59 // prior composition spans set. To avoid keyboard conflicts, remove all composing spans |
58 // when taking ownership of an existing Editable. | 60 // when taking ownership of an existing Editable. |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
132 * selection. | 134 * selection. |
133 * @param isNonImeChange True when the update was caused by non-IME (e.g. Ja vascript). | 135 * @param isNonImeChange True when the update was caused by non-IME (e.g. Ja vascript). |
134 */ | 136 */ |
135 @VisibleForTesting | 137 @VisibleForTesting |
136 public void updateState(String text, int selectionStart, int selectionEnd, i nt compositionStart, | 138 public void updateState(String text, int selectionStart, int selectionEnd, i nt compositionStart, |
137 int compositionEnd, boolean isNonImeChange) { | 139 int compositionEnd, boolean isNonImeChange) { |
138 if (DEBUG) { | 140 if (DEBUG) { |
139 Log.w(TAG, "updateState [" + text + "] [" + selectionStart + " " + s electionEnd + "] [" | 141 Log.w(TAG, "updateState [" + text + "] [" + selectionStart + " " + s electionEnd + "] [" |
140 + compositionStart + " " + compositionEnd + "] [" + isNonIme Change + "]"); | 142 + compositionStart + " " + compositionEnd + "] [" + isNonIme Change + "]"); |
141 } | 143 } |
144 mUpdateStateCalls++; | |
aurimas (slooooooooow)
2014/07/21 20:35:54
mUpdateStateCalls does not seem to be used. It if
bcwhite
2014/07/21 20:46:07
Done.
| |
145 | |
142 // If this update is from the IME, no further state modification is nece ssary because the | 146 // If this update is from the IME, no further state modification is nece ssary because the |
143 // state should have been updated already by the IM framework directly. | 147 // state should have been updated already by the IM framework directly. |
144 if (!isNonImeChange) return; | 148 if (!isNonImeChange) return; |
145 | 149 |
146 // Non-breaking spaces can cause the IME to get confused. Replace with n ormal spaces. | 150 // Non-breaking spaces can cause the IME to get confused. Replace with n ormal spaces. |
147 text = text.replace('\u00A0', ' '); | 151 text = text.replace('\u00A0', ' '); |
148 | 152 |
149 selectionStart = Math.min(selectionStart, text.length()); | 153 selectionStart = Math.min(selectionStart, text.length()); |
150 selectionEnd = Math.min(selectionEnd, text.length()); | 154 selectionEnd = Math.min(selectionEnd, text.length()); |
151 compositionStart = Math.min(compositionStart, text.length()); | 155 compositionStart = Math.min(compositionStart, text.length()); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
206 mLastUpdateCompositionStart = compositionStart; | 210 mLastUpdateCompositionStart = compositionStart; |
207 mLastUpdateCompositionEnd = compositionEnd; | 211 mLastUpdateCompositionEnd = compositionEnd; |
208 } | 212 } |
209 | 213 |
210 /** | 214 /** |
211 * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int) | 215 * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int) |
212 */ | 216 */ |
213 @Override | 217 @Override |
214 public boolean setComposingText(CharSequence text, int newCursorPosition) { | 218 public boolean setComposingText(CharSequence text, int newCursorPosition) { |
215 if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPos ition + "]"); | 219 if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPos ition + "]"); |
216 if (maybePerformEmptyCompositionWorkaround(text)) return true; | |
217 super.setComposingText(text, newCursorPosition); | 220 super.setComposingText(text, newCursorPosition); |
218 updateSelectionIfRequired(); | 221 updateSelectionIfRequired(); |
219 return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPos ition, false); | 222 return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPos ition, false); |
220 } | 223 } |
221 | 224 |
222 /** | 225 /** |
223 * @see BaseInputConnection#commitText(java.lang.CharSequence, int) | 226 * @see BaseInputConnection#commitText(java.lang.CharSequence, int) |
224 */ | 227 */ |
225 @Override | 228 @Override |
226 public boolean commitText(CharSequence text, int newCursorPosition) { | 229 public boolean commitText(CharSequence text, int newCursorPosition) { |
227 if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]"); | 230 if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]"); |
228 if (maybePerformEmptyCompositionWorkaround(text)) return true; | |
229 super.commitText(text, newCursorPosition); | 231 super.commitText(text, newCursorPosition); |
230 updateSelectionIfRequired(); | 232 updateSelectionIfRequired(); |
231 return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPos ition, | 233 return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPos ition, |
232 text.length() > 0); | 234 text.length() > 0); |
233 } | 235 } |
234 | 236 |
235 /** | 237 /** |
236 * @see BaseInputConnection#performEditorAction(int) | 238 * @see BaseInputConnection#performEditorAction(int) |
237 */ | 239 */ |
238 @Override | 240 @Override |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
453 if (b < 0) b = 0; | 455 if (b < 0) b = 0; |
454 if (a > textLength) a = textLength; | 456 if (a > textLength) a = textLength; |
455 if (b > textLength) b = textLength; | 457 if (b > textLength) b = textLength; |
456 | 458 |
457 if (a == b) { | 459 if (a == b) { |
458 removeComposingSpans(mEditable); | 460 removeComposingSpans(mEditable); |
459 } else { | 461 } else { |
460 super.setComposingRegion(a, b); | 462 super.setComposingRegion(a, b); |
461 } | 463 } |
462 updateSelectionIfRequired(); | 464 updateSelectionIfRequired(); |
463 return mImeAdapter.setComposingRegion(a, b); | 465 |
466 CharSequence regionText = null; | |
467 if (b > a) { | |
468 regionText = mEditable.subSequence(start, end); | |
469 } | |
470 return mImeAdapter.setComposingRegion(regionText, a, b); | |
464 } | 471 } |
465 | 472 |
466 boolean isActive() { | 473 boolean isActive() { |
467 return getInputMethodManagerWrapper().isActive(mInternalView); | 474 return getInputMethodManagerWrapper().isActive(mInternalView); |
468 } | 475 } |
469 | 476 |
470 private InputMethodManagerWrapper getInputMethodManagerWrapper() { | 477 private InputMethodManagerWrapper getInputMethodManagerWrapper() { |
471 return mImeAdapter.getInputMethodManagerWrapper(); | 478 return mImeAdapter.getInputMethodManagerWrapper(); |
472 } | 479 } |
473 | 480 |
474 /** | |
475 * This method works around the issue crbug.com/373934 where Blink does not cancel | |
476 * the composition when we send a commit with the empty text. | |
477 * | |
478 * TODO(aurimas) Remove this once crbug.com/373934 is fixed. | |
479 * | |
480 * @param text Text that software keyboard requested to commit. | |
481 * @return Whether the workaround was performed. | |
482 */ | |
483 private boolean maybePerformEmptyCompositionWorkaround(CharSequence text) { | |
aurimas (slooooooooow)
2014/07/21 20:21:57
Can we remove this workaround already? Does it wor
bcwhite
2014/07/21 20:27:18
Possibly, but I don't want to do that as part of t
aurimas (slooooooooow)
2014/07/21 20:35:54
Can you undo the removal of this call then?
| |
484 int selectionStart = Selection.getSelectionStart(mEditable); | |
485 int selectionEnd = Selection.getSelectionEnd(mEditable); | |
486 int compositionStart = getComposingSpanStart(mEditable); | |
487 int compositionEnd = getComposingSpanEnd(mEditable); | |
488 if (TextUtils.isEmpty(text) && (selectionStart == selectionEnd) | |
489 && compositionStart != INVALID_COMPOSITION | |
490 && compositionEnd != INVALID_COMPOSITION) { | |
491 beginBatchEdit(); | |
492 finishComposingText(); | |
493 int selection = Selection.getSelectionStart(mEditable); | |
494 deleteSurroundingText(selection - compositionStart, selection - comp ositionEnd); | |
495 endBatchEdit(); | |
496 return true; | |
497 } | |
498 return false; | |
499 } | |
500 | |
501 @VisibleForTesting | 481 @VisibleForTesting |
502 static class ImeState { | 482 static class ImeState { |
503 public final String text; | 483 public final String text; |
504 public final int selectionStart; | 484 public final int selectionStart; |
505 public final int selectionEnd; | 485 public final int selectionEnd; |
506 public final int compositionStart; | 486 public final int compositionStart; |
507 public final int compositionEnd; | 487 public final int compositionEnd; |
508 | 488 |
509 public ImeState(String text, int selectionStart, int selectionEnd, | 489 public ImeState(String text, int selectionStart, int selectionEnd, |
510 int compositionStart, int compositionEnd) { | 490 int compositionStart, int compositionEnd) { |
511 this.text = text; | 491 this.text = text; |
512 this.selectionStart = selectionStart; | 492 this.selectionStart = selectionStart; |
513 this.selectionEnd = selectionEnd; | 493 this.selectionEnd = selectionEnd; |
514 this.compositionStart = compositionStart; | 494 this.compositionStart = compositionStart; |
515 this.compositionEnd = compositionEnd; | 495 this.compositionEnd = compositionEnd; |
516 } | 496 } |
517 } | 497 } |
518 | 498 |
519 @VisibleForTesting | 499 @VisibleForTesting |
520 ImeState getImeStateForTesting() { | 500 ImeState getImeStateForTesting() { |
521 String text = mEditable.toString(); | 501 String text = mEditable.toString(); |
522 int selectionStart = Selection.getSelectionStart(mEditable); | 502 int selectionStart = Selection.getSelectionStart(mEditable); |
523 int selectionEnd = Selection.getSelectionEnd(mEditable); | 503 int selectionEnd = Selection.getSelectionEnd(mEditable); |
524 int compositionStart = getComposingSpanStart(mEditable); | 504 int compositionStart = getComposingSpanStart(mEditable); |
525 int compositionEnd = getComposingSpanEnd(mEditable); | 505 int compositionEnd = getComposingSpanEnd(mEditable); |
526 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd); | 506 return new ImeState(text, selectionStart, selectionEnd, compositionStart , compositionEnd); |
527 } | 507 } |
528 } | 508 } |
OLD | NEW |