Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb225ec3 authored by Justin Ghan's avatar Justin Ghan
Browse files

Show toast when handwriting in unsupported view

Bug: 297962571
Test: atest StylusHandwritingTest
Change-Id: Iab2ab1b154e91ab9c15930f22b5dfaa09cb92d26
parent 54552737
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -126,3 +126,10 @@ flag {
  description: "When handwriting is initiated in an unfocused TextView, cursor is placed at the end of the closest paragraph."
  bug: "323376217"
}

flag {
  name: "handwriting_unsupported_message"
  namespace: "text"
  description: "Feature flag for showing error message when user tries stylus handwriting on a text field which doesn't support it"
  bug: "297962571"
}
+35 −6
Original line number Diff line number Diff line
@@ -34,7 +34,9 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.Editor;
import android.widget.TextView;
import android.widget.Toast;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;

import java.lang.ref.WeakReference;
@@ -223,7 +225,24 @@ public class HandwritingInitiator {
                    View candidateView = findBestCandidateView(mState.mStylusDownX,
                            mState.mStylusDownY, /* isHover */ false);
                    if (candidateView != null && candidateView.isEnabled()) {
                        if (candidateView == getConnectedOrFocusedView()) {
                        if (shouldShowHandwritingUnavailableMessageForView(candidateView)) {
                            int messagesResId = (candidateView instanceof TextView tv
                                    && tv.isAnyPasswordInputType())
                                    ? R.string.error_handwriting_unsupported_password
                                    : R.string.error_handwriting_unsupported;
                            Toast.makeText(candidateView.getContext(), messagesResId,
                                    Toast.LENGTH_SHORT).show();
                            if (!candidateView.hasFocus()) {
                                requestFocusWithoutReveal(candidateView);
                            }
                            mImm.showSoftInput(candidateView, 0);
                            mState.mHandled = true;
                            mState.mShouldInitHandwriting = false;
                            motionEvent.setAction((motionEvent.getAction()
                                    & MotionEvent.ACTION_POINTER_INDEX_MASK)
                                    | MotionEvent.ACTION_CANCEL);
                            candidateView.getRootView().dispatchTouchEvent(motionEvent);
                        } else if (candidateView == getConnectedOrFocusedView()) {
                            if (!mInitiateWithoutConnection && !candidateView.hasFocus()) {
                                requestFocusWithoutReveal(candidateView);
                            }
@@ -484,6 +503,15 @@ public class HandwritingInitiator {
        return view.isStylusHandwritingAvailable();
    }

    private static boolean shouldShowHandwritingUnavailableMessageForView(@NonNull View view) {
        return (view instanceof TextView) && !shouldTriggerStylusHandwritingForView(view);
    }

    private static boolean shouldTriggerHandwritingOrShowUnavailableMessageForView(
            @NonNull View view) {
        return (view instanceof TextView) || shouldTriggerStylusHandwritingForView(view);
    }

    /**
     * Returns the pointer icon for the motion event, or null if it doesn't specify the icon.
     * This gives HandwritingInitiator a chance to show the stylus handwriting icon over a
@@ -491,7 +519,7 @@ public class HandwritingInitiator {
     */
    public PointerIcon onResolvePointerIcon(Context context, MotionEvent event) {
        final View hoverView = findHoverView(event);
        if (hoverView == null) {
        if (hoverView == null || !shouldTriggerStylusHandwritingForView(hoverView)) {
            return null;
        }

@@ -594,7 +622,7 @@ public class HandwritingInitiator {

    /**
     * Given the location of the stylus event, return the best candidate view to initialize
     * handwriting mode.
     * handwriting mode or show the handwriting unavailable error message.
     *
     * @param x the x coordinates of the stylus event, in the coordinates of the window.
     * @param y the y coordinates of the stylus event, in the coordinates of the window.
@@ -610,7 +638,8 @@ public class HandwritingInitiator {
            Rect handwritingArea = mTempRect;
            if (getViewHandwritingArea(connectedOrFocusedView, handwritingArea)
                    && isInHandwritingArea(handwritingArea, x, y, connectedOrFocusedView, isHover)
                    && shouldTriggerStylusHandwritingForView(connectedOrFocusedView)) {
                    && shouldTriggerHandwritingOrShowUnavailableMessageForView(
                            connectedOrFocusedView)) {
                if (!isHover && mState != null) {
                    mState.mStylusDownWithinEditorBounds =
                            contains(handwritingArea, x, y, 0f, 0f, 0f, 0f);
@@ -628,7 +657,7 @@ public class HandwritingInitiator {
            final View view = viewInfo.getView();
            final Rect handwritingArea = viewInfo.getHandwritingArea();
            if (!isInHandwritingArea(handwritingArea, x, y, view, isHover)
                    || !shouldTriggerStylusHandwritingForView(view)) {
                    || !shouldTriggerHandwritingOrShowUnavailableMessageForView(view)) {
                continue;
            }

@@ -856,7 +885,7 @@ public class HandwritingInitiator {
    /** The helper method to check if the given view is still active for handwriting. */
    private static boolean isViewActive(@Nullable View view) {
        return view != null && view.isAttachedToWindow() && view.isAggregatedVisible()
                && view.shouldInitiateHandwriting();
                && view.shouldTrackHandwritingArea();
    }

    private CursorAnchorInfo getCursorAnchorInfoForConnectionless(View view) {
+12 −2
Original line number Diff line number Diff line
@@ -12673,7 +12673,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        if (getSystemGestureExclusionRects().isEmpty()
                && collectPreferKeepClearRects().isEmpty()
                && collectUnrestrictedPreferKeepClearRects().isEmpty()
                && (info.mHandwritingArea == null || !shouldInitiateHandwriting())) {
                && (info.mHandwritingArea == null || !shouldTrackHandwritingArea())) {
            if (info.mPositionUpdateListener != null) {
                mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener);
                info.mPositionUpdateListener = null;
@@ -13040,7 +13040,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    void updateHandwritingArea() {
        // If autoHandwritingArea is not enabled, do nothing.
        if (!shouldInitiateHandwriting()) return;
        if (!shouldTrackHandwritingArea()) return;
        final AttachInfo ai = mAttachInfo;
        if (ai != null) {
            ai.mViewRootImpl.getHandwritingInitiator().updateHandwritingAreasForView(this);
@@ -13057,6 +13057,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return isAutoHandwritingEnabled() || getHandwritingDelegatorCallback() != null;
    }
    /**
     * Returns whether the handwriting initiator should track the handwriting area for this view,
     * either to initiate handwriting mode, or to prepare handwriting delegation, or to show the
     * handwriting unsupported message.
     * @hide
     */
    public boolean shouldTrackHandwritingArea() {
        return shouldInitiateHandwriting();
    }
    /**
     * Sets a callback which should be called when a stylus {@link MotionEvent} occurs within this
     * view's bounds. The callback will be called from the UI thread.
+9 −0
Original line number Diff line number Diff line
@@ -13563,6 +13563,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        return super.isAutoHandwritingEnabled() && !isAnyPasswordInputType();
    }
    /** @hide */
    @Override
    public boolean shouldTrackHandwritingArea() {
        // The handwriting initiator tracks all editable TextViews regardless of whether handwriting
        // is supported, so that it can show an error message for unsupported editable TextViews.
        return super.shouldTrackHandwritingArea()
                || (Flags.handwritingUnsupportedMessage() && onCheckIsTextEditor());
    }
    /** @hide */
    @Override
    public boolean isStylusHandwritingAvailable() {
+6 −0
Original line number Diff line number Diff line
@@ -3244,6 +3244,12 @@
    <!-- Title for EditText context menu [CHAR LIMIT=20] -->
    <string name="editTextMenuTitle">Text actions</string>

    <!-- Error shown when a user uses a stylus to try handwriting on a text field which doesn't support stylus handwriting. [CHAR LIMIT=TOAST] -->
    <string name="error_handwriting_unsupported">Handwriting is not supported in this field</string>

    <!-- Error shown when a user uses a stylus to try handwriting on a password text field which doesn't support stylus handwriting. [CHAR LIMIT=TOAST] -->
    <string name="error_handwriting_unsupported_password">Handwriting is not supported in password fields</string>

    <!-- Content description of the back button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
    <string name="input_method_nav_back_button_desc">Back</string>
    <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
Loading