Chromium Code Reviews| 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 |