Merge "Polish new IME API for L: CursorAnchorInfo"
This commit is contained in:
@@ -34837,6 +34837,7 @@ package android.view.inputmethod {
|
||||
ctor public CursorAnchorInfo(android.os.Parcel);
|
||||
method public int describeContents();
|
||||
method public android.graphics.RectF getCharacterRect(int);
|
||||
method public int getCharacterRectFlags(int);
|
||||
method public java.lang.CharSequence getComposingText();
|
||||
method public int getComposingTextStart();
|
||||
method public float getInsertionMarkerBaseline();
|
||||
@@ -34846,17 +34847,24 @@ package android.view.inputmethod {
|
||||
method public android.graphics.Matrix getMatrix();
|
||||
method public int getSelectionEnd();
|
||||
method public int getSelectionStart();
|
||||
method public boolean isInsertionMarkerClipped();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1; // 0x1
|
||||
field public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3; // 0x3
|
||||
field public static final int CHARACTER_RECT_TYPE_MASK = 15; // 0xf
|
||||
field public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4; // 0x4
|
||||
field public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2; // 0x2
|
||||
field public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0; // 0x0
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
}
|
||||
|
||||
public static final class CursorAnchorInfo.Builder {
|
||||
ctor public CursorAnchorInfo.Builder();
|
||||
method public android.view.inputmethod.CursorAnchorInfo.Builder addCharacterRect(int, float, float, float, float);
|
||||
method public android.view.inputmethod.CursorAnchorInfo.Builder addCharacterRect(int, float, float, float, float, int);
|
||||
method public android.view.inputmethod.CursorAnchorInfo build();
|
||||
method public void reset();
|
||||
method public android.view.inputmethod.CursorAnchorInfo.Builder setComposingText(int, java.lang.CharSequence);
|
||||
method public android.view.inputmethod.CursorAnchorInfo.Builder setInsertionMarkerLocation(float, float, float, float);
|
||||
method public android.view.inputmethod.CursorAnchorInfo.Builder setInsertionMarkerLocation(float, float, float, float, boolean);
|
||||
method public android.view.inputmethod.CursorAnchorInfo.Builder setMatrix(android.graphics.Matrix);
|
||||
method public android.view.inputmethod.CursorAnchorInfo.Builder setSelectionRange(int, int);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,10 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
*/
|
||||
private final CharSequence mComposingText;
|
||||
|
||||
/**
|
||||
* {@code True} if the insertion marker is partially or entirely clipped by other UI elements.
|
||||
*/
|
||||
private final boolean mInsertionMarkerClipped;
|
||||
/**
|
||||
* Horizontal position of the insertion marker, in the local coordinates that will be
|
||||
* transformed with the transformation matrix when rendered on the screen. This should be
|
||||
@@ -86,11 +90,36 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
*/
|
||||
private final Matrix mMatrix;
|
||||
|
||||
public static final int CHARACTER_RECT_TYPE_MASK = 0x0f;
|
||||
/**
|
||||
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this
|
||||
* character. Editor authors should not use this flag.
|
||||
*/
|
||||
public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0;
|
||||
/**
|
||||
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible.
|
||||
*/
|
||||
public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1;
|
||||
/**
|
||||
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible.
|
||||
*/
|
||||
public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2;
|
||||
/**
|
||||
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible.
|
||||
*/
|
||||
public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3;
|
||||
/**
|
||||
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle
|
||||
* for this character. Input method authors should ignore the returned rectangle.
|
||||
*/
|
||||
public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4;
|
||||
|
||||
public CursorAnchorInfo(final Parcel source) {
|
||||
mSelectionStart = source.readInt();
|
||||
mSelectionEnd = source.readInt();
|
||||
mComposingTextStart = source.readInt();
|
||||
mComposingText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
|
||||
mInsertionMarkerClipped = (source.readInt() != 0);
|
||||
mInsertionMarkerHorizontal = source.readFloat();
|
||||
mInsertionMarkerTop = source.readFloat();
|
||||
mInsertionMarkerBaseline = source.readFloat();
|
||||
@@ -112,6 +141,7 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
dest.writeInt(mSelectionEnd);
|
||||
dest.writeInt(mComposingTextStart);
|
||||
TextUtils.writeToParcel(mComposingText, dest, flags);
|
||||
dest.writeInt(mInsertionMarkerClipped ? 1 : 0);
|
||||
dest.writeFloat(mInsertionMarkerHorizontal);
|
||||
dest.writeFloat(mInsertionMarkerTop);
|
||||
dest.writeFloat(mInsertionMarkerBaseline);
|
||||
@@ -129,6 +159,8 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
+ mInsertionMarkerBaseline + mInsertionMarkerBottom;
|
||||
int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash);
|
||||
hash *= 31;
|
||||
hash += (mInsertionMarkerClipped ? 2 : 1);
|
||||
hash *= 31;
|
||||
hash += mSelectionStart + mSelectionEnd + mComposingTextStart;
|
||||
hash *= 31;
|
||||
hash += Objects.hashCode(mComposingText);
|
||||
@@ -172,7 +204,8 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
|| !Objects.equals(mComposingText, that.mComposingText)) {
|
||||
return false;
|
||||
}
|
||||
if (!areSameFloatImpl(mInsertionMarkerHorizontal, that.mInsertionMarkerHorizontal)
|
||||
if (mInsertionMarkerClipped != that.mInsertionMarkerClipped
|
||||
|| !areSameFloatImpl(mInsertionMarkerHorizontal, that.mInsertionMarkerHorizontal)
|
||||
|| !areSameFloatImpl(mInsertionMarkerTop, that.mInsertionMarkerTop)
|
||||
|| !areSameFloatImpl(mInsertionMarkerBaseline, that.mInsertionMarkerBaseline)
|
||||
|| !areSameFloatImpl(mInsertionMarkerBottom, that.mInsertionMarkerBottom)) {
|
||||
@@ -195,6 +228,7 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd
|
||||
+ " mComposingTextStart=" + mComposingTextStart
|
||||
+ " mComposingText=" + Objects.toString(mComposingText)
|
||||
+ " mInsertionMarkerClipped=" + mInsertionMarkerClipped
|
||||
+ " mInsertionMarkerHorizontal=" + mInsertionMarkerHorizontal
|
||||
+ " mInsertionMarkerTop=" + mInsertionMarkerTop
|
||||
+ " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline
|
||||
@@ -256,25 +290,27 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
* @param lineBottom vertical position of the insertion marker, in the local coordinates
|
||||
* that will be transformed with the transformation matrix when rendered on the screen. This
|
||||
* should be calculated or compatible with {@link Layout#getLineBottom(int)}.
|
||||
* @param clipped {@code true} is the insertion marker is partially or entierly clipped by
|
||||
* other UI elements.
|
||||
*/
|
||||
public Builder setInsertionMarkerLocation(final float horizontalPosition,
|
||||
final float lineTop, final float lineBaseline, final float lineBottom){
|
||||
final float lineTop, final float lineBaseline, final float lineBottom,
|
||||
final boolean clipped){
|
||||
mInsertionMarkerHorizontal = horizontalPosition;
|
||||
mInsertionMarkerTop = lineTop;
|
||||
mInsertionMarkerBaseline = lineBaseline;
|
||||
mInsertionMarkerBottom = lineBottom;
|
||||
mInsertionMarkerClipped = clipped;
|
||||
return this;
|
||||
}
|
||||
private float mInsertionMarkerHorizontal = Float.NaN;
|
||||
private float mInsertionMarkerTop = Float.NaN;
|
||||
private float mInsertionMarkerBaseline = Float.NaN;
|
||||
private float mInsertionMarkerBottom = Float.NaN;
|
||||
private boolean mInsertionMarkerClipped = false;
|
||||
|
||||
/**
|
||||
* Adds the bounding box of the character specified with the index.
|
||||
* <p>
|
||||
* Editor authors should not call this method for characters that are invisible.
|
||||
* </p>
|
||||
*
|
||||
* @param index index of the character in Java chars units. Must be specified in
|
||||
* ascending order across successive calls.
|
||||
@@ -286,19 +322,27 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
* coordinates, that is, right edge for LTR text and left edge for RTL text.
|
||||
* @param trailingEdgeY y coordinate of the trailing edge of the character in local
|
||||
* coordinates.
|
||||
* @param flags type and flags for this character. See
|
||||
* {@link #CHARACTER_RECT_TYPE_FULLY_VISIBLE} for example.
|
||||
* @throws IllegalArgumentException If the index is a negative value, or not greater than
|
||||
* all of the previously called indices.
|
||||
*/
|
||||
public Builder addCharacterRect(final int index, final float leadingEdgeX,
|
||||
final float leadingEdgeY, final float trailingEdgeX, final float trailingEdgeY) {
|
||||
final float leadingEdgeY, final float trailingEdgeX, final float trailingEdgeY,
|
||||
final int flags) {
|
||||
if (index < 0) {
|
||||
throw new IllegalArgumentException("index must not be a negative integer.");
|
||||
}
|
||||
final int type = flags & CHARACTER_RECT_TYPE_MASK;
|
||||
if (type == CHARACTER_RECT_TYPE_UNSPECIFIED) {
|
||||
throw new IllegalArgumentException("Type except for "
|
||||
+ "CHARACTER_RECT_TYPE_UNSPECIFIED must be specified.");
|
||||
}
|
||||
if (mCharacterRectBuilder == null) {
|
||||
mCharacterRectBuilder = new SparseRectFArrayBuilder();
|
||||
}
|
||||
mCharacterRectBuilder.append(index, leadingEdgeX, leadingEdgeY, trailingEdgeX,
|
||||
trailingEdgeY);
|
||||
trailingEdgeY, flags);
|
||||
return this;
|
||||
}
|
||||
private SparseRectFArrayBuilder mCharacterRectBuilder = null;
|
||||
@@ -346,6 +390,7 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
mSelectionEnd = -1;
|
||||
mComposingTextStart = -1;
|
||||
mComposingText = null;
|
||||
mInsertionMarkerClipped = false;
|
||||
mInsertionMarkerHorizontal = Float.NaN;
|
||||
mInsertionMarkerTop = Float.NaN;
|
||||
mInsertionMarkerBaseline = Float.NaN;
|
||||
@@ -363,6 +408,7 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
mSelectionEnd = builder.mSelectionEnd;
|
||||
mComposingTextStart = builder.mComposingTextStart;
|
||||
mComposingText = builder.mComposingText;
|
||||
mInsertionMarkerClipped = builder.mInsertionMarkerClipped;
|
||||
mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal;
|
||||
mInsertionMarkerTop = builder.mInsertionMarkerTop;
|
||||
mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline;
|
||||
@@ -404,6 +450,14 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
return mComposingText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the visibility of the insertion marker.
|
||||
* @return {@code true} if the insertion marker is partially or entirely clipped.
|
||||
*/
|
||||
public boolean isInsertionMarkerClipped() {
|
||||
return mInsertionMarkerClipped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal start of the insertion marker, in the local coordinates that will
|
||||
* be transformed with {@link #getMatrix()} when rendered on the screen.
|
||||
@@ -415,6 +469,7 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
public float getInsertionMarkerHorizontal() {
|
||||
return mInsertionMarkerHorizontal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertical top position of the insertion marker, in the local coordinates that
|
||||
* will be transformed with {@link #getMatrix()} when rendered on the screen.
|
||||
@@ -424,6 +479,7 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
public float getInsertionMarkerTop() {
|
||||
return mInsertionMarkerTop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertical baseline position of the insertion marker, in the local coordinates
|
||||
* that will be transformed with {@link #getMatrix()} when rendered on the screen.
|
||||
@@ -433,6 +489,7 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
public float getInsertionMarkerBaseline() {
|
||||
return mInsertionMarkerBaseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertical bottom position of the insertion marker, in the local coordinates
|
||||
* that will be transformed with {@link #getMatrix()} when rendered on the screen.
|
||||
@@ -466,6 +523,20 @@ public final class CursorAnchorInfo implements Parcelable {
|
||||
return mCharacterRects.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flags associated with the character specified with the index.
|
||||
* @param index index of the character in a Java chars.
|
||||
* @return {@link #CHARACTER_RECT_TYPE_UNSPECIFIED} if no flag is specified.
|
||||
*/
|
||||
// TODO: Prepare a document about the expected behavior for surrogate pairs, combining
|
||||
// characters, and non-graphical chars.
|
||||
public int getCharacterRectFlags(final int index) {
|
||||
if (mCharacterRects == null) {
|
||||
return CHARACTER_RECT_TYPE_UNSPECIFIED;
|
||||
}
|
||||
return mCharacterRects.getFlags(index, CHARACTER_RECT_TYPE_UNSPECIFIED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@link android.graphics.Matrix} that indicates the transformation
|
||||
* matrix that is to be applied other positional data in this class.
|
||||
|
||||
@@ -50,9 +50,15 @@ public final class SparseRectFArray implements Parcelable {
|
||||
*/
|
||||
private final float[] mCoordinates;
|
||||
|
||||
/**
|
||||
* Stores visibility information.
|
||||
*/
|
||||
private final int[] mFlagsArray;
|
||||
|
||||
public SparseRectFArray(final Parcel source) {
|
||||
mKeys = source.createIntArray();
|
||||
mCoordinates = source.createFloatArray();
|
||||
mFlagsArray = source.createIntArray();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,6 +71,7 @@ public final class SparseRectFArray implements Parcelable {
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeIntArray(mKeys);
|
||||
dest.writeFloatArray(mCoordinates);
|
||||
dest.writeIntArray(mFlagsArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,6 +86,8 @@ public final class SparseRectFArray implements Parcelable {
|
||||
hash *= 31;
|
||||
hash += mCoordinates[i];
|
||||
}
|
||||
hash *= 31;
|
||||
hash += mFlagsArray[0];
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -95,12 +104,13 @@ public final class SparseRectFArray implements Parcelable {
|
||||
}
|
||||
final SparseRectFArray that = (SparseRectFArray) obj;
|
||||
|
||||
return Arrays.equals(mKeys, that.mKeys) && Arrays.equals(mCoordinates, that.mCoordinates);
|
||||
return Arrays.equals(mKeys, that.mKeys) && Arrays.equals(mCoordinates, that.mCoordinates)
|
||||
&& Arrays.equals(mFlagsArray, that.mFlagsArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (mKeys == null || mCoordinates == null) {
|
||||
if (mKeys == null || mCoordinates == null || mFlagsArray == null) {
|
||||
return "SparseRectFArray{}";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
@@ -119,7 +129,8 @@ public final class SparseRectFArray implements Parcelable {
|
||||
sb.append(mCoordinates[baseIndex + 2]);
|
||||
sb.append(",");
|
||||
sb.append(mCoordinates[baseIndex + 3]);
|
||||
sb.append("]");
|
||||
sb.append("]:flagsArray=");
|
||||
sb.append(mFlagsArray[i]);
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
@@ -153,6 +164,9 @@ public final class SparseRectFArray implements Parcelable {
|
||||
if (mCoordinates == null) {
|
||||
mCoordinates = new float[INITIAL_SIZE * 4];
|
||||
}
|
||||
if (mFlagsArray == null) {
|
||||
mFlagsArray = new int[INITIAL_SIZE];
|
||||
}
|
||||
final int requiredIndexArraySize = mCount + 1;
|
||||
if (mKeys.length <= requiredIndexArraySize) {
|
||||
final int[] newArray = new int[requiredIndexArraySize * 2];
|
||||
@@ -165,6 +179,12 @@ public final class SparseRectFArray implements Parcelable {
|
||||
System.arraycopy(mCoordinates, 0, newArray, 0, mCount * 4);
|
||||
mCoordinates = newArray;
|
||||
}
|
||||
final int requiredFlagsArraySize = requiredIndexArraySize;
|
||||
if (mFlagsArray.length <= requiredFlagsArraySize) {
|
||||
final int[] newArray = new int[requiredFlagsArraySize * 2];
|
||||
System.arraycopy(mFlagsArray, 0, newArray, 0, mCount);
|
||||
mFlagsArray = newArray;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,11 +195,13 @@ public final class SparseRectFArray implements Parcelable {
|
||||
* @param top top of the rectangle.
|
||||
* @param right right of the rectangle.
|
||||
* @param bottom bottom of the rectangle.
|
||||
* @param flags an arbitrary integer value to be associated with this rectangle.
|
||||
* @return the receiver object itself for chaining method calls.
|
||||
* @throws IllegalArgumentException If the index is not greater than all of existing keys.
|
||||
*/
|
||||
public SparseRectFArrayBuilder append(final int key,
|
||||
final float left, final float top, final float right, final float bottom) {
|
||||
final float left, final float top, final float right, final float bottom,
|
||||
final int flags) {
|
||||
checkIndex(key);
|
||||
ensureBufferSize();
|
||||
final int baseCoordinatesIndex = mCount * 4;
|
||||
@@ -187,6 +209,8 @@ public final class SparseRectFArray implements Parcelable {
|
||||
mCoordinates[baseCoordinatesIndex + 1] = top;
|
||||
mCoordinates[baseCoordinatesIndex + 2] = right;
|
||||
mCoordinates[baseCoordinatesIndex + 3] = bottom;
|
||||
final int flagsIndex = mCount;
|
||||
mFlagsArray[flagsIndex] = flags;
|
||||
mKeys[mCount] = key;
|
||||
++mCount;
|
||||
return this;
|
||||
@@ -194,6 +218,7 @@ public final class SparseRectFArray implements Parcelable {
|
||||
private int mCount = 0;
|
||||
private int[] mKeys = null;
|
||||
private float[] mCoordinates = null;
|
||||
private int[] mFlagsArray = null;
|
||||
private static int INITIAL_SIZE = 16;
|
||||
|
||||
public boolean isEmpty() {
|
||||
@@ -211,6 +236,7 @@ public final class SparseRectFArray implements Parcelable {
|
||||
if (mCount == 0) {
|
||||
mKeys = null;
|
||||
mCoordinates = null;
|
||||
mFlagsArray = null;
|
||||
}
|
||||
mCount = 0;
|
||||
}
|
||||
@@ -220,11 +246,14 @@ public final class SparseRectFArray implements Parcelable {
|
||||
if (builder.mCount == 0) {
|
||||
mKeys = null;
|
||||
mCoordinates = null;
|
||||
mFlagsArray = null;
|
||||
} else {
|
||||
mKeys = new int[builder.mCount];
|
||||
mCoordinates = new float[builder.mCount * 4];
|
||||
mFlagsArray = new int[builder.mCount];
|
||||
System.arraycopy(builder.mKeys, 0, mKeys, 0, builder.mCount);
|
||||
System.arraycopy(builder.mCoordinates, 0, mCoordinates, 0, builder.mCount * 4);
|
||||
System.arraycopy(builder.mFlagsArray, 0, mFlagsArray, 0, builder.mCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +275,20 @@ public final class SparseRectFArray implements Parcelable {
|
||||
mCoordinates[baseCoordIndex + 3]);
|
||||
}
|
||||
|
||||
public int getFlags(final int index, final int valueIfKeyNotFound) {
|
||||
if (mKeys == null) {
|
||||
return valueIfKeyNotFound;
|
||||
}
|
||||
if (index < 0) {
|
||||
return valueIfKeyNotFound;
|
||||
}
|
||||
final int arrayIndex = Arrays.binarySearch(mKeys, index);
|
||||
if (arrayIndex < 0) {
|
||||
return valueIfKeyNotFound;
|
||||
}
|
||||
return mFlagsArray[arrayIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to make this class parcelable.
|
||||
*/
|
||||
|
||||
@@ -3088,13 +3088,22 @@ public class Editor {
|
||||
final float bottom = layout.getLineBottom(line)
|
||||
+ viewportToContentVerticalOffset;
|
||||
// Take TextView's padding and scroll into account.
|
||||
if (isPositionVisible(left, top) && isPositionVisible(right, bottom)) {
|
||||
// Here offset is the index in Java chars.
|
||||
// TODO: We must have a well-defined specification. For example, how
|
||||
// RTL, surrogate pairs, and composition letters are handled must be
|
||||
// documented.
|
||||
builder.addCharacterRect(offset, left, top, right, bottom);
|
||||
// TODO: Check right-top and left-bottom as well.
|
||||
final boolean leftTopVisible = isPositionVisible(left, top);
|
||||
final boolean rightBottomVisible = isPositionVisible(right, bottom);
|
||||
final int characterRectFlags;
|
||||
if (leftTopVisible && rightBottomVisible) {
|
||||
characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_FULLY_VISIBLE;
|
||||
} else if (leftTopVisible || rightBottomVisible) {
|
||||
characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE;
|
||||
} else {
|
||||
characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_INVISIBLE;
|
||||
}
|
||||
// Here offset is the index in Java chars.
|
||||
// TODO: We must have a well-defined specification. For example, how
|
||||
// RTL, surrogate pairs, and composition letters are handled must be
|
||||
// documented.
|
||||
builder.addCharacterRect(offset, left, top, right, bottom, characterRectFlags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3111,11 +3120,10 @@ public class Editor {
|
||||
final float insertionMarkerBottom = layout.getLineBottom(line)
|
||||
+ viewportToContentVerticalOffset;
|
||||
// Take TextView's padding and scroll into account.
|
||||
if (isPositionVisible(insertionMarkerX, insertionMarkerTop) &&
|
||||
isPositionVisible(insertionMarkerX, insertionMarkerBottom)) {
|
||||
builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
|
||||
insertionMarkerBaseline, insertionMarkerBottom);
|
||||
}
|
||||
final boolean isClipped = !isPositionVisible(insertionMarkerX, insertionMarkerTop)
|
||||
|| !isPositionVisible(insertionMarkerX, insertionMarkerBottom);
|
||||
builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
|
||||
insertionMarkerBaseline, insertionMarkerBottom, isClipped);
|
||||
}
|
||||
|
||||
imm.updateCursorAnchorInfo(mTextView, builder.build());
|
||||
|
||||
@@ -26,17 +26,21 @@ import android.view.inputmethod.CursorAnchorInfo.Builder;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static android.view.inputmethod.CursorAnchorInfo.CHARACTER_RECT_TYPE_FULLY_VISIBLE;
|
||||
import static android.view.inputmethod.CursorAnchorInfo.CHARACTER_RECT_TYPE_INVISIBLE;
|
||||
import static android.view.inputmethod.CursorAnchorInfo.CHARACTER_RECT_TYPE_NOT_FEASIBLE;
|
||||
import static android.view.inputmethod.CursorAnchorInfo.CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE;
|
||||
import static android.view.inputmethod.CursorAnchorInfo.CHARACTER_RECT_TYPE_UNSPECIFIED;
|
||||
|
||||
public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
// null represents a character that is invisible, for example because it's overlapped by some
|
||||
// other UI elements.
|
||||
private static final RectF[] MANY_RECTS = new RectF[] {
|
||||
null,
|
||||
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),
|
||||
null,
|
||||
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),
|
||||
@@ -47,8 +51,29 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
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),
|
||||
null,
|
||||
null,
|
||||
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[] {
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_INVISIBLE,
|
||||
CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_NOT_FEASIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE,
|
||||
CHARACTER_RECT_TYPE_NOT_FEASIBLE,
|
||||
CHARACTER_RECT_TYPE_NOT_FEASIBLE,
|
||||
};
|
||||
|
||||
@SmallTest
|
||||
@@ -57,6 +82,7 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
final int SELECTION_END = 40;
|
||||
final int COMPOSING_TEXT_START = 32;
|
||||
final String COMPOSING_TEXT = "test";
|
||||
final boolean INSERTION_MARKER_CLIPPED = true;
|
||||
final float INSERTION_MARKER_HORIZONTAL = 10.5f;
|
||||
final float INSERTION_MARKER_TOP = 100.1f;
|
||||
final float INSERTION_MARKER_BASELINE = 110.4f;
|
||||
@@ -68,13 +94,13 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
builder.setSelectionRange(SELECTION_START, SELECTION_END)
|
||||
.setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT)
|
||||
.setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
|
||||
INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM)
|
||||
INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM,
|
||||
INSERTION_MARKER_CLIPPED)
|
||||
.setMatrix(TRANSFORM_MATRIX);
|
||||
for (int i = 0; i < MANY_RECTS.length; i++) {
|
||||
final RectF rect = MANY_RECTS[i];
|
||||
if (rect != null) {
|
||||
builder.addCharacterRect(i, rect.left, rect.top, rect.right, rect.bottom);
|
||||
}
|
||||
final int flags = MANY_FLAGS_ARRAY[i];
|
||||
builder.addCharacterRect(i, rect.left, rect.top, rect.right, rect.bottom, flags);
|
||||
}
|
||||
|
||||
final CursorAnchorInfo info = builder.build();
|
||||
@@ -82,6 +108,7 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
assertEquals(SELECTION_END, info.getSelectionEnd());
|
||||
assertEquals(COMPOSING_TEXT_START, info.getComposingTextStart());
|
||||
assertTrue(TextUtils.equals(COMPOSING_TEXT, info.getComposingText()));
|
||||
assertTrue(info.isInsertionMarkerClipped());
|
||||
assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal());
|
||||
assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop());
|
||||
assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline());
|
||||
@@ -93,6 +120,14 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
}
|
||||
assertNull(info.getCharacterRect(-1));
|
||||
assertNull(info.getCharacterRect(MANY_RECTS.length + 1));
|
||||
for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) {
|
||||
final int expectedFlags = MANY_FLAGS_ARRAY[i];
|
||||
assertEquals(expectedFlags, info.getCharacterRectFlags(i));
|
||||
}
|
||||
assertEquals(CHARACTER_RECT_TYPE_UNSPECIFIED,
|
||||
info.getCharacterRectFlags(-1));
|
||||
assertEquals(CHARACTER_RECT_TYPE_UNSPECIFIED,
|
||||
info.getCharacterRectFlags(MANY_RECTS.length + 1));
|
||||
|
||||
// Make sure that the builder can reproduce the same object.
|
||||
final CursorAnchorInfo info2 = builder.build();
|
||||
@@ -100,6 +135,7 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
assertEquals(SELECTION_END, info2.getSelectionEnd());
|
||||
assertEquals(COMPOSING_TEXT_START, info2.getComposingTextStart());
|
||||
assertTrue(TextUtils.equals(COMPOSING_TEXT, info2.getComposingText()));
|
||||
assertTrue(info2.isInsertionMarkerClipped());
|
||||
assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal());
|
||||
assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop());
|
||||
assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline());
|
||||
@@ -111,6 +147,13 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
}
|
||||
assertNull(info2.getCharacterRect(-1));
|
||||
assertNull(info2.getCharacterRect(MANY_RECTS.length + 1));
|
||||
for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) {
|
||||
final int expectedFlags = MANY_FLAGS_ARRAY[i];
|
||||
assertEquals(expectedFlags, info2.getCharacterRectFlags(i));
|
||||
}
|
||||
assertEquals(CHARACTER_RECT_TYPE_UNSPECIFIED, info2.getCharacterRectFlags(-1));
|
||||
assertEquals(CHARACTER_RECT_TYPE_UNSPECIFIED,
|
||||
info2.getCharacterRectFlags(MANY_RECTS.length + 1));
|
||||
assertEquals(info, info2);
|
||||
assertEquals(info.hashCode(), info2.hashCode());
|
||||
|
||||
@@ -120,6 +163,7 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
assertEquals(SELECTION_END, info3.getSelectionEnd());
|
||||
assertEquals(COMPOSING_TEXT_START, info3.getComposingTextStart());
|
||||
assertTrue(TextUtils.equals(COMPOSING_TEXT, info3.getComposingText()));
|
||||
assertTrue(info3.isInsertionMarkerClipped());
|
||||
assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal());
|
||||
assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop());
|
||||
assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline());
|
||||
@@ -131,6 +175,13 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
}
|
||||
assertNull(info3.getCharacterRect(-1));
|
||||
assertNull(info3.getCharacterRect(MANY_RECTS.length + 1));
|
||||
for (int i = 0; i < MANY_FLAGS_ARRAY.length; i++) {
|
||||
final int expectedFlags = MANY_FLAGS_ARRAY[i];
|
||||
assertEquals(expectedFlags, info3.getCharacterRectFlags(i));
|
||||
}
|
||||
assertEquals(CHARACTER_RECT_TYPE_UNSPECIFIED, info3.getCharacterRectFlags(-1));
|
||||
assertEquals(CHARACTER_RECT_TYPE_UNSPECIFIED,
|
||||
info3.getCharacterRectFlags(MANY_RECTS.length + 1));
|
||||
assertEquals(info.hashCode(), info3.hashCode());
|
||||
|
||||
builder.reset();
|
||||
@@ -139,6 +190,7 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
assertEquals(-1, uninitializedInfo.getSelectionEnd());
|
||||
assertEquals(-1, uninitializedInfo.getComposingTextStart());
|
||||
assertNull(uninitializedInfo.getComposingText());
|
||||
assertFalse(uninitializedInfo.isInsertionMarkerClipped());
|
||||
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal());
|
||||
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop());
|
||||
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline());
|
||||
@@ -166,6 +218,7 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
final int SELECTION_END1 = 7;
|
||||
final String COMPOSING_TEXT1 = "0123456789";
|
||||
final int COMPOSING_TEXT_START1 = 0;
|
||||
final boolean INSERTION_MARKER_CLIPPED1 = true;
|
||||
final float INSERTION_MARKER_HORIZONTAL1 = 10.5f;
|
||||
final float INSERTION_MARKER_TOP1 = 100.1f;
|
||||
final float INSERTION_MARKER_BASELINE1 = 110.4f;
|
||||
@@ -174,6 +227,7 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
final int SELECTION_END2 = 8;
|
||||
final String COMPOSING_TEXT2 = "9876543210";
|
||||
final int COMPOSING_TEXT_START2 = 3;
|
||||
final boolean INSERTION_MARKER_CLIPPED2 = false;
|
||||
final float INSERTION_MARKER_HORIZONTAL2 = 14.5f;
|
||||
final float INSERTION_MARKER_TOP2 = 200.1f;
|
||||
final float INSERTION_MARKER_BASELINE2 = 210.4f;
|
||||
@@ -210,9 +264,11 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
// For insertion marker locations, {@link Float#NaN} is treated as if it was a number.
|
||||
assertEquals(
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
Float.NaN, Float.NaN, Float.NaN, Float.NaN).build(),
|
||||
Float.NaN, Float.NaN, Float.NaN, Float.NaN,
|
||||
INSERTION_MARKER_CLIPPED1).build(),
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
Float.NaN, Float.NaN, Float.NaN, Float.NaN).build());
|
||||
Float.NaN, Float.NaN, Float.NaN, Float.NaN,
|
||||
INSERTION_MARKER_CLIPPED1).build());
|
||||
|
||||
// Check Matrix.
|
||||
assertEquals(
|
||||
@@ -233,52 +289,75 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
assertEquals(
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build(),
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build(),
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build());
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build());
|
||||
assertNotEquals(
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
Float.NaN, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build(),
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build(),
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build());
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build());
|
||||
assertNotEquals(
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build(),
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build(),
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL2, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build());
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build());
|
||||
assertNotEquals(
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build(),
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build(),
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP2,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build());
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build());
|
||||
assertNotEquals(
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build(),
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build(),
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE2, INSERTION_MARKER_BOTOM1).build());
|
||||
INSERTION_MARKER_BASELINE2, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build());
|
||||
assertNotEquals(
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build(),
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build(),
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL2, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build());
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build());
|
||||
assertNotEquals(
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1).build(),
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build(),
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM2).build());
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM2,
|
||||
INSERTION_MARKER_CLIPPED1).build());
|
||||
assertNotEquals(
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED1).build(),
|
||||
new Builder().setMatrix(MATRIX1).setInsertionMarkerLocation(
|
||||
INSERTION_MARKER_HORIZONTAL1, INSERTION_MARKER_TOP1,
|
||||
INSERTION_MARKER_BASELINE1, INSERTION_MARKER_BOTOM1,
|
||||
INSERTION_MARKER_CLIPPED2).build());
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@@ -315,6 +394,7 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
final int SELECTION_END = 40;
|
||||
final int COMPOSING_TEXT_START = 32;
|
||||
final String COMPOSING_TEXT = "test";
|
||||
final boolean INSERTION_MARKER_CLIPPED = true;
|
||||
final float INSERTION_MARKER_HORIZONTAL = 10.5f;
|
||||
final float INSERTION_MARKER_TOP = 100.1f;
|
||||
final float INSERTION_MARKER_BASELINE = 110.4f;
|
||||
@@ -330,25 +410,25 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
try {
|
||||
// Should succeed as coordinate transformation matrix is not required if no
|
||||
// positional information is specified.
|
||||
new Builder().build();
|
||||
builder.build();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertTrue(false);
|
||||
}
|
||||
|
||||
builder.setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
|
||||
INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM);
|
||||
INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM, INSERTION_MARKER_CLIPPED);
|
||||
try {
|
||||
// Coordinate transformation matrix is required if no positional information is
|
||||
// specified.
|
||||
new Builder().build();
|
||||
builder.build();
|
||||
assertTrue(false);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
builder.setMatrix(TRANSFORM_MATRIX);
|
||||
try {
|
||||
// Should succeed as coordinate transformation matrix is required.
|
||||
new Builder().build();
|
||||
builder.build();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertTrue(false);
|
||||
}
|
||||
@@ -358,12 +438,21 @@ public class CursorAnchorInfoTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testBuilderAdd() throws Exception {
|
||||
public void testBuilderAddCharacterRect() throws Exception {
|
||||
// A negative index should be rejected.
|
||||
try {
|
||||
new Builder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
new Builder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f,
|
||||
CHARACTER_RECT_TYPE_FULLY_VISIBLE);
|
||||
assertTrue(false);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
}
|
||||
|
||||
// CHARACTER_RECT_TYPE_UNSPECIFIED is not allowed.
|
||||
try {
|
||||
new Builder().addCharacterRect(0, 0.0f, 0.0f, 0.0f, 0.0f,
|
||||
CHARACTER_RECT_TYPE_UNSPECIFIED);
|
||||
assertTrue(false);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,14 +52,22 @@ public class SparseRectFArrayTest extends InstrumentationTestCase {
|
||||
@SmallTest
|
||||
public void testBuilder() throws Exception {
|
||||
final RectF TEMP_RECT = new RectF(10.0f, 20.0f, 30.0f, 40.0f);
|
||||
final int TEMP_FLAGS = 0x1234;
|
||||
|
||||
final SparseRectFArrayBuilder builder = new SparseRectFArrayBuilder();
|
||||
builder.append(100, TEMP_RECT.left, TEMP_RECT.top, TEMP_RECT.right, TEMP_RECT.bottom);
|
||||
builder.append(100, TEMP_RECT.left, TEMP_RECT.top, TEMP_RECT.right, TEMP_RECT.bottom,
|
||||
TEMP_FLAGS);
|
||||
assertNull(builder.build().get(-1));
|
||||
assertNull(builder.build().get(0));
|
||||
assertNull(builder.build().get(99));
|
||||
assertEquals(0, builder.build().getFlags(99, 0 /* valueIfKeyNotFound */));
|
||||
assertEquals(1, builder.build().getFlags(99, 1 /* valueIfKeyNotFound */));
|
||||
assertEquals(TEMP_RECT, builder.build().get(100));
|
||||
assertEquals(TEMP_FLAGS, builder.build().getFlags(100, 0 /* valueIfKeyNotFound */));
|
||||
assertEquals(TEMP_FLAGS, builder.build().getFlags(100, 1 /* valueIfKeyNotFound */));
|
||||
assertNull(builder.build().get(101));
|
||||
assertEquals(0, builder.build().getFlags(101, 0 /* valueIfKeyNotFound */));
|
||||
assertEquals(1, builder.build().getFlags(101, 1 /* valueIfKeyNotFound */));
|
||||
|
||||
// Test if {@link SparseRectFArrayBuilder#reset} resets its internal state.
|
||||
builder.reset();
|
||||
@@ -69,28 +77,49 @@ public class SparseRectFArrayTest extends InstrumentationTestCase {
|
||||
for (int i = 0; i < MANY_RECTS.length; i++) {
|
||||
final RectF rect = MANY_RECTS[i];
|
||||
if (rect != null) {
|
||||
builder.append(i, rect.left, rect.top, rect.right, rect.bottom);
|
||||
builder.append(i, rect.left, rect.top, rect.right, rect.bottom, i);
|
||||
}
|
||||
}
|
||||
final SparseRectFArray array = builder.build();
|
||||
for (int i = 0; i < MANY_RECTS.length; i++) {
|
||||
final RectF rect = MANY_RECTS[i];
|
||||
assertEquals(rect, array.get(i));
|
||||
final RectF expectedRect = MANY_RECTS[i];
|
||||
assertEquals(expectedRect, array.get(i));
|
||||
if (expectedRect != null) {
|
||||
assertEquals(i, array.getFlags(i, 0x1234 /* valueIfKeyNotFound */));
|
||||
assertEquals(i, array.getFlags(i, 0x4321 /* valueIfKeyNotFound */));
|
||||
} else {
|
||||
assertEquals(0x1234, array.getFlags(i, 0x1234 /* valueIfKeyNotFound */));
|
||||
assertEquals(0x4321, array.getFlags(i, 0x4321 /* valueIfKeyNotFound */));
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the builder reproduces an equivalent object.
|
||||
final SparseRectFArray array2 = builder.build();
|
||||
for (int i = 0; i < MANY_RECTS.length; i++) {
|
||||
final RectF rect = MANY_RECTS[i];
|
||||
assertEquals(rect, array2.get(i));
|
||||
final RectF expectedRect = MANY_RECTS[i];
|
||||
assertEquals(expectedRect, array2.get(i));
|
||||
if (expectedRect != null) {
|
||||
assertEquals(i, array2.getFlags(i, 0x1234 /* valueIfKeyNotFound */));
|
||||
assertEquals(i, array2.getFlags(i, 0x4321 /* valueIfKeyNotFound */));
|
||||
} else {
|
||||
assertEquals(0x1234, array2.getFlags(i, 0x1234 /* valueIfKeyNotFound */));
|
||||
assertEquals(0x4321, array2.getFlags(i, 0x4321 /* valueIfKeyNotFound */));
|
||||
}
|
||||
}
|
||||
assertEqualRects(array, array2);
|
||||
|
||||
// Make sure the instance can be marshaled via {@link Parcel}.
|
||||
final SparseRectFArray array3 = cloneViaParcel(array);
|
||||
for (int i = 0; i < MANY_RECTS.length; i++) {
|
||||
final RectF rect = MANY_RECTS[i];
|
||||
assertEquals(rect, array3.get(i));
|
||||
final RectF expectedRect = MANY_RECTS[i];
|
||||
assertEquals(expectedRect, array3.get(i));
|
||||
if (expectedRect != null) {
|
||||
assertEquals(i, array3.getFlags(i, 0x1234 /* valueIfKeyNotFound */));
|
||||
assertEquals(i, array3.getFlags(i, 0x4321 /* valueIfKeyNotFound */));
|
||||
} else {
|
||||
assertEquals(0x1234, array3.getFlags(i, 0x1234 /* valueIfKeyNotFound */));
|
||||
assertEquals(0x4321, array3.getFlags(i, 0x4321 /* valueIfKeyNotFound */));
|
||||
}
|
||||
}
|
||||
assertEqualRects(array, array3);
|
||||
|
||||
@@ -106,87 +135,93 @@ public class SparseRectFArrayTest extends InstrumentationTestCase {
|
||||
new SparseRectFArrayBuilder().build());
|
||||
|
||||
assertEqualRects(
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build());
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build(),
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build());
|
||||
assertEqualRects(
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build(),
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build());
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
|
||||
new SparseRectFArrayBuilder().append(100, 2.0f, 2.0f, 3.0f, 4.0f).build());
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build(),
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build());
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
|
||||
new SparseRectFArrayBuilder().append(101, 1.0f, 2.0f, 3.0f, 4.0f).build());
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build(),
|
||||
new SparseRectFArrayBuilder().append(100, 2.0f, 2.0f, 3.0f, 4.0f, 1).build());
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f, 1).build(),
|
||||
new SparseRectFArrayBuilder().append(101, 1.0f, 2.0f, 3.0f, 4.0f, 1).build());
|
||||
|
||||
assertEqualRects(
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build(),
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f).build());
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build());
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build(),
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f).build());
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build());
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build(),
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f).build());
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0).build());
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build(),
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(101, 1.0f, 0.0f, 0.0f, 0.0f).build());
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(101, 1.0f, 0.0f, 0.0f, 0.0f, 0).build());
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(101, 1.0f, 0.0f, 0.0f, 0.0f).build(),
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(101, 1.0f, 0.0f, 0.0f, 0.0f, 0).build(),
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f).build());
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build());
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(101, 0.0f, 0.0f, 0.0f, 0.0f, 0).build(),
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(102, 0.0f, 0.0f, 0.0f, 0.0f).build());
|
||||
.append(100, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(102, 0.0f, 0.0f, 0.0f, 0.0f, 0).build());
|
||||
|
||||
assertEqualRects(
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(1000, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.build(),
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(1000, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.build());
|
||||
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(1000, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.build(),
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.build());
|
||||
assertNotEqualRects(
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(1000, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.build(),
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f)
|
||||
.append(1000, 1.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.append(1, 1.0f, 2.0f, 3.0f, 4.0f, 0)
|
||||
.append(1000, 1.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.append(100000000, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.build());
|
||||
}
|
||||
|
||||
@@ -194,13 +229,17 @@ public class SparseRectFArrayTest extends InstrumentationTestCase {
|
||||
public void testBuilderAppend() throws Exception {
|
||||
// Key should be appended in ascending order.
|
||||
try {
|
||||
new SparseRectFArrayBuilder().append(10, 0, 0, 0, 0).append(0, 1, 2, 3, 4);
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(10, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.append(0, 1.0f, 2.0f, 3.0f, 4.0f, 0);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new SparseRectFArrayBuilder().append(10, 0, 0, 0, 0).append(10, 1, 2, 3, 4);
|
||||
new SparseRectFArrayBuilder()
|
||||
.append(10, 0.0f, 0.0f, 0.0f, 0.0f, 0)
|
||||
.append(10, 1.0f, 2.0f, 3.0f, 4.0f, 0);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user