Merge "Handwriting initiation delegation"
This commit is contained in:
committed by
Android (Google) Code Review
commit
9fa6872e1c
@@ -48571,6 +48571,12 @@ package android.view {
|
||||
field public static final int VERTICAL_GRAVITY_MASK = 112; // 0x70
|
||||
}
|
||||
|
||||
public class HandwritingDelegateConfiguration {
|
||||
ctor public HandwritingDelegateConfiguration(@IdRes int, @NonNull Runnable);
|
||||
method public int getDelegatorViewId();
|
||||
method @NonNull public Runnable getInitiationCallback();
|
||||
}
|
||||
|
||||
public class HapticFeedbackConstants {
|
||||
field public static final int CLOCK_TICK = 4; // 0x4
|
||||
field public static final int CONFIRM = 16; // 0x10
|
||||
@@ -50187,6 +50193,7 @@ package android.view {
|
||||
method public float getHandwritingBoundsOffsetLeft();
|
||||
method public float getHandwritingBoundsOffsetRight();
|
||||
method public float getHandwritingBoundsOffsetTop();
|
||||
method @Nullable public android.view.HandwritingDelegateConfiguration getHandwritingDelegateConfiguration();
|
||||
method public final boolean getHasOverlappingRendering();
|
||||
method public final int getHeight();
|
||||
method public void getHitRect(android.graphics.Rect);
|
||||
@@ -50553,6 +50560,7 @@ package android.view {
|
||||
method public void setForegroundTintList(@Nullable android.content.res.ColorStateList);
|
||||
method public void setForegroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
|
||||
method public void setHandwritingBoundsOffsets(float, float, float, float);
|
||||
method public void setHandwritingDelegateConfiguration(@Nullable android.view.HandwritingDelegateConfiguration);
|
||||
method public void setHapticFeedbackEnabled(boolean);
|
||||
method public void setHasTransientState(boolean);
|
||||
method public void setHorizontalFadingEdgeEnabled(boolean);
|
||||
|
||||
74
core/java/android/view/HandwritingDelegateConfiguration.java
Normal file
74
core/java/android/view/HandwritingDelegateConfiguration.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.annotation.IdRes;
|
||||
import android.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Configuration for a view to act as a handwriting initiation delegate. This allows handwriting
|
||||
* mode for a delegator editor view to be initiated by stylus movement on the delegate view.
|
||||
*
|
||||
* <p>If a stylus {@link MotionEvent} occurs within the delegate view's bounds, the callback
|
||||
* returned by {@link #getInitiationCallback()} will be called. The callback implementation is
|
||||
* expected to show and focus the delegator editor view. If a view with identifier matching {@link
|
||||
* #getDelegatorViewId()} creates an input connection while the same stylus {@link MotionEvent}
|
||||
* sequence is ongoing, handwriting mode will be initiated for that view.
|
||||
*
|
||||
* <p>A common use case is a custom view which looks like a text editor but does not actually
|
||||
* support text editing itself, and clicking on the custom view causes an EditText to be shown. To
|
||||
* support handwriting initiation in this case, {@link View#setHandwritingDelegateConfiguration} can
|
||||
* be called on the custom view to configure it as a delegate, and set the EditText as the delegator
|
||||
* by passing the EditText's identifier as the {@code delegatorViewId}. The {@code
|
||||
* initiationCallback} implementation is typically the same as the click listener implementation
|
||||
* which shows the EditText.
|
||||
*/
|
||||
public class HandwritingDelegateConfiguration {
|
||||
@IdRes private final int mDelegatorViewId;
|
||||
@NonNull private final Runnable mInitiationCallback;
|
||||
|
||||
/**
|
||||
* Constructs a HandwritingDelegateConfiguration instance.
|
||||
*
|
||||
* @param delegatorViewId identifier of the delegator editor view for which handwriting mode
|
||||
* should be initiated
|
||||
* @param initiationCallback callback called when a stylus {@link MotionEvent} occurs within
|
||||
* this view's bounds
|
||||
*/
|
||||
public HandwritingDelegateConfiguration(
|
||||
@IdRes int delegatorViewId, @NonNull Runnable initiationCallback) {
|
||||
mDelegatorViewId = delegatorViewId;
|
||||
mInitiationCallback = initiationCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of the delegator editor view for which handwriting mode should be
|
||||
* initiated.
|
||||
*/
|
||||
public int getDelegatorViewId() {
|
||||
return mDelegatorViewId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the callback which should be called when a stylus {@link MotionEvent} occurs within
|
||||
* the delegate view's bounds.
|
||||
*/
|
||||
@NonNull
|
||||
public Runnable getInitiationCallback() {
|
||||
return mInitiationCallback;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.view;
|
||||
|
||||
import android.annotation.IdRes;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Rect;
|
||||
@@ -161,6 +162,15 @@ public class HandwritingInitiator {
|
||||
if (candidateView != null) {
|
||||
if (candidateView == getConnectedView()) {
|
||||
startHandwriting(candidateView);
|
||||
} else if (candidateView.getHandwritingDelegateConfiguration() != null) {
|
||||
mState.mDelegatorViewId =
|
||||
candidateView
|
||||
.getHandwritingDelegateConfiguration()
|
||||
.getDelegatorViewId();
|
||||
candidateView
|
||||
.getHandwritingDelegateConfiguration()
|
||||
.getInitiationCallback()
|
||||
.run();
|
||||
} else {
|
||||
if (candidateView.getRevealOnFocusHint()) {
|
||||
candidateView.setRevealOnFocusHint(false);
|
||||
@@ -259,8 +269,10 @@ public class HandwritingInitiator {
|
||||
}
|
||||
|
||||
final Rect handwritingArea = getViewHandwritingArea(connectedView);
|
||||
if (isInHandwritingArea(handwritingArea, mState.mStylusDownX,
|
||||
mState.mStylusDownY, connectedView)) {
|
||||
if ((mState.mDelegatorViewId != View.NO_ID
|
||||
&& mState.mDelegatorViewId == connectedView.getId())
|
||||
|| isInHandwritingArea(
|
||||
handwritingArea, mState.mStylusDownX, mState.mStylusDownY, connectedView)) {
|
||||
startHandwriting(connectedView);
|
||||
} else {
|
||||
mState.mShouldInitHandwriting = false;
|
||||
@@ -287,6 +299,11 @@ public class HandwritingInitiator {
|
||||
if (!view.isAutoHandwritingEnabled()) {
|
||||
return false;
|
||||
}
|
||||
// The view may be a handwriting initiation delegate, in which case it is not the editor
|
||||
// view for which handwriting would be started. However, in almost all cases, the return
|
||||
// values of View#isStylusHandwritingAvailable will be the same for the delegate view and
|
||||
// the delegator editor view. So the delegate view can be used to decide whether handwriting
|
||||
// should be triggered.
|
||||
return view.isStylusHandwritingAvailable();
|
||||
}
|
||||
|
||||
@@ -473,6 +490,13 @@ public class HandwritingInitiator {
|
||||
* built InputConnection.
|
||||
*/
|
||||
private boolean mExceedHandwritingSlop;
|
||||
/**
|
||||
* If the current ongoing stylus MotionEvent sequence started over a handwriting initiation
|
||||
* delegate view, then this is the view identifier of the corresponding delegator view. If
|
||||
* the delegator view creates an input connection while the MotionEvent sequence is still
|
||||
* ongoing, then handwriting mode will be initiated for the delegator view.
|
||||
*/
|
||||
@IdRes private int mDelegatorViewId = View.NO_ID;
|
||||
|
||||
/** The pointer id of the stylus pointer that is being tracked. */
|
||||
private final int mStylusPointerId;
|
||||
|
||||
@@ -5062,6 +5062,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
*/
|
||||
private boolean mHoveringTouchDelegate = false;
|
||||
|
||||
/**
|
||||
* Configuration for this view to act as a handwriting initiation delegate. This allows
|
||||
* handwriting mode for a delegator editor view to be initiated by stylus movement on this
|
||||
* delegate view.
|
||||
*/
|
||||
private HandwritingDelegateConfiguration mHandwritingDelegateConfiguration;
|
||||
|
||||
/**
|
||||
* Solid color to use as a background when creating the drawing cache. Enables
|
||||
* the cache to use 16 bit bitmaps instead of 32 bit.
|
||||
@@ -12254,6 +12261,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this view to act as a handwriting initiation delegate. This allows handwriting
|
||||
* mode for a delegator editor view to be initiated by stylus movement on this delegate view.
|
||||
*
|
||||
* <p>If {@code null} is passed, this view will no longer act as a handwriting initiation
|
||||
* delegate.
|
||||
*/
|
||||
public void setHandwritingDelegateConfiguration(
|
||||
@Nullable HandwritingDelegateConfiguration configuration) {
|
||||
mHandwritingDelegateConfiguration = configuration;
|
||||
if (configuration != null) {
|
||||
setHandwritingArea(new Rect(0, 0, getWidth(), getHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this view has been configured as a handwriting initiation delegate, returns the delegate
|
||||
* configuration.
|
||||
*/
|
||||
@Nullable
|
||||
public HandwritingDelegateConfiguration getHandwritingDelegateConfiguration() {
|
||||
return mHandwritingDelegateConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the coordinates of this view in the coordinate space of the
|
||||
* {@link Surface} that contains the view.
|
||||
@@ -24205,7 +24236,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
}
|
||||
rebuildOutline();
|
||||
if (onCheckIsTextEditor()) {
|
||||
if (onCheckIsTextEditor() || mHandwritingDelegateConfiguration != null) {
|
||||
setHandwritingArea(new Rect(0, 0, newWidth, newHeight));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.view.HandwritingDelegateConfiguration;
|
||||
import android.view.HandwritingInitiator;
|
||||
import android.view.InputDevice;
|
||||
import android.view.MotionEvent;
|
||||
@@ -207,6 +208,30 @@ public class HandwritingInitiatorTest {
|
||||
verify(mHandwritingInitiator, times(1)).startHandwriting(mTestView);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTouchEvent_startHandwriting_delegate() {
|
||||
int delegatorViewId = 234;
|
||||
View delegatorView = new View(mContext);
|
||||
delegatorView.setId(delegatorViewId);
|
||||
|
||||
mTestView.setHandwritingDelegateConfiguration(
|
||||
new HandwritingDelegateConfiguration(
|
||||
delegatorViewId,
|
||||
() -> mHandwritingInitiator.onInputConnectionCreated(delegatorView)));
|
||||
|
||||
final int x1 = (sHwArea.left + sHwArea.right) / 2;
|
||||
final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
|
||||
MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
|
||||
mHandwritingInitiator.onTouchEvent(stylusEvent1);
|
||||
|
||||
final int x2 = x1 + mHandwritingSlop * 2;
|
||||
final int y2 = y1;
|
||||
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
|
||||
mHandwritingInitiator.onTouchEvent(stylusEvent2);
|
||||
|
||||
verify(mHandwritingInitiator, times(1)).startHandwriting(delegatorView);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onTouchEvent_notStartHandwriting_whenHandwritingNotAvailable() {
|
||||
final Rect rect = new Rect(600, 600, 900, 900);
|
||||
|
||||
Reference in New Issue
Block a user