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

Commit a03b1b67 authored by Justin Ghan's avatar Justin Ghan Committed by Automerger Merge Worker
Browse files

Merge "Set cursor position in handwriting initiation" into udc-qpr-dev am: 8c13cc3a

parents 829ca7f5 8c13cc3a
Loading
Loading
Loading
Loading
+32 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;

import com.android.internal.annotations.VisibleForTesting;
@@ -81,6 +82,8 @@ public class HandwritingInitiator {
    private int mConnectionCount = 0;
    private final InputMethodManager mImm;

    private final int[] mTempLocation = new int[2];

    private final Rect mTempRect = new Rect();

    private final RectF mTempRectF = new RectF();
@@ -429,7 +432,19 @@ public class HandwritingInitiator {
        return null;
    }

    private static void requestFocusWithoutReveal(View view) {
    private void requestFocusWithoutReveal(View view) {
        if (view instanceof EditText editText && !mState.mStylusDownWithinEditorBounds) {
            // If the stylus down point was inside the EditText's bounds, then the EditText will
            // automatically set its cursor position nearest to the stylus down point when it
            // gains focus. If the stylus down point was outside the EditText's bounds (within
            // the extended handwriting bounds), then we must calculate and set the cursor
            // position manually.
            view.getLocationInWindow(mTempLocation);
            int offset = editText.getOffsetForPosition(
                    mState.mStylusDownX - mTempLocation[0],
                    mState.mStylusDownY - mTempLocation[1]);
            editText.setSelection(offset);
        }
        if (view.getRevealOnFocusHint()) {
            view.setRevealOnFocusHint(false);
            view.requestFocus();
@@ -457,6 +472,10 @@ public class HandwritingInitiator {
            if (getViewHandwritingArea(connectedView, handwritingArea)
                    && isInHandwritingArea(handwritingArea, x, y, connectedView, isHover)
                    && shouldTriggerStylusHandwritingForView(connectedView)) {
                if (!isHover && mState != null) {
                    mState.mStylusDownWithinEditorBounds =
                            contains(handwritingArea, x, y, 0f, 0f, 0f, 0f);
                }
                return connectedView;
            }
        }
@@ -475,7 +494,12 @@ public class HandwritingInitiator {
            }

            final float distance = distance(handwritingArea, x, y);
            if (distance == 0f) return view;
            if (distance == 0f) {
                if (!isHover && mState != null) {
                    mState.mStylusDownWithinEditorBounds = true;
                }
                return view;
            }
            if (distance < minDistance) {
                minDistance = distance;
                bestCandidate = view;
@@ -657,6 +681,12 @@ public class HandwritingInitiator {
         */
        private boolean mExceedHandwritingSlop;

        /**
         * Whether the stylus down point of the MotionEvent sequence was within the editor's bounds
         * (not including the extended handwriting bounds).
         */
        private boolean mStylusDownWithinEditorBounds;

        /**
         * A view which has requested focus and is pending input connection creation. When an input
         * connection is created for the view, a handwriting session should be started for the view.
+19 −2
Original line number Diff line number Diff line
@@ -88,8 +88,8 @@ public class HandwritingInitiatorTest {
    }

    private HandwritingInitiator mHandwritingInitiator;
    private View mTestView1;
    private View mTestView2;
    private EditText mTestView1;
    private EditText mTestView2;
    private Context mContext;

    @Before
@@ -123,6 +123,9 @@ public class HandwritingInitiatorTest {

    @Test
    public void onTouchEvent_startHandwriting_when_stylusMoveOnce_withinHWArea() {
        mTestView1.setText("hello");
        when(mTestView1.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(4);

        mHandwritingInitiator.onInputConnectionCreated(mTestView1);
        final int x1 = (sHwArea1.left + sHwArea1.right) / 2;
        final int y1 = (sHwArea1.top + sHwArea1.bottom) / 2;
@@ -141,6 +144,9 @@ public class HandwritingInitiatorTest {
        // After IMM.startHandwriting is triggered, onTouchEvent should return true for ACTION_MOVE
        // events so that the events are not dispatched to the view tree.
        assertThat(onTouchEventResult2).isTrue();
        // Since the stylus down point was inside the TextView's bounds, the handwriting initiator
        // does not need to set the cursor position.
        verify(mTestView1, never()).setSelection(anyInt());
    }

    @Test
@@ -185,6 +191,9 @@ public class HandwritingInitiatorTest {

    @Test
    public void onTouchEvent_startHandwriting_when_stylusMove_withinExtendedHWArea() {
        mTestView1.setText("hello");
        when(mTestView1.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(4);

        mHandwritingInitiator.onInputConnectionCreated(mTestView1);
        final int x1 = sHwArea1.left - HW_BOUNDS_OFFSETS_LEFT_PX / 2;
        final int y1 = sHwArea1.top - HW_BOUNDS_OFFSETS_TOP_PX / 2;
@@ -199,6 +208,9 @@ public class HandwritingInitiatorTest {

        // Stylus movement within extended HandwritingArea should trigger IMM.startHandwriting once.
        verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView1);
        // Since the stylus down point was outside the TextView's bounds, the handwriting initiator
        // sets the cursor position.
        verify(mTestView1).setSelection(4);
    }

    @Test
@@ -221,6 +233,8 @@ public class HandwritingInitiatorTest {

    @Test
    public void onTouchEvent_startHandwriting_inputConnectionBuilt_stylusMoveInExtendedHWArea() {
        mTestView1.setText("hello");
        when(mTestView1.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(4);
        // The stylus down point is between mTestView1 and  mTestView2, but it is within the
        // extended handwriting area of both views. It is closer to mTestView1.
        final int x1 = sHwArea1.right + HW_BOUNDS_OFFSETS_RIGHT_PX / 2;
@@ -241,6 +255,9 @@ public class HandwritingInitiatorTest {
        // the stylus down point is closest to this view.
        mHandwritingInitiator.onInputConnectionCreated(mTestView1);
        verify(mHandwritingInitiator).startHandwriting(mTestView1);
        // Since the stylus down point was outside the TextView's bounds, the handwriting initiator
        // sets the cursor position.
        verify(mTestView1).setSelection(4);
    }

    @Test
+15 −4
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package android.view.stylus;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

@@ -26,22 +29,23 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;

import androidx.test.platform.app.InstrumentationRegistry;

public class HandwritingTestUtil {
    public static View createView(Rect handwritingArea) {
    public static EditText createView(Rect handwritingArea) {
        return createView(handwritingArea, true /* autoHandwritingEnabled */,
                true /* isStylusHandwritingAvailable */);
    }

    public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled,
    public static EditText createView(Rect handwritingArea, boolean autoHandwritingEnabled,
            boolean isStylusHandwritingAvailable) {
        return createView(handwritingArea, autoHandwritingEnabled, isStylusHandwritingAvailable,
                0, 0, 0, 0);
    }

    public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled,
    public static EditText createView(Rect handwritingArea, boolean autoHandwritingEnabled,
            boolean isStylusHandwritingAvailable,
            float handwritingBoundsOffsetLeft, float handwritingBoundsOffsetTop,
            float handwritingBoundsOffsetRight, float handwritingBoundsOffsetBottom) {
@@ -68,7 +72,7 @@ public class HandwritingTestUtil {
            }
        };

        View view = spy(new View(context));
        EditText view = spy(new EditText(context));
        when(view.isAttachedToWindow()).thenReturn(true);
        when(view.isAggregatedVisible()).thenReturn(true);
        when(view.isStylusHandwritingAvailable()).thenReturn(isStylusHandwritingAvailable);
@@ -77,6 +81,13 @@ public class HandwritingTestUtil {
        when(view.getHandwritingBoundsOffsetTop()).thenReturn(handwritingBoundsOffsetTop);
        when(view.getHandwritingBoundsOffsetRight()).thenReturn(handwritingBoundsOffsetRight);
        when(view.getHandwritingBoundsOffsetBottom()).thenReturn(handwritingBoundsOffsetBottom);
        doAnswer(invocation -> {
            int[] outLocation = invocation.getArgument(0);
            outLocation[0] = handwritingArea.left;
            outLocation[1] = handwritingArea.top;
            return null;
        }).when(view).getLocationInWindow(any());
        when(view.getOffsetForPosition(anyFloat(), anyFloat())).thenReturn(0);
        view.setAutoHandwritingEnabled(autoHandwritingEnabled);
        parent.addView(view);
        return view;