From 01f665ae47b1fb3e8a789b4128acd6345e6f14d2 Mon Sep 17 00:00:00 2001 From: Justin Ghan Date: Fri, 17 Mar 2023 15:38:00 -0700 Subject: [PATCH] Prevent scrolling for handwriting delegator When stylus movement occurs on a handwriting delegator view, there may be some latency before the handwriting session starts. During this latency, the stylus movement should not cause scrolling. This can be suppressed in the same way that was done for standard handwriting initiation. Bug: 228210945 Test: atest android.view.stylus.HandwritingInitiatorTest Change-Id: Ibafb6031f87fb1b1c1c9e4cfd679eb09b69b8f2a --- .../android/view/HandwritingInitiator.java | 12 +++++-- .../view/stylus/HandwritingInitiatorTest.java | 35 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java index 6b604422ffbaa..77f3b1da92b41 100644 --- a/core/java/android/view/HandwritingInitiator.java +++ b/core/java/android/view/HandwritingInitiator.java @@ -151,14 +151,16 @@ public class HandwritingInitiator { // Either we've already tried to initiate handwriting, or the ongoing MotionEvent // sequence is considered to be tap, long-click or other gestures. if (!mState.mShouldInitHandwriting || mState.mExceedHandwritingSlop) { - return mState.mHasInitiatedHandwriting; + return mState.mHasInitiatedHandwriting + || mState.mHasPreparedHandwritingDelegation; } final long timeElapsed = motionEvent.getEventTime() - mState.mStylusDownTimeInMillis; if (timeElapsed > mHandwritingTimeoutInMillis) { mState.mShouldInitHandwriting = false; - return mState.mHasInitiatedHandwriting; + return mState.mHasInitiatedHandwriting + || mState.mHasPreparedHandwritingDelegation; } final int pointerIndex = motionEvent.findPointerIndex(mState.mStylusPointerId); @@ -183,12 +185,13 @@ public class HandwritingInitiator { mImm.prepareStylusHandwritingDelegation( candidateView, delegatePackageName); candidateView.getHandwritingDelegatorCallback().run(); + mState.mHasPreparedHandwritingDelegation = true; } else { requestFocusWithoutReveal(candidateView); } } } - return mState.mHasInitiatedHandwriting; + return mState.mHasInitiatedHandwriting || mState.mHasPreparedHandwritingDelegation; } return false; } @@ -568,6 +571,8 @@ public class HandwritingInitiator { * Whether handwriting mode has already been initiated for the current MotionEvent sequence. */ private boolean mHasInitiatedHandwriting; + + private boolean mHasPreparedHandwritingDelegation; /** * Whether the current ongoing stylus MotionEvent sequence already exceeds the * handwriting slop. @@ -593,6 +598,7 @@ public class HandwritingInitiator { mShouldInitHandwriting = true; mHasInitiatedHandwriting = false; + mHasPreparedHandwritingDelegation = false; mExceedHandwritingSlop = false; } } diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java index fccb177dad4fd..8ae63816ba163 100644 --- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java +++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java @@ -268,6 +268,41 @@ public class HandwritingInitiatorTest { verify(mHandwritingInitiator, times(1)).tryAcceptStylusHandwritingDelegation(delegateView); } + @Test + public void onTouchEvent_startHandwriting_delegate_touchEventsHandled() { + // There is no delegator view and the delegate callback does nothing so handwriting will not + // be started. This is so we can test how touch events are handled before handwriting is + // started. + mTestView1.setHandwritingDelegatorCallback(() -> {}); + + final int x1 = (sHwArea1.left + sHwArea1.right) / 2; + final int y = (sHwArea1.top + sHwArea1.bottom) / 2; + MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y, 0); + boolean onTouchEventResult1 = mHandwritingInitiator.onTouchEvent(stylusEvent1); + + final int x2 = x1 + mHandwritingSlop / 2; + MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y, 0); + boolean onTouchEventResult2 = mHandwritingInitiator.onTouchEvent(stylusEvent2); + + final int x3 = x2 + mHandwritingSlop * 2; + MotionEvent stylusEvent3 = createStylusEvent(ACTION_MOVE, x3, y, 0); + boolean onTouchEventResult3 = mHandwritingInitiator.onTouchEvent(stylusEvent3); + + final int x4 = x3 + mHandwritingSlop * 2; + MotionEvent stylusEvent4 = createStylusEvent(ACTION_MOVE, x4, y, 0); + boolean onTouchEventResult4 = mHandwritingInitiator.onTouchEvent(stylusEvent4); + + assertThat(onTouchEventResult1).isFalse(); + // stylusEvent2 does not trigger delegation since the touch slop distance has not been + // exceeded. onTouchEvent should return false so that the event is dispatched to the view + // tree. + assertThat(onTouchEventResult2).isFalse(); + // After delegation is triggered by stylusEvent3, onTouchEvent should return true for + // ACTION_MOVE events so that the events are not dispatched to the view tree. + assertThat(onTouchEventResult3).isTrue(); + assertThat(onTouchEventResult4).isTrue(); + } + @Test public void onTouchEvent_notStartHandwriting_whenHandwritingNotAvailable() { final Rect rect = new Rect(600, 600, 900, 900);