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

Commit 57620822 authored by Haoyu Zhang's avatar Haoyu Zhang
Browse files

Scribe in View: enable Handwriting

Bug: 209854913
Test: atest FrameworksCoreTests:HandwritingInitiatorTest
Change-Id: I8449b3d9e713e226a2cd2b772103e79bf65b88c9
parent 8b22e7b7
Loading
Loading
Loading
Loading
+2 −13
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import static android.view.MotionEvent.TOOL_TYPE_STYLUS;

import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Rect;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.view.inputmethod.EditorInfo;
@@ -190,7 +189,7 @@ public class HandwritingInitiatorPerfTest {
        final View view = new View(mContext);
        final EditorInfo editorInfo = new EditorInfo();
        while (state.keepRunning()) {
            mHandwritingInitiator.onInputConnectionCreated(view, editorInfo);
            mHandwritingInitiator.onInputConnectionCreated(view);
            state.pauseTiming();
            mHandwritingInitiator.onInputConnectionClosed(view);
            state.resumeTiming();
@@ -201,24 +200,14 @@ public class HandwritingInitiatorPerfTest {
    public void onInputConnectionClosed() {
        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        final View view = new View(mContext);
        final EditorInfo editorInfo = new EditorInfo();
        while (state.keepRunning()) {
            state.pauseTiming();
            mHandwritingInitiator.onInputConnectionCreated(view, editorInfo);
            mHandwritingInitiator.onInputConnectionCreated(view);
            state.resumeTiming();
            mHandwritingInitiator.onInputConnectionClosed(view);
        }
    }

    @Test
    public void updateEditorBoundary() {
        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        final Rect rect = new Rect(0, 0, 100, 100);
        while (state.keepRunning()) {
            mHandwritingInitiator.updateEditorBound(rect);
        }
    }

    private MotionEvent createMotionEvent(int action, int toolType, int x, int y, long eventTime) {
        MotionEvent.PointerProperties[] properties = MotionEvent.PointerProperties.createArray(1);
        properties[0].toolType = toolType;
+6 −30
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package android.view;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;

import com.android.internal.annotations.VisibleForTesting;
@@ -75,11 +74,6 @@ public class HandwritingInitiator {
    @VisibleForTesting
    public WeakReference<View> mConnectedView = null;

    /** The editor bound reported by the connected View. */
    @Nullable
    @VisibleForTesting
    public Rect mEditorBound = null;

    /**
     * When InputConnection restarts for a View, View#onInputConnectionCreatedInternal
     * might be called before View#onInputConnectionClosedInternal, so we need to count the input
@@ -174,9 +168,8 @@ public class HandwritingInitiator {
     * @param view the view that created the current InputConnection.
     * @see  #onInputConnectionClosed(View)
     */
    public void onInputConnectionCreated(@NonNull View view, @NonNull EditorInfo editorInfo) {
    public void onInputConnectionCreated(@NonNull View view) {
        final View connectedView = getConnectedView();
//        updateEditorBound(editorInfo.getInitialEditorBound());
        if (connectedView == view) {
            ++mConnectionCount;
        } else {
@@ -198,32 +191,14 @@ public class HandwritingInitiator {
            --mConnectionCount;
            if (mConnectionCount == 0) {
                mConnectedView = null;
                mEditorBound = null;
            }
        } else {
            // Unexpected branch, set mConnectedView to null to avoid further problem.
            mConnectedView = null;
            mEditorBound = null;
            mConnectionCount = 0;
        }
    }

    /**
     * Notify the HandwritingInitiator that editor bound of the connected view(the view with
     * active InputConnection) has be updated.
     * @param editorBound new the editor bounds of the connected view.
     */
    public void updateEditorBound(@NonNull Rect editorBound) {
        if (mEditorBound == null) {
            mEditorBound = new Rect(editorBound);
        } else {
            mEditorBound.left = editorBound.left;
            mEditorBound.top = editorBound.top;
            mEditorBound.right = editorBound.right;
            mEditorBound.bottom = editorBound.bottom;
        }
    }

    /**
     * Try to initiate handwriting. For this method to successfully send startHandwriting signal,
     * the following 3 conditions should meet:
@@ -240,18 +215,19 @@ public class HandwritingInitiator {
            return;
        }
        final View connectedView = getConnectedView();
        if (connectedView == null || mEditorBound == null) {
        if (connectedView == null) {
            return;
        }
        final ViewParent viewParent = connectedView.getParent();
        // Do a final check before startHandwriting.
        if (viewParent != null && connectedView.isAttachedToWindow()) {
            final Rect editorBounds = new Rect(mEditorBound);
            final Rect editorBounds =
                    new Rect(0, 0, connectedView.getWidth(), connectedView.getHeight());
            if (viewParent.getChildVisibleRect(connectedView, editorBounds, null)) {
                final int roundedInitX = Math.round(mState.mStylusDownX);
                final int roundedInitY = Math.round(mState.mStylusDownY);
                if (editorBounds.contains(roundedInitX, roundedInitY)) {
                    startHandwriting(mConnectedView.get());
                    startHandwriting(connectedView);
                }
            }
        }
@@ -261,7 +237,7 @@ public class HandwritingInitiator {
    /** For test only. */
    @VisibleForTesting
    public void startHandwriting(View view) {
        // mImm.startHandwriting(view);
        mImm.startStylusHandwriting(view);
    }

    private boolean largerThanTouchSlop(float x1, float y1, float x2, float y2) {
+1 −1
Original line number Diff line number Diff line
@@ -2139,7 +2139,7 @@ public final class InputMethodManager {
            view.onInputConnectionOpenedInternal(ic, tba, icHandler);
            final ViewRootImpl viewRoot = view.getViewRootImpl();
            if (viewRoot != null) {
                viewRoot.getHandwritingInitiator().onInputConnectionCreated(view, tba);
                viewRoot.getHandwritingInitiator().onInputConnectionCreated(view);
            }
        }

+12 −27
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@ import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;

import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -57,7 +56,6 @@ public class HandwritingInitiatorTest {
    private static final int TOUCH_SLOP = 8;
    private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
    private static final Rect sHwArea = new Rect(100, 200, 500, 500);
    private static final EditorInfo sFakeEditorInfo = new EditorInfo();

    private HandwritingInitiator mHandwritingInitiator;
    private View mTestView;
@@ -72,7 +70,6 @@ public class HandwritingInitiatorTest {
        InputMethodManager inputMethodManager = context.getSystemService(InputMethodManager.class);
        mHandwritingInitiator =
                spy(new HandwritingInitiator(viewConfiguration, inputMethodManager));
        mHandwritingInitiator.updateEditorBound(sHwArea);

        // mock a parent so that HandwritingInitiator can get
        ViewGroup parent = new ViewGroup(context) {
@@ -82,10 +79,7 @@ public class HandwritingInitiatorTest {
            }
            @Override
            public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
                r.left = sHwArea.left;
                r.top = sHwArea.top;
                r.right = sHwArea.right;
                r.bottom = sHwArea.bottom;
                r.set(sHwArea);
                return true;
            }
        };
@@ -97,7 +91,7 @@ public class HandwritingInitiatorTest {

    @Test
    public void onTouchEvent_startHandwriting_when_stylusMoveOnce_withinHWArea() {
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);
        final int x1 = (sHwArea.left + sHwArea.right) / 2;
        final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -109,13 +103,13 @@ public class HandwritingInitiatorTest {
        MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
        mHandwritingInitiator.onTouchEvent(stylusEvent2);

        // Stylus movement win HandwritingArea should trigger IMM.startHandwriting once.
        // Stylus movement within HandwritingArea should trigger IMM.startHandwriting once.
        verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView);
    }

    @Test
    public void onTouchEvent_startHandwritingOnce_when_stylusMoveMultiTimes_withinHWArea() {
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);
        final int x1 = (sHwArea.left + sHwArea.right) / 2;
        final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -152,14 +146,14 @@ public class HandwritingInitiatorTest {
        mHandwritingInitiator.onTouchEvent(stylusEvent2);

        // InputConnection is created after stylus movement.
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);

        verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView);
    }

    @Test
    public void onTouchEvent_notStartHandwriting_when_stylusTap_withinHWArea() {
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);
        final int x1 = 200;
        final int y1 = 200;
        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -175,7 +169,7 @@ public class HandwritingInitiatorTest {

    @Test
    public void onTouchEvent_notStartHandwriting_when_stylusMove_outOfHWArea() {
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);
        final int x1 = 10;
        final int y1 = 10;
        MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
@@ -191,7 +185,7 @@ public class HandwritingInitiatorTest {

    @Test
    public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTapTimeOut() {
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);
        final int x1 = 10;
        final int y1 = 10;
        final long time1 = 10L;
@@ -210,18 +204,17 @@ public class HandwritingInitiatorTest {

    @Test
    public void onInputConnectionCreated_inputConnectionCreated() {
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);
        assertThat(mHandwritingInitiator.mConnectedView).isNotNull();
        assertThat(mHandwritingInitiator.mConnectedView.get()).isEqualTo(mTestView);
    }

    @Test
    public void onInputConnectionCreated_inputConnectionClosed() {
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);
        mHandwritingInitiator.onInputConnectionClosed(mTestView);

        assertThat(mHandwritingInitiator.mConnectedView).isNull();
        assertThat(mHandwritingInitiator.mEditorBound).isNull();
    }

    @Test
@@ -229,22 +222,14 @@ public class HandwritingInitiatorTest {
        // When IMM restarts input connection, View#onInputConnectionCreatedInternal might be
        // called before View#onInputConnectionClosedInternal. As a result, we need to handle the
        // case where "one view "2 InputConnections".
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView, sFakeEditorInfo);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);
        mHandwritingInitiator.onInputConnectionCreated(mTestView);
        mHandwritingInitiator.onInputConnectionClosed(mTestView);

        assertThat(mHandwritingInitiator.mConnectedView).isNotNull();
        assertThat(mHandwritingInitiator.mConnectedView.get()).isEqualTo(mTestView);
    }

    @Test
    public void updateEditorBound() {
        Rect rect = new Rect(1, 2, 3, 4);
        mHandwritingInitiator.updateEditorBound(rect);

        assertThat(mHandwritingInitiator.mEditorBound).isEqualTo(rect);
    }

    private MotionEvent createStylusEvent(int action, int x, int y, long eventTime) {
        MotionEvent.PointerProperties[] properties = MotionEvent.PointerProperties.createArray(1);
        properties[0].toolType = MotionEvent.TOOL_TYPE_STYLUS;