1 /* 2 * Copyright (C) 2022 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 org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertThrows; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.fail; 23 24 import android.graphics.Matrix; 25 import android.graphics.RectF; 26 import android.os.Parcel; 27 import android.text.SegmentFinder; 28 import android.view.inputmethod.TextBoundsInfo; 29 import android.view.inputmethod.TextBoundsInfoResult; 30 31 import androidx.test.filters.SmallTest; 32 import androidx.test.runner.AndroidJUnit4; 33 34 import com.android.compatibility.common.util.ApiTest; 35 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 39 @SmallTest 40 @RunWith(AndroidJUnit4.class) 41 public class TextBoundsInfoTest { 42 private static final float[] CHARACTER_BOUNDS1 = new float[] { 43 0.0f, 0.0f, 10.0f, 20.0f, 44 10.0f, 0.0f, 20.0f, 20.0f, 45 20.0f, 0.0f, 30.0f, 20.0f, 46 10.0f, 20.0f, 20.0f, 40.0f, 47 0.0f, 20.0f, 10.0f, 40.0f}; 48 49 private static final float[] CHARACTER_BOUNDS2 = new float[] { 50 20.0f, 0.0f, 30.0f, 20.0f, 51 10.0f, 0.0f, 20.0f, 20.0f, 52 0.0f, 0.0f, 10.0f, 20.0f, 53 0.0f, 20.0f, 10.0f, 40.0f, 54 10.0f, 20.0f, 20.0f, 40.0f}; 55 56 private static final int LTR_BIDI_LEVEL = 0; 57 private static final int RTL_BIDI_LEVEL = 1; 58 private static final int MAX_BIDI_LEVEL = 125; 59 private static final int[] CHARACTER_BIDI_LEVEL1 = new int[] {LTR_BIDI_LEVEL, LTR_BIDI_LEVEL, 60 LTR_BIDI_LEVEL, RTL_BIDI_LEVEL, MAX_BIDI_LEVEL}; 61 private static final int[] CHARACTER_BIDI_LEVEL2 = new int[] {MAX_BIDI_LEVEL, RTL_BIDI_LEVEL, 62 LTR_BIDI_LEVEL, LTR_BIDI_LEVEL, LTR_BIDI_LEVEL}; 63 private static final int[] CHARACTER_FLAGS1 = new int[] { 64 TextBoundsInfo.FLAG_CHARACTER_WHITESPACE, 65 TextBoundsInfo.FLAG_CHARACTER_PUNCTUATION, 66 TextBoundsInfo.FLAG_CHARACTER_LINEFEED, 67 TextBoundsInfo.FLAG_LINE_IS_RTL, 68 TextBoundsInfo.FLAG_LINE_IS_RTL 69 }; 70 71 private static final int[] CHARACTER_FLAGS2 = new int[] {TextBoundsInfo.FLAG_LINE_IS_RTL, 72 TextBoundsInfo.FLAG_LINE_IS_RTL, TextBoundsInfo.FLAG_CHARACTER_WHITESPACE, 0, 0}; 73 74 private static final SegmentFinder GRAPHEME_SEGMENT_FINDER1 = 75 new SegmentFinder.PrescribedSegmentFinder( 76 new int[] { 0, 1, 1, 2, 2, 4, 4, 5, 5, 7, 7, 8, 8, 9, 9, 10, 10, 11 }); 77 78 private static final SegmentFinder GRAPHEME_SEGMENT_FINDER2 = 79 new SegmentFinder.PrescribedSegmentFinder( 80 new int[] { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10 }); 81 82 private static final SegmentFinder WORD_SEGMENT_FINDER1 = 83 new SegmentFinder.PrescribedSegmentFinder(new int[] { 0, 3, 4, 5, 5, 10 }); 84 private static final SegmentFinder WORD_SEGMENT_FINDER2 = 85 new SegmentFinder.PrescribedSegmentFinder(new int[] { 0, 4, 5, 8, 9, 11 }); 86 87 88 private static final SegmentFinder LINE_SEGMENT_FINDER1 = 89 new SegmentFinder.PrescribedSegmentFinder(new int[] { 0, 5, 5, 8, 8, 10, 10, 15 }); 90 private static final SegmentFinder LINE_SEGMENT_FINDER2 = 91 new SegmentFinder.PrescribedSegmentFinder(new int[] { 0, 5, 5, 7, 7, 10, 10, 15 }); 92 93 @Test 94 @ApiTest( 95 apis = { 96 "android.view.inputmethod.TextBoundsInfo#getStart", 97 "android.view.inputmethod.TextBoundsInfo#getEnd", 98 "android.view.inputmethod.TextBoundsInfo#getMatrix", 99 "android.view.inputmethod.TextBoundsInfo#getCharacterBounds", 100 "android.view.inputmethod.TextBoundsInfo#getCharacterFlags", 101 "android.view.inputmethod.TextBoundsInfo#getCharacterBidiLevel", 102 "android.view.inputmethod.TextBoundsInfo#getGraphemeSegmentFinder", 103 "android.view.inputmethod.TextBoundsInfo#getWordSegmentFinder", 104 "android.view.inputmethod.TextBoundsInfo#getLineSegmentFinder", 105 "android.view.inputmethod.TextBoundsInfo.Builder#setStart", 106 "android.view.inputmethod.TextBoundsInfo.Builder#setEnd", 107 "android.view.inputmethod.TextBoundsInfo.Builder#setMatrix", 108 "android.view.inputmethod.TextBoundsInfo.Builder#setCharacterBounds", 109 "android.view.inputmethod.TextBoundsInfo.Builder#setCharacterFlags", 110 "android.view.inputmethod.TextBoundsInfo.Builder#setCharacterBidiLevel", 111 "android.view.inputmethod.TextBoundsInfo.Builder#setGraphemeSegmentFinder", 112 "android.view.inputmethod.TextBoundsInfo.Builder#setWordSegmentFinder", 113 "android.view.inputmethod.TextBoundsInfo.Builder#setLineSegmentFinder", 114 "android.view.inputmethod.TextBoundsInfo.Builder#build", 115 } 116 ) testBuilder()117 public void testBuilder() { 118 final int start1 = 5; 119 final int end1 = 10; 120 final Matrix matrix1 = new Matrix(); 121 matrix1.setRotate(10f); 122 123 TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder(start1, end1); 124 TextBoundsInfo textBoundsInfo1 = builder.setMatrix(matrix1) 125 .setCharacterBounds(CHARACTER_BOUNDS1) 126 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 127 .setCharacterFlags(CHARACTER_FLAGS1) 128 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 129 .setWordSegmentFinder(WORD_SEGMENT_FINDER1) 130 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 131 .build(); 132 133 assertEquals(start1, textBoundsInfo1.getStartIndex()); 134 assertEquals(end1, textBoundsInfo1.getEndIndex()); 135 final Matrix actualMatrix = new Matrix(); 136 textBoundsInfo1.getMatrix(actualMatrix); 137 assertEquals(matrix1, actualMatrix); 138 assertCharacterBounds(CHARACTER_BOUNDS1, textBoundsInfo1); 139 assertCharacterBidiLevel(CHARACTER_BIDI_LEVEL1, textBoundsInfo1); 140 assertCharacterFlags(CHARACTER_FLAGS1, textBoundsInfo1); 141 assertEquals(GRAPHEME_SEGMENT_FINDER1, textBoundsInfo1.getGraphemeSegmentFinder()); 142 assertEquals(WORD_SEGMENT_FINDER1, textBoundsInfo1.getWordSegmentFinder()); 143 assertEquals(LINE_SEGMENT_FINDER1, textBoundsInfo1.getLineSegmentFinder()); 144 145 // Build another TextBoundsInfo, making sure the Builder creates an identical object. 146 TextBoundsInfo textBoundsInfo2 = builder.build(); 147 assertEquals(start1, textBoundsInfo2.getStartIndex()); 148 assertEquals(end1, textBoundsInfo2.getEndIndex()); 149 textBoundsInfo2.getMatrix(actualMatrix); 150 assertEquals(matrix1, actualMatrix); 151 assertCharacterBounds(CHARACTER_BOUNDS1, textBoundsInfo2); 152 assertCharacterBidiLevel(CHARACTER_BIDI_LEVEL1, textBoundsInfo2); 153 assertCharacterFlags(CHARACTER_FLAGS1, textBoundsInfo2); 154 assertEquals(GRAPHEME_SEGMENT_FINDER1, textBoundsInfo2.getGraphemeSegmentFinder()); 155 assertEquals(WORD_SEGMENT_FINDER1, textBoundsInfo2.getWordSegmentFinder()); 156 assertEquals(LINE_SEGMENT_FINDER1, textBoundsInfo2.getLineSegmentFinder()); 157 158 final int start2 = 8; 159 final int end2 = 13; 160 final Matrix matrix2 = new Matrix(); 161 matrix2.setTranslate(20f, 30f); 162 163 // Clear the existing parameters and build a different object. 164 TextBoundsInfo textBoundsInfo3 = builder.clear() 165 .setStartAndEnd(start2, end2) 166 .setMatrix(matrix2) 167 .setCharacterBounds(CHARACTER_BOUNDS2) 168 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL2) 169 .setCharacterFlags(CHARACTER_FLAGS2) 170 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER2) 171 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 172 .setLineSegmentFinder(LINE_SEGMENT_FINDER2) 173 .build(); 174 175 assertEquals(start2, textBoundsInfo3.getStartIndex()); 176 assertEquals(end2, textBoundsInfo3.getEndIndex()); 177 textBoundsInfo3.getMatrix(actualMatrix); 178 assertEquals(matrix2, actualMatrix); 179 assertCharacterBounds(CHARACTER_BOUNDS2, textBoundsInfo3); 180 assertCharacterBidiLevel(CHARACTER_BIDI_LEVEL2, textBoundsInfo3); 181 assertCharacterFlags(CHARACTER_FLAGS2, textBoundsInfo3); 182 assertEquals(GRAPHEME_SEGMENT_FINDER2, textBoundsInfo3.getGraphemeSegmentFinder()); 183 assertEquals(WORD_SEGMENT_FINDER2, textBoundsInfo3.getWordSegmentFinder()); 184 assertEquals(LINE_SEGMENT_FINDER2, textBoundsInfo3.getLineSegmentFinder()); 185 } 186 187 @Test 188 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo#writeToParcel" }) testTextBoundsInfo_writeToParcel()189 public void testTextBoundsInfo_writeToParcel() { 190 final Matrix matrix = new Matrix(); 191 matrix.setRotate(15f); 192 193 TextBoundsInfo textBoundsInfo1 = new TextBoundsInfo.Builder(5, 10) 194 .setMatrix(matrix) 195 .setCharacterBounds(CHARACTER_BOUNDS1) 196 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 197 .setCharacterFlags(CHARACTER_FLAGS1) 198 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 199 .setWordSegmentFinder(WORD_SEGMENT_FINDER1) 200 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 201 .build(); 202 203 // Gut check, making sure the first TextBoundsInfo is built correctly. 204 assertEquals(5, textBoundsInfo1.getStartIndex()); 205 assertEquals(10, textBoundsInfo1.getEndIndex()); 206 final Matrix actualMatrix = new Matrix(); 207 textBoundsInfo1.getMatrix(actualMatrix); 208 assertEquals(matrix, actualMatrix); 209 assertCharacterBounds(CHARACTER_BOUNDS1, textBoundsInfo1); 210 assertCharacterFlags(CHARACTER_FLAGS1, textBoundsInfo1); 211 assertCharacterBidiLevel(CHARACTER_BIDI_LEVEL1, textBoundsInfo1); 212 assertEquals(GRAPHEME_SEGMENT_FINDER1, textBoundsInfo1.getGraphemeSegmentFinder()); 213 assertEquals(WORD_SEGMENT_FINDER1, textBoundsInfo1.getWordSegmentFinder()); 214 assertEquals(LINE_SEGMENT_FINDER1, textBoundsInfo1.getLineSegmentFinder()); 215 216 Parcel parcel = Parcel.obtain(); 217 final int dataPosition = parcel.dataPosition(); 218 parcel.writeParcelable(textBoundsInfo1, 0); 219 parcel.setDataPosition(dataPosition); 220 221 TextBoundsInfo textBoundsInfo2 = 222 parcel.readParcelable(TextBoundsInfo.class.getClassLoader(), TextBoundsInfo.class); 223 224 assertEquals(5, textBoundsInfo2.getStartIndex()); 225 assertEquals(10, textBoundsInfo2.getEndIndex()); 226 textBoundsInfo2.getMatrix(actualMatrix); 227 assertEquals(matrix, actualMatrix); 228 assertCharacterBounds(CHARACTER_BOUNDS1, textBoundsInfo2); 229 assertCharacterFlags(CHARACTER_FLAGS1, textBoundsInfo1); 230 assertCharacterBidiLevel(CHARACTER_BIDI_LEVEL1, textBoundsInfo1); 231 // Only check the iterator in the given range. 232 assertSegmentFinderEqualsInRange(GRAPHEME_SEGMENT_FINDER1, 233 textBoundsInfo2.getGraphemeSegmentFinder(), 5, 10); 234 assertSegmentFinderEqualsInRange(WORD_SEGMENT_FINDER1, 235 textBoundsInfo2.getWordSegmentFinder(), 5, 10); 236 assertSegmentFinderEqualsInRange(LINE_SEGMENT_FINDER1, 237 textBoundsInfo2.getLineSegmentFinder(), 5, 10); 238 } 239 240 241 @Test(expected = IllegalStateException.class) 242 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_matrix_isRequired()243 public void testBuilder_matrix_isRequired() { 244 new TextBoundsInfo.Builder(5, 10) 245 .setCharacterBounds(CHARACTER_BOUNDS1) 246 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 247 .setCharacterFlags(CHARACTER_FLAGS1) 248 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 249 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 250 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 251 .build(); 252 } 253 254 @Test(expected = IllegalStateException.class) 255 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_startAndEnd_isRequired()256 public void testBuilder_startAndEnd_isRequired() { 257 final TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder(5, 10); 258 builder.clear(); 259 builder.setMatrix(Matrix.IDENTITY_MATRIX) 260 .setCharacterBounds(CHARACTER_BOUNDS1) 261 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 262 .setCharacterFlags(CHARACTER_FLAGS1) 263 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 264 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 265 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 266 .build(); 267 } 268 269 @Test(expected = IllegalArgumentException.class) 270 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setStart" }) testBuilder_start_isNegative()271 public void testBuilder_start_isNegative() { 272 new TextBoundsInfo.Builder(-1 , 5); 273 } 274 275 @Test(expected = IllegalArgumentException.class) 276 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setEnd" }) testBuilder_end_isNegative()277 public void testBuilder_end_isNegative() { 278 new TextBoundsInfo.Builder(0, -1); 279 } 280 281 @Test(expected = IllegalArgumentException.class) 282 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_startGreaterThanEnd()283 public void testBuilder_startGreaterThanEnd() { 284 new TextBoundsInfo.Builder(1, 0); 285 } 286 287 @Test(expected = IllegalStateException.class) 288 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_characterBounds_isRequired()289 public void testBuilder_characterBounds_isRequired() { 290 new TextBoundsInfo.Builder(5, 10) 291 .setMatrix(Matrix.IDENTITY_MATRIX) 292 .setCharacterFlags(CHARACTER_FLAGS1) 293 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 294 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 295 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 296 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 297 .build(); 298 } 299 300 @Test(expected = NullPointerException.class) 301 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setCharacterBounds" }) testBuilder_characterBounds_isNull()302 public void testBuilder_characterBounds_isNull() { 303 new TextBoundsInfo.Builder(0, 5).setCharacterBounds(null); 304 } 305 306 @Test(expected = IllegalStateException.class) 307 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_characterBounds_wrongLength()308 public void testBuilder_characterBounds_wrongLength() { 309 // Expected characterBounds.length == 20 to match the given range [0, 5). 310 new TextBoundsInfo.Builder(5, 10) 311 .setMatrix(Matrix.IDENTITY_MATRIX) 312 .setCharacterBounds(new float[16]) 313 .setCharacterFlags(CHARACTER_FLAGS1) 314 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 315 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 316 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 317 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 318 .build(); 319 } 320 321 @Test(expected = IllegalStateException.class) 322 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_characterFlags_isRequired()323 public void testBuilder_characterFlags_isRequired() { 324 new TextBoundsInfo.Builder(5, 10) 325 .setMatrix(Matrix.IDENTITY_MATRIX) 326 .setCharacterBounds(CHARACTER_BOUNDS1) 327 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 328 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 329 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 330 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 331 .build(); 332 } 333 334 @Test(expected = NullPointerException.class) 335 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setCharacterFlags" }) testBuilder_characterFlags_isNull()336 public void testBuilder_characterFlags_isNull() { 337 new TextBoundsInfo.Builder(5, 10).setCharacterFlags(null); 338 } 339 340 @Test(expected = IllegalStateException.class) 341 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_characterFlags_wrongLength()342 public void testBuilder_characterFlags_wrongLength() { 343 // Expected characterFlags.length == 5 to match the given range [0, 5). 344 new TextBoundsInfo.Builder(5, 10) 345 .setMatrix(Matrix.IDENTITY_MATRIX) 346 .setCharacterFlags(new int[6]) 347 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 348 .setCharacterBounds(CHARACTER_BOUNDS1) 349 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 350 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 351 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 352 .build(); 353 } 354 355 @Test(expected = IllegalStateException.class) 356 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_characterBidiLevel_isRequired()357 public void testBuilder_characterBidiLevel_isRequired() { 358 new TextBoundsInfo.Builder(5, 10) 359 .setMatrix(Matrix.IDENTITY_MATRIX) 360 .setCharacterBounds(CHARACTER_BOUNDS1) 361 .setCharacterFlags(CHARACTER_FLAGS1) 362 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 363 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 364 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 365 .build(); 366 } 367 368 @Test(expected = NullPointerException.class) 369 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setCharacterBidiLevel" }) testBuilder_characterBidiLevel_isNull()370 public void testBuilder_characterBidiLevel_isNull() { 371 new TextBoundsInfo.Builder(5, 10).setCharacterBidiLevel(null); 372 } 373 374 @Test(expected = IllegalStateException.class) 375 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_characterBidiLevel_wrongLength()376 public void testBuilder_characterBidiLevel_wrongLength() { 377 // Expected characterBidiLevel.length == 5 to match the given range [0, 5). 378 new TextBoundsInfo.Builder(5, 10) 379 .setMatrix(Matrix.IDENTITY_MATRIX) 380 .setCharacterFlags(CHARACTER_FLAGS1) 381 .setCharacterBidiLevel(new int[6]) 382 .setCharacterBounds(CHARACTER_BOUNDS1) 383 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 384 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 385 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 386 .build(); 387 } 388 389 @Test 390 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setCharacterBidiLevel" }) testBuilder_characterBidiLevel_invalidBidiLevel()391 public void testBuilder_characterBidiLevel_invalidBidiLevel() { 392 // Bidi level must be in the range of [0, 125]. 393 try { 394 new TextBoundsInfo.Builder(0, 1).setCharacterBidiLevel(new int[] { 126 }); 395 fail(); 396 } catch (IllegalArgumentException ignored) { } 397 398 try { 399 new TextBoundsInfo.Builder(0 , 1).setCharacterBidiLevel(new int[] { -1 }); 400 fail(); 401 } catch (IllegalArgumentException ignored) { } 402 } 403 404 @Test 405 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setCharacterBidiLevel" }) testBuilder_characterBidiLevel_isCleared()406 public void testBuilder_characterBidiLevel_isCleared() { 407 final var builder = new TextBoundsInfo.Builder(5, 10) 408 .setMatrix(Matrix.IDENTITY_MATRIX) 409 .setCharacterFlags(CHARACTER_FLAGS1) 410 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 411 .setCharacterBounds(CHARACTER_BOUNDS1) 412 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 413 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 414 .setLineSegmentFinder(LINE_SEGMENT_FINDER1); 415 builder.build(); 416 417 builder.clear(); 418 builder.setMatrix(Matrix.IDENTITY_MATRIX) 419 .setStartAndEnd(5, 10) 420 .setCharacterFlags(CHARACTER_FLAGS1) 421 // omit setting characterBidiLevel. 422 .setCharacterBounds(CHARACTER_BOUNDS1) 423 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 424 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 425 .setLineSegmentFinder(LINE_SEGMENT_FINDER1); 426 427 assertThrows(IllegalStateException.class, builder::build); 428 } 429 430 @Test(expected = IllegalArgumentException.class) 431 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setCharacterFlags" }) testBuilder_characterFlags_invalidFlag()432 public void testBuilder_characterFlags_invalidFlag() { 433 TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder(0, 5); 434 435 // 1 << 20 is an unknown flags 436 int[] characterFlags = new int[] { 0, 1 << 20, 0, 0, 0}; 437 builder.setCharacterFlags(characterFlags); 438 } 439 440 @Test(expected = IllegalStateException.class) 441 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_graphemeSegmentFinder_isRequired()442 public void testBuilder_graphemeSegmentFinder_isRequired() { 443 new TextBoundsInfo.Builder(5, 10) 444 .setMatrix(Matrix.IDENTITY_MATRIX) 445 .setCharacterBounds(CHARACTER_BOUNDS1) 446 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 447 .setCharacterFlags(CHARACTER_FLAGS1) 448 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 449 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 450 .build(); 451 } 452 453 @Test(expected = NullPointerException.class) 454 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setGraphemeSegmentFinder" }) testBuilder_graphemeSegmentFinder_isNull()455 public void testBuilder_graphemeSegmentFinder_isNull() { 456 new TextBoundsInfo.Builder(5, 10).setGraphemeSegmentFinder(null); 457 } 458 459 @Test(expected = IllegalStateException.class) 460 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_wordSegmentFinder_isRequired()461 public void testBuilder_wordSegmentFinder_isRequired() { 462 new TextBoundsInfo.Builder(5, 10) 463 .setMatrix(Matrix.IDENTITY_MATRIX) 464 .setCharacterBounds(CHARACTER_BOUNDS1) 465 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 466 .setCharacterFlags(CHARACTER_FLAGS1) 467 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 468 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 469 .build(); 470 } 471 472 @Test(expected = NullPointerException.class) 473 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setWordSegmentFinder" }) testBuilder_wordSegmentFinder_isNull()474 public void testBuilder_wordSegmentFinder_isNull() { 475 new TextBoundsInfo.Builder(5, 10).setWordSegmentFinder(null); 476 } 477 478 @Test(expected = IllegalStateException.class) 479 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#build" }) testBuilder_lineSegmentFinder_isRequired()480 public void testBuilder_lineSegmentFinder_isRequired() { 481 new TextBoundsInfo.Builder(5, 10) 482 .setMatrix(Matrix.IDENTITY_MATRIX) 483 .setCharacterBounds(CHARACTER_BOUNDS1) 484 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 485 .setCharacterFlags(CHARACTER_FLAGS1) 486 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 487 .setWordSegmentFinder(WORD_SEGMENT_FINDER2) 488 .build(); 489 } 490 491 @Test(expected = NullPointerException.class) 492 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfo.Builder#setLineSegmentFinder" }) testBuilder_lineSegmentFinder_isNull()493 public void testBuilder_lineSegmentFinder_isNull() { 494 new TextBoundsInfo.Builder(5, 10).setLineSegmentFinder(null); 495 } 496 497 @Test 498 @ApiTest(apis = { "android.view.inputmethod.TextBoundsInfoResult#getResultCode", 499 "android.view.inputmethod.TextBoundsInfoResult#getTextBoundsInfo"}) testTextBoundsInfoResult_constructor()500 public void testTextBoundsInfoResult_constructor() { 501 TextBoundsInfoResult result = 502 new TextBoundsInfoResult(TextBoundsInfoResult.CODE_UNSUPPORTED); 503 assertEquals(result.getResultCode(), TextBoundsInfoResult.CODE_UNSUPPORTED); 504 505 result = new TextBoundsInfoResult(TextBoundsInfoResult.CODE_FAILED); 506 assertEquals(result.getResultCode(), TextBoundsInfoResult.CODE_FAILED); 507 508 result = new TextBoundsInfoResult(TextBoundsInfoResult.CODE_CANCELLED); 509 assertEquals(result.getResultCode(), TextBoundsInfoResult.CODE_CANCELLED); 510 511 final TextBoundsInfo textBoundsInfo = new TextBoundsInfo.Builder(5, 10) 512 .setCharacterBounds(CHARACTER_BOUNDS1) 513 .setCharacterBidiLevel(CHARACTER_BIDI_LEVEL1) 514 .setMatrix(Matrix.IDENTITY_MATRIX) 515 .setCharacterFlags(CHARACTER_FLAGS1) 516 .setGraphemeSegmentFinder(GRAPHEME_SEGMENT_FINDER1) 517 .setWordSegmentFinder(WORD_SEGMENT_FINDER1) 518 .setLineSegmentFinder(LINE_SEGMENT_FINDER1) 519 .build(); 520 521 result = new TextBoundsInfoResult(TextBoundsInfoResult.CODE_SUCCESS, 522 textBoundsInfo); 523 assertEquals(result.getResultCode(), TextBoundsInfoResult.CODE_SUCCESS); 524 assertEquals(result.getTextBoundsInfo(), textBoundsInfo); 525 } 526 527 @Test testTextBoundsInfoResult_resultCodeIsSuccess_textBoundsInfoIsRequired()528 public void testTextBoundsInfoResult_resultCodeIsSuccess_textBoundsInfoIsRequired() { 529 try { 530 new TextBoundsInfoResult(TextBoundsInfoResult.CODE_SUCCESS); 531 fail(); 532 } catch (IllegalStateException ignored) { } 533 534 try { 535 new TextBoundsInfoResult(TextBoundsInfoResult.CODE_SUCCESS, null); 536 fail(); 537 } catch (IllegalStateException ignored) { } 538 539 } 540 assertCharacterBounds(float[] characterBounds, TextBoundsInfo textBoundsInfo)541 private static void assertCharacterBounds(float[] characterBounds, 542 TextBoundsInfo textBoundsInfo) { 543 final int start = textBoundsInfo.getStartIndex(); 544 final int end = textBoundsInfo.getEndIndex(); 545 for (int offset = 0; offset < end - start; ++offset) { 546 final RectF expectedRect = new RectF( 547 characterBounds[4 * offset], 548 characterBounds[4 * offset + 1], 549 characterBounds[4 * offset + 2], 550 characterBounds[4 * offset + 3]); 551 552 final RectF actualRectF = new RectF(); 553 textBoundsInfo.getCharacterBounds(offset + start, actualRectF); 554 assertEquals(expectedRect, actualRectF); 555 } 556 } 557 assertCharacterFlags(int[] characterFlags, TextBoundsInfo textBoundsInfo)558 private static void assertCharacterFlags(int[] characterFlags, 559 TextBoundsInfo textBoundsInfo) { 560 final int start = textBoundsInfo.getStartIndex(); 561 final int end = textBoundsInfo.getEndIndex(); 562 for (int offset = 0; offset < end - start; ++offset) { 563 assertEquals(characterFlags[offset], 564 textBoundsInfo.getCharacterFlags(offset + start)); 565 } 566 } 567 assertCharacterBidiLevel(int[] characterBidiLevels, TextBoundsInfo textBoundsInfo)568 private static void assertCharacterBidiLevel(int[] characterBidiLevels, 569 TextBoundsInfo textBoundsInfo) { 570 final int start = textBoundsInfo.getStartIndex(); 571 final int end = textBoundsInfo.getEndIndex(); 572 for (int offset = 0; offset < end - start; ++offset) { 573 assertEquals(characterBidiLevels[offset], 574 textBoundsInfo.getCharacterBidiLevel(offset + start)); 575 } 576 } 577 578 /** 579 * Helper method to assert that the given {@link SegmentFinder}s are the same in the given 580 * range. 581 */ assertSegmentFinderEqualsInRange(SegmentFinder expect, SegmentFinder actual, int start, int end)582 private static void assertSegmentFinderEqualsInRange(SegmentFinder expect, 583 SegmentFinder actual, int start, int end) { 584 int expectSegmentEnd = expect.nextEndBoundary(start); 585 int expectSegmentStart = expect.previousStartBoundary(expectSegmentEnd); 586 587 int actualSegmentEnd = actual.nextEndBoundary(start); 588 int actualSegmentStart = actual.previousStartBoundary(actualSegmentEnd); 589 590 while (expectSegmentStart != SegmentFinder.DONE && expectSegmentEnd <= end) { 591 assertEquals(expectSegmentStart, actualSegmentStart); 592 assertEquals(expectSegmentEnd, actualSegmentEnd); 593 594 expectSegmentStart = expect.nextStartBoundary(expectSegmentStart); 595 actualSegmentStart = actual.nextStartBoundary(actualSegmentStart); 596 597 expectSegmentEnd = expect.nextEndBoundary(expectSegmentEnd); 598 actualSegmentEnd = actual.nextEndBoundary(actualSegmentEnd); 599 } 600 601 // The actual SegmentFinder doesn't have more segments within the range. 602 assertTrue(actualSegmentEnd > end || actualSegmentEnd == SegmentFinder.DONE); 603 } 604 } 605