Merge "Address API feedbacks for TextBoundsInfo"

This commit is contained in:
Haoyu Zhang
2023-01-12 02:12:35 +00:00
committed by Android (Google) Code Review
11 changed files with 79 additions and 62 deletions

View File

@@ -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[]);

View File

@@ -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)));
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}
/**

View File

@@ -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();

View File

@@ -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));
}
/**

View File

@@ -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();
}
/**

View File

@@ -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;

View File

@@ -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,