Index: content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java |
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..be18a330291ffab6a21ac6ade56d20c9ed68176b |
--- /dev/null |
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java |
@@ -0,0 +1,576 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.content.browser.input; |
+ |
+import android.graphics.Matrix; |
+import android.graphics.RectF; |
+import android.test.InstrumentationTestCase; |
+import android.test.suitebuilder.annotation.SmallTest; |
+import android.text.TextUtils; |
+import android.view.View; |
+ |
+import org.chromium.base.test.util.Feature; |
+import org.chromium.content.browser.RenderCoordinates; |
+import org.chromium.content.browser.test.util.TestCursorAnchorInfoWrapper; |
+import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper; |
+ |
+/** |
+ * Test for {@link CursorAnchorInfoController}. |
+ */ |
+public class CursorAnchorInfoControllerTest extends InstrumentationTestCase { |
+ |
+ public static final int CURSOR_UPDATE_IMMEDIATE = 1 << 0; |
+ public static final int CURSOR_UPDATE_MONITOR = 1 << 1; |
+ |
+ private static RenderCoordinates createRenderCoordinates(float deviceScaleFactor, |
+ float pageScaleFactor, float scrollXCss, float scrollYCss, float contentOffsetYPix) { |
+ RenderCoordinates renderCoordinates = new RenderCoordinates(); |
+ renderCoordinates.setFrameInfoForTest(deviceScaleFactor, pageScaleFactor, scrollXCss, |
+ scrollYCss, contentOffsetYPix); |
+ return renderCoordinates; |
+ } |
+ |
+ private static final class TestViewDelegate implements CursorAnchorInfoController.ViewDelegate { |
+ public int mLocationX; |
+ public int mLocationY; |
+ @Override |
+ public void getLocationOnScreen(View view, int[] location) { |
+ location[0] = mLocationX; |
+ location[1] = mLocationY; |
+ } |
+ } |
+ |
+ private void assertScaleAndTranslate(float expectedScale, float expectedTranslateX, |
+ float expectedTranslateY, CursorAnchorInfoWrapper actual) { |
+ Matrix expectedMatrix = new Matrix(); |
+ expectedMatrix.setScale(expectedScale, expectedScale); |
+ expectedMatrix.postTranslate(expectedTranslateX, expectedTranslateY); |
+ float[] expectedMatrixValues = new float[12]; |
+ expectedMatrix.getValues(expectedMatrixValues); |
+ float[] actualMatrixValues = new float[12]; |
+ actual.getMatrix().getValues(actualMatrixValues); |
+ for (int i = 0; i < expectedMatrixValues.length; ++i) { |
+ assertEquals(expectedMatrixValues[i], actualMatrixValues[i]); |
+ } |
+ } |
+ |
+ private void assertHasInsertionMarker(int expectedFlags, float expectedHorizontal, |
+ float expectedTop, float expectedBaseline, float expectedBottom, |
+ CursorAnchorInfoWrapper actual) { |
+ assertEquals(expectedFlags, actual.getInsertionMarkerFlags()); |
+ assertEquals(expectedHorizontal, actual.getInsertionMarkerHorizontal()); |
+ assertEquals(expectedTop, actual.getInsertionMarkerTop()); |
+ assertEquals(expectedBaseline, actual.getInsertionMarkerBaseline()); |
+ assertEquals(expectedBottom, actual.getInsertionMarkerBottom()); |
+ } |
+ |
+ private void assertHasNoInsertionMarker(CursorAnchorInfoWrapper actual) { |
+ assertEquals(0, actual.getInsertionMarkerFlags()); |
+ assertTrue(Float.isNaN(actual.getInsertionMarkerHorizontal())); |
+ assertTrue(Float.isNaN(actual.getInsertionMarkerTop())); |
+ assertTrue(Float.isNaN(actual.getInsertionMarkerBaseline())); |
+ assertTrue(Float.isNaN(actual.getInsertionMarkerBottom())); |
+ } |
+ |
+ private void assertComposingText(CharSequence expectedComposingText, |
+ int expectedComposingTextStart, CursorAnchorInfoWrapper actual) { |
+ assertTrue(TextUtils.equals(expectedComposingText, actual.getComposingText())); |
+ assertEquals(expectedComposingTextStart, actual.getComposingTextStart()); |
+ } |
+ |
+ private void assertSelection(int expecteSelectionStart, int expecteSelectionEnd, |
+ CursorAnchorInfoWrapper actual) { |
+ assertEquals(expecteSelectionStart, actual.getSelectionStart()); |
+ assertEquals(expecteSelectionEnd, actual.getSelectionEnd()); |
+ } |
+ |
+ private void assertEquals(RectF expectedRect, RectF actualRect) { |
+ if (expectedRect == null) { |
+ assertNull(actualRect); |
+ return; |
+ } |
+ assertNotNull(actualRect); |
+ assertEquals(actualRect.left, expectedRect.left); |
+ assertEquals(actualRect.top, expectedRect.top); |
+ assertEquals(actualRect.right, expectedRect.right); |
+ assertEquals(actualRect.bottom, expectedRect.bottom); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Input-Text-IME"}) |
+ public void testFocusedNodeChanged() { |
+ TestInputMethodManagerWrapper immw = |
+ new TestInputMethodManagerWrapper(null); |
+ TestViewDelegate viewDelegate = new TestViewDelegate(); |
+ TestCursorAnchorInfoWrapper.Builder builder = new TestCursorAnchorInfoWrapper.Builder(); |
+ CursorAnchorInfoController controller = CursorAnchorInfoController.createForTest( |
+ immw, builder, viewDelegate); |
+ View view = null; |
+ |
+ viewDelegate.mLocationX = 0; |
+ viewDelegate.mLocationY = 0; |
+ |
+ assertFalse( |
+ "IC#onRequestCursorUpdates() must be rejected if the focused node is not editable.", |
+ controller.onRequestCursorUpdates(CURSOR_UPDATE_MONITOR, view)); |
+ |
+ // Make sure that the focused node is considered to be non-editable by default. |
+ controller.setCompositionCharacterBounds(new float[]{0.0f, 1.0f, 2.0f, 3.0f}); |
+ controller.updateTextAndSelection("0", 0, 1, 0, 1); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(0, immw.getUpdateCursorAnchorInfoCounter()); |
+ |
+ controller.focusedNodeChanged(false); |
+ |
+ // Make sure that the controller does not crash even if it is called while the focused node |
+ // is not editable. |
+ controller.setCompositionCharacterBounds(new float[]{30.0f, 1.0f, 32.0f, 3.0f}); |
+ controller.updateTextAndSelection("1", 0, 1, 0, 1); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 2.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(0, immw.getUpdateCursorAnchorInfoCounter()); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Input-Text-IME"}) |
+ public void testImmediateMode() { |
+ TestInputMethodManagerWrapper immw = |
+ new TestInputMethodManagerWrapper(null); |
+ TestViewDelegate viewDelegate = new TestViewDelegate(); |
+ TestCursorAnchorInfoWrapper.Builder builder = new TestCursorAnchorInfoWrapper.Builder(); |
+ CursorAnchorInfoController controller = CursorAnchorInfoController.createForTest( |
+ immw, builder, viewDelegate); |
+ View view = null; |
+ viewDelegate.mLocationX = 0; |
+ viewDelegate.mLocationY = 0; |
+ |
+ controller.focusedNodeChanged(true); |
+ |
+ // Make sure that #updateCursorAnchorInfo() is not be called until the matrix info becomes |
+ // available with #onUpdateFrameInfo(). |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_IMMEDIATE, view)); |
+ controller.setCompositionCharacterBounds(new float[]{0.0f, 1.0f, 2.0f, 3.0f}); |
+ controller.updateTextAndSelection("0", 0, 1, 0, 1); |
+ assertEquals(0, immw.getUpdateCursorAnchorInfoCounter()); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(1.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(new RectF(0.0f, 1.0f, 2.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText("0", 0, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(0, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Make sure that 2nd call of #onUpdateFrameInfo() is ignored. |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 2.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); |
+ |
+ // Make sure that #onUpdateFrameInfo() is immediately called because the matrix info is |
+ // already available. |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_IMMEDIATE, view)); |
+ assertEquals(2, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(2.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(new RectF(0.0f, 1.0f, 2.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText("0", 0, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(0, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Make sure that CURSOR_UPDATE_IMMEDIATE and CURSOR_UPDATE_MONITOR can be specified at |
+ // the same time. |
+ assertTrue(controller.onRequestCursorUpdates( |
+ CURSOR_UPDATE_IMMEDIATE | CURSOR_UPDATE_MONITOR, view)); |
+ assertEquals(3, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(2.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(4, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(1.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(new RectF(0.0f, 1.0f, 2.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText("0", 0, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(0, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Make sure that CURSOR_UPDATE_IMMEDIATE is cleared if the focused node becomes |
+ // non-editable. |
+ controller.focusedNodeChanged(false); |
+ controller.focusedNodeChanged(true); |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_IMMEDIATE, view)); |
+ controller.focusedNodeChanged(false); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 2.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(4, immw.getUpdateCursorAnchorInfoCounter()); |
+ |
+ // Make sure that CURSOR_UPDATE_IMMEDIATE can be enabled again. |
+ controller.focusedNodeChanged(true); |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_IMMEDIATE, view)); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(5, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(1.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(null, immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(0, immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText(null, -1, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(-1, -1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Input-Text-IME"}) |
+ public void testMonitorMode() { |
+ TestInputMethodManagerWrapper immw = |
+ new TestInputMethodManagerWrapper(null); |
+ TestViewDelegate viewDelegate = new TestViewDelegate(); |
+ TestCursorAnchorInfoWrapper.Builder builder = new TestCursorAnchorInfoWrapper.Builder(); |
+ CursorAnchorInfoController controller = CursorAnchorInfoController.createForTest( |
+ immw, builder, viewDelegate); |
+ View view = null; |
+ viewDelegate.mLocationX = 0; |
+ viewDelegate.mLocationY = 0; |
+ |
+ controller.focusedNodeChanged(true); |
+ |
+ // Make sure that #updateCursorAnchorInfo() is not be called until the matrix info becomes |
+ // available with #onUpdateFrameInfo(). |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_MONITOR, view)); |
+ controller.setCompositionCharacterBounds(new float[]{0.0f, 1.0f, 2.0f, 3.0f}); |
+ controller.updateTextAndSelection("0", 0, 1, 0, 1); |
+ assertEquals(0, immw.getUpdateCursorAnchorInfoCounter()); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(1.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(new RectF(0.0f, 1.0f, 2.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText("0", 0, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(0, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Make sure that #updateCursorAnchorInfo() is not be called if any parameter is changed |
+ // for better performance. |
+ controller.setCompositionCharacterBounds(new float[]{0.0f, 1.0f, 2.0f, 3.0f}); |
+ controller.updateTextAndSelection("0", 0, 1, 0, 1); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); |
+ |
+ // Make sure that #updateCursorAnchorInfo() is called if #setCompositionCharacterBounds() |
+ // is called with a different parameter. |
+ controller.setCompositionCharacterBounds(new float[]{30.0f, 1.0f, 32.0f, 3.0f}); |
+ assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(2, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(1.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(new RectF(30.0f, 1.0f, 32.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText("0", 0, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(0, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Make sure that #updateCursorAnchorInfo() is called if #updateTextAndSelection() |
+ // is called with a different parameter. |
+ controller.updateTextAndSelection("1", 0, 1, 0, 1); |
+ assertEquals(2, immw.getUpdateCursorAnchorInfoCounter()); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(3, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(1.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(new RectF(30.0f, 1.0f, 32.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText("1", 0, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(0, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Make sure that #updateCursorAnchorInfo() is called if #onUpdateFrameInfo() |
+ // is called with a different parameter. |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 2.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(4, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(2.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(new RectF(30.0f, 1.0f, 32.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText("1", 0, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(0, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Make sure that #updateCursorAnchorInfo() is called when the view origin is changed. |
+ viewDelegate.mLocationX = 7; |
+ viewDelegate.mLocationY = 9; |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 2.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(5, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(2.0f, 7.0f, 9.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(new RectF(30.0f, 1.0f, 32.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText("1", 0, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(0, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Make sure that CURSOR_UPDATE_IMMEDIATE is cleared if the focused node becomes |
+ // non-editable. |
+ controller.focusedNodeChanged(false); |
+ controller.focusedNodeChanged(true); |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_MONITOR, view)); |
+ controller.focusedNodeChanged(false); |
+ controller.setCompositionCharacterBounds(new float[]{0.0f, 1.0f, 2.0f, 3.0f}); |
+ controller.updateTextAndSelection("0", 0, 1, 0, 1); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(5, immw.getUpdateCursorAnchorInfoCounter()); |
+ |
+ // Make sure that CURSOR_UPDATE_MONITOR can be enabled again. |
+ controller.focusedNodeChanged(true); |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_MONITOR, view)); |
+ controller.setCompositionCharacterBounds(new float[]{0.0f, 1.0f, 2.0f, 3.0f}); |
+ controller.updateTextAndSelection("0", 0, 1, 0, 1); |
+ assertEquals(5, immw.getUpdateCursorAnchorInfoCounter()); |
+ viewDelegate.mLocationX = 0; |
+ viewDelegate.mLocationY = 0; |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 2.0f, 0.0f, 3.0f, view); |
+ assertEquals(6, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(1.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, |
+ 3.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ assertEquals(new RectF(0.0f, 1.0f, 2.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertComposingText("0", 0, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(0, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Input-Text-IME"}) |
+ public void testSetCompositionCharacterBounds() { |
+ TestInputMethodManagerWrapper immw = |
+ new TestInputMethodManagerWrapper(null); |
+ TestViewDelegate viewDelegate = new TestViewDelegate(); |
+ TestCursorAnchorInfoWrapper.Builder builder = new TestCursorAnchorInfoWrapper.Builder(); |
+ CursorAnchorInfoController controller = CursorAnchorInfoController.createForTest( |
+ immw, builder, viewDelegate); |
+ View view = null; |
+ |
+ viewDelegate.mLocationX = 0; |
+ viewDelegate.mLocationY = 0; |
+ |
+ controller.focusedNodeChanged(true); |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_MONITOR, view)); |
+ |
+ controller.updateTextAndSelection("01234", 1, 3, 1, 1); |
+ controller.setCompositionCharacterBounds(new float[]{0.0f, 1.0f, 2.0f, 3.0f, |
+ 4.0f, 1.1f, 6.0f, 2.9f}); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ false, false, Float.NaN, Float.NaN, Float.NaN, view); |
+ assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertEquals(null, immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(0, immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertEquals(new RectF(0.0f, 1.0f, 2.0f, 3.0f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(1)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(1)); |
+ assertEquals(new RectF(4.0f, 1.1f, 6.0f, 2.9f), |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(2)); |
+ assertEquals(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(2)); |
+ assertEquals(null, immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(3)); |
+ assertEquals(0, immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(3)); |
+ assertComposingText("12", 1, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(1, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Input-Text-IME"}) |
+ public void testUpdateTextAndSelection() { |
+ TestInputMethodManagerWrapper immw = |
+ new TestInputMethodManagerWrapper(null); |
+ TestViewDelegate viewDelegate = new TestViewDelegate(); |
+ TestCursorAnchorInfoWrapper.Builder builder = new TestCursorAnchorInfoWrapper.Builder(); |
+ CursorAnchorInfoController controller = CursorAnchorInfoController.createForTest( |
+ immw, builder, viewDelegate); |
+ View view = null; |
+ |
+ viewDelegate.mLocationX = 0; |
+ viewDelegate.mLocationY = 0; |
+ |
+ controller.focusedNodeChanged(true); |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_MONITOR, view)); |
+ |
+ controller.updateTextAndSelection("01234", 3, 3, 1, 1); |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ false, false, Float.NaN, Float.NaN, Float.NaN, view); |
+ assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertEquals(null, immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(0)); |
+ assertEquals(0, immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(0)); |
+ assertEquals(null, immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(1)); |
+ assertEquals(0, immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(1)); |
+ assertEquals(null, immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(2)); |
+ assertEquals(0, immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(2)); |
+ assertEquals(null, immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(3)); |
+ assertEquals(0, immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(3)); |
+ assertEquals(null, immw.getLastCursorAnchorInfoWrapper().getCharacterBounds(4)); |
+ assertEquals(0, immw.getLastCursorAnchorInfoWrapper().getCharacterBoundsFlags(4)); |
+ assertComposingText("", 3, immw.getLastCursorAnchorInfoWrapper()); |
+ assertSelection(1, 1, immw.getLastCursorAnchorInfoWrapper()); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Input-Text-IME"}) |
+ public void testInsertionMarker() { |
+ TestInputMethodManagerWrapper immw = |
+ new TestInputMethodManagerWrapper(null); |
+ TestViewDelegate viewDelegate = new TestViewDelegate(); |
+ TestCursorAnchorInfoWrapper.Builder builder = new TestCursorAnchorInfoWrapper.Builder(); |
+ CursorAnchorInfoController controller = CursorAnchorInfoController.createForTest( |
+ immw, builder, viewDelegate); |
+ View view = null; |
+ |
+ controller.focusedNodeChanged(true); |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_MONITOR, view)); |
+ |
+ // Test no insertion marker. |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ false, false, Float.NaN, Float.NaN, Float.NaN, view); |
+ assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertHasNoInsertionMarker(immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Test a visible insertion marker. |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, true, 10.0f, 23.0f, 29.0f, view); |
+ assertEquals(2, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_VISIBLE_REGION, |
+ 10.0f, 23.0f, 29.0f, 29.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // Test a invisible insertion marker. |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ true, false, 10.0f, 23.0f, 29.0f, view); |
+ assertEquals(3, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertHasInsertionMarker(CursorAnchorInfoWrapper.FLAG_HAS_INVISIBLE_REGION, |
+ 10.0f, 23.0f, 29.0f, 29.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Input-Text-IME"}) |
+ public void testMatrix() { |
+ TestInputMethodManagerWrapper immw = |
+ new TestInputMethodManagerWrapper(null); |
+ TestViewDelegate viewDelegate = new TestViewDelegate(); |
+ TestCursorAnchorInfoWrapper.Builder builder = new TestCursorAnchorInfoWrapper.Builder(); |
+ CursorAnchorInfoController controller = CursorAnchorInfoController.createForTest( |
+ immw, builder, viewDelegate); |
+ View view = null; |
+ |
+ controller.focusedNodeChanged(true); |
+ assertTrue(controller.onRequestCursorUpdates(CURSOR_UPDATE_MONITOR, view)); |
+ |
+ // Test no transformation |
+ viewDelegate.mLocationX = 0; |
+ viewDelegate.mLocationY = 0; |
+ controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ false, false, Float.NaN, Float.NaN, Float.NaN, view); |
+ assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(1.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // device scale factor == 2.0 |
+ viewDelegate.mLocationX = 0; |
+ viewDelegate.mLocationY = 0; |
+ controller.onUpdateFrameInfo(createRenderCoordinates(2.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ false, false, Float.NaN, Float.NaN, Float.NaN, view); |
+ assertEquals(2, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(2.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // device scale factor == 2.0 |
+ // view origin == (10, 141) |
+ viewDelegate.mLocationX = 10; |
+ viewDelegate.mLocationY = 141; |
+ controller.onUpdateFrameInfo(createRenderCoordinates(2.0f, 1.0f, 0.0f, 0.0f, 0.0f), |
+ false, false, Float.NaN, Float.NaN, Float.NaN, view); |
+ assertEquals(3, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(2.0f, 10.0f, 141.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // device scale factor == 2.0 |
+ // root scroll offset == (1.0f, 2.0f) |
+ // view origin == (10, 141) |
+ viewDelegate.mLocationX = 10; |
+ viewDelegate.mLocationY = 141; |
+ controller.onUpdateFrameInfo(createRenderCoordinates(2.0f, 1.0f, 1.0f, 2.0f, 0.0f), |
+ false, false, Float.NaN, Float.NaN, Float.NaN, view); |
+ assertEquals(4, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(2.0f, 8.0f, 137.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // device scale factor == 2.0 |
+ // page scale factor == 3.0f |
+ // root scroll offset == (1.0f, 2.0f) |
+ // view origin == (10, 141) |
+ viewDelegate.mLocationX = 10; |
+ viewDelegate.mLocationY = 141; |
+ controller.onUpdateFrameInfo(createRenderCoordinates(2.0f, 3.0f, 1.0f, 2.0f, 0.0f), |
+ false, false, Float.NaN, Float.NaN, Float.NaN, view); |
+ assertEquals(5, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(6.0f, 4.0f, 129.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ |
+ // device scale factor == 2.0 |
+ // page scale factor == 3.0f |
+ // root scroll offset == (1.0f, 2.0f) |
+ // content offset Y = 40.0f |
+ // view origin == (10, 141) |
+ viewDelegate.mLocationX = 10; |
+ viewDelegate.mLocationY = 141; |
+ controller.onUpdateFrameInfo(createRenderCoordinates(2.0f, 3.0f, 1.0f, 2.0f, 40.0f), |
+ false, false, Float.NaN, Float.NaN, Float.NaN, view); |
+ assertEquals(6, immw.getUpdateCursorAnchorInfoCounter()); |
+ assertScaleAndTranslate(6.0f, 4.0f, 169.0f, immw.getLastCursorAnchorInfoWrapper()); |
+ immw.clearLastCursorAnchorInfoWrapper(); |
+ } |
+} |