summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Justin Ghan <justinghan@google.com> 2022-11-11 16:14:28 -0800
committer Justin Ghan <justinghan@google.com> 2022-12-02 17:13:07 -0800
commit691cbb963ae554b1a767885ce48dde3ec58b6aaf (patch)
tree30431562aca5b52c38666cba3bfa4c982d30f901
parentedff783dee2060a8f49e13df47a101b15b4f547c (diff)
TextView implementation of select and delete gesture previews
Bug: 240436893 Test: atest android.widget.cts.TextViewHandwritingGestureTest Change-Id: Ia4f02636b3bcaf2e2ac8a1baaa1c7b40c33d0dd6
-rw-r--r--core/java/android/widget/TextView.java114
-rw-r--r--core/java/com/android/internal/inputmethod/EditableInputConnection.java9
2 files changed, 98 insertions, 25 deletions
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7e7f9c99b948..b9b928e4c2f9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -88,6 +88,7 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.LocaleList;
import android.os.Parcel;
@@ -149,6 +150,7 @@ import android.text.style.SuggestionSpan;
import android.text.style.URLSpan;
import android.text.style.UpdateAppearance;
import android.text.util.Linkify;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.FeatureFlagUtils;
@@ -200,6 +202,7 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InsertGesture;
import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.PreviewableHandwritingGesture;
import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.view.inputmethod.SelectRangeGesture;
@@ -244,6 +247,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@@ -9275,6 +9279,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
gestures.add(RemoveSpaceGesture.class);
gestures.add(JoinOrSplitGesture.class);
outAttrs.setSupportedHandwritingGestures(gestures);
+
+ Set<Class<? extends PreviewableHandwritingGesture>> previews = new ArraySet<>();
+ previews.add(SelectGesture.class);
+ previews.add(SelectRangeGesture.class);
+ previews.add(DeleteGesture.class);
+ previews.add(DeleteRangeGesture.class);
+ outAttrs.setSupportedHandwritingGesturePreviews(previews);
+
return ic;
}
}
@@ -9486,83 +9498,130 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/** @hide */
+ public boolean previewHandwritingGesture(
+ @NonNull PreviewableHandwritingGesture gesture,
+ @Nullable CancellationSignal cancellationSignal) {
+ if (gesture instanceof SelectGesture) {
+ performHandwritingSelectGesture((SelectGesture) gesture, /* isPreview= */ true);
+ } else if (gesture instanceof SelectRangeGesture) {
+ performHandwritingSelectRangeGesture(
+ (SelectRangeGesture) gesture, /* isPreview= */ true);
+ } else if (gesture instanceof DeleteGesture) {
+ performHandwritingDeleteGesture((DeleteGesture) gesture, /* isPreview= */ true);
+ } else if (gesture instanceof DeleteRangeGesture) {
+ performHandwritingDeleteRangeGesture(
+ (DeleteRangeGesture) gesture, /* isPreview= */ true);
+ } else {
+ return false;
+ }
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(this::clearGesturePreviewHighlight);
+ }
+ return true;
+ }
+
+ /** @hide */
public int performHandwritingSelectGesture(@NonNull SelectGesture gesture) {
+ return performHandwritingSelectGesture(gesture, /* isPreview= */ false);
+ }
+
+ private int performHandwritingSelectGesture(@NonNull SelectGesture gesture, boolean isPreview) {
int[] range = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getSelectionArea()),
gesture.getGranularity());
if (range == null) {
- return handleGestureFailure(gesture);
+ return handleGestureFailure(gesture, isPreview);
+ }
+ return performHandwritingSelectGesture(range, isPreview);
+ }
+
+ private int performHandwritingSelectGesture(int[] range, boolean isPreview) {
+ if (isPreview) {
+ setSelectGesturePreviewHighlight(range[0], range[1]);
+ } else {
+ Selection.setSelection(getEditableText(), range[0], range[1]);
+ mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
}
- Selection.setSelection(getEditableText(), range[0], range[1]);
- mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
}
/** @hide */
public int performHandwritingSelectRangeGesture(@NonNull SelectRangeGesture gesture) {
+ return performHandwritingSelectRangeGesture(gesture, /* isPreview= */ false);
+ }
+
+ private int performHandwritingSelectRangeGesture(
+ @NonNull SelectRangeGesture gesture, boolean isPreview) {
int[] startRange = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getSelectionStartArea()),
gesture.getGranularity());
if (startRange == null) {
- return handleGestureFailure(gesture);
+ return handleGestureFailure(gesture, isPreview);
}
int[] endRange = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getSelectionEndArea()),
gesture.getGranularity());
if (endRange == null) {
- return handleGestureFailure(gesture);
+ return handleGestureFailure(gesture, isPreview);
}
int[] range = new int[] {
Math.min(startRange[0], endRange[0]), Math.max(startRange[1], endRange[1])
};
- Selection.setSelection(getEditableText(), range[0], range[1]);
- mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
- return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
+ return performHandwritingSelectGesture(range, isPreview);
}
/** @hide */
public int performHandwritingDeleteGesture(@NonNull DeleteGesture gesture) {
+ return performHandwritingDeleteGesture(gesture, /* isPreview= */ false);
+ }
+
+ private int performHandwritingDeleteGesture(@NonNull DeleteGesture gesture, boolean isPreview) {
int[] range = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getDeletionArea()),
gesture.getGranularity());
if (range == null) {
- return handleGestureFailure(gesture);
+ return handleGestureFailure(gesture, isPreview);
}
+ return performHandwritingDeleteGesture(range, gesture.getGranularity(), isPreview);
+ }
- if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) {
- range = adjustHandwritingDeleteGestureRange(range);
- }
+ private int performHandwritingDeleteGesture(int[] range, int granularity, boolean isPreview) {
+ if (isPreview) {
+ setDeleteGesturePreviewHighlight(range[0], range[1]);
+ } else {
+ if (granularity == HandwritingGesture.GRANULARITY_WORD) {
+ range = adjustHandwritingDeleteGestureRange(range);
+ }
- getEditableText().delete(range[0], range[1]);
- Selection.setSelection(getEditableText(), range[0]);
+ getEditableText().delete(range[0], range[1]);
+ Selection.setSelection(getEditableText(), range[0]);
+ }
return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
}
/** @hide */
public int performHandwritingDeleteRangeGesture(@NonNull DeleteRangeGesture gesture) {
+ return performHandwritingDeleteRangeGesture(gesture, /* isPreview= */ false);
+ }
+
+ private int performHandwritingDeleteRangeGesture(
+ @NonNull DeleteRangeGesture gesture, boolean isPreview) {
int[] startRange = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getDeletionStartArea()),
gesture.getGranularity());
if (startRange == null) {
- return handleGestureFailure(gesture);
+ return handleGestureFailure(gesture, isPreview);
}
int[] endRange = getRangeForRect(
convertFromScreenToContentCoordinates(gesture.getDeletionEndArea()),
gesture.getGranularity());
if (endRange == null) {
- return handleGestureFailure(gesture);
+ return handleGestureFailure(gesture, isPreview);
}
int[] range = new int[] {
Math.min(startRange[0], endRange[0]), Math.max(startRange[1], endRange[1])
};
-
- if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) {
- range = adjustHandwritingDeleteGestureRange(range);
- }
-
- getEditableText().delete(range[0], range[1]);
- Selection.setSelection(getEditableText(), range[0]);
- return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
+ return performHandwritingDeleteGesture(range, gesture.getGranularity(), isPreview);
}
private int[] adjustHandwritingDeleteGestureRange(int[] range) {
@@ -9740,7 +9799,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private int handleGestureFailure(HandwritingGesture gesture) {
- if (!TextUtils.isEmpty(gesture.getFallbackText())) {
+ return handleGestureFailure(gesture, /* isPreview= */ false);
+ }
+
+ private int handleGestureFailure(HandwritingGesture gesture, boolean isPreview) {
+ clearGesturePreviewHighlight();
+ if (!isPreview && !TextUtils.isEmpty(gesture.getFallbackText())) {
getEditableText()
.replace(getSelectionStart(), getSelectionEnd(), gesture.getFallbackText());
return InputConnection.HANDWRITING_GESTURE_RESULT_FALLBACK;
diff --git a/core/java/com/android/internal/inputmethod/EditableInputConnection.java b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
index 330ff8e61609..52e747150789 100644
--- a/core/java/com/android/internal/inputmethod/EditableInputConnection.java
+++ b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
@@ -27,6 +27,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.RectF;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.text.Editable;
import android.text.Selection;
import android.text.method.KeyListener;
@@ -44,6 +45,7 @@ import android.view.inputmethod.HandwritingGesture;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InsertGesture;
import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.PreviewableHandwritingGesture;
import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.view.inputmethod.SelectRangeGesture;
@@ -321,6 +323,13 @@ public final class EditableInputConnection extends BaseInputConnection
}
@Override
+ public boolean previewHandwritingGesture(
+ @NonNull PreviewableHandwritingGesture gesture,
+ @Nullable CancellationSignal cancellationSignal) {
+ return mTextView.previewHandwritingGesture(gesture, cancellationSignal);
+ }
+
+ @Override
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
CharSequence editableText = mTextView.getText();