Merge "Address API feedbacks for TextBoundsInfo"
This commit is contained in:
@@ -46637,8 +46637,8 @@ package android.text {
|
||||
field public static final int DONE = -1; // 0xffffffff
|
||||
}
|
||||
|
||||
public static class SegmentFinder.DefaultSegmentFinder extends android.text.SegmentFinder {
|
||||
ctor public SegmentFinder.DefaultSegmentFinder(@NonNull int[]);
|
||||
public static class SegmentFinder.PrescribedSegmentFinder extends android.text.SegmentFinder {
|
||||
ctor public SegmentFinder.PrescribedSegmentFinder(@NonNull int[]);
|
||||
method public int nextEndBoundary(@IntRange(from=0) int);
|
||||
method public int nextStartBoundary(@IntRange(from=0) int);
|
||||
method public int previousEndBoundary(@IntRange(from=0) int);
|
||||
@@ -55099,15 +55099,15 @@ package android.view.inputmethod {
|
||||
public final class TextBoundsInfo implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @IntRange(from=0, to=125) public int getCharacterBidiLevel(int);
|
||||
method @NonNull public android.graphics.RectF getCharacterBounds(int);
|
||||
method @NonNull public void getCharacterBounds(int, @NonNull android.graphics.RectF);
|
||||
method public int getCharacterFlags(int);
|
||||
method public int getEnd();
|
||||
method public int getEndIndex();
|
||||
method @NonNull public android.text.SegmentFinder getGraphemeSegmentFinder();
|
||||
method @NonNull public android.text.SegmentFinder getLineSegmentFinder();
|
||||
method @NonNull public android.graphics.Matrix getMatrix();
|
||||
method @NonNull public void getMatrix(@NonNull android.graphics.Matrix);
|
||||
method public int getOffsetForPosition(float, float);
|
||||
method @Nullable public int[] getRangeForRect(@NonNull android.graphics.RectF, @NonNull android.text.SegmentFinder, @NonNull android.text.Layout.TextInclusionStrategy);
|
||||
method public int getStart();
|
||||
method public int getStartIndex();
|
||||
method @NonNull public android.text.SegmentFinder getWordSegmentFinder();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.TextBoundsInfo> CREATOR;
|
||||
@@ -55118,7 +55118,7 @@ package android.view.inputmethod {
|
||||
}
|
||||
|
||||
public static final class TextBoundsInfo.Builder {
|
||||
ctor public TextBoundsInfo.Builder();
|
||||
ctor public TextBoundsInfo.Builder(int, int);
|
||||
method @NonNull public android.view.inputmethod.TextBoundsInfo build();
|
||||
method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder clear();
|
||||
method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setCharacterBidiLevel(@NonNull int[]);
|
||||
|
||||
@@ -767,20 +767,20 @@ final class IRemoteInputConnectionInvoker {
|
||||
/**
|
||||
* Invokes {@link IRemoteInputConnection#requestTextBoundsInfo(InputConnectionCommandHeader,
|
||||
* RectF, ResultReceiver)}
|
||||
* @param rectF {@code rectF} parameter to be passed.
|
||||
* @param bounds {@code rectF} parameter to be passed.
|
||||
* @param executor {@code Executor} parameter to be passed.
|
||||
* @param consumer {@code Consumer} parameter to be passed.
|
||||
*/
|
||||
@AnyThread
|
||||
public void requestTextBoundsInfo(
|
||||
@NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull RectF bounds, @NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<TextBoundsInfoResult> consumer) {
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(consumer);
|
||||
|
||||
final ResultReceiver resultReceiver = new TextBoundsInfoResultReceiver(executor, consumer);
|
||||
try {
|
||||
mConnection.requestTextBoundsInfo(createHeader(), rectF, resultReceiver);
|
||||
mConnection.requestTextBoundsInfo(createHeader(), bounds, resultReceiver);
|
||||
} catch (RemoteException e) {
|
||||
executor.execute(() -> consumer.accept(new TextBoundsInfoResult(CODE_CANCELLED)));
|
||||
}
|
||||
|
||||
@@ -476,9 +476,9 @@ final class RemoteInputConnection implements InputConnection {
|
||||
|
||||
@AnyThread
|
||||
public void requestTextBoundsInfo(
|
||||
@NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull RectF bounds, @NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<TextBoundsInfoResult> consumer) {
|
||||
mInvoker.requestTextBoundsInfo(rectF, executor, consumer);
|
||||
mInvoker.requestTextBoundsInfo(bounds, executor, consumer);
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
|
||||
@@ -74,7 +74,7 @@ public abstract class SegmentFinder {
|
||||
/**
|
||||
* The default {@link SegmentFinder} implementation based on given segment ranges.
|
||||
*/
|
||||
public static class DefaultSegmentFinder extends SegmentFinder {
|
||||
public static class PrescribedSegmentFinder extends SegmentFinder {
|
||||
private final int[] mSegments;
|
||||
|
||||
/**
|
||||
@@ -87,7 +87,7 @@ public abstract class SegmentFinder {
|
||||
* @throws IllegalArgumentException if the given segments array's length is not even; the
|
||||
* given segments are not sorted or there are segments overlap with others.
|
||||
*/
|
||||
public DefaultSegmentFinder(@NonNull int[] segments) {
|
||||
public PrescribedSegmentFinder(@NonNull int[] segments) {
|
||||
checkSegmentsValid(segments);
|
||||
mSegments = segments;
|
||||
}
|
||||
|
||||
@@ -1262,13 +1262,13 @@ public interface InputConnection {
|
||||
|
||||
/**
|
||||
* Called by input method to request the {@link TextBoundsInfo} for a range of text which is
|
||||
* covered by or in vicinity of the given {@code RectF}. It can be used as a supplementary
|
||||
* covered by or in vicinity of the given {@code bounds}. It can be used as a supplementary
|
||||
* method to implement the handwriting gesture API -
|
||||
* {@link #performHandwritingGesture(HandwritingGesture, Executor, IntConsumer)}.
|
||||
*
|
||||
* <p><strong>Editor authors</strong>: It's preferred that the editor returns a
|
||||
* {@link TextBoundsInfo} of all the text lines whose bounds intersect with the given
|
||||
* {@code rectF}.
|
||||
* {@code bounds}.
|
||||
* </p>
|
||||
*
|
||||
* <p><strong>IME authors</strong>: This method is expensive when the text is long. Please
|
||||
@@ -1276,7 +1276,7 @@ public interface InputConnection {
|
||||
* consuming. It's preferable to only request text bounds in smaller areas.
|
||||
* </p>
|
||||
*
|
||||
* @param rectF the interested area where the text bounds are requested, in the screen
|
||||
* @param bounds the interested area where the text bounds are requested, in the screen
|
||||
* coordinates.
|
||||
* @param executor the executor to run the callback.
|
||||
* @param consumer the callback invoked by editor to return the result. It must return a
|
||||
@@ -1286,7 +1286,7 @@ public interface InputConnection {
|
||||
* @see android.view.inputmethod.TextBoundsInfoResult
|
||||
*/
|
||||
default void requestTextBoundsInfo(
|
||||
@NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull RectF bounds, @NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<TextBoundsInfoResult> consumer) {
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(consumer);
|
||||
|
||||
@@ -362,9 +362,9 @@ public class InputConnectionWrapper implements InputConnection {
|
||||
*/
|
||||
@Override
|
||||
public void requestTextBoundsInfo(
|
||||
@NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull RectF bounds, @NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<TextBoundsInfoResult> consumer) {
|
||||
mTarget.requestTextBoundsInfo(rectF, executor, consumer);
|
||||
mTarget.requestTextBoundsInfo(bounds, executor, consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1106,7 +1106,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
|
||||
@Dispatching(cancellable = true)
|
||||
@Override
|
||||
public void requestTextBoundsInfo(
|
||||
InputConnectionCommandHeader header, RectF rectF,
|
||||
InputConnectionCommandHeader header, RectF bounds,
|
||||
@NonNull ResultReceiver resultReceiver) {
|
||||
dispatchWithTracing("requestTextBoundsInfo", () -> {
|
||||
if (header.mSessionId != mCurrentSessionId.get()) {
|
||||
@@ -1121,7 +1121,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
|
||||
}
|
||||
|
||||
ic.requestTextBoundsInfo(
|
||||
rectF,
|
||||
bounds,
|
||||
Runnable::run,
|
||||
(textBoundsInfoResult) -> {
|
||||
final int resultCode = textBoundsInfoResult.getResultCode();
|
||||
|
||||
@@ -43,8 +43,8 @@ import java.util.function.Consumer;
|
||||
* The text bounds information of a slice of text in the editor.
|
||||
*
|
||||
* <p> This class provides IME the layout information of the text within the range from
|
||||
* {@link #getStart()} to {@link #getEnd()}. It's intended to be used by IME as a supplementary API
|
||||
* to support handwriting gestures.
|
||||
* {@link #getStartIndex()} to {@link #getEndIndex()}. It's intended to be used by IME as a
|
||||
* supplementary API to support handwriting gestures.
|
||||
* </p>
|
||||
*/
|
||||
public final class TextBoundsInfo implements Parcelable {
|
||||
@@ -168,16 +168,13 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
private final SegmentFinder mGraphemeSegmentFinder;
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@link android.graphics.Matrix} that indicates the transformation
|
||||
* Set the given {@link android.graphics.Matrix} to be the transformation
|
||||
* matrix that is to be applied other positional data in this class.
|
||||
*
|
||||
* @return a new instance (copy) of the transformation matrix.
|
||||
*/
|
||||
@NonNull
|
||||
public Matrix getMatrix() {
|
||||
final Matrix matrix = new Matrix();
|
||||
public void getMatrix(@NonNull Matrix matrix) {
|
||||
Objects.requireNonNull(matrix);
|
||||
matrix.setValues(mMatrixValues);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +183,7 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
*
|
||||
* @see Builder#setStartAndEnd(int, int)
|
||||
*/
|
||||
public int getStart() {
|
||||
public int getStartIndex() {
|
||||
return mStart;
|
||||
}
|
||||
|
||||
@@ -196,28 +193,28 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
*
|
||||
* @see Builder#setStartAndEnd(int, int)
|
||||
*/
|
||||
public int getEnd() {
|
||||
public int getEndIndex() {
|
||||
return mEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bounds of the character at the given {@code index}, in the coordinates of the
|
||||
* editor.
|
||||
* Set the bounds of the character at the given {@code index} to the given {@link RectF}, in
|
||||
* the coordinates of the editor.
|
||||
*
|
||||
* @param index the index of the queried character.
|
||||
* @return the bounding box of the queried character.
|
||||
* @param bounds the {@link RectF} used to receive the result.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if the given {@code index} is out of the range from
|
||||
* the {@code start} to the {@code end}.
|
||||
*/
|
||||
@NonNull
|
||||
public RectF getCharacterBounds(int index) {
|
||||
public void getCharacterBounds(int index, @NonNull RectF bounds) {
|
||||
if (index < mStart || index >= mEnd) {
|
||||
throw new IndexOutOfBoundsException("Index is out of the bounds of "
|
||||
+ "[" + mStart + ", " + mEnd + ").");
|
||||
}
|
||||
final int offset = 4 * (index - mStart);
|
||||
return new RectF(mCharacterBounds[offset], mCharacterBounds[offset + 1],
|
||||
bounds.set(mCharacterBounds[offset], mCharacterBounds[offset + 1],
|
||||
mCharacterBounds[offset + 2], mCharacterBounds[offset + 3]);
|
||||
}
|
||||
|
||||
@@ -333,6 +330,16 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
* won't check the text in the ranges of [5, 7) and [12, 15).
|
||||
* </p>
|
||||
*
|
||||
* <p> Under the following conditions, this method will return -1 indicating that no valid
|
||||
* character is found:
|
||||
* <ul>
|
||||
* <li> The given {@code y} coordinate is above the first line or below the last line (the
|
||||
* first line or the last line is identified by the {@link SegmentFinder} returned from
|
||||
* {@link #getLineSegmentFinder()}). </li>
|
||||
* <li> There is no character in this {@link TextBoundsInfo}. </li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @param x the x coordinates of the interested location, in the editor's coordinates.
|
||||
* @param y the y coordinates of the interested location, in the editor's coordinates.
|
||||
* @return the index of the character whose position is closest to the given location. It will
|
||||
@@ -990,8 +997,8 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
public static final class Builder {
|
||||
private final float[] mMatrixValues = new float[9];
|
||||
private boolean mMatrixInitialized;
|
||||
private int mStart;
|
||||
private int mEnd;
|
||||
private int mStart = -1;
|
||||
private int mEnd = -1;
|
||||
private float[] mCharacterBounds;
|
||||
private int[] mCharacterFlags;
|
||||
private int[] mCharacterBidiLevels;
|
||||
@@ -999,6 +1006,17 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
private SegmentFinder mWordSegmentFinder;
|
||||
private SegmentFinder mGraphemeSegmentFinder;
|
||||
|
||||
/**
|
||||
* Create a builder for {@link TextBoundsInfo}.
|
||||
* @param start the start index of the {@link TextBoundsInfo}, inclusive.
|
||||
* @param end the end index of the {@link TextBoundsInfo}, exclusive.
|
||||
* @throws IllegalArgumentException if the given {@code start} or {@code end} is negative,
|
||||
* or {@code end} is smaller than the {@code start}.
|
||||
*/
|
||||
public Builder(int start, int end) {
|
||||
setStartAndEnd(start, end);
|
||||
}
|
||||
|
||||
/** Clear all the parameters set on this {@link Builder} to reuse it. */
|
||||
@NonNull
|
||||
public Builder clear() {
|
||||
@@ -1152,7 +1170,7 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
*
|
||||
* @see #getGraphemeSegmentFinder()
|
||||
* @see SegmentFinder
|
||||
* @see SegmentFinder.DefaultSegmentFinder
|
||||
* @see SegmentFinder.PrescribedSegmentFinder
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setGraphemeSegmentFinder(@NonNull SegmentFinder graphemeSegmentFinder) {
|
||||
@@ -1171,7 +1189,7 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
*
|
||||
* @see #getWordSegmentFinder()
|
||||
* @see SegmentFinder
|
||||
* @see SegmentFinder.DefaultSegmentFinder
|
||||
* @see SegmentFinder.PrescribedSegmentFinder
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setWordSegmentFinder(@NonNull SegmentFinder wordSegmentFinder) {
|
||||
@@ -1193,7 +1211,7 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
*
|
||||
* @see #getLineSegmentFinder()
|
||||
* @see SegmentFinder
|
||||
* @see SegmentFinder.DefaultSegmentFinder
|
||||
* @see SegmentFinder.PrescribedSegmentFinder
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setLineSegmentFinder(@NonNull SegmentFinder lineSegmentFinder) {
|
||||
@@ -1360,7 +1378,7 @@ public final class TextBoundsInfo implements Parcelable {
|
||||
breaks = GrowingArrayUtils.append(breaks, count++, start + offset);
|
||||
}
|
||||
}
|
||||
return new SegmentFinder.DefaultSegmentFinder(Arrays.copyOf(breaks, count));
|
||||
return new SegmentFinder.PrescribedSegmentFinder(Arrays.copyOf(breaks, count));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13245,7 +13245,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
* Creates the {@link TextBoundsInfo} for the text lines that intersects with the {@code rectF}.
|
||||
* @hide
|
||||
*/
|
||||
public TextBoundsInfo getTextBoundsInfo(@NonNull RectF rectF) {
|
||||
public TextBoundsInfo getTextBoundsInfo(@NonNull RectF bounds) {
|
||||
final Layout layout = getLayout();
|
||||
if (layout == null) {
|
||||
// No valid text layout, return null.
|
||||
@@ -13268,19 +13268,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
final float layoutLeft = viewportToContentHorizontalOffset();
|
||||
final float layoutTop = viewportToContentVerticalOffset();
|
||||
|
||||
final RectF localRectF = new RectF(rectF);
|
||||
globalToLocalMatrix.mapRect(localRectF);
|
||||
localRectF.offset(-layoutLeft, -layoutTop);
|
||||
final RectF localBounds = new RectF(bounds);
|
||||
globalToLocalMatrix.mapRect(localBounds);
|
||||
localBounds.offset(-layoutLeft, -layoutTop);
|
||||
|
||||
// Text length is 0. There is no character bounds, return empty TextBoundsInfo.
|
||||
// rectF doesn't intersect with the layout, return empty TextBoundsInfo.
|
||||
if (!localRectF.intersects(0f, 0f, layout.getWidth(), layout.getHeight())
|
||||
if (!localBounds.intersects(0f, 0f, layout.getWidth(), layout.getHeight())
|
||||
|| text.length() == 0) {
|
||||
final TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder();
|
||||
final TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder(0, 0);
|
||||
final SegmentFinder emptySegmentFinder =
|
||||
new SegmentFinder.DefaultSegmentFinder(new int[0]);
|
||||
builder.setStartAndEnd(0, 0)
|
||||
.setMatrix(localToGlobalMatrix)
|
||||
new SegmentFinder.PrescribedSegmentFinder(new int[0]);
|
||||
builder.setMatrix(localToGlobalMatrix)
|
||||
.setCharacterBounds(new float[0])
|
||||
.setCharacterBidiLevel(new int[0])
|
||||
.setCharacterFlags(new int[0])
|
||||
@@ -13290,8 +13289,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
final int startLine = layout.getLineForVertical((int) Math.floor(localRectF.top));
|
||||
final int endLine = layout.getLineForVertical((int) Math.floor(localRectF.bottom));
|
||||
final int startLine = layout.getLineForVertical((int) Math.floor(localBounds.top));
|
||||
final int endLine = layout.getLineForVertical((int) Math.floor(localBounds.bottom));
|
||||
final int start = layout.getLineStart(startLine);
|
||||
final int end = layout.getLineEnd(endLine);
|
||||
|
||||
@@ -13349,18 +13348,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
lineRanges[2 * offset] = layout.getLineStart(line);
|
||||
lineRanges[2 * offset + 1] = layout.getLineEnd(line);
|
||||
}
|
||||
final SegmentFinder lineSegmentFinder = new SegmentFinder.DefaultSegmentFinder(lineRanges);
|
||||
final SegmentFinder lineSegmentFinder =
|
||||
new SegmentFinder.PrescribedSegmentFinder(lineRanges);
|
||||
|
||||
final TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder();
|
||||
builder.setStartAndEnd(start, end)
|
||||
return new TextBoundsInfo.Builder(start, end)
|
||||
.setMatrix(localToGlobalMatrix)
|
||||
.setCharacterBounds(characterBounds)
|
||||
.setCharacterBidiLevel(characterBidiLevels)
|
||||
.setCharacterFlags(characterFlags)
|
||||
.setGraphemeSegmentFinder(graphemeSegmentFinder)
|
||||
.setLineSegmentFinder(lineSegmentFinder)
|
||||
.setWordSegmentFinder(wordSegmentFinder);
|
||||
return builder.build();
|
||||
.setWordSegmentFinder(wordSegmentFinder)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -271,9 +271,9 @@ public final class EditableInputConnection extends BaseInputConnection
|
||||
|
||||
@Override
|
||||
public void requestTextBoundsInfo(
|
||||
@NonNull RectF rectF, @Nullable @CallbackExecutor Executor executor,
|
||||
@NonNull RectF bounds, @Nullable @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<TextBoundsInfoResult> consumer) {
|
||||
final TextBoundsInfo textBoundsInfo = mTextView.getTextBoundsInfo(rectF);
|
||||
final TextBoundsInfo textBoundsInfo = mTextView.getTextBoundsInfo(bounds);
|
||||
final int resultCode;
|
||||
if (textBoundsInfo != null) {
|
||||
resultCode = TextBoundsInfoResult.CODE_SUCCESS;
|
||||
|
||||
@@ -111,7 +111,7 @@ import com.android.internal.inputmethod.InputConnectionCommandHeader;
|
||||
int cursorUpdateMode, int cursorUpdateFilter, int imeDisplayId,
|
||||
in AndroidFuture future /* T=Boolean */);
|
||||
|
||||
void requestTextBoundsInfo(in InputConnectionCommandHeader header, in RectF rect,
|
||||
void requestTextBoundsInfo(in InputConnectionCommandHeader header, in RectF bounds,
|
||||
in ResultReceiver resultReceiver /* T=TextBoundsInfoResult */);
|
||||
|
||||
void commitContent(in InputConnectionCommandHeader header, in InputContentInfo inputContentInfo,
|
||||
|
||||
Reference in New Issue
Block a user