diff options
| author | 2022-11-04 18:12:07 +0000 | |
|---|---|---|
| committer | 2022-11-04 18:12:07 +0000 | |
| commit | 48cba7c99a5eb2de425f4713e366e37bf0c8eee5 (patch) | |
| tree | 1ac11c01e044749f339e611f5fae625d0c741cb4 | |
| parent | 5dedf4cdefd0d17039fbdf0a6937db6dffc755b7 (diff) | |
| parent | 95baa907de566451093ea576a25b2ab963728416 (diff) | |
Merge "API for realtime Scribe gesture preview"
14 files changed, 263 insertions, 10 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 6e0e26f204fc..c8241066b258 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -53403,7 +53403,7 @@ package android.view.inputmethod { method @NonNull public android.view.inputmethod.CursorAnchorInfo.Builder setTextAppearanceInfo(@Nullable android.view.inputmethod.TextAppearanceInfo); } - public final class DeleteGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable { + public final class DeleteGesture extends android.view.inputmethod.PreviewableHandwritingGesture implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.graphics.RectF getDeletionArea(); method public int getGranularity(); @@ -53419,7 +53419,7 @@ package android.view.inputmethod { method @NonNull public android.view.inputmethod.DeleteGesture.Builder setGranularity(int); } - public final class DeleteRangeGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable { + public final class DeleteRangeGesture extends android.view.inputmethod.PreviewableHandwritingGesture implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.graphics.RectF getDeletionEndArea(); method @NonNull public android.graphics.RectF getDeletionStartArea(); @@ -53461,11 +53461,13 @@ package android.view.inputmethod { method @Nullable public CharSequence getInitialTextAfterCursor(@IntRange(from=0) int, int); method @Nullable public CharSequence getInitialTextBeforeCursor(@IntRange(from=0) int, int); method public int getInitialToolType(); + method @NonNull public java.util.Set<java.lang.Class<? extends android.view.inputmethod.PreviewableHandwritingGesture>> getSupportedHandwritingGesturePreviews(); method @NonNull public java.util.List<java.lang.Class<? extends android.view.inputmethod.HandwritingGesture>> getSupportedHandwritingGestures(); method public final void makeCompatible(int); method public void setInitialSurroundingSubText(@NonNull CharSequence, int); method public void setInitialSurroundingText(@NonNull CharSequence); method public void setInitialToolType(int); + method public void setSupportedHandwritingGesturePreviews(@NonNull java.util.Set<java.lang.Class<? extends android.view.inputmethod.PreviewableHandwritingGesture>>); method public void setSupportedHandwritingGestures(@NonNull java.util.List<java.lang.Class<? extends android.view.inputmethod.HandwritingGesture>>); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.EditorInfo> CREATOR; @@ -53640,6 +53642,7 @@ package android.view.inputmethod { method public default void performHandwritingGesture(@NonNull android.view.inputmethod.HandwritingGesture, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.IntConsumer); method public boolean performPrivateCommand(String, android.os.Bundle); method public default boolean performSpellCheck(); + method public default boolean previewHandwritingGesture(@NonNull android.view.inputmethod.PreviewableHandwritingGesture, @Nullable android.os.CancellationSignal); method public default boolean replaceText(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull CharSequence, int, @Nullable android.view.inputmethod.TextAttribute); method public boolean reportFullscreenMode(boolean); method public boolean requestCursorUpdates(int); @@ -53900,6 +53903,9 @@ package android.view.inputmethod { method @NonNull public android.view.inputmethod.JoinOrSplitGesture.Builder setJoinOrSplitPoint(@NonNull android.graphics.PointF); } + public abstract class PreviewableHandwritingGesture extends android.view.inputmethod.HandwritingGesture { + } + public final class RemoveSpaceGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.graphics.PointF getEndPoint(); @@ -53915,7 +53921,7 @@ package android.view.inputmethod { method @NonNull public android.view.inputmethod.RemoveSpaceGesture.Builder setPoints(@NonNull android.graphics.PointF, @NonNull android.graphics.PointF); } - public final class SelectGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable { + public final class SelectGesture extends android.view.inputmethod.PreviewableHandwritingGesture implements android.os.Parcelable { method public int describeContents(); method public int getGranularity(); method @NonNull public android.graphics.RectF getSelectionArea(); @@ -53931,7 +53937,7 @@ package android.view.inputmethod { method @NonNull public android.view.inputmethod.SelectGesture.Builder setSelectionArea(@NonNull android.graphics.RectF); } - public final class SelectRangeGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable { + public final class SelectRangeGesture extends android.view.inputmethod.PreviewableHandwritingGesture implements android.os.Parcelable { method public int describeContents(); method public int getGranularity(); method @NonNull public android.graphics.RectF getSelectionEndArea(); diff --git a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java index 95aecfe4c7af..c6a37259f992 100644 --- a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java +++ b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.RectF; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.RemoteException; import android.os.ResultReceiver; import android.view.KeyEvent; @@ -697,6 +698,27 @@ final class IRemoteInputConnectionInvoker { } /** + * Invokes one of {@link IRemoteInputConnection#previewHandwritingGesture( + * InputConnectionCommandHeader, ParcelableHandwritingGesture, CancellationSignal)} + */ + @AnyThread + public boolean previewHandwritingGesture( + @NonNull ParcelableHandwritingGesture gesture, + @Nullable CancellationSignal cancellationSignal) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return false; // cancelled. + } + + // TODO(b/254727073): Implement CancellationSignal + try { + mConnection.previewHandwritingGesture(createHeader(), gesture, null); + return true; + } catch (RemoteException e) { + return false; + } + } + + /** * Invokes {@link IRemoteInputConnection#requestCursorUpdates(InputConnectionCommandHeader, int, * int, AndroidFuture)}. * diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java index 976e71f2b85a..f93f9abc3bb0 100644 --- a/core/java/android/inputmethodservice/RemoteInputConnection.java +++ b/core/java/android/inputmethodservice/RemoteInputConnection.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.RectF; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; import android.util.Log; import android.view.KeyEvent; @@ -34,6 +35,7 @@ import android.view.inputmethod.HandwritingGesture; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputContentInfo; import android.view.inputmethod.ParcelableHandwritingGesture; +import android.view.inputmethod.PreviewableHandwritingGesture; import android.view.inputmethod.SurroundingText; import android.view.inputmethod.TextAttribute; import android.view.inputmethod.TextBoundsInfoResult; @@ -427,6 +429,14 @@ final class RemoteInputConnection implements InputConnection { } @AnyThread + public boolean previewHandwritingGesture( + @NonNull PreviewableHandwritingGesture gesture, + @Nullable CancellationSignal cancellationSignal) { + return mInvoker.previewHandwritingGesture(ParcelableHandwritingGesture.of(gesture), + cancellationSignal); + } + + @AnyThread public boolean requestCursorUpdates(int cursorUpdateMode) { if (mCancellationGroup.isCanceled()) { return false; diff --git a/core/java/android/view/inputmethod/DeleteGesture.java b/core/java/android/view/inputmethod/DeleteGesture.java index c88158f3b39a..b8435945a6c0 100644 --- a/core/java/android/view/inputmethod/DeleteGesture.java +++ b/core/java/android/view/inputmethod/DeleteGesture.java @@ -33,7 +33,7 @@ import java.util.Objects; * <p>Note: This deletes all text <em>within</em> the given area. To delete a range <em>between</em> * two areas, use {@link DeleteRangeGesture}.</p> */ -public final class DeleteGesture extends HandwritingGesture implements Parcelable { +public final class DeleteGesture extends PreviewableHandwritingGesture implements Parcelable { private @Granularity int mGranularity; private RectF mArea; diff --git a/core/java/android/view/inputmethod/DeleteRangeGesture.java b/core/java/android/view/inputmethod/DeleteRangeGesture.java index 53b42092c181..0bce15e3f18b 100644 --- a/core/java/android/view/inputmethod/DeleteRangeGesture.java +++ b/core/java/android/view/inputmethod/DeleteRangeGesture.java @@ -34,7 +34,7 @@ import java.util.Objects; * <p>Note: this deletes text within a range <em>between</em> two given areas. To delete all text * <em>within</em> a single area, use {@link DeleteGesture}.</p> */ -public final class DeleteRangeGesture extends HandwritingGesture implements Parcelable { +public final class DeleteRangeGesture extends PreviewableHandwritingGesture implements Parcelable { private @Granularity int mGranularity; private RectF mStartArea; diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index febdac26a0f2..9ebaa67b11f3 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -55,8 +55,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; /** * An EditorInfo describes several attributes of a text editing object @@ -534,6 +536,8 @@ public class EditorInfo implements InputType, Parcelable { private @HandwritingGesture.GestureTypeFlags int mSupportedHandwritingGestureTypes; + private @HandwritingGesture.GestureTypeFlags int mSupportedHandwritingGesturePreviewTypes; + /** * Set the Handwriting gestures supported by the current {@code Editor}. * For an editor that supports Stylus Handwriting @@ -541,8 +545,11 @@ public class EditorInfo implements InputType, Parcelable { * supported gestures. * <p> If editor doesn't support one of the declared types, IME will not send those Gestures * to the editor. Instead they will fallback to using normal text input. </p> + * <p>Note: A supported gesture may not have preview supported + * {@link #getSupportedHandwritingGesturePreviews()}.</p> * @param gestures List of supported gesture classes including any of {@link SelectGesture}, * {@link InsertGesture}, {@link DeleteGesture}. + * @see #setSupportedHandwritingGesturePreviews(Set) */ public void setSupportedHandwritingGestures( @NonNull List<Class<? extends HandwritingGesture>> gestures) { @@ -584,6 +591,7 @@ public class EditorInfo implements InputType, Parcelable { * {@link InputMethodManager#startStylusHandwriting}, it also declares supported gestures. * @return List of supported gesture classes including any of {@link SelectGesture}, * {@link InsertGesture}, {@link DeleteGesture}. + * @see #getSupportedHandwritingGesturePreviews() */ @NonNull public List<Class<? extends HandwritingGesture>> getSupportedHandwritingGestures() { @@ -623,6 +631,86 @@ public class EditorInfo implements InputType, Parcelable { } /** + * Set the Handwriting gesture previews supported by the current {@code Editor}. + * For an editor that supports Stylus Handwriting + * {@link InputMethodManager#startStylusHandwriting}, it is also recommended that it declares + * supported gesture previews. + * <p>Note: A supported gesture {@link EditorInfo#getSupportedHandwritingGestures()} may not + * have preview supported {@link EditorInfo#getSupportedHandwritingGesturePreviews()}.</p> + * <p> If editor doesn't support one of the declared types, gesture preview will be ignored.</p> + * @param gestures Set of supported gesture classes. One of {@link SelectGesture}, + * {@link SelectRangeGesture}, {@link DeleteGesture}, {@link DeleteRangeGesture}. + * @see #setSupportedHandwritingGestures(List) + */ + public void setSupportedHandwritingGesturePreviews( + @NonNull Set<Class<? extends PreviewableHandwritingGesture>> gestures) { + Objects.requireNonNull(gestures); + if (gestures.isEmpty()) { + mSupportedHandwritingGesturePreviewTypes = 0; + return; + } + + int supportedTypes = 0; + for (Class<? extends PreviewableHandwritingGesture> gesture : gestures) { + Objects.requireNonNull(gesture); + if (gesture.equals(SelectGesture.class)) { + supportedTypes |= HandwritingGesture.GESTURE_TYPE_SELECT; + } else if (gesture.equals(SelectRangeGesture.class)) { + supportedTypes |= HandwritingGesture.GESTURE_TYPE_SELECT_RANGE; + } else if (gesture.equals(DeleteGesture.class)) { + supportedTypes |= HandwritingGesture.GESTURE_TYPE_DELETE; + } else if (gesture.equals(DeleteRangeGesture.class)) { + supportedTypes |= HandwritingGesture.GESTURE_TYPE_DELETE_RANGE; + } else { + throw new IllegalArgumentException( + "Unsupported gesture type for preview: " + gesture); + } + } + + mSupportedHandwritingGesturePreviewTypes = supportedTypes; + } + + /** + * Returns the combination of Stylus handwriting gesture preview types + * supported by the current {@code Editor}. + * For an editor that supports Stylus Handwriting. + * {@link InputMethodManager#startStylusHandwriting}, it also declares supported gesture + * previews. + * <p>Note: A supported gesture {@link EditorInfo#getSupportedHandwritingGestures()} may not + * have preview supported {@link EditorInfo#getSupportedHandwritingGesturePreviews()}.</p> + * @return Set of supported gesture preview classes. One of {@link SelectGesture}, + * {@link SelectRangeGesture}, {@link DeleteGesture}, {@link DeleteRangeGesture}. + * @see #getSupportedHandwritingGestures() + */ + @NonNull + public Set<Class<? extends PreviewableHandwritingGesture>> + getSupportedHandwritingGesturePreviews() { + Set<Class<? extends PreviewableHandwritingGesture>> set = new HashSet<>(); + if (mSupportedHandwritingGesturePreviewTypes == 0) { + return set; + } + if ((mSupportedHandwritingGesturePreviewTypes & HandwritingGesture.GESTURE_TYPE_SELECT) + == HandwritingGesture.GESTURE_TYPE_SELECT) { + set.add(SelectGesture.class); + } + if ((mSupportedHandwritingGesturePreviewTypes + & HandwritingGesture.GESTURE_TYPE_SELECT_RANGE) + == HandwritingGesture.GESTURE_TYPE_SELECT_RANGE) { + set.add(SelectRangeGesture.class); + } + if ((mSupportedHandwritingGesturePreviewTypes & HandwritingGesture.GESTURE_TYPE_DELETE) + == HandwritingGesture.GESTURE_TYPE_DELETE) { + set.add(DeleteGesture.class); + } + if ((mSupportedHandwritingGesturePreviewTypes + & HandwritingGesture.GESTURE_TYPE_DELETE_RANGE) + == HandwritingGesture.GESTURE_TYPE_DELETE_RANGE) { + set.add(DeleteRangeGesture.class); + } + return set; + } + + /** * If not {@code null}, this editor needs to talk to IMEs that run for the specified user, no * matter what user ID the calling process has. * @@ -1114,6 +1202,9 @@ public class EditorInfo implements InputType, Parcelable { pw.println(prefix + "supportedHandwritingGestureTypes=" + InputMethodDebug.handwritingGestureTypeFlagsToString( mSupportedHandwritingGestureTypes)); + pw.println(prefix + "supportedHandwritingGesturePreviewTypes=" + + InputMethodDebug.handwritingGestureTypeFlagsToString( + mSupportedHandwritingGesturePreviewTypes)); pw.println(prefix + "contentMimeTypes=" + Arrays.toString(contentMimeTypes)); if (targetInputMethodUser != null) { pw.println(prefix + "targetInputMethodUserId=" + targetInputMethodUser.getIdentifier()); @@ -1149,6 +1240,8 @@ public class EditorInfo implements InputType, Parcelable { newEditorInfo.contentMimeTypes = ArrayUtils.cloneOrNull(contentMimeTypes); newEditorInfo.targetInputMethodUser = targetInputMethodUser; newEditorInfo.mSupportedHandwritingGestureTypes = mSupportedHandwritingGestureTypes; + newEditorInfo.mSupportedHandwritingGesturePreviewTypes = + mSupportedHandwritingGesturePreviewTypes; return newEditorInfo; } @@ -1177,6 +1270,7 @@ public class EditorInfo implements InputType, Parcelable { dest.writeString(fieldName); dest.writeBundle(extras); dest.writeInt(mSupportedHandwritingGestureTypes); + dest.writeInt(mSupportedHandwritingGesturePreviewTypes); dest.writeBoolean(mInitialSurroundingText != null); if (mInitialSurroundingText != null) { mInitialSurroundingText.writeToParcel(dest, flags); @@ -1215,6 +1309,7 @@ public class EditorInfo implements InputType, Parcelable { res.fieldName = source.readString(); res.extras = source.readBundle(); res.mSupportedHandwritingGestureTypes = source.readInt(); + res.mSupportedHandwritingGesturePreviewTypes = source.readInt(); boolean hasInitialSurroundingText = source.readBoolean(); if (hasInitialSurroundingText) { res.mInitialSurroundingText = @@ -1258,6 +1353,8 @@ public class EditorInfo implements InputType, Parcelable { && initialCapsMode == that.initialCapsMode && fieldId == that.fieldId && mSupportedHandwritingGestureTypes == that.mSupportedHandwritingGestureTypes + && mSupportedHandwritingGesturePreviewTypes + == that.mSupportedHandwritingGesturePreviewTypes && Objects.equals(autofillId, that.autofillId) && Objects.equals(privateImeOptions, that.privateImeOptions) && Objects.equals(packageName, that.packageName) diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java index 2099a31c3e11..c94a3721df3c 100644 --- a/core/java/android/view/inputmethod/InputConnection.java +++ b/core/java/android/view/inputmethod/InputConnection.java @@ -26,6 +26,7 @@ import android.annotation.Nullable; import android.graphics.RectF; import android.inputmethodservice.InputMethodService; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; import android.text.TextUtils; import android.view.KeyCharacterMap; @@ -1031,6 +1032,8 @@ public interface InputConnection { /** * Perform a handwriting gesture on text. * + * <p>Note: A supported gesture {@link EditorInfo#getSupportedHandwritingGestures()} may not + * have preview supported {@link EditorInfo#getSupportedHandwritingGesturePreviews()}.</p> * @param gesture the gesture to perform * @param executor The executor to run the callback on. * @param consumer if the caller passes a non-null consumer, the editor must invoke this @@ -1041,6 +1044,7 @@ public interface InputConnection { * completed. Will be invoked on the given {@link Executor}. * Default implementation provides a callback to {@link IntConsumer} with * {@link #HANDWRITING_GESTURE_RESULT_UNSUPPORTED}. + * @see #previewHandwritingGesture(PreviewableHandwritingGesture, CancellationSignal) */ default void performHandwritingGesture( @NonNull HandwritingGesture gesture, @Nullable @CallbackExecutor Executor executor, @@ -1051,6 +1055,31 @@ public interface InputConnection { } /** + * Preview a handwriting gesture on text. + * Provides a real-time preview for a gesture to user for an ongoing gesture. e.g. as user + * begins to draw a circle around text, resulting selection {@link SelectGesture} is previewed + * while stylus is moving over applicable text. + * + * <p>Note: A supported gesture {@link EditorInfo#getSupportedHandwritingGestures()} might not + * have preview supported {@link EditorInfo#getSupportedHandwritingGesturePreviews()}.</p> + * @param gesture the gesture to preview. Preview support for a gesture (regardless of whether + * implemented by editor) can be determined if gesture subclasses + * {@link PreviewableHandwritingGesture}. Supported previewable gestures include + * {@link SelectGesture}, {@link SelectRangeGesture}, {@link DeleteGesture} and + * {@link DeleteRangeGesture}. + * @param cancellationSignal signal to cancel an ongoing preview. + * @return true on successfully sending command to Editor, false if not implemented by editor or + * the input connection is no longer valid or preview was cancelled with + * {@link CancellationSignal}. + * @see #performHandwritingGesture(HandwritingGesture, Executor, IntConsumer) + */ + default boolean previewHandwritingGesture( + @NonNull PreviewableHandwritingGesture gesture, + @Nullable CancellationSignal cancellationSignal) { + return false; + } + + /** * The editor is requested to call * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} at * once, as soon as possible, regardless of cursor/anchor position changes. This flag can be diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java index 7af96b60938c..4befd6f026ca 100644 --- a/core/java/android/view/inputmethod/InputConnectionWrapper.java +++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.RectF; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; import android.view.KeyEvent; @@ -340,6 +341,17 @@ public class InputConnectionWrapper implements InputConnection { * @throws NullPointerException if the target is {@code null}. */ @Override + public boolean previewHandwritingGesture( + @NonNull PreviewableHandwritingGesture gesture, + @Nullable CancellationSignal cancellationSignal) { + return mTarget.previewHandwritingGesture(gesture, cancellationSignal); + } + + /** + * {@inheritDoc} + * @throws NullPointerException if the target is {@code null}. + */ + @Override public boolean requestCursorUpdates(int cursorUpdateMode) { return mTarget.requestCursorUpdates(cursorUpdateMode); } diff --git a/core/java/android/view/inputmethod/PreviewableHandwritingGesture.java b/core/java/android/view/inputmethod/PreviewableHandwritingGesture.java new file mode 100644 index 000000000000..7683ece69412 --- /dev/null +++ b/core/java/android/view/inputmethod/PreviewableHandwritingGesture.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.inputmethod; + +import android.os.CancellationSignal; + +import java.util.Set; + +/** + * A {@link HandwritingGesture} that can be + * {@link InputConnection#previewHandwritingGesture( + * PreviewableHandwritingGesture, CancellationSignal) previewed}. + * + * Note: An editor might only implement a subset of gesture previews and declares the supported + * ones via {@link EditorInfo#getSupportedHandwritingGesturePreviews}. + * + * @see EditorInfo#setSupportedHandwritingGesturePreviews(Set) + * @see EditorInfo#getSupportedHandwritingGesturePreviews() + */ +public abstract class PreviewableHandwritingGesture extends HandwritingGesture { + PreviewableHandwritingGesture() { + // intentionally empty. + } +} diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java index c01c310dda1b..7525d723b802 100644 --- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java +++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java @@ -30,7 +30,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.RectF; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; +import android.os.ICancellationSignal; import android.os.Looper; import android.os.ResultReceiver; import android.os.Trace; @@ -1017,6 +1019,34 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { @Dispatching(cancellable = true) @Override + public void previewHandwritingGesture( + InputConnectionCommandHeader header, ParcelableHandwritingGesture gestureContainer, + ICancellationSignal transport) { + + // TODO(b/254727073): Implement CancellationSignal receiver + final CancellationSignal cancellationSignal = CancellationSignal.fromTransport(transport); + // Previews always use PreviewableHandwritingGesture but if incorrectly wrong class is + // passed, ClassCastException will be sent back to caller. + final PreviewableHandwritingGesture gesture = + (PreviewableHandwritingGesture) gestureContainer.get(); + + dispatchWithTracing("previewHandwritingGesture", () -> { + if (header.mSessionId != mCurrentSessionId.get() + || (cancellationSignal != null && cancellationSignal.isCanceled())) { + return; // cancelled + } + InputConnection ic = getInputConnection(); + if (ic == null || !isActive()) { + Log.w(TAG, "previewHandwritingGesture on inactive InputConnection"); + return; // cancelled + } + + ic.previewHandwritingGesture(gesture, cancellationSignal); + }); + } + + @Dispatching(cancellable = true) + @Override public void requestCursorUpdates(InputConnectionCommandHeader header, int cursorUpdateMode, int imeDisplayId, AndroidFuture future /* T=Boolean */) { dispatchWithTracing("requestCursorUpdates", future, () -> { diff --git a/core/java/android/view/inputmethod/SelectGesture.java b/core/java/android/view/inputmethod/SelectGesture.java index 6dc4ed295669..ba600df970bf 100644 --- a/core/java/android/view/inputmethod/SelectGesture.java +++ b/core/java/android/view/inputmethod/SelectGesture.java @@ -33,7 +33,7 @@ import java.util.Objects; * <p>Note: This selects all text <em>within</em> the given area. To select a range <em>between</em> * two areas, use {@link SelectRangeGesture}.</p> */ -public final class SelectGesture extends HandwritingGesture implements Parcelable { +public final class SelectGesture extends PreviewableHandwritingGesture implements Parcelable { private @Granularity int mGranularity; private RectF mArea; @@ -72,7 +72,6 @@ public final class SelectGesture extends HandwritingGesture implements Parcelabl return mArea; } - /** * Builder for {@link SelectGesture}. This class is not designed to be thread-safe. */ diff --git a/core/java/android/view/inputmethod/SelectRangeGesture.java b/core/java/android/view/inputmethod/SelectRangeGesture.java index 7cb60023bd31..c31bc275056e 100644 --- a/core/java/android/view/inputmethod/SelectRangeGesture.java +++ b/core/java/android/view/inputmethod/SelectRangeGesture.java @@ -34,7 +34,7 @@ import java.util.Objects; * <p>Note: this selects text within a range <em>between</em> two given areas. To select all text * <em>within</em> a single area, use {@link SelectGesture}</p> */ -public final class SelectRangeGesture extends HandwritingGesture implements Parcelable { +public final class SelectRangeGesture extends PreviewableHandwritingGesture implements Parcelable { private @Granularity int mGranularity; private RectF mStartArea; @@ -87,7 +87,6 @@ public final class SelectRangeGesture extends HandwritingGesture implements Parc return mEndArea; } - /** * Builder for {@link SelectRangeGesture}. This class is not designed to be thread-safe. */ diff --git a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl index 81e060d8c648..65016c27575e 100644 --- a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl +++ b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl @@ -18,6 +18,7 @@ package com.android.internal.inputmethod; import android.graphics.RectF; import android.os.Bundle; +import android.os.ICancellationSignal; import android.os.ResultReceiver; import android.view.KeyEvent; import android.view.inputmethod.CompletionInfo; @@ -92,6 +93,9 @@ import com.android.internal.inputmethod.InputConnectionCommandHeader; void performHandwritingGesture(in InputConnectionCommandHeader header, in ParcelableHandwritingGesture gesture, in ResultReceiver resultReceiver); + void previewHandwritingGesture(in InputConnectionCommandHeader header, + in ParcelableHandwritingGesture gesture, in ICancellationSignal transport); + void setComposingRegion(in InputConnectionCommandHeader header, int start, int end); void setComposingRegionWithTextAttribute(in InputConnectionCommandHeader header, int start, diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java index 599cf97cc89c..6e73b9fa35d5 100644 --- a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java +++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java @@ -52,6 +52,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Supplemental tests that cannot be covered by CTS (e.g. due to hidden API dependencies). @@ -500,6 +502,7 @@ public class EditorInfoTest { + "prefix: extras=null\n" + "prefix: hintLocales=null\n" + "prefix: supportedHandwritingGestureTypes=(none)\n" + + "prefix: supportedHandwritingGesturePreviewTypes=(none)\n" + "prefix: contentMimeTypes=null\n"); } @@ -516,6 +519,8 @@ public class EditorInfoTest { info.label = "testLabel"; info.setInitialToolType(MotionEvent.TOOL_TYPE_STYLUS); info.setSupportedHandwritingGestures(Arrays.asList(SelectGesture.class)); + info.setSupportedHandwritingGesturePreviews( + Stream.of(SelectGesture.class).collect(Collectors.toSet())); info.packageName = "android.view.inputmethod"; info.autofillId = new AutofillId(123); info.fieldId = 456; @@ -538,6 +543,7 @@ public class EditorInfoTest { + "prefix2: extras=Bundle[{testKey=testValue}]\n" + "prefix2: hintLocales=[en,es,zh]\n" + "prefix2: supportedHandwritingGestureTypes=SELECT\n" + + "prefix2: supportedHandwritingGesturePreviewTypes=SELECT\n" + "prefix2: contentMimeTypes=[image/png]\n" + "prefix2: targetInputMethodUserId=10\n"); } @@ -558,6 +564,7 @@ public class EditorInfoTest { + "prefix: packageName=null autofillId=null fieldId=0 fieldName=null\n" + "prefix: hintLocales=null\n" + "prefix: supportedHandwritingGestureTypes=(none)\n" + + "prefix: supportedHandwritingGesturePreviewTypes=(none)\n" + "prefix: contentMimeTypes=null\n"); } |