CursorAnchorInfoTest.java revision b5268dcc17cd9ecb540b06ad59bd74188b57a069
1/*
2 * Copyright (C) 2014 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
17package android.os;
18
19import android.graphics.Matrix;
20import android.graphics.RectF;
21import android.test.InstrumentationTestCase;
22import android.test.suitebuilder.annotation.SmallTest;
23import android.text.TextUtils;
24import android.view.inputmethod.CursorAnchorInfo;
25import android.view.inputmethod.CursorAnchorInfo.Builder;
26
27public class CursorAnchorInfoTest extends InstrumentationTestCase {
28    // null represents a character that is invisible, for example because it's overlapped by some
29    // other UI elements.
30    private static final RectF[] MANY_RECTS = new RectF[] {
31            null,
32            new RectF(102.0f, 202.0f, 302.0f, 402.0f),
33            new RectF(103.0f, 203.0f, 303.0f, 403.0f),
34            new RectF(104.0f, 204.0f, 304.0f, 404.0f),
35            new RectF(105.0f, 205.0f, 305.0f, 405.0f),
36            new RectF(106.0f, 206.0f, 306.0f, 406.0f),
37            null,
38            new RectF(108.0f, 208.0f, 308.0f, 408.0f),
39            new RectF(109.0f, 209.0f, 309.0f, 409.0f),
40            new RectF(110.0f, 210.0f, 310.0f, 410.0f),
41            new RectF(111.0f, 211.0f, 311.0f, 411.0f),
42            new RectF(112.0f, 212.0f, 312.0f, 412.0f),
43            new RectF(113.0f, 213.0f, 313.0f, 413.0f),
44            new RectF(114.0f, 214.0f, 314.0f, 414.0f),
45            new RectF(115.0f, 215.0f, 315.0f, 415.0f),
46            new RectF(116.0f, 216.0f, 316.0f, 416.0f),
47            new RectF(117.0f, 217.0f, 317.0f, 417.0f),
48            null,
49            null,
50    };
51
52    @SmallTest
53    public void testBuilder() throws Exception {
54        final int SELECTION_START = 30;
55        final int SELECTION_END = 40;
56        final int COMPOSING_TEXT_START = 32;
57        final String COMPOSING_TEXT = "test";
58        final float INSERTION_MARKER_HORIZONTAL = 10.5f;
59        final float INSERTION_MARKER_TOP = 100.1f;
60        final float INSERTION_MARKER_BASELINE = 110.4f;
61        final float INSERTION_MARKER_BOTOM = 111.0f;
62        Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
63        TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
64
65        final Builder builder = new Builder();
66        builder.setSelectionRange(SELECTION_START, SELECTION_END)
67                .setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT)
68                .setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
69                        INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM)
70                .setMatrix(TRANSFORM_MATRIX);
71        for (int i = 0; i < MANY_RECTS.length; i++) {
72            final RectF rect = MANY_RECTS[i];
73            if (rect != null) {
74                builder.addCharacterRect(i, rect.left, rect.top, rect.right, rect.bottom);
75            }
76        }
77
78        final CursorAnchorInfo info = builder.build();
79        assertEquals(SELECTION_START, info.getSelectionStart());
80        assertEquals(SELECTION_END, info.getSelectionEnd());
81        assertEquals(COMPOSING_TEXT_START, info.getComposingTextStart());
82        assertTrue(TextUtils.equals(COMPOSING_TEXT, info.getComposingText()));
83        assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal());
84        assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop());
85        assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline());
86        assertEquals(INSERTION_MARKER_BOTOM, info.getInsertionMarkerBottom());
87        assertEquals(TRANSFORM_MATRIX, info.getMatrix());
88        for (int i = 0; i < MANY_RECTS.length; i++) {
89            final RectF rect = MANY_RECTS[i];
90            assertEquals(rect, info.getCharacterRect(i));
91        }
92
93        // Make sure that the builder can reproduce the same object.
94        final CursorAnchorInfo info2 = builder.build();
95        assertEquals(SELECTION_START, info2.getSelectionStart());
96        assertEquals(SELECTION_END, info2.getSelectionEnd());
97        assertEquals(COMPOSING_TEXT_START, info2.getComposingTextStart());
98        assertTrue(TextUtils.equals(COMPOSING_TEXT, info2.getComposingText()));
99        assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal());
100        assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop());
101        assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline());
102        assertEquals(INSERTION_MARKER_BOTOM, info2.getInsertionMarkerBottom());
103        assertEquals(TRANSFORM_MATRIX, info2.getMatrix());
104        for (int i = 0; i < MANY_RECTS.length; i++) {
105            final RectF rect = MANY_RECTS[i];
106            assertEquals(rect, info2.getCharacterRect(i));
107        }
108        assertEquals(info, info2);
109        assertEquals(info.hashCode(), info2.hashCode());
110
111        // Make sure that object can be marshaled via {@link Parsel}.
112        final CursorAnchorInfo info3 = cloneViaParcel(info2);
113        assertEquals(SELECTION_START, info3.getSelectionStart());
114        assertEquals(SELECTION_END, info3.getSelectionEnd());
115        assertEquals(COMPOSING_TEXT_START, info3.getComposingTextStart());
116        assertTrue(TextUtils.equals(COMPOSING_TEXT, info3.getComposingText()));
117        assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal());
118        assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop());
119        assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline());
120        assertEquals(INSERTION_MARKER_BOTOM, info3.getInsertionMarkerBottom());
121        assertEquals(TRANSFORM_MATRIX, info3.getMatrix());
122        for (int i = 0; i < MANY_RECTS.length; i++) {
123            final RectF rect = MANY_RECTS[i];
124            assertEquals(rect, info3.getCharacterRect(i));
125        }
126        assertEquals(info.hashCode(), info3.hashCode());
127
128        builder.reset();
129        final CursorAnchorInfo uninitializedInfo = builder.build();
130        assertEquals(-1, uninitializedInfo.getSelectionStart());
131        assertEquals(-1, uninitializedInfo.getSelectionEnd());
132        assertEquals(-1, uninitializedInfo.getComposingTextStart());
133        assertNull(uninitializedInfo.getComposingText());
134        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal());
135        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop());
136        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline());
137        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom());
138        assertEquals(Matrix.IDENTITY_MATRIX, uninitializedInfo.getMatrix());
139    }
140
141    @SmallTest
142    public void testMatrixIsCopied() throws Exception {
143        final Matrix MATRIX1 = new Matrix();
144        MATRIX1.setTranslate(10.0f, 20.0f);
145        final Matrix MATRIX2 = new Matrix();
146        MATRIX2.setTranslate(110.0f, 120.0f);
147        final Matrix MATRIX3 = new Matrix();
148        MATRIX3.setTranslate(210.0f, 220.0f);
149        final Matrix matrix = new Matrix();
150        final Builder builder = new Builder();
151
152        matrix.set(MATRIX1);
153        builder.setMatrix(matrix);
154        matrix.postRotate(90.0f);
155
156        final CursorAnchorInfo firstInstance = builder.build();
157        assertEquals(MATRIX1, firstInstance.getMatrix());
158        matrix.set(MATRIX2);
159        builder.setMatrix(matrix);
160        final CursorAnchorInfo secondInstance = builder.build();
161        assertEquals(MATRIX1, firstInstance.getMatrix());
162        assertEquals(MATRIX2, secondInstance.getMatrix());
163
164        matrix.set(MATRIX3);
165        assertEquals(MATRIX1, firstInstance.getMatrix());
166        assertEquals(MATRIX2, secondInstance.getMatrix());
167    }
168
169    @SmallTest
170    public void testMatrixIsRequired() throws Exception {
171        final int SELECTION_START = 30;
172        final int SELECTION_END = 40;
173        final int COMPOSING_TEXT_START = 32;
174        final String COMPOSING_TEXT = "test";
175        final float INSERTION_MARKER_HORIZONTAL = 10.5f;
176        final float INSERTION_MARKER_TOP = 100.1f;
177        final float INSERTION_MARKER_BASELINE = 110.4f;
178        final float INSERTION_MARKER_BOTOM = 111.0f;
179        Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
180        TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
181
182        final Builder builder = new Builder();
183        // Check twice to make sure if Builder#reset() works as expected.
184        for (int repeatCount = 0; repeatCount < 2; ++repeatCount) {
185            builder.setSelectionRange(SELECTION_START, SELECTION_END)
186                    .setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT);
187            try {
188                // Should succeed as coordinate transformation matrix is not required if no
189                // positional information is specified.
190                new Builder().build();
191            } catch (IllegalArgumentException ex) {
192                assertTrue(false);
193            }
194
195            builder.setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
196                    INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM);
197            try {
198                // Coordinate transformation matrix is required if no positional information is
199                // specified.
200                new Builder().build();
201            } catch (IllegalArgumentException ex) {
202                assertTrue(true);
203            }
204
205            builder.setMatrix(TRANSFORM_MATRIX);
206            try {
207                // Should succeed as coordinate transformation matrix is required.
208                new Builder().build();
209            } catch (IllegalArgumentException ex) {
210                assertTrue(false);
211            }
212
213            builder.reset();
214        }
215    }
216
217    @SmallTest
218    public void testBuilderAdd() throws Exception {
219        // A negative index should be rejected.
220        try {
221            new Builder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
222        } catch (IllegalArgumentException ex) {
223            assertTrue(true);
224        }
225    }
226
227    private static CursorAnchorInfo cloneViaParcel(final CursorAnchorInfo src) {
228        Parcel parcel = null;
229        try {
230            parcel = Parcel.obtain();
231            src.writeToParcel(parcel, 0);
232            parcel.setDataPosition(0);
233            return new CursorAnchorInfo(parcel);
234        } finally {
235            if (parcel != null) {
236                parcel.recycle();
237            }
238        }
239    }
240}
241