CursorAnchorInfoTest.java revision a41c4bcc3dcac9e808c9d524e24454d132790e9a
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
27import java.util.Objects;
28
29import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
30import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
31import static android.view.inputmethod.CursorAnchorInfo.FLAG_IS_RTL;
32
33public class CursorAnchorInfoTest extends InstrumentationTestCase {
34    private static final RectF[] MANY_BOUNDS = new RectF[] {
35            new RectF(101.0f, 201.0f, 301.0f, 401.0f),
36            new RectF(102.0f, 202.0f, 302.0f, 402.0f),
37            new RectF(103.0f, 203.0f, 303.0f, 403.0f),
38            new RectF(104.0f, 204.0f, 304.0f, 404.0f),
39            new RectF(105.0f, 205.0f, 305.0f, 405.0f),
40            new RectF(106.0f, 206.0f, 306.0f, 406.0f),
41            new RectF(107.0f, 207.0f, 307.0f, 407.0f),
42            new RectF(108.0f, 208.0f, 308.0f, 408.0f),
43            new RectF(109.0f, 209.0f, 309.0f, 409.0f),
44            new RectF(110.0f, 210.0f, 310.0f, 410.0f),
45            new RectF(111.0f, 211.0f, 311.0f, 411.0f),
46            new RectF(112.0f, 212.0f, 312.0f, 412.0f),
47            new RectF(113.0f, 213.0f, 313.0f, 413.0f),
48            new RectF(114.0f, 214.0f, 314.0f, 414.0f),
49            new RectF(115.0f, 215.0f, 315.0f, 415.0f),
50            new RectF(116.0f, 216.0f, 316.0f, 416.0f),
51            new RectF(117.0f, 217.0f, 317.0f, 417.0f),
52            new RectF(118.0f, 218.0f, 318.0f, 418.0f),
53            new RectF(119.0f, 219.0f, 319.0f, 419.0f),
54    };
55    private static final int[] MANY_FLAGS_ARRAY = new int[] {
56        FLAG_HAS_INVISIBLE_REGION,
57        FLAG_HAS_INVISIBLE_REGION | FLAG_HAS_VISIBLE_REGION,
58        FLAG_HAS_VISIBLE_REGION,
59        FLAG_HAS_VISIBLE_REGION,
60        FLAG_HAS_VISIBLE_REGION,
61        FLAG_HAS_VISIBLE_REGION,
62        FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
63        FLAG_HAS_INVISIBLE_REGION | FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
64        FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL,
65        FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
66        FLAG_HAS_VISIBLE_REGION,
67        FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
68        FLAG_HAS_VISIBLE_REGION,
69        FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
70        FLAG_HAS_VISIBLE_REGION,
71        FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
72        FLAG_HAS_VISIBLE_REGION,
73        FLAG_HAS_INVISIBLE_REGION,
74        FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL,
75    };
76
77    @SmallTest
78    public void testBuilder() throws Exception {
79        final int SELECTION_START = 30;
80        final int SELECTION_END = 40;
81        final int COMPOSING_TEXT_START = 32;
82        final String COMPOSING_TEXT = "test";
83        final int INSERTION_MARKER_FLAGS =
84                FLAG_HAS_VISIBLE_REGION | FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL;
85        final float INSERTION_MARKER_HORIZONTAL = 10.5f;
86        final float INSERTION_MARKER_TOP = 100.1f;
87        final float INSERTION_MARKER_BASELINE = 110.4f;
88        final float INSERTION_MARKER_BOTOM = 111.0f;
89
90        Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
91        TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
92
93        final Builder builder = new Builder();
94        builder.setSelectionRange(SELECTION_START, SELECTION_END)
95                .setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT)
96                .setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
97                        INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM, INSERTION_MARKER_FLAGS)
98                .setMatrix(TRANSFORM_MATRIX);
99        for (int i = 0; i < MANY_BOUNDS.length; i++) {
100            final RectF bounds = MANY_BOUNDS[i];
101            final int flags = MANY_FLAGS_ARRAY[i];
102            builder.addCharacterBounds(i, bounds.left, bounds.top, bounds.right, bounds.bottom,
103                    flags);
104        }
105
106        final CursorAnchorInfo info = builder.build();
107        assertEquals(SELECTION_START, info.getSelectionStart());
108        assertEquals(SELECTION_END, info.getSelectionEnd());
109        assertEquals(COMPOSING_TEXT_START, info.getComposingTextStart());
110        assertTrue(TextUtils.equals(COMPOSING_TEXT, info.getComposingText()));
111        assertEquals(INSERTION_MARKER_FLAGS, info.getInsertionMarkerFlags());
112        assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal());
113        assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop());
114        assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline());
115        assertEquals(INSERTION_MARKER_BOTOM, info.getInsertionMarkerBottom());
116        assertEquals(TRANSFORM_MATRIX, info.getMatrix());
117        for (int i = 0; i < MANY_BOUNDS.length; i++) {
118            final RectF expectedBounds = MANY_BOUNDS[i];
119            assertEquals(expectedBounds, info.getCharacterRect(i));
120        }
121        assertNull(info.getCharacterRect(-1));
122        assertNull(info.getCharacterRect(MANY_BOUNDS.length + 1));
123        for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) {
124            final int expectedFlags = MANY_FLAGS_ARRAY[i];
125            assertEquals(expectedFlags, info.getCharacterRectFlags(i));
126        }
127        assertEquals(0, info.getCharacterRectFlags(-1));
128        assertEquals(0, info.getCharacterRectFlags(MANY_BOUNDS.length + 1));
129
130        // Make sure that the builder can reproduce the same object.
131        final CursorAnchorInfo info2 = builder.build();
132        assertEquals(SELECTION_START, info2.getSelectionStart());
133        assertEquals(SELECTION_END, info2.getSelectionEnd());
134        assertEquals(COMPOSING_TEXT_START, info2.getComposingTextStart());
135        assertTrue(TextUtils.equals(COMPOSING_TEXT, info2.getComposingText()));
136        assertEquals(INSERTION_MARKER_FLAGS, info2.getInsertionMarkerFlags());
137        assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal());
138        assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop());
139        assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline());
140        assertEquals(INSERTION_MARKER_BOTOM, info2.getInsertionMarkerBottom());
141        assertEquals(TRANSFORM_MATRIX, info2.getMatrix());
142        for (int i = 0; i < MANY_BOUNDS.length; i++) {
143            final RectF expectedBounds = MANY_BOUNDS[i];
144            assertEquals(expectedBounds, info2.getCharacterRect(i));
145        }
146        assertNull(info2.getCharacterRect(-1));
147        assertNull(info2.getCharacterRect(MANY_BOUNDS.length + 1));
148        for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) {
149            final int expectedFlags = MANY_FLAGS_ARRAY[i];
150            assertEquals(expectedFlags, info2.getCharacterRectFlags(i));
151        }
152        assertEquals(0, info2.getCharacterRectFlags(-1));
153        assertEquals(0, info2.getCharacterRectFlags(MANY_BOUNDS.length + 1));
154        assertEquals(info, info2);
155        assertEquals(info.hashCode(), info2.hashCode());
156
157        // Make sure that object can be marshaled via {@link Parsel}.
158        final CursorAnchorInfo info3 = cloneViaParcel(info2);
159        assertEquals(SELECTION_START, info3.getSelectionStart());
160        assertEquals(SELECTION_END, info3.getSelectionEnd());
161        assertEquals(COMPOSING_TEXT_START, info3.getComposingTextStart());
162        assertTrue(TextUtils.equals(COMPOSING_TEXT, info3.getComposingText()));
163        assertEquals(INSERTION_MARKER_FLAGS, info3.getInsertionMarkerFlags());
164        assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal());
165        assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop());
166        assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline());
167        assertEquals(INSERTION_MARKER_BOTOM, info3.getInsertionMarkerBottom());
168        assertEquals(TRANSFORM_MATRIX, info3.getMatrix());
169        for (int i = 0; i < MANY_BOUNDS.length; i++) {
170            final RectF expectedBounds = MANY_BOUNDS[i];
171            assertEquals(expectedBounds, info3.getCharacterRect(i));
172        }
173        assertNull(info3.getCharacterRect(-1));
174        assertNull(info3.getCharacterRect(MANY_BOUNDS.length + 1));
175        for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) {
176            final int expectedFlags = MANY_FLAGS_ARRAY[i];
177            assertEquals(expectedFlags, info3.getCharacterRectFlags(i));
178        }
179        assertEquals(0, info3.getCharacterRectFlags(-1));
180        assertEquals(0, info3.getCharacterRectFlags(MANY_BOUNDS.length + 1));
181        assertEquals(info.hashCode(), info3.hashCode());
182
183        builder.reset();
184        final CursorAnchorInfo uninitializedInfo = builder.build();
185        assertEquals(-1, uninitializedInfo.getSelectionStart());
186        assertEquals(-1, uninitializedInfo.getSelectionEnd());
187        assertEquals(-1, uninitializedInfo.getComposingTextStart());
188        assertNull(uninitializedInfo.getComposingText());
189        assertEquals(0, uninitializedInfo.getInsertionMarkerFlags());
190        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal());
191        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop());
192        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline());
193        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom());
194        assertEquals(Matrix.IDENTITY_MATRIX, uninitializedInfo.getMatrix());
195    }
196
197    private static void assertNotEquals(final CursorAnchorInfo reference,
198            final CursorAnchorInfo actual) {
199        assertFalse(Objects.equals(reference, actual));
200    }
201
202    @SmallTest
203    public void testEquality() throws Exception {
204        final Matrix MATRIX1 = new Matrix();
205        MATRIX1.setTranslate(10.0f, 20.0f);
206        final Matrix MATRIX2 = new Matrix();
207        MATRIX2.setTranslate(110.0f, 120.0f);
208        final Matrix NAN_MATRIX = new Matrix();
209        NAN_MATRIX.setValues(new float[]{
210                Float.NaN, Float.NaN, Float.NaN,
211                Float.NaN, Float.NaN, Float.NaN,
212                Float.NaN, Float.NaN, Float.NaN});
213        final int SELECTION_START1 = 2;
214        final int SELECTION_END1 = 7;
215        final String COMPOSING_TEXT1 = "0123456789";
216        final int COMPOSING_TEXT_START1 = 0;
217        final int INSERTION_MARKER_FLAGS1 = FLAG_HAS_VISIBLE_REGION;
218        final float INSERTION_MARKER_HORIZONTAL1 = 10.5f;
219        final float INSERTION_MARKER_TOP1 = 100.1f;
220        final float INSERTION_MARKER_BASELINE1 = 110.4f;
221        final float INSERTION_MARKER_BOTOM1 = 111.0f;
222        final int SELECTION_START2 = 4;
223        final int SELECTION_END2 = 8;
224        final String COMPOSING_TEXT2 = "9876543210";
225        final int COMPOSING_TEXT_START2 = 3;
226        final int INSERTION_MARKER_FLAGS2 =
227                FLAG_HAS_VISIBLE_REGION | FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL;
228        final float INSERTION_MARKER_HORIZONTAL2 = 14.5f;
229        final float INSERTION_MARKER_TOP2 = 200.1f;
230        final float INSERTION_MARKER_BASELINE2 = 210.4f;
231        final float INSERTION_MARKER_BOTOM2 = 211.0f;
232
233        // Default instance should be equal.
234        assertEquals(new Builder().build(), new Builder().build());
235
236        assertEquals(
237                new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build(),
238                new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build());
239        assertNotEquals(
240                new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build(),
241                new Builder().setSelectionRange(SELECTION_START1, SELECTION_END2).build());
242        assertNotEquals(
243                new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build(),
244                new Builder().setSelectionRange(SELECTION_START2, SELECTION_END1).build());
245        assertNotEquals(
246                new Builder().setSelectionRange(SELECTION_START1, SELECTION_END1).build(),
247                new Builder().setSelectionRange(SELECTION_START2, SELECTION_END2).build());
248        assertEquals(
249                new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build(),
250                new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build());
251        assertNotEquals(
252                new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build(),
253                new Builder().setComposingText(COMPOSING_TEXT_START2, COMPOSING_TEXT1).build());
254        assertNotEquals(
255                new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build(),
256                new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT2).build());
257        assertNotEquals(
258                new Builder().setComposingText(COMPOSING_TEXT_START1, COMPOSING_TEXT1).build(),
259                new Builder().setComposingText(COMPOSING_TEXT_START2, COMPOSING_TEXT2).build());
260
261        // For insertion marker locations, {@link Float#NaN} is treated as if it was a number.
262        assertEquals(
263                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
264                        Float.NaN, Float.NaN, Float.NaN, Float.NaN,
265                        INSERTION_MARKER_FLAGS1).build(),
266                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
267                        Float.NaN, Float.NaN, Float.NaN, Float.NaN,
268                        INSERTION_MARKER_FLAGS1).build());
269
270        // Check Matrix.
271        assertEquals(
272                new Builder().setMatrix(MATRIX1).build(),
273                new Builder().setMatrix(MATRIX1).build());
274        assertNotEquals(
275                new Builder().setMatrix(MATRIX1).build(),
276                new Builder().setMatrix(MATRIX2).build());
277        assertNotEquals(
278                new Builder().setMatrix(MATRIX1).build(),
279                new Builder().setMatrix(NAN_MATRIX).build());
280        // Unlike insertion marker locations, {@link Float#NaN} in the matrix is treated as just a
281        // NaN as usual (NaN == NaN -> false).
282        assertNotEquals(
283                new Builder().setMatrix(NAN_MATRIX).build(),
284                new Builder().setMatrix(NAN_MATRIX).build());
285
286        assertEquals(
287                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
288                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
289                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
290                        INSERTION_MARKER_FLAGS1).build(),
291                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
292                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
293                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
294                        INSERTION_MARKER_FLAGS1).build());
295        assertNotEquals(
296                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
297                        Float.NaN, INSERTION_MARKER_TOP1,
298                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
299                        INSERTION_MARKER_FLAGS1).build(),
300                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
301                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
302                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
303                        INSERTION_MARKER_FLAGS1).build());
304        assertNotEquals(
305                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
306                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
307                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
308                        INSERTION_MARKER_FLAGS1).build(),
309                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
310                        INSERTION_MARKER_HORIZONTAL2, INSERTION_MARKER_TOP1,
311                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
312                        INSERTION_MARKER_FLAGS1).build());
313        assertNotEquals(
314                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
315                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
316                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
317                        INSERTION_MARKER_FLAGS1).build(),
318                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
319                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP2,
320                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
321                        INSERTION_MARKER_FLAGS1).build());
322        assertNotEquals(
323                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
324                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
325                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
326                        INSERTION_MARKER_FLAGS1).build(),
327                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
328                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
329                        INSERTION_MARKER_BASELINE2, INSERTION_MARKER_BOTOM1,
330                        INSERTION_MARKER_FLAGS1).build());
331        assertNotEquals(
332                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
333                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
334                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
335                        INSERTION_MARKER_FLAGS1).build(),
336                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
337                        INSERTION_MARKER_HORIZONTAL2, INSERTION_MARKER_TOP1,
338                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
339                        INSERTION_MARKER_FLAGS1).build());
340        assertNotEquals(
341                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
342                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
343                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
344                        INSERTION_MARKER_FLAGS1).build(),
345                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
346                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
347                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM2,
348                        INSERTION_MARKER_FLAGS1).build());
349        assertNotEquals(
350                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
351                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
352                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
353                        INSERTION_MARKER_FLAGS1).build(),
354                new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
355                        INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
356                        INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
357                        INSERTION_MARKER_FLAGS2).build());
358    }
359
360    @SmallTest
361    public void testMatrixIsCopied() throws Exception {
362        final Matrix MATRIX1 = new Matrix();
363        MATRIX1.setTranslate(10.0f, 20.0f);
364        final Matrix MATRIX2 = new Matrix();
365        MATRIX2.setTranslate(110.0f, 120.0f);
366        final Matrix MATRIX3 = new Matrix();
367        MATRIX3.setTranslate(210.0f, 220.0f);
368        final Matrix matrix = new Matrix();
369        final Builder builder = new Builder();
370
371        matrix.set(MATRIX1);
372        builder.setMatrix(matrix);
373        matrix.postRotate(90.0f);
374
375        final CursorAnchorInfo firstInstance = builder.build();
376        assertEquals(MATRIX1, firstInstance.getMatrix());
377        matrix.set(MATRIX2);
378        builder.setMatrix(matrix);
379        final CursorAnchorInfo secondInstance = builder.build();
380        assertEquals(MATRIX1, firstInstance.getMatrix());
381        assertEquals(MATRIX2, secondInstance.getMatrix());
382
383        matrix.set(MATRIX3);
384        assertEquals(MATRIX1, firstInstance.getMatrix());
385        assertEquals(MATRIX2, secondInstance.getMatrix());
386    }
387
388    @SmallTest
389    public void testMatrixIsRequired() throws Exception {
390        final int SELECTION_START = 30;
391        final int SELECTION_END = 40;
392        final int COMPOSING_TEXT_START = 32;
393        final String COMPOSING_TEXT = "test";
394        final int INSERTION_MARKER_FLAGS = FLAG_HAS_VISIBLE_REGION;
395        final float INSERTION_MARKER_HORIZONTAL = 10.5f;
396        final float INSERTION_MARKER_TOP = 100.1f;
397        final float INSERTION_MARKER_BASELINE = 110.4f;
398        final float INSERTION_MARKER_BOTOM = 111.0f;
399        Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
400        TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
401
402        final Builder builder = new Builder();
403        // Check twice to make sure if Builder#reset() works as expected.
404        for (int repeatCount = 0; repeatCount < 2; ++repeatCount) {
405            builder.setSelectionRange(SELECTION_START, SELECTION_END)
406                    .setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT);
407            try {
408                // Should succeed as coordinate transformation matrix is not required if no
409                // positional information is specified.
410                builder.build();
411            } catch (IllegalArgumentException ex) {
412                assertTrue(false);
413            }
414
415            builder.setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
416                    INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM, INSERTION_MARKER_FLAGS);
417            try {
418                // Coordinate transformation matrix is required if no positional information is
419                // specified.
420                builder.build();
421                assertTrue(false);
422            } catch (IllegalArgumentException ex) {
423            }
424
425            builder.setMatrix(TRANSFORM_MATRIX);
426            try {
427                // Should succeed as coordinate transformation matrix is required.
428                builder.build();
429            } catch (IllegalArgumentException ex) {
430                assertTrue(false);
431            }
432
433            builder.reset();
434        }
435    }
436
437    @SmallTest
438    public void testBuilderAddCharacterBounds() throws Exception {
439        // A negative index should be rejected.
440        try {
441            new Builder().addCharacterBounds(-1, 0.0f, 0.0f, 0.0f, 0.0f, FLAG_HAS_VISIBLE_REGION);
442            assertTrue(false);
443        } catch (IllegalArgumentException ex) {
444        }
445    }
446
447    private static CursorAnchorInfo cloneViaParcel(final CursorAnchorInfo src) {
448        Parcel parcel = null;
449        try {
450            parcel = Parcel.obtain();
451            src.writeToParcel(parcel, 0);
452            parcel.setDataPosition(0);
453            return new CursorAnchorInfo(parcel);
454        } finally {
455            if (parcel != null) {
456                parcel.recycle();
457            }
458        }
459    }
460}
461