summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorYohei Yukawa <yukawa@google.com>2014-07-10 11:45:44 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-07-10 01:20:57 +0000
commitc09a04da297ff85b97aa6ec0a457e9292b8bf7fa (patch)
tree3306b6b2abcf3b23015ac05569fab80f7de76e8c /core/java
parent931a0e27e114aee8e8297f4d6499d4e1891f0591 (diff)
parent0b01e7fc58cdde00d8350285a3386c4209b72d78 (diff)
downloadframeworks_base-c09a04da297ff85b97aa6ec0a457e9292b8bf7fa.zip
frameworks_base-c09a04da297ff85b97aa6ec0a457e9292b8bf7fa.tar.gz
frameworks_base-c09a04da297ff85b97aa6ec0a457e9292b8bf7fa.tar.bz2
Merge "Polish new IME API for L: CursorAnchorInfo"
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/view/inputmethod/CursorAnchorInfo.java85
-rw-r--r--core/java/android/view/inputmethod/SparseRectFArray.java51
-rw-r--r--core/java/android/widget/Editor.java30
3 files changed, 144 insertions, 22 deletions
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index 434b1aa..04d875d 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -45,6 +45,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
* calculated or compatible with {@link Layout#getPrimaryHorizontal(int)}. This can 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;
@@ -405,6 +451,14 @@ public final class CursorAnchorInfo implements Parcelable {
}
/**
+ * 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.
* @return x coordinate that is compatible with {@link Layout#getPrimaryHorizontal(int)}.
@@ -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.
@@ -467,6 +524,20 @@ public final class CursorAnchorInfo implements Parcelable {
}
/**
+ * 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.
* @return a new instance (copy) of the transformation matrix.
diff --git a/core/java/android/view/inputmethod/SparseRectFArray.java b/core/java/android/view/inputmethod/SparseRectFArray.java
index d4ec9d0..484fe46 100644
--- a/core/java/android/view/inputmethod/SparseRectFArray.java
+++ b/core/java/android/view/inputmethod/SparseRectFArray.java
@@ -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.
*/
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 13a0849..170a316 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -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());