1 /* 2 * Copyright (C) 2019 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.cts; 18 19 import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION; 20 import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; 21 import static android.view.inputmethod.CursorAnchorInfo.FLAG_IS_RTL; 22 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertNotEquals; 25 import static org.junit.Assert.assertNull; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 29 import android.graphics.Color; 30 import android.graphics.Matrix; 31 import android.graphics.RectF; 32 import android.graphics.Typeface; 33 import android.graphics.text.LineBreakConfig; 34 import android.os.LocaleList; 35 import android.os.Parcel; 36 import android.platform.test.annotations.AppModeSdkSandbox; 37 import android.text.TextUtils; 38 import android.view.inputmethod.CursorAnchorInfo; 39 import android.view.inputmethod.CursorAnchorInfo.Builder; 40 import android.view.inputmethod.EditorBoundsInfo; 41 import android.view.inputmethod.TextAppearanceInfo; 42 43 import androidx.test.filters.SmallTest; 44 45 import com.android.compatibility.common.util.ApiTest; 46 47 import org.junit.Test; 48 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.Collections; 52 import java.util.List; 53 54 @SmallTest 55 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 56 public final class CursorAnchorInfoTest { 57 private static final float EPSILON = 0.0000001f; 58 59 private static final RectF[] MANY_BOUNDS = new RectF[] { 60 new RectF(101.0f, 201.0f, 301.0f, 401.0f), 61 new RectF(102.0f, 202.0f, 302.0f, 402.0f), 62 new RectF(103.0f, 203.0f, 303.0f, 403.0f), 63 new RectF(104.0f, 204.0f, 304.0f, 404.0f), 64 new RectF(105.0f, 205.0f, 305.0f, 405.0f), 65 new RectF(106.0f, 206.0f, 306.0f, 406.0f), 66 new RectF(107.0f, 207.0f, 307.0f, 407.0f), 67 new RectF(108.0f, 208.0f, 308.0f, 408.0f), 68 new RectF(109.0f, 209.0f, 309.0f, 409.0f), 69 new RectF(110.0f, 210.0f, 310.0f, 410.0f), 70 new RectF(111.0f, 211.0f, 311.0f, 411.0f), 71 new RectF(112.0f, 212.0f, 312.0f, 412.0f), 72 new RectF(113.0f, 213.0f, 313.0f, 413.0f), 73 new RectF(114.0f, 214.0f, 314.0f, 414.0f), 74 new RectF(115.0f, 215.0f, 315.0f, 415.0f), 75 new RectF(116.0f, 216.0f, 316.0f, 416.0f), 76 new RectF(117.0f, 217.0f, 317.0f, 417.0f), 77 new RectF(118.0f, 218.0f, 318.0f, 418.0f), 78 new RectF(119.0f, 219.0f, 319.0f, 419.0f), 79 }; 80 private static final int[] MANY_FLAGS_ARRAY = new int[] { 81 FLAG_HAS_INVISIBLE_REGION, 82 FLAG_HAS_INVISIBLE_REGION | FLAG_HAS_VISIBLE_REGION, 83 FLAG_HAS_VISIBLE_REGION, 84 FLAG_HAS_VISIBLE_REGION, 85 FLAG_HAS_VISIBLE_REGION, 86 FLAG_HAS_VISIBLE_REGION, 87 FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, 88 FLAG_HAS_INVISIBLE_REGION | FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, 89 FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL, 90 FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, 91 FLAG_HAS_VISIBLE_REGION, 92 FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, 93 FLAG_HAS_VISIBLE_REGION, 94 FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, 95 FLAG_HAS_VISIBLE_REGION, 96 FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL, 97 FLAG_HAS_VISIBLE_REGION, 98 FLAG_HAS_INVISIBLE_REGION, 99 FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL, 100 }; 101 102 @Test 103 @ApiTest( 104 apis = { 105 "android.view.inputmethod.CursorAnchorInfo#getComposingText", 106 "android.view.inputmethod.CursorAnchorInfo#getEditorBoundsInfo", 107 "android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerFlags", 108 "android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerHorizontal", 109 "android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerTop", 110 "android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerBaseline", 111 "android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerBottom", 112 "android.view.inputmethod.CursorAnchorInfo#getSelectionStart", 113 "android.view.inputmethod.CursorAnchorInfo#getSelectionEnd", 114 "android.view.inputmethod.CursorAnchorInfo#getMatrix", 115 "android.view.inputmethod.CursorAnchorInfo#getVisibleLineBounds", 116 "android.view.inputmethod.CursorAnchorInfo#getTextAppearanceInfo", 117 "android.view.inputmethod.CursorAnchorInfo.Builder#build", 118 "android.view.inputmethod.CursorAnchorInfo.Builder#setComposingText", 119 "android.view.inputmethod.CursorAnchorInfo.Builder#setEditorBoundsInfo", 120 "android.view.inputmethod.CursorAnchorInfo.Builder#setMatrix", 121 "android.view.inputmethod.CursorAnchorInfo.Builder#setInsertionMarkerLocation", 122 "android.view.inputmethod.CursorAnchorInfo.Builder#setSelectinRange", 123 "android.view.inputmethod.CursorAnchorInfo.Builder#setVisibleLineBounds", 124 "android.view.inputmethod.CursorAnchorInfo.Builder#setTextAppearanceInfo", 125 } 126 ) testBuilder()127 public void testBuilder() { 128 final int selectionStart = 30; 129 final int selectionEnd = 40; 130 final int composingTextStart = 32; 131 final String composingText = "test"; 132 final int insertionMarkerFlags = 133 FLAG_HAS_VISIBLE_REGION | FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL; 134 final float insertionMarkerHorizontal = 10.5f; 135 final float insertionMarkerTop = 100.1f; 136 final float insertionMarkerBaseline = 110.4f; 137 final float insertionMarkerBottom = 111.0f; 138 139 Matrix transformMatrix = new Matrix(); 140 transformMatrix.setScale(10.0f, 20.0f); 141 142 final EditorBoundsInfo boundsInfo = 143 new EditorBoundsInfo.Builder().setEditorBounds(MANY_BOUNDS[0]) 144 .setHandwritingBounds(MANY_BOUNDS[1]).build(); 145 146 final TextAppearanceInfo textAppearanceInfo = createTextAppearanceInfoBuilder().build(); 147 148 final Builder builder = new Builder(); 149 builder.setSelectionRange(selectionStart, selectionEnd) 150 .setComposingText(composingTextStart, composingText) 151 .setInsertionMarkerLocation(insertionMarkerHorizontal, insertionMarkerTop, 152 insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags) 153 .setMatrix(transformMatrix) 154 .setEditorBoundsInfo(boundsInfo) 155 .setTextAppearanceInfo(textAppearanceInfo); 156 157 for (int i = 0; i < MANY_BOUNDS.length; i++) { 158 final RectF bounds = MANY_BOUNDS[i]; 159 final int flags = MANY_FLAGS_ARRAY[i]; 160 builder.addCharacterBounds(i, bounds.left, bounds.top, bounds.right, bounds.bottom, 161 flags); 162 builder.addVisibleLineBounds(bounds.left, bounds.top, bounds.right, bounds.bottom); 163 } 164 165 final CursorAnchorInfo info = builder.build(); 166 assertEquals(selectionStart, info.getSelectionStart()); 167 assertEquals(selectionEnd, info.getSelectionEnd()); 168 assertEquals(composingTextStart, info.getComposingTextStart()); 169 assertTrue(TextUtils.equals(composingText, info.getComposingText())); 170 assertEquals(insertionMarkerFlags, info.getInsertionMarkerFlags()); 171 assertEquals(insertionMarkerHorizontal, info.getInsertionMarkerHorizontal(), EPSILON); 172 assertEquals(insertionMarkerTop, info.getInsertionMarkerTop(), EPSILON); 173 assertEquals(insertionMarkerBaseline, info.getInsertionMarkerBaseline(), EPSILON); 174 assertEquals(insertionMarkerBottom, info.getInsertionMarkerBottom(), EPSILON); 175 assertEquals(transformMatrix, info.getMatrix()); 176 assertEquals(boundsInfo, info.getEditorBoundsInfo()); 177 assertEquals(Arrays.asList(MANY_BOUNDS), info.getVisibleLineBounds()); 178 assertEquals(MANY_BOUNDS[0], 179 info.getEditorBoundsInfo().getEditorBounds()); 180 assertEquals(MANY_BOUNDS[1], 181 info.getEditorBoundsInfo().getHandwritingBounds()); 182 for (int i = 0; i < MANY_BOUNDS.length; i++) { 183 final RectF expectedBounds = MANY_BOUNDS[i]; 184 assertEquals(expectedBounds, info.getCharacterBounds(i)); 185 } 186 assertNull(info.getCharacterBounds(-1)); 187 assertNull(info.getCharacterBounds(MANY_BOUNDS.length + 1)); 188 for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) { 189 final int expectedFlags = MANY_FLAGS_ARRAY[i]; 190 assertEquals(expectedFlags, info.getCharacterBoundsFlags(i)); 191 } 192 assertEquals(0, info.getCharacterBoundsFlags(-1)); 193 assertEquals(0, info.getCharacterBoundsFlags(MANY_BOUNDS.length + 1)); 194 assertEquals(textAppearanceInfo, info.getTextAppearanceInfo()); 195 assertTextAppearanceInfoContentsEqual(info.getTextAppearanceInfo()); 196 197 // Make sure that the builder can reproduce the same object. 198 final CursorAnchorInfo info2 = builder.build(); 199 assertEquals(selectionStart, info2.getSelectionStart()); 200 assertEquals(selectionEnd, info2.getSelectionEnd()); 201 assertEquals(composingTextStart, info2.getComposingTextStart()); 202 assertTrue(TextUtils.equals(composingText, info2.getComposingText())); 203 assertEquals(insertionMarkerFlags, info2.getInsertionMarkerFlags()); 204 assertEquals(insertionMarkerHorizontal, info2.getInsertionMarkerHorizontal(), EPSILON); 205 assertEquals(insertionMarkerTop, info2.getInsertionMarkerTop(), EPSILON); 206 assertEquals(insertionMarkerBaseline, info2.getInsertionMarkerBaseline(), EPSILON); 207 assertEquals(insertionMarkerBottom, info2.getInsertionMarkerBottom(), EPSILON); 208 assertEquals(boundsInfo, info2.getEditorBoundsInfo()); 209 assertEquals(Arrays.asList(MANY_BOUNDS), info2.getVisibleLineBounds()); 210 assertEquals(transformMatrix, info2.getMatrix()); 211 for (int i = 0; i < MANY_BOUNDS.length; i++) { 212 final RectF expectedBounds = MANY_BOUNDS[i]; 213 assertEquals(expectedBounds, info2.getCharacterBounds(i)); 214 } 215 assertNull(info2.getCharacterBounds(-1)); 216 assertNull(info2.getCharacterBounds(MANY_BOUNDS.length + 1)); 217 for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) { 218 final int expectedFlags = MANY_FLAGS_ARRAY[i]; 219 assertEquals(expectedFlags, info2.getCharacterBoundsFlags(i)); 220 } 221 assertEquals(0, info2.getCharacterBoundsFlags(-1)); 222 assertEquals(0, info2.getCharacterBoundsFlags(MANY_BOUNDS.length + 1)); 223 assertEquals(textAppearanceInfo, info2.getTextAppearanceInfo()); 224 assertTextAppearanceInfoContentsEqual(info2.getTextAppearanceInfo()); 225 assertEquals(info, info2); 226 assertEquals(info.hashCode(), info2.hashCode()); 227 228 // Make sure that object can be marshaled via Parcel. 229 final CursorAnchorInfo info3 = cloneViaParcel(info2); 230 assertEquals(selectionStart, info3.getSelectionStart()); 231 assertEquals(selectionEnd, info3.getSelectionEnd()); 232 assertEquals(composingTextStart, info3.getComposingTextStart()); 233 assertTrue(TextUtils.equals(composingText, info3.getComposingText())); 234 assertEquals(insertionMarkerFlags, info3.getInsertionMarkerFlags()); 235 assertEquals(insertionMarkerHorizontal, info3.getInsertionMarkerHorizontal(), EPSILON); 236 assertEquals(insertionMarkerTop, info3.getInsertionMarkerTop(), EPSILON); 237 assertEquals(insertionMarkerBaseline, info3.getInsertionMarkerBaseline(), EPSILON); 238 assertEquals(insertionMarkerBottom, info3.getInsertionMarkerBottom(), EPSILON); 239 assertEquals(boundsInfo, info3.getEditorBoundsInfo()); 240 assertEquals(Arrays.asList(MANY_BOUNDS), info3.getVisibleLineBounds()); 241 assertEquals(transformMatrix, info3.getMatrix()); 242 for (int i = 0; i < MANY_BOUNDS.length; i++) { 243 final RectF expectedBounds = MANY_BOUNDS[i]; 244 assertEquals(expectedBounds, info3.getCharacterBounds(i)); 245 } 246 assertNull(info3.getCharacterBounds(-1)); 247 assertNull(info3.getCharacterBounds(MANY_BOUNDS.length + 1)); 248 for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) { 249 final int expectedFlags = MANY_FLAGS_ARRAY[i]; 250 assertEquals(expectedFlags, info3.getCharacterBoundsFlags(i)); 251 } 252 assertEquals(0, info3.getCharacterBoundsFlags(-1)); 253 assertEquals(0, info3.getCharacterBoundsFlags(MANY_BOUNDS.length + 1)); 254 assertEquals(textAppearanceInfo, info3.getTextAppearanceInfo()); 255 assertTextAppearanceInfoContentsEqual(info3.getTextAppearanceInfo()); 256 assertEquals(info.hashCode(), info3.hashCode()); 257 258 builder.reset(); 259 final CursorAnchorInfo uninitializedInfo = builder.build(); 260 assertEquals(-1, uninitializedInfo.getSelectionStart()); 261 assertEquals(-1, uninitializedInfo.getSelectionEnd()); 262 assertEquals(-1, uninitializedInfo.getComposingTextStart()); 263 assertNull(uninitializedInfo.getComposingText()); 264 assertEquals(0, uninitializedInfo.getInsertionMarkerFlags()); 265 assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal(), EPSILON); 266 assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop(), EPSILON); 267 assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline(), EPSILON); 268 assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom(), EPSILON); 269 assertEquals(null, uninitializedInfo.getEditorBoundsInfo()); 270 assertEquals(new ArrayList<>(), uninitializedInfo.getVisibleLineBounds()); 271 assertEquals(new Matrix(), uninitializedInfo.getMatrix()); 272 assertEquals(null, uninitializedInfo.getTextAppearanceInfo()); 273 } 274 275 @Test 276 @ApiTest( 277 apis = { 278 "android.view.inputmethod.CursorAnchorInfo.Builder#build", 279 "android.view.inputmethod.CursorAnchorInfo.Builder#setComposingText", 280 "android.view.inputmethod.CursorAnchorInfo.Builder#setMatrix", 281 "android.view.inputmethod.CursorAnchorInfo.Builder#setInsertionMarkerLocation", 282 "android.view.inputmethod.CursorAnchorInfo.Builder#setSelectinRange", 283 "android.view.inputmethod.CursorAnchorInfo.Builder#setVisibleLineBounds", 284 "android.view.inputmethod.CursorAnchorInfo.Builder#setTextAppearanceInfo", 285 } 286 ) testEquality()287 public void testEquality() { 288 final Matrix matrix1 = new Matrix(); 289 matrix1.setTranslate(10.0f, 20.0f); 290 final Matrix matrix2 = new Matrix(); 291 matrix2.setTranslate(110.0f, 120.0f); 292 final Matrix nanMatrix = new Matrix(); 293 nanMatrix.setValues(new float[]{ 294 Float.NaN, Float.NaN, Float.NaN, 295 Float.NaN, Float.NaN, Float.NaN, 296 Float.NaN, Float.NaN, Float.NaN}); 297 final int selectionStart1 = 2; 298 final int selectionEnd1 = 7; 299 final String composingText1 = "0123456789"; 300 final int composingTextStart1 = 0; 301 final int insertionMarkerFlags1 = FLAG_HAS_VISIBLE_REGION; 302 final float insertionMarkerHorizontal1 = 10.5f; 303 final float insertionMarkerTop1 = 100.1f; 304 final float insertionMarkerBaseline1 = 110.4f; 305 final float insertionMarkerBottom1 = 111.0f; 306 final int selectionStart2 = 4; 307 final int selectionEnd2 = 8; 308 final String composingText2 = "9876543210"; 309 final int composingTextStart2 = 3; 310 final int insertionMarkerFlags2 = 311 FLAG_HAS_VISIBLE_REGION | FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL; 312 final float insertionMarkerHorizontal2 = 14.5f; 313 final float insertionMarkerTop2 = 200.1f; 314 final float insertionMarkerBaseline2 = 210.4f; 315 final float insertionMarkerBottom2 = 211.0f; 316 final List<RectF> visibleLineBounds1 = Arrays.asList(MANY_BOUNDS[0], MANY_BOUNDS[1]); 317 final List<RectF> visibleLineBounds2 = Arrays.asList(MANY_BOUNDS[2], MANY_BOUNDS[3]); 318 319 // Default instance should be equal. 320 assertEquals(new Builder().build(), new Builder().build()); 321 322 assertEquals( 323 new Builder().setSelectionRange(selectionStart1, selectionEnd1).build(), 324 new Builder().setSelectionRange(selectionStart1, selectionEnd1).build()); 325 assertNotEquals( 326 new Builder().setSelectionRange(selectionStart1, selectionEnd1).build(), 327 new Builder().setSelectionRange(selectionStart1, selectionEnd2).build()); 328 assertNotEquals( 329 new Builder().setSelectionRange(selectionStart1, selectionEnd1).build(), 330 new Builder().setSelectionRange(selectionStart2, selectionEnd1).build()); 331 assertNotEquals( 332 new Builder().setSelectionRange(selectionStart1, selectionEnd1).build(), 333 new Builder().setSelectionRange(selectionStart2, selectionEnd2).build()); 334 assertEquals( 335 new Builder().setComposingText(composingTextStart1, composingText1).build(), 336 new Builder().setComposingText(composingTextStart1, composingText1).build()); 337 assertNotEquals( 338 new Builder().setComposingText(composingTextStart1, composingText1).build(), 339 new Builder().setComposingText(composingTextStart2, composingText1).build()); 340 assertNotEquals( 341 new Builder().setComposingText(composingTextStart1, composingText1).build(), 342 new Builder().setComposingText(composingTextStart1, composingText2).build()); 343 assertNotEquals( 344 new Builder().setComposingText(composingTextStart1, composingText1).build(), 345 new Builder().setComposingText(composingTextStart2, composingText2).build()); 346 347 // For insertion marker locations, Float#NaN is treated as if it was a number. 348 assertEquals( 349 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 350 Float.NaN, Float.NaN, Float.NaN, Float.NaN, 351 insertionMarkerFlags1).build(), 352 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 353 Float.NaN, Float.NaN, Float.NaN, Float.NaN, 354 insertionMarkerFlags1).build()); 355 356 // Check Matrix. 357 assertEquals( 358 new Builder().setMatrix(matrix1).build(), 359 new Builder().setMatrix(matrix1).build()); 360 assertNotEquals( 361 new Builder().setMatrix(matrix1).build(), 362 new Builder().setMatrix(matrix2).build()); 363 assertNotEquals( 364 new Builder().setMatrix(matrix1).build(), 365 new Builder().setMatrix(nanMatrix).build()); 366 // Unlike insertion marker locations, Float#NaN in the matrix is treated as just a NaN as 367 // usual (NaN == NaN -> false). 368 assertNotEquals( 369 new Builder().setMatrix(nanMatrix).build(), 370 new Builder().setMatrix(nanMatrix).build()); 371 372 assertEquals( 373 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 374 insertionMarkerHorizontal1, insertionMarkerTop1, 375 insertionMarkerBaseline1, insertionMarkerBottom1, 376 insertionMarkerFlags1).build(), 377 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 378 insertionMarkerHorizontal1, insertionMarkerTop1, 379 insertionMarkerBaseline1, insertionMarkerBottom1, 380 insertionMarkerFlags1).build()); 381 assertNotEquals( 382 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 383 Float.NaN, insertionMarkerTop1, 384 insertionMarkerBaseline1, insertionMarkerBottom1, 385 insertionMarkerFlags1).build(), 386 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 387 insertionMarkerHorizontal1, insertionMarkerTop1, 388 insertionMarkerBaseline1, insertionMarkerBottom1, 389 insertionMarkerFlags1).build()); 390 assertNotEquals( 391 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 392 insertionMarkerHorizontal1, insertionMarkerTop1, 393 insertionMarkerBaseline1, insertionMarkerBottom1, 394 insertionMarkerFlags1).build(), 395 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 396 insertionMarkerHorizontal2, insertionMarkerTop1, 397 insertionMarkerBaseline1, insertionMarkerBottom1, 398 insertionMarkerFlags1).build()); 399 assertNotEquals( 400 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 401 insertionMarkerHorizontal1, insertionMarkerTop1, 402 insertionMarkerBaseline1, insertionMarkerBottom1, 403 insertionMarkerFlags1).build(), 404 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 405 insertionMarkerHorizontal1, insertionMarkerTop2, 406 insertionMarkerBaseline1, insertionMarkerBottom1, 407 insertionMarkerFlags1).build()); 408 assertNotEquals( 409 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 410 insertionMarkerHorizontal1, insertionMarkerTop1, 411 insertionMarkerBaseline1, insertionMarkerBottom1, 412 insertionMarkerFlags1).build(), 413 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 414 insertionMarkerHorizontal1, insertionMarkerTop1, 415 insertionMarkerBaseline2, insertionMarkerBottom1, 416 insertionMarkerFlags1).build()); 417 assertNotEquals( 418 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 419 insertionMarkerHorizontal1, insertionMarkerTop1, 420 insertionMarkerBaseline1, insertionMarkerBottom1, 421 insertionMarkerFlags1).build(), 422 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 423 insertionMarkerHorizontal2, insertionMarkerTop1, 424 insertionMarkerBaseline1, insertionMarkerBottom1, 425 insertionMarkerFlags1).build()); 426 assertNotEquals( 427 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 428 insertionMarkerHorizontal1, insertionMarkerTop1, 429 insertionMarkerBaseline1, insertionMarkerBottom1, 430 insertionMarkerFlags1).build(), 431 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 432 insertionMarkerHorizontal1, insertionMarkerTop1, 433 insertionMarkerBaseline1, insertionMarkerBottom2, 434 insertionMarkerFlags1).build()); 435 assertNotEquals( 436 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 437 insertionMarkerHorizontal1, insertionMarkerTop1, 438 insertionMarkerBaseline1, insertionMarkerBottom1, 439 insertionMarkerFlags1).build(), 440 new Builder().setMatrix(matrix1).setInsertionMarkerLocation( 441 insertionMarkerHorizontal1, insertionMarkerTop1, 442 insertionMarkerBaseline1, insertionMarkerBottom1, 443 insertionMarkerFlags2).build()); 444 { 445 CursorAnchorInfo.Builder builder1 = new Builder().setMatrix(matrix1); 446 for (RectF rectF : visibleLineBounds1) { 447 builder1.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom); 448 } 449 450 CursorAnchorInfo.Builder builder2 = new Builder().setMatrix(matrix1); 451 for (RectF rectF : visibleLineBounds1) { 452 builder2.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom); 453 } 454 455 assertEquals(builder1.build(), builder2.build()); 456 } 457 { 458 CursorAnchorInfo.Builder builder1 = new Builder().setMatrix(matrix1); 459 for (RectF rectF : visibleLineBounds1) { 460 builder1.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom); 461 } 462 463 CursorAnchorInfo.Builder builder2 = new Builder().setMatrix(matrix1); 464 for (RectF rectF : visibleLineBounds2) { 465 builder2.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom); 466 } 467 468 assertNotEquals(builder1.build(), builder2.build()); 469 } 470 { 471 TextAppearanceInfo.Builder appearanceBuilder1 = createTextAppearanceInfoBuilder(); 472 TextAppearanceInfo.Builder appearanceBuilder2 = createTextAppearanceInfoBuilder(); 473 TextAppearanceInfo.Builder appearanceBuilder3 = createTextAppearanceInfoBuilder(); 474 appearanceBuilder3.setTextSize(30f); 475 476 TextAppearanceInfo textAppearanceInfo1 = appearanceBuilder1.build(); 477 TextAppearanceInfo textAppearanceInfo2 = appearanceBuilder2.build(); 478 TextAppearanceInfo textAppearanceInfo3 = appearanceBuilder3.build(); 479 480 assertEquals(new Builder().setTextAppearanceInfo(textAppearanceInfo1).build(), 481 new Builder().setTextAppearanceInfo(textAppearanceInfo1).build()); 482 assertEquals(new Builder().setTextAppearanceInfo(textAppearanceInfo1).build(), 483 new Builder().setTextAppearanceInfo(textAppearanceInfo2).build()); 484 assertNotEquals(new Builder().setTextAppearanceInfo(textAppearanceInfo1).build(), 485 new Builder().setTextAppearanceInfo(textAppearanceInfo3).build()); 486 } 487 } 488 489 @Test testMatrixIsCopied()490 public void testMatrixIsCopied() { 491 final Matrix matrix1 = new Matrix(); 492 matrix1.setTranslate(10.0f, 20.0f); 493 final Matrix matrix2 = new Matrix(); 494 matrix2.setTranslate(110.0f, 120.0f); 495 final Matrix matrix3 = new Matrix(); 496 matrix3.setTranslate(210.0f, 220.0f); 497 final Matrix matrix = new Matrix(); 498 final Builder builder = new Builder(); 499 500 matrix.set(matrix1); 501 builder.setMatrix(matrix); 502 matrix.postRotate(90.0f); 503 504 final CursorAnchorInfo firstInstance = builder.build(); 505 assertEquals(matrix1, firstInstance.getMatrix()); 506 matrix.set(matrix2); 507 builder.setMatrix(matrix); 508 final CursorAnchorInfo secondInstance = builder.build(); 509 assertEquals(matrix1, firstInstance.getMatrix()); 510 assertEquals(matrix2, secondInstance.getMatrix()); 511 512 matrix.set(matrix3); 513 assertEquals(matrix1, firstInstance.getMatrix()); 514 assertEquals(matrix2, secondInstance.getMatrix()); 515 } 516 517 @Test testMatrixIsRequired()518 public void testMatrixIsRequired() { 519 final int selectionStart = 30; 520 final int selectionEnd = 40; 521 final int composingTextStart = 32; 522 final String composingText = "test"; 523 final int insertionMarkerFlags = FLAG_HAS_VISIBLE_REGION; 524 final float insertionMarkerHorizontal = 10.5f; 525 final float insertionMarkerTop = 100.1f; 526 final float insertionMarkerBaseline = 110.4f; 527 final float insertionMarkerBottom = 111.0f; 528 Matrix transformMatrix = new Matrix(); 529 transformMatrix.setScale(10.0f, 20.0f); 530 531 final Builder builder = new Builder(); 532 // Check twice to make sure if Builder#reset() works as expected. 533 for (int repeatCount = 0; repeatCount < 2; ++repeatCount) { 534 builder.setSelectionRange(selectionStart, selectionEnd) 535 .setComposingText(composingTextStart, composingText); 536 try { 537 // Should succeed as coordinate transformation matrix is not required if no 538 // positional information is specified. 539 builder.build(); 540 } catch (IllegalArgumentException ex) { 541 fail(); 542 } 543 544 builder.setInsertionMarkerLocation(insertionMarkerHorizontal, insertionMarkerTop, 545 insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags); 546 try { 547 // Coordinate transformation matrix is required if no positional information is 548 // specified. 549 builder.build(); 550 fail(); 551 } catch (IllegalArgumentException ex) { 552 } 553 554 builder.setMatrix(transformMatrix); 555 try { 556 // Should succeed as coordinate transformation matrix is required. 557 builder.build(); 558 } catch (IllegalArgumentException ex) { 559 fail(); 560 } 561 562 builder.reset(); 563 } 564 } 565 566 @Test 567 @ApiTest(apis = "android.view.inputmethod.CursorAnchorInfo.Builder#setVisibleLineBounds") testMatrixIsRequiredForVisibleLineBounds()568 public void testMatrixIsRequiredForVisibleLineBounds() { 569 final List<RectF> visibleLineBounds = Arrays.asList(MANY_BOUNDS); 570 final Matrix transformMatrix = new Matrix(); 571 572 final Builder builder = new Builder(); 573 try { 574 // Should succeed as coordinate transformation matrix is not required if no 575 // positional information is specified. 576 builder.build(); 577 } catch (IllegalArgumentException ex) { 578 fail(); 579 } 580 581 for (RectF rectF: visibleLineBounds) { 582 builder.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom); 583 } 584 try { 585 // Should fail since visible line bounds requires coordinates transformation matrix. 586 builder.build(); 587 fail(); 588 } catch (IllegalArgumentException ex) { 589 } 590 591 builder.setMatrix(transformMatrix); 592 try { 593 // Should succeed as coordinate transformation matrix is provided. 594 builder.build(); 595 } catch (IllegalArgumentException ex) { 596 fail(); 597 } 598 } 599 600 @Test 601 @ApiTest(apis = "android.view.inputmethod.CursorAnchorInfo.Builder#addCharacterBounds") testBuilderAddCharacterBounds()602 public void testBuilderAddCharacterBounds() { 603 // A negative index should be rejected. 604 try { 605 new Builder().addCharacterBounds(-1, 0.0f, 0.0f, 0.0f, 0.0f, FLAG_HAS_VISIBLE_REGION); 606 fail(); 607 } catch (IllegalArgumentException ex) { 608 } 609 } 610 611 @Test 612 @ApiTest(apis = "android.view.inputmethod.CursorAnchorInfo.Builder#clearVisibleLineBounds") testBuilderClearVisibleLineBounds()613 public void testBuilderClearVisibleLineBounds() { 614 CursorAnchorInfo.Builder builder = new Builder().setMatrix(Matrix.IDENTITY_MATRIX); 615 for (RectF rectF: MANY_BOUNDS) { 616 builder.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom); 617 } 618 619 // Making sure visible line bounds are added correctly. 620 assertEquals(Arrays.asList(MANY_BOUNDS), builder.build().getVisibleLineBounds()); 621 622 builder.clearVisibleLineBounds(); 623 // No visible line bounds is returned after clearVisibleLineBounds is called. 624 assertEquals(Collections.emptyList(), builder.build().getVisibleLineBounds()); 625 626 // Add more line bounds and verify again. 627 List<RectF> rectFs = Arrays.asList(MANY_BOUNDS[1], MANY_BOUNDS[0]); 628 629 for (RectF rectF: rectFs) { 630 builder.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom); 631 } 632 assertEquals(rectFs, builder.build().getVisibleLineBounds()); 633 } 634 635 @Test 636 @ApiTest(apis = {"android.view.inputmethod.CursorAnchorInfo#getTextAppearanceInfo", 637 "android.view.inputmethod.CursorAnchorInfo.Builder#setTextAppearanceInfo"}) testTextAppearanceInfoWithEmptyEditText()638 public void testTextAppearanceInfoWithEmptyEditText() { 639 TextAppearanceInfo textAppearanceInfo = new TextAppearanceInfo.Builder().build(); 640 CursorAnchorInfo.Builder builder = new Builder().setTextAppearanceInfo(textAppearanceInfo); 641 CursorAnchorInfo info1 = builder.build(); 642 CursorAnchorInfo info2 = builder.build(); 643 CursorAnchorInfo info3 = cloneViaParcel(info2); 644 assertEquals(textAppearanceInfo, info1.getTextAppearanceInfo()); 645 assertEquals(textAppearanceInfo, info2.getTextAppearanceInfo()); 646 assertEquals(textAppearanceInfo, info3.getTextAppearanceInfo()); 647 } 648 cloneViaParcel(CursorAnchorInfo src)649 private static CursorAnchorInfo cloneViaParcel(CursorAnchorInfo src) { 650 Parcel parcel = null; 651 try { 652 parcel = Parcel.obtain(); 653 src.writeToParcel(parcel, 0); 654 parcel.setDataPosition(0); 655 return new CursorAnchorInfo(parcel); 656 } finally { 657 if (parcel != null) { 658 parcel.recycle(); 659 } 660 } 661 } 662 createTextAppearanceInfoBuilder()663 private TextAppearanceInfo.Builder createTextAppearanceInfoBuilder() { 664 TextAppearanceInfo.Builder builder = new TextAppearanceInfo.Builder() 665 .setTextSize(16.5f) 666 .setTextLocales(LocaleList.forLanguageTags("en,ja")) 667 .setSystemFontFamilyName("sans-serif") 668 .setTextFontWeight(10) 669 .setTextStyle(Typeface.ITALIC) 670 .setAllCaps(true) 671 .setShadowDx(2.0f) 672 .setShadowDy(2.0f) 673 .setShadowRadius(2.0f) 674 .setShadowColor(Color.GRAY) 675 .setElegantTextHeight(true) 676 .setFallbackLineSpacing(true) 677 .setLetterSpacing(5.0f) 678 .setFontFeatureSettings("smcp") 679 .setFontVariationSettings("'wdth' 1.0") 680 .setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE) 681 .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE) 682 .setTextScaleX(1.5f) 683 .setHighlightTextColor(Color.YELLOW) 684 .setTextColor(Color.RED) 685 .setHintTextColor(Color.GREEN) 686 .setLinkTextColor(Color.BLUE); 687 return builder; 688 } 689 assertTextAppearanceInfoContentsEqual(TextAppearanceInfo textAppearanceInfo)690 private void assertTextAppearanceInfoContentsEqual(TextAppearanceInfo textAppearanceInfo) { 691 assertEquals(textAppearanceInfo.getTextSize(), 16.5f, EPSILON); 692 assertEquals(textAppearanceInfo.getTextLocales(), LocaleList.forLanguageTags("en,ja")); 693 assertEquals(textAppearanceInfo.getSystemFontFamilyName(), "sans-serif"); 694 assertEquals(textAppearanceInfo.getTextFontWeight(), 10); 695 assertEquals(textAppearanceInfo.getTextStyle(), Typeface.ITALIC); 696 assertTrue(textAppearanceInfo.isAllCaps()); 697 assertEquals(textAppearanceInfo.getShadowRadius(), 2.0f, EPSILON); 698 assertEquals(textAppearanceInfo.getShadowDx(), 2.0f, EPSILON); 699 assertEquals(textAppearanceInfo.getShadowDy(), 2.0f, EPSILON); 700 assertEquals(textAppearanceInfo.getShadowColor(), Color.GRAY); 701 assertTrue(textAppearanceInfo.isElegantTextHeight()); 702 assertTrue(textAppearanceInfo.isFallbackLineSpacing()); 703 assertEquals(textAppearanceInfo.getLetterSpacing(), 5.0f, EPSILON); 704 assertEquals(textAppearanceInfo.getFontFeatureSettings(), "smcp"); 705 assertEquals(textAppearanceInfo.getFontVariationSettings(), "'wdth' 1.0"); 706 assertEquals(textAppearanceInfo.getLineBreakStyle(), 707 LineBreakConfig.LINE_BREAK_STYLE_LOOSE); 708 assertEquals(textAppearanceInfo.getLineBreakWordStyle(), 709 LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE); 710 assertEquals(textAppearanceInfo.getTextScaleX(), 1.5f, EPSILON); 711 assertEquals(textAppearanceInfo.getHighlightTextColor(), Color.YELLOW); 712 assertEquals(textAppearanceInfo.getTextColor(), Color.RED); 713 assertEquals(textAppearanceInfo.getHintTextColor(), Color.GREEN); 714 assertEquals(textAppearanceInfo.getLinkTextColor(), Color.BLUE); 715 } 716 } 717