Home | History | Annotate | Download | only in inputmethod
      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 
     17 package android.view.inputmethod;
     18 
     19 import android.graphics.Matrix;
     20 import android.graphics.RectF;
     21 import android.os.Parcel;
     22 import android.test.InstrumentationTestCase;
     23 import android.test.suitebuilder.annotation.SmallTest;
     24 import android.text.TextUtils;
     25 import android.view.inputmethod.CursorAnchorInfo.Builder;
     26 
     27 import java.util.Objects;
     28 
     29 import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
     30 import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
     31 import static android.view.inputmethod.CursorAnchorInfo.FLAG_IS_RTL;
     32 
     33 public 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.getCharacterBounds(i));
    120         }
    121         assertNull(info.getCharacterBounds(-1));
    122         assertNull(info.getCharacterBounds(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.getCharacterBoundsFlags(i));
    126         }
    127         assertEquals(0, info.getCharacterBoundsFlags(-1));
    128         assertEquals(0, info.getCharacterBoundsFlags(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.getCharacterBounds(i));
    145         }
    146         assertNull(info2.getCharacterBounds(-1));
    147         assertNull(info2.getCharacterBounds(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.getCharacterBoundsFlags(i));
    151         }
    152         assertEquals(0, info2.getCharacterBoundsFlags(-1));
    153         assertEquals(0, info2.getCharacterBoundsFlags(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.getCharacterBounds(i));
    172         }
    173         assertNull(info3.getCharacterBounds(-1));
    174         assertNull(info3.getCharacterBounds(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.getCharacterBoundsFlags(i));
    178         }
    179         assertEquals(0, info3.getCharacterBoundsFlags(-1));
    180         assertEquals(0, info3.getCharacterBoundsFlags(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