blob: 2cb51c7774b07df0d5499bb88bc61f51cd6e6ce7 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view.inputmethod.cts;
import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
import static android.view.inputmethod.CursorAnchorInfo.FLAG_IS_RTL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.text.LineBreakConfig;
import android.os.LocaleList;
import android.os.Parcel;
import android.platform.test.annotations.AppModeSdkSandbox;
import android.text.TextUtils;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.CursorAnchorInfo.Builder;
import android.view.inputmethod.EditorBoundsInfo;
import android.view.inputmethod.TextAppearanceInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.ApiTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
@AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).")
public class CursorAnchorInfoTest {
private static final float EPSILON = 0.0000001f;
private static final RectF[] MANY_BOUNDS = new RectF[] {
new RectF(101.0f, 201.0f, 301.0f, 401.0f),
new RectF(102.0f, 202.0f, 302.0f, 402.0f),
new RectF(103.0f, 203.0f, 303.0f, 403.0f),
new RectF(104.0f, 204.0f, 304.0f, 404.0f),
new RectF(105.0f, 205.0f, 305.0f, 405.0f),
new RectF(106.0f, 206.0f, 306.0f, 406.0f),
new RectF(107.0f, 207.0f, 307.0f, 407.0f),
new RectF(108.0f, 208.0f, 308.0f, 408.0f),
new RectF(109.0f, 209.0f, 309.0f, 409.0f),
new RectF(110.0f, 210.0f, 310.0f, 410.0f),
new RectF(111.0f, 211.0f, 311.0f, 411.0f),
new RectF(112.0f, 212.0f, 312.0f, 412.0f),
new RectF(113.0f, 213.0f, 313.0f, 413.0f),
new RectF(114.0f, 214.0f, 314.0f, 414.0f),
new RectF(115.0f, 215.0f, 315.0f, 415.0f),
new RectF(116.0f, 216.0f, 316.0f, 416.0f),
new RectF(117.0f, 217.0f, 317.0f, 417.0f),
new RectF(118.0f, 218.0f, 318.0f, 418.0f),
new RectF(119.0f, 219.0f, 319.0f, 419.0f),
};
private static final int[] MANY_FLAGS_ARRAY = new int[] {
FLAG_HAS_INVISIBLE_REGION,
FLAG_HAS_INVISIBLE_REGION | FLAG_HAS_VISIBLE_REGION,
FLAG_HAS_VISIBLE_REGION,
FLAG_HAS_VISIBLE_REGION,
FLAG_HAS_VISIBLE_REGION,
FLAG_HAS_VISIBLE_REGION,
FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
FLAG_HAS_INVISIBLE_REGION | FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL,
FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
FLAG_HAS_VISIBLE_REGION,
FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
FLAG_HAS_VISIBLE_REGION,
FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
FLAG_HAS_VISIBLE_REGION,
FLAG_HAS_VISIBLE_REGION | FLAG_IS_RTL,
FLAG_HAS_VISIBLE_REGION,
FLAG_HAS_INVISIBLE_REGION,
FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL,
};
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
@Test
@ApiTest(
apis = {
"android.view.inputmethod.CursorAnchorInfo#getComposingText",
"android.view.inputmethod.CursorAnchorInfo#getEditorBoundsInfo",
"android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerFlags",
"android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerHorizontal",
"android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerTop",
"android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerBaseline",
"android.view.inputmethod.CursorAnchorInfo#getInsertionMarkerBottom",
"android.view.inputmethod.CursorAnchorInfo#getSelectionStart",
"android.view.inputmethod.CursorAnchorInfo#getSelectionEnd",
"android.view.inputmethod.CursorAnchorInfo#getMatrix",
"android.view.inputmethod.CursorAnchorInfo#getVisibleLineBounds",
"android.view.inputmethod.CursorAnchorInfo#getTextAppearanceInfo",
"android.view.inputmethod.CursorAnchorInfo.Builder#build",
"android.view.inputmethod.CursorAnchorInfo.Builder#setComposingText",
"android.view.inputmethod.CursorAnchorInfo.Builder#setEditorBoundsInfo",
"android.view.inputmethod.CursorAnchorInfo.Builder#setMatrix",
"android.view.inputmethod.CursorAnchorInfo.Builder#setInsertionMarkerLocation",
"android.view.inputmethod.CursorAnchorInfo.Builder#setSelectinRange",
"android.view.inputmethod.CursorAnchorInfo.Builder#setVisibleLineBounds",
"android.view.inputmethod.CursorAnchorInfo.Builder#setTextAppearanceInfo",
}
)
public void testBuilder() {
final int selectionStart = 30;
final int selectionEnd = 40;
final int composingTextStart = 32;
final String composingText = "test";
final int insertionMarkerFlags =
FLAG_HAS_VISIBLE_REGION | FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL;
final float insertionMarkerHorizontal = 10.5f;
final float insertionMarkerTop = 100.1f;
final float insertionMarkerBaseline = 110.4f;
final float insertionMarkerBottom = 111.0f;
Matrix transformMatrix = new Matrix();
transformMatrix.setScale(10.0f, 20.0f);
final EditorBoundsInfo boundsInfo =
new EditorBoundsInfo.Builder().setEditorBounds(MANY_BOUNDS[0])
.setHandwritingBounds(MANY_BOUNDS[1]).build();
final TextAppearanceInfo textAppearanceInfo = createTextAppearanceInfoBuilder().build();
final Builder builder = new Builder();
builder.setSelectionRange(selectionStart, selectionEnd)
.setComposingText(composingTextStart, composingText)
.setInsertionMarkerLocation(insertionMarkerHorizontal, insertionMarkerTop,
insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags)
.setMatrix(transformMatrix)
.setEditorBoundsInfo(boundsInfo)
.setTextAppearanceInfo(textAppearanceInfo);
for (int i = 0; i < MANY_BOUNDS.length; i++) {
final RectF bounds = MANY_BOUNDS[i];
final int flags = MANY_FLAGS_ARRAY[i];
builder.addCharacterBounds(i, bounds.left, bounds.top, bounds.right, bounds.bottom,
flags);
builder.addVisibleLineBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
final CursorAnchorInfo info = builder.build();
assertEquals(selectionStart, info.getSelectionStart());
assertEquals(selectionEnd, info.getSelectionEnd());
assertEquals(composingTextStart, info.getComposingTextStart());
assertTrue(TextUtils.equals(composingText, info.getComposingText()));
assertEquals(insertionMarkerFlags, info.getInsertionMarkerFlags());
assertEquals(insertionMarkerHorizontal, info.getInsertionMarkerHorizontal(), EPSILON);
assertEquals(insertionMarkerTop, info.getInsertionMarkerTop(), EPSILON);
assertEquals(insertionMarkerBaseline, info.getInsertionMarkerBaseline(), EPSILON);
assertEquals(insertionMarkerBottom, info.getInsertionMarkerBottom(), EPSILON);
assertEquals(transformMatrix, info.getMatrix());
assertEquals(boundsInfo, info.getEditorBoundsInfo());
assertEquals(Arrays.asList(MANY_BOUNDS), info.getVisibleLineBounds());
assertEquals(MANY_BOUNDS[0],
info.getEditorBoundsInfo().getEditorBounds());
assertEquals(MANY_BOUNDS[1],
info.getEditorBoundsInfo().getHandwritingBounds());
for (int i = 0; i < MANY_BOUNDS.length; i++) {
final RectF expectedBounds = MANY_BOUNDS[i];
assertEquals(expectedBounds, info.getCharacterBounds(i));
}
assertNull(info.getCharacterBounds(-1));
assertNull(info.getCharacterBounds(MANY_BOUNDS.length + 1));
for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) {
final int expectedFlags = MANY_FLAGS_ARRAY[i];
assertEquals(expectedFlags, info.getCharacterBoundsFlags(i));
}
assertEquals(0, info.getCharacterBoundsFlags(-1));
assertEquals(0, info.getCharacterBoundsFlags(MANY_BOUNDS.length + 1));
assertEquals(textAppearanceInfo, info.getTextAppearanceInfo());
assertTextAppearanceInfoContentsEqual(info.getTextAppearanceInfo());
// Make sure that the builder can reproduce the same object.
final CursorAnchorInfo info2 = builder.build();
assertEquals(selectionStart, info2.getSelectionStart());
assertEquals(selectionEnd, info2.getSelectionEnd());
assertEquals(composingTextStart, info2.getComposingTextStart());
assertTrue(TextUtils.equals(composingText, info2.getComposingText()));
assertEquals(insertionMarkerFlags, info2.getInsertionMarkerFlags());
assertEquals(insertionMarkerHorizontal, info2.getInsertionMarkerHorizontal(), EPSILON);
assertEquals(insertionMarkerTop, info2.getInsertionMarkerTop(), EPSILON);
assertEquals(insertionMarkerBaseline, info2.getInsertionMarkerBaseline(), EPSILON);
assertEquals(insertionMarkerBottom, info2.getInsertionMarkerBottom(), EPSILON);
assertEquals(boundsInfo, info2.getEditorBoundsInfo());
assertEquals(Arrays.asList(MANY_BOUNDS), info2.getVisibleLineBounds());
assertEquals(transformMatrix, info2.getMatrix());
for (int i = 0; i < MANY_BOUNDS.length; i++) {
final RectF expectedBounds = MANY_BOUNDS[i];
assertEquals(expectedBounds, info2.getCharacterBounds(i));
}
assertNull(info2.getCharacterBounds(-1));
assertNull(info2.getCharacterBounds(MANY_BOUNDS.length + 1));
for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) {
final int expectedFlags = MANY_FLAGS_ARRAY[i];
assertEquals(expectedFlags, info2.getCharacterBoundsFlags(i));
}
assertEquals(0, info2.getCharacterBoundsFlags(-1));
assertEquals(0, info2.getCharacterBoundsFlags(MANY_BOUNDS.length + 1));
assertEquals(textAppearanceInfo, info2.getTextAppearanceInfo());
assertTextAppearanceInfoContentsEqual(info2.getTextAppearanceInfo());
assertEquals(info, info2);
assertEquals(info.hashCode(), info2.hashCode());
// Make sure that object can be marshaled via Parcel.
final CursorAnchorInfo info3 = cloneViaParcel(info2);
assertEquals(selectionStart, info3.getSelectionStart());
assertEquals(selectionEnd, info3.getSelectionEnd());
assertEquals(composingTextStart, info3.getComposingTextStart());
assertTrue(TextUtils.equals(composingText, info3.getComposingText()));
assertEquals(insertionMarkerFlags, info3.getInsertionMarkerFlags());
assertEquals(insertionMarkerHorizontal, info3.getInsertionMarkerHorizontal(), EPSILON);
assertEquals(insertionMarkerTop, info3.getInsertionMarkerTop(), EPSILON);
assertEquals(insertionMarkerBaseline, info3.getInsertionMarkerBaseline(), EPSILON);
assertEquals(insertionMarkerBottom, info3.getInsertionMarkerBottom(), EPSILON);
assertEquals(boundsInfo, info3.getEditorBoundsInfo());
assertEquals(Arrays.asList(MANY_BOUNDS), info3.getVisibleLineBounds());
assertEquals(transformMatrix, info3.getMatrix());
for (int i = 0; i < MANY_BOUNDS.length; i++) {
final RectF expectedBounds = MANY_BOUNDS[i];
assertEquals(expectedBounds, info3.getCharacterBounds(i));
}
assertNull(info3.getCharacterBounds(-1));
assertNull(info3.getCharacterBounds(MANY_BOUNDS.length + 1));
for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) {
final int expectedFlags = MANY_FLAGS_ARRAY[i];
assertEquals(expectedFlags, info3.getCharacterBoundsFlags(i));
}
assertEquals(0, info3.getCharacterBoundsFlags(-1));
assertEquals(0, info3.getCharacterBoundsFlags(MANY_BOUNDS.length + 1));
assertEquals(textAppearanceInfo, info3.getTextAppearanceInfo());
assertTextAppearanceInfoContentsEqual(info3.getTextAppearanceInfo());
assertEquals(info.hashCode(), info3.hashCode());
builder.reset();
final CursorAnchorInfo uninitializedInfo = builder.build();
assertEquals(-1, uninitializedInfo.getSelectionStart());
assertEquals(-1, uninitializedInfo.getSelectionEnd());
assertEquals(-1, uninitializedInfo.getComposingTextStart());
assertNull(uninitializedInfo.getComposingText());
assertEquals(0, uninitializedInfo.getInsertionMarkerFlags());
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal(), EPSILON);
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop(), EPSILON);
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline(), EPSILON);
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom(), EPSILON);
assertEquals(null, uninitializedInfo.getEditorBoundsInfo());
assertEquals(new ArrayList<>(), uninitializedInfo.getVisibleLineBounds());
assertEquals(new Matrix(), uninitializedInfo.getMatrix());
assertEquals(null, uninitializedInfo.getTextAppearanceInfo());
}
@Test
@ApiTest(
apis = {
"android.view.inputmethod.CursorAnchorInfo.Builder#build",
"android.view.inputmethod.CursorAnchorInfo.Builder#setComposingText",
"android.view.inputmethod.CursorAnchorInfo.Builder#setMatrix",
"android.view.inputmethod.CursorAnchorInfo.Builder#setInsertionMarkerLocation",
"android.view.inputmethod.CursorAnchorInfo.Builder#setSelectinRange",
"android.view.inputmethod.CursorAnchorInfo.Builder#setVisibleLineBounds",
"android.view.inputmethod.CursorAnchorInfo.Builder#setTextAppearanceInfo",
}
)
public void testEquality() {
final Matrix matrix1 = new Matrix();
matrix1.setTranslate(10.0f, 20.0f);
final Matrix matrix2 = new Matrix();
matrix2.setTranslate(110.0f, 120.0f);
final Matrix nanMatrix = new Matrix();
nanMatrix.setValues(new float[]{
Float.NaN, Float.NaN, Float.NaN,
Float.NaN, Float.NaN, Float.NaN,
Float.NaN, Float.NaN, Float.NaN});
final int selectionStart1 = 2;
final int selectionEnd1 = 7;
final String composingText1 = "0123456789";
final int composingTextStart1 = 0;
final int insertionMarkerFlags1 = FLAG_HAS_VISIBLE_REGION;
final float insertionMarkerHorizontal1 = 10.5f;
final float insertionMarkerTop1 = 100.1f;
final float insertionMarkerBaseline1 = 110.4f;
final float insertionMarkerBottom1 = 111.0f;
final int selectionStart2 = 4;
final int selectionEnd2 = 8;
final String composingText2 = "9876543210";
final int composingTextStart2 = 3;
final int insertionMarkerFlags2 =
FLAG_HAS_VISIBLE_REGION | FLAG_HAS_INVISIBLE_REGION | FLAG_IS_RTL;
final float insertionMarkerHorizontal2 = 14.5f;
final float insertionMarkerTop2 = 200.1f;
final float insertionMarkerBaseline2 = 210.4f;
final float insertionMarkerBottom2 = 211.0f;
final List<RectF> visibleLineBounds1 = Arrays.asList(MANY_BOUNDS[0], MANY_BOUNDS[1]);
final List<RectF> visibleLineBounds2 = Arrays.asList(MANY_BOUNDS[2], MANY_BOUNDS[3]);
// Default instance should be equal.
assertEquals(new Builder().build(), new Builder().build());
assertEquals(
new Builder().setSelectionRange(selectionStart1, selectionEnd1).build(),
new Builder().setSelectionRange(selectionStart1, selectionEnd1).build());
assertNotEquals(
new Builder().setSelectionRange(selectionStart1, selectionEnd1).build(),
new Builder().setSelectionRange(selectionStart1, selectionEnd2).build());
assertNotEquals(
new Builder().setSelectionRange(selectionStart1, selectionEnd1).build(),
new Builder().setSelectionRange(selectionStart2, selectionEnd1).build());
assertNotEquals(
new Builder().setSelectionRange(selectionStart1, selectionEnd1).build(),
new Builder().setSelectionRange(selectionStart2, selectionEnd2).build());
assertEquals(
new Builder().setComposingText(composingTextStart1, composingText1).build(),
new Builder().setComposingText(composingTextStart1, composingText1).build());
assertNotEquals(
new Builder().setComposingText(composingTextStart1, composingText1).build(),
new Builder().setComposingText(composingTextStart2, composingText1).build());
assertNotEquals(
new Builder().setComposingText(composingTextStart1, composingText1).build(),
new Builder().setComposingText(composingTextStart1, composingText2).build());
assertNotEquals(
new Builder().setComposingText(composingTextStart1, composingText1).build(),
new Builder().setComposingText(composingTextStart2, composingText2).build());
// For insertion marker locations, Float#NaN is treated as if it was a number.
assertEquals(
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
Float.NaN, Float.NaN, Float.NaN, Float.NaN,
insertionMarkerFlags1).build(),
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
Float.NaN, Float.NaN, Float.NaN, Float.NaN,
insertionMarkerFlags1).build());
// Check Matrix.
assertEquals(
new Builder().setMatrix(matrix1).build(),
new Builder().setMatrix(matrix1).build());
assertNotEquals(
new Builder().setMatrix(matrix1).build(),
new Builder().setMatrix(matrix2).build());
assertNotEquals(
new Builder().setMatrix(matrix1).build(),
new Builder().setMatrix(nanMatrix).build());
// Unlike insertion marker locations, Float#NaN in the matrix is treated as just a NaN as
// usual (NaN == NaN -> false).
assertNotEquals(
new Builder().setMatrix(nanMatrix).build(),
new Builder().setMatrix(nanMatrix).build());
assertEquals(
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build(),
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build());
assertNotEquals(
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
Float.NaN, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build(),
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build());
assertNotEquals(
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build(),
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal2, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build());
assertNotEquals(
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build(),
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop2,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build());
assertNotEquals(
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build(),
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline2, insertionMarkerBottom1,
insertionMarkerFlags1).build());
assertNotEquals(
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build(),
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal2, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build());
assertNotEquals(
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build(),
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom2,
insertionMarkerFlags1).build());
assertNotEquals(
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags1).build(),
new Builder().setMatrix(matrix1).setInsertionMarkerLocation(
insertionMarkerHorizontal1, insertionMarkerTop1,
insertionMarkerBaseline1, insertionMarkerBottom1,
insertionMarkerFlags2).build());
{
CursorAnchorInfo.Builder builder1 = new Builder().setMatrix(matrix1);
for (RectF rectF : visibleLineBounds1) {
builder1.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom);
}
CursorAnchorInfo.Builder builder2 = new Builder().setMatrix(matrix1);
for (RectF rectF : visibleLineBounds1) {
builder2.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom);
}
assertEquals(builder1.build(), builder2.build());
}
{
CursorAnchorInfo.Builder builder1 = new Builder().setMatrix(matrix1);
for (RectF rectF : visibleLineBounds1) {
builder1.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom);
}
CursorAnchorInfo.Builder builder2 = new Builder().setMatrix(matrix1);
for (RectF rectF : visibleLineBounds2) {
builder2.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom);
}
assertNotEquals(builder1.build(), builder2.build());
}
{
TextAppearanceInfo.Builder appearanceBuilder1 = createTextAppearanceInfoBuilder();
TextAppearanceInfo.Builder appearanceBuilder2 = createTextAppearanceInfoBuilder();
TextAppearanceInfo.Builder appearanceBuilder3 = createTextAppearanceInfoBuilder();
appearanceBuilder3.setTextSize(30f);
TextAppearanceInfo textAppearanceInfo1 = appearanceBuilder1.build();
TextAppearanceInfo textAppearanceInfo2 = appearanceBuilder2.build();
TextAppearanceInfo textAppearanceInfo3 = appearanceBuilder3.build();
assertEquals(new Builder().setTextAppearanceInfo(textAppearanceInfo1).build(),
new Builder().setTextAppearanceInfo(textAppearanceInfo1).build());
assertEquals(new Builder().setTextAppearanceInfo(textAppearanceInfo1).build(),
new Builder().setTextAppearanceInfo(textAppearanceInfo2).build());
assertNotEquals(new Builder().setTextAppearanceInfo(textAppearanceInfo1).build(),
new Builder().setTextAppearanceInfo(textAppearanceInfo3).build());
}
}
@Test
public void testMatrixIsCopied() {
final Matrix matrix1 = new Matrix();
matrix1.setTranslate(10.0f, 20.0f);
final Matrix matrix2 = new Matrix();
matrix2.setTranslate(110.0f, 120.0f);
final Matrix matrix3 = new Matrix();
matrix3.setTranslate(210.0f, 220.0f);
final Matrix matrix = new Matrix();
final Builder builder = new Builder();
matrix.set(matrix1);
builder.setMatrix(matrix);
matrix.postRotate(90.0f);
final CursorAnchorInfo firstInstance = builder.build();
assertEquals(matrix1, firstInstance.getMatrix());
matrix.set(matrix2);
builder.setMatrix(matrix);
final CursorAnchorInfo secondInstance = builder.build();
assertEquals(matrix1, firstInstance.getMatrix());
assertEquals(matrix2, secondInstance.getMatrix());
matrix.set(matrix3);
assertEquals(matrix1, firstInstance.getMatrix());
assertEquals(matrix2, secondInstance.getMatrix());
}
@Test
public void testMatrixIsRequired() {
final int selectionStart = 30;
final int selectionEnd = 40;
final int composingTextStart = 32;
final String composingText = "test";
final int insertionMarkerFlags = FLAG_HAS_VISIBLE_REGION;
final float insertionMarkerHorizontal = 10.5f;
final float insertionMarkerTop = 100.1f;
final float insertionMarkerBaseline = 110.4f;
final float insertionMarkerBottom = 111.0f;
Matrix transformMatrix = new Matrix();
transformMatrix.setScale(10.0f, 20.0f);
final Builder builder = new Builder();
// Check twice to make sure if Builder#reset() works as expected.
for (int repeatCount = 0; repeatCount < 2; ++repeatCount) {
builder.setSelectionRange(selectionStart, selectionEnd)
.setComposingText(composingTextStart, composingText);
try {
// Should succeed as coordinate transformation matrix is not required if no
// positional information is specified.
builder.build();
} catch (IllegalArgumentException ex) {
fail();
}
builder.setInsertionMarkerLocation(insertionMarkerHorizontal, insertionMarkerTop,
insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags);
try {
// Coordinate transformation matrix is required if no positional information is
// specified.
builder.build();
fail();
} catch (IllegalArgumentException ex) {
}
builder.setMatrix(transformMatrix);
try {
// Should succeed as coordinate transformation matrix is required.
builder.build();
} catch (IllegalArgumentException ex) {
fail();
}
builder.reset();
}
}
@Test
@ApiTest(apis = "android.view.inputmethod.CursorAnchorInfo.Builder#setVisibleLineBounds")
public void testMatrixIsRequiredForVisibleLineBounds() {
final List<RectF> visibleLineBounds = Arrays.asList(MANY_BOUNDS);
final Matrix transformMatrix = new Matrix();
final Builder builder = new Builder();
try {
// Should succeed as coordinate transformation matrix is not required if no
// positional information is specified.
builder.build();
} catch (IllegalArgumentException ex) {
fail();
}
for (RectF rectF: visibleLineBounds) {
builder.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom);
}
try {
// Should fail since visible line bounds requires coordinates transformation matrix.
builder.build();
fail();
} catch (IllegalArgumentException ex) {
}
builder.setMatrix(transformMatrix);
try {
// Should succeed as coordinate transformation matrix is provided.
builder.build();
} catch (IllegalArgumentException ex) {
fail();
}
}
@Test
@ApiTest(apis = "android.view.inputmethod.CursorAnchorInfo.Builder#addCharacterBounds")
public void testBuilderAddCharacterBounds() {
// A negative index should be rejected.
try {
new Builder().addCharacterBounds(-1, 0.0f, 0.0f, 0.0f, 0.0f, FLAG_HAS_VISIBLE_REGION);
fail();
} catch (IllegalArgumentException ex) {
}
}
@Test
@ApiTest(apis = "android.view.inputmethod.CursorAnchorInfo.Builder#clearVisibleLineBounds")
public void testBuilderClearVisibleLineBounds() {
CursorAnchorInfo.Builder builder = new Builder().setMatrix(Matrix.IDENTITY_MATRIX);
for (RectF rectF: MANY_BOUNDS) {
builder.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom);
}
// Making sure visible line bounds are added correctly.
assertEquals(Arrays.asList(MANY_BOUNDS), builder.build().getVisibleLineBounds());
builder.clearVisibleLineBounds();
// No visible line bounds is returned after clearVisibleLineBounds is called.
assertEquals(Collections.emptyList(), builder.build().getVisibleLineBounds());
// Add more line bounds and verify again.
List<RectF> rectFs = Arrays.asList(MANY_BOUNDS[1], MANY_BOUNDS[0]);
for (RectF rectF: rectFs) {
builder.addVisibleLineBounds(rectF.left, rectF.top, rectF.right, rectF.bottom);
}
assertEquals(rectFs, builder.build().getVisibleLineBounds());
}
@Test
@ApiTest(apis = {"android.view.inputmethod.CursorAnchorInfo#getTextAppearanceInfo",
"android.view.inputmethod.CursorAnchorInfo.Builder#setTextAppearanceInfo"})
public void testTextAppearanceInfoWithEmptyEditText() {
TextAppearanceInfo textAppearanceInfo = new TextAppearanceInfo.Builder().build();
CursorAnchorInfo.Builder builder = new Builder().setTextAppearanceInfo(textAppearanceInfo);
CursorAnchorInfo info1 = builder.build();
CursorAnchorInfo info2 = builder.build();
CursorAnchorInfo info3 = cloneViaParcel(info2);
assertEquals(textAppearanceInfo, info1.getTextAppearanceInfo());
assertEquals(textAppearanceInfo, info2.getTextAppearanceInfo());
assertEquals(textAppearanceInfo, info3.getTextAppearanceInfo());
}
private static CursorAnchorInfo cloneViaParcel(CursorAnchorInfo src) {
Parcel parcel = null;
try {
parcel = Parcel.obtain();
src.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
return new CursorAnchorInfo(parcel);
} finally {
if (parcel != null) {
parcel.recycle();
}
}
}
private TextAppearanceInfo.Builder createTextAppearanceInfoBuilder() {
TextAppearanceInfo.Builder builder = new TextAppearanceInfo.Builder()
.setTextSize(16.5f)
.setTextLocales(LocaleList.forLanguageTags("en,ja"))
.setSystemFontFamilyName("sans-serif")
.setTextFontWeight(10)
.setTextStyle(Typeface.ITALIC)
.setAllCaps(true)
.setShadowDx(2.0f)
.setShadowDy(2.0f)
.setShadowRadius(2.0f)
.setShadowColor(Color.GRAY)
.setElegantTextHeight(true)
.setFallbackLineSpacing(true)
.setLetterSpacing(5.0f)
.setFontFeatureSettings("smcp")
.setFontVariationSettings("'wdth' 1.0")
.setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_LOOSE)
.setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE)
.setTextScaleX(1.5f)
.setHighlightTextColor(Color.YELLOW)
.setTextColor(Color.RED)
.setHintTextColor(Color.GREEN)
.setLinkTextColor(Color.BLUE);
return builder;
}
private void assertTextAppearanceInfoContentsEqual(TextAppearanceInfo textAppearanceInfo) {
assertEquals(textAppearanceInfo.getTextSize(), 16.5f, EPSILON);
assertEquals(textAppearanceInfo.getTextLocales(), LocaleList.forLanguageTags("en,ja"));
assertEquals(textAppearanceInfo.getSystemFontFamilyName(), "sans-serif");
assertEquals(textAppearanceInfo.getTextFontWeight(), 10);
assertEquals(textAppearanceInfo.getTextStyle(), Typeface.ITALIC);
assertTrue(textAppearanceInfo.isAllCaps());
assertEquals(textAppearanceInfo.getShadowRadius(), 2.0f, EPSILON);
assertEquals(textAppearanceInfo.getShadowDx(), 2.0f, EPSILON);
assertEquals(textAppearanceInfo.getShadowDy(), 2.0f, EPSILON);
assertEquals(textAppearanceInfo.getShadowColor(), Color.GRAY);
assertTrue(textAppearanceInfo.isElegantTextHeight());
assertTrue(textAppearanceInfo.isFallbackLineSpacing());
assertEquals(textAppearanceInfo.getLetterSpacing(), 5.0f, EPSILON);
assertEquals(textAppearanceInfo.getFontFeatureSettings(), "smcp");
assertEquals(textAppearanceInfo.getFontVariationSettings(), "'wdth' 1.0");
assertEquals(textAppearanceInfo.getLineBreakStyle(),
LineBreakConfig.LINE_BREAK_STYLE_LOOSE);
assertEquals(textAppearanceInfo.getLineBreakWordStyle(),
LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE);
assertEquals(textAppearanceInfo.getTextScaleX(), 1.5f, EPSILON);
assertEquals(textAppearanceInfo.getHighlightTextColor(), Color.YELLOW);
assertEquals(textAppearanceInfo.getTextColor(), Color.RED);
assertEquals(textAppearanceInfo.getHintTextColor(), Color.GREEN);
assertEquals(textAppearanceInfo.getLinkTextColor(), Color.BLUE);
}
}