Add DeviceConfig flag for drag direction angle threshold for cursor drag
Bug: 160786691 Test: Manual and unit tests atest FrameworksCoreTests:EditorTouchStateTest atest FrameworksCoreTests:EditorCursorDragTest Change-Id: Ib2e88fbdce4f901772d73bc7ee60483c98e02509
This commit is contained in:
@@ -385,6 +385,7 @@ public class Editor {
|
|||||||
private final SuggestionHelper mSuggestionHelper = new SuggestionHelper();
|
private final SuggestionHelper mSuggestionHelper = new SuggestionHelper();
|
||||||
|
|
||||||
private boolean mFlagCursorDragFromAnywhereEnabled;
|
private boolean mFlagCursorDragFromAnywhereEnabled;
|
||||||
|
private float mCursorDragDirectionMinXYRatio;
|
||||||
private boolean mFlagInsertionHandleGesturesEnabled;
|
private boolean mFlagInsertionHandleGesturesEnabled;
|
||||||
|
|
||||||
// Specifies whether the new magnifier (with fish-eye effect) is enabled.
|
// Specifies whether the new magnifier (with fish-eye effect) is enabled.
|
||||||
@@ -425,6 +426,11 @@ public class Editor {
|
|||||||
mFlagCursorDragFromAnywhereEnabled = AppGlobals.getIntCoreSetting(
|
mFlagCursorDragFromAnywhereEnabled = AppGlobals.getIntCoreSetting(
|
||||||
WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
|
WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
|
||||||
WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT ? 1 : 0) != 0;
|
WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT ? 1 : 0) != 0;
|
||||||
|
final int cursorDragMinAngleFromVertical = AppGlobals.getIntCoreSetting(
|
||||||
|
WidgetFlags.KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL,
|
||||||
|
WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT);
|
||||||
|
mCursorDragDirectionMinXYRatio = EditorTouchState.getXYRatio(
|
||||||
|
cursorDragMinAngleFromVertical);
|
||||||
mFlagInsertionHandleGesturesEnabled = AppGlobals.getIntCoreSetting(
|
mFlagInsertionHandleGesturesEnabled = AppGlobals.getIntCoreSetting(
|
||||||
WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES,
|
WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES,
|
||||||
WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT ? 1 : 0) != 0;
|
WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT ? 1 : 0) != 0;
|
||||||
@@ -437,6 +443,8 @@ public class Editor {
|
|||||||
if (TextView.DEBUG_CURSOR) {
|
if (TextView.DEBUG_CURSOR) {
|
||||||
logCursor("Editor", "Cursor drag from anywhere is %s.",
|
logCursor("Editor", "Cursor drag from anywhere is %s.",
|
||||||
mFlagCursorDragFromAnywhereEnabled ? "enabled" : "disabled");
|
mFlagCursorDragFromAnywhereEnabled ? "enabled" : "disabled");
|
||||||
|
logCursor("Editor", "Cursor drag min angle from vertical is %d (= %f x/y ratio)",
|
||||||
|
cursorDragMinAngleFromVertical, mCursorDragDirectionMinXYRatio);
|
||||||
logCursor("Editor", "Insertion handle gestures is %s.",
|
logCursor("Editor", "Insertion handle gestures is %s.",
|
||||||
mFlagInsertionHandleGesturesEnabled ? "enabled" : "disabled");
|
mFlagInsertionHandleGesturesEnabled ? "enabled" : "disabled");
|
||||||
logCursor("Editor", "New magnifier is %s.",
|
logCursor("Editor", "New magnifier is %s.",
|
||||||
@@ -462,6 +470,11 @@ public class Editor {
|
|||||||
mFlagCursorDragFromAnywhereEnabled = enabled;
|
mFlagCursorDragFromAnywhereEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setCursorDragMinAngleFromVertical(int degreesFromVertical) {
|
||||||
|
mCursorDragDirectionMinXYRatio = EditorTouchState.getXYRatio(degreesFromVertical);
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public boolean getFlagInsertionHandleGesturesEnabled() {
|
public boolean getFlagInsertionHandleGesturesEnabled() {
|
||||||
return mFlagInsertionHandleGesturesEnabled;
|
return mFlagInsertionHandleGesturesEnabled;
|
||||||
@@ -6127,10 +6140,11 @@ public class Editor {
|
|||||||
if (mIsDraggingCursor) {
|
if (mIsDraggingCursor) {
|
||||||
performCursorDrag(event);
|
performCursorDrag(event);
|
||||||
} else if (mFlagCursorDragFromAnywhereEnabled
|
} else if (mFlagCursorDragFromAnywhereEnabled
|
||||||
&& mTextView.getLayout() != null
|
&& mTextView.getLayout() != null
|
||||||
&& mTextView.isFocused()
|
&& mTextView.isFocused()
|
||||||
&& mTouchState.isMovedEnoughForDrag()
|
&& mTouchState.isMovedEnoughForDrag()
|
||||||
&& !mTouchState.isDragCloseToVertical()) {
|
&& (mTouchState.getInitialDragDirectionXYRatio()
|
||||||
|
> mCursorDragDirectionMinXYRatio || mTouchState.isOnHandle())) {
|
||||||
startCursorDrag(event);
|
startCursorDrag(event);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public class EditorTouchState {
|
|||||||
private boolean mMultiTapInSameArea;
|
private boolean mMultiTapInSameArea;
|
||||||
|
|
||||||
private boolean mMovedEnoughForDrag;
|
private boolean mMovedEnoughForDrag;
|
||||||
private boolean mIsDragCloseToVertical;
|
private float mInitialDragDirectionXYRatio;
|
||||||
|
|
||||||
public float getLastDownX() {
|
public float getLastDownX() {
|
||||||
return mLastDownX;
|
return mLastDownX;
|
||||||
@@ -98,8 +98,23 @@ public class EditorTouchState {
|
|||||||
return mMovedEnoughForDrag;
|
return mMovedEnoughForDrag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDragCloseToVertical() {
|
/**
|
||||||
return mIsDragCloseToVertical && !mIsOnHandle;
|
* When {@link #isMovedEnoughForDrag()} is {@code true}, this function returns the x/y ratio for
|
||||||
|
* the initial drag direction. Smaller values indicate that the direction is closer to vertical,
|
||||||
|
* while larger values indicate that the direction is closer to horizontal. For example:
|
||||||
|
* <ul>
|
||||||
|
* <li>if the drag direction is exactly vertical, this returns 0
|
||||||
|
* <li>if the drag direction is exactly horizontal, this returns {@link Float#MAX_VALUE}
|
||||||
|
* <li>if the drag direction is 45 deg from vertical, this returns 1
|
||||||
|
* <li>if the drag direction is 30 deg from vertical, this returns 0.58 (x delta is smaller
|
||||||
|
* than y delta)
|
||||||
|
* <li>if the drag direction is 60 deg from vertical, this returns 1.73 (x delta is bigger
|
||||||
|
* than y delta)
|
||||||
|
* </ul>
|
||||||
|
* This function never returns negative values, regardless of the direction of the drag.
|
||||||
|
*/
|
||||||
|
public float getInitialDragDirectionXYRatio() {
|
||||||
|
return mInitialDragDirectionXYRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIsOnHandle(boolean onHandle) {
|
public void setIsOnHandle(boolean onHandle) {
|
||||||
@@ -155,7 +170,7 @@ public class EditorTouchState {
|
|||||||
mLastDownY = event.getY();
|
mLastDownY = event.getY();
|
||||||
mLastDownMillis = event.getEventTime();
|
mLastDownMillis = event.getEventTime();
|
||||||
mMovedEnoughForDrag = false;
|
mMovedEnoughForDrag = false;
|
||||||
mIsDragCloseToVertical = false;
|
mInitialDragDirectionXYRatio = 0.0f;
|
||||||
} else if (action == MotionEvent.ACTION_UP) {
|
} else if (action == MotionEvent.ACTION_UP) {
|
||||||
if (TextView.DEBUG_CURSOR) {
|
if (TextView.DEBUG_CURSOR) {
|
||||||
logCursor("EditorTouchState", "ACTION_UP");
|
logCursor("EditorTouchState", "ACTION_UP");
|
||||||
@@ -164,7 +179,7 @@ public class EditorTouchState {
|
|||||||
mLastUpY = event.getY();
|
mLastUpY = event.getY();
|
||||||
mLastUpMillis = event.getEventTime();
|
mLastUpMillis = event.getEventTime();
|
||||||
mMovedEnoughForDrag = false;
|
mMovedEnoughForDrag = false;
|
||||||
mIsDragCloseToVertical = false;
|
mInitialDragDirectionXYRatio = 0.0f;
|
||||||
} else if (action == MotionEvent.ACTION_MOVE) {
|
} else if (action == MotionEvent.ACTION_MOVE) {
|
||||||
if (!mMovedEnoughForDrag) {
|
if (!mMovedEnoughForDrag) {
|
||||||
float deltaX = event.getX() - mLastDownX;
|
float deltaX = event.getX() - mLastDownX;
|
||||||
@@ -174,9 +189,8 @@ public class EditorTouchState {
|
|||||||
int touchSlop = config.getScaledTouchSlop();
|
int touchSlop = config.getScaledTouchSlop();
|
||||||
mMovedEnoughForDrag = distanceSquared > touchSlop * touchSlop;
|
mMovedEnoughForDrag = distanceSquared > touchSlop * touchSlop;
|
||||||
if (mMovedEnoughForDrag) {
|
if (mMovedEnoughForDrag) {
|
||||||
// If the direction of the swipe motion is within 45 degrees of vertical, it is
|
mInitialDragDirectionXYRatio = (deltaY == 0) ? Float.MAX_VALUE :
|
||||||
// considered a vertical drag.
|
Math.abs(deltaX / deltaY);
|
||||||
mIsDragCloseToVertical = Math.abs(deltaX) <= Math.abs(deltaY);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (action == MotionEvent.ACTION_CANCEL) {
|
} else if (action == MotionEvent.ACTION_CANCEL) {
|
||||||
@@ -185,7 +199,7 @@ public class EditorTouchState {
|
|||||||
mMultiTapStatus = MultiTapStatus.NONE;
|
mMultiTapStatus = MultiTapStatus.NONE;
|
||||||
mMultiTapInSameArea = false;
|
mMultiTapInSameArea = false;
|
||||||
mMovedEnoughForDrag = false;
|
mMovedEnoughForDrag = false;
|
||||||
mIsDragCloseToVertical = false;
|
mInitialDragDirectionXYRatio = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,4 +215,27 @@ public class EditorTouchState {
|
|||||||
float distanceSquared = (deltaX * deltaX) + (deltaY * deltaY);
|
float distanceSquared = (deltaX * deltaX) + (deltaY * deltaY);
|
||||||
return distanceSquared <= maxDistance * maxDistance;
|
return distanceSquared <= maxDistance * maxDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the x/y ratio corresponding to the given angle relative to vertical. Smaller angle
|
||||||
|
* values (ie, closer to vertical) will result in a smaller x/y ratio. For example:
|
||||||
|
* <ul>
|
||||||
|
* <li>if the angle is 45 deg, the ratio is 1
|
||||||
|
* <li>if the angle is 30 deg, the ratio is 0.58 (x delta is smaller than y delta)
|
||||||
|
* <li>if the angle is 60 deg, the ratio is 1.73 (x delta is bigger than y delta)
|
||||||
|
* </ul>
|
||||||
|
* If the passed-in value is <= 0, this function returns 0. If the passed-in value is >= 90,
|
||||||
|
* this function returns {@link Float#MAX_VALUE}.
|
||||||
|
*
|
||||||
|
* @see #getInitialDragDirectionXYRatio()
|
||||||
|
*/
|
||||||
|
public static float getXYRatio(int angleFromVerticalInDegrees) {
|
||||||
|
if (angleFromVerticalInDegrees <= 0) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
if (angleFromVerticalInDegrees >= 90) {
|
||||||
|
return Float.MAX_VALUE;
|
||||||
|
}
|
||||||
|
return (float) Math.tan(Math.toRadians(angleFromVerticalInDegrees));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,28 @@ public final class WidgetFlags {
|
|||||||
*/
|
*/
|
||||||
public static final boolean ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT = true;
|
public static final boolean ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Threshold for the direction of a swipe gesture in order for it to be handled as a cursor drag
|
||||||
|
* rather than a scroll. The direction angle of the swipe gesture must exceed this value in
|
||||||
|
* order to trigger cursor drag; otherwise, the swipe will be assumed to be a scroll gesture.
|
||||||
|
* The value units for this flag is degrees and the valid range is [0,90] inclusive. If a value
|
||||||
|
* < 0 is set, 0 will be used instead; if a value > 90 is set, 90 will be used instead.
|
||||||
|
*/
|
||||||
|
public static final String CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL =
|
||||||
|
"CursorControlFeature__min_angle_from_vertical_to_start_cursor_drag";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key used in app core settings for the flag
|
||||||
|
* {@link #CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL}.
|
||||||
|
*/
|
||||||
|
public static final String KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL =
|
||||||
|
"widget__min_angle_from_vertical_to_start_cursor_drag";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value for the flag {@link #CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL}.
|
||||||
|
*/
|
||||||
|
public static final int CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT = 45;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The flag of finger-to-cursor distance in DP for cursor dragging.
|
* The flag of finger-to-cursor distance in DP for cursor dragging.
|
||||||
* The value unit is DP and the range is {0..100}. If the value is out of range, the legacy
|
* The value unit is DP and the range is {0..100}. If the value is out of range, the legacy
|
||||||
|
|||||||
@@ -200,6 +200,38 @@ public class EditorCursorDragTest {
|
|||||||
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
|
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCursorDrag_diagonal_thresholdConfig() throws Throwable {
|
||||||
|
TextView tv = mActivity.findViewById(R.id.textview);
|
||||||
|
Editor editor = tv.getEditorForTesting();
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 1; i <= 9; i++) {
|
||||||
|
sb.append("here is some text").append(i).append("\n");
|
||||||
|
}
|
||||||
|
sb.append(Strings.repeat("abcdefghij\n", 400)).append("Last");
|
||||||
|
String text = sb.toString();
|
||||||
|
onView(withId(R.id.textview)).perform(replaceText(text));
|
||||||
|
|
||||||
|
int index = text.indexOf("text9");
|
||||||
|
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index));
|
||||||
|
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
|
||||||
|
|
||||||
|
// Configure the drag direction threshold to require the drag to be exactly horizontal. With
|
||||||
|
// this set, a swipe that is slightly off horizontal should not trigger cursor drag.
|
||||||
|
editor.setCursorDragMinAngleFromVertical(90);
|
||||||
|
int startIdx = text.indexOf("5");
|
||||||
|
int endIdx = text.indexOf("here is some text3");
|
||||||
|
onView(withId(R.id.textview)).perform(dragOnText(startIdx, endIdx));
|
||||||
|
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
|
||||||
|
|
||||||
|
// Configure the drag direction threshold to require the drag to be 45 degrees or more from
|
||||||
|
// vertical. With this set, the same swipe gesture as above should now trigger cursor drag.
|
||||||
|
editor.setCursorDragMinAngleFromVertical(45);
|
||||||
|
onView(withId(R.id.textview)).perform(dragOnText(startIdx, endIdx));
|
||||||
|
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(endIdx));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCursorDrag_vertical_whenTextViewContentsFitOnScreen() throws Throwable {
|
public void testCursorDrag_vertical_whenTextViewContentsFitOnScreen() throws Throwable {
|
||||||
String text = "012345_aaa\n"
|
String text = "012345_aaa\n"
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ public class EditorTouchStateTest {
|
|||||||
long event2Time = 1001;
|
long event2Time = 1001;
|
||||||
MotionEvent event2 = moveEvent(event1Time, event2Time, 200f, 31f);
|
MotionEvent event2 = moveEvent(event1Time, event2Time, 200f, 31f);
|
||||||
mTouchState.update(event2, mConfig);
|
mTouchState.update(event2, mConfig);
|
||||||
assertDrag(mTouchState, 20f, 30f, 0, 0, false);
|
assertDrag(mTouchState, 20f, 30f, 0, 0, 180f);
|
||||||
|
|
||||||
// Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout.
|
// Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout.
|
||||||
long event3Time = 5000;
|
long event3Time = 5000;
|
||||||
@@ -280,7 +280,7 @@ public class EditorTouchStateTest {
|
|||||||
long event3Time = 1002;
|
long event3Time = 1002;
|
||||||
MotionEvent event3 = moveEvent(event3Time, event3Time, newX, newY);
|
MotionEvent event3 = moveEvent(event3Time, event3Time, newX, newY);
|
||||||
mTouchState.update(event3, mConfig);
|
mTouchState.update(event3, mConfig);
|
||||||
assertDrag(mTouchState, 20f, 30f, 0, 0, false);
|
assertDrag(mTouchState, 20f, 30f, 0, 0, Float.MAX_VALUE);
|
||||||
|
|
||||||
// Simulate an ACTION_UP event.
|
// Simulate an ACTION_UP event.
|
||||||
long event4Time = 1003;
|
long event4Time = 1003;
|
||||||
@@ -301,15 +301,15 @@ public class EditorTouchStateTest {
|
|||||||
long event2Time = 1002;
|
long event2Time = 1002;
|
||||||
MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 174f);
|
MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 174f);
|
||||||
mTouchState.update(event2, mConfig);
|
mTouchState.update(event2, mConfig);
|
||||||
assertDrag(mTouchState, 0f, 0f, 0, 0, true);
|
assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 174f);
|
||||||
|
|
||||||
// Simulate another ACTION_MOVE event that is horizontal from the original down event.
|
// Simulate another ACTION_MOVE event that is horizontal from the original down event.
|
||||||
// The value of `isDragCloseToVertical` should NOT change since it should only reflect the
|
// The drag direction ratio should NOT change since it should only reflect the initial
|
||||||
// initial direction of movement.
|
// direction of movement.
|
||||||
long event3Time = 1003;
|
long event3Time = 1003;
|
||||||
MotionEvent event3 = moveEvent(event1Time, event3Time, 200f, 0f);
|
MotionEvent event3 = moveEvent(event1Time, event3Time, 200f, 0f);
|
||||||
mTouchState.update(event3, mConfig);
|
mTouchState.update(event3, mConfig);
|
||||||
assertDrag(mTouchState, 0f, 0f, 0, 0, true);
|
assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 174f);
|
||||||
|
|
||||||
// Simulate an ACTION_UP event.
|
// Simulate an ACTION_UP event.
|
||||||
long event4Time = 1004;
|
long event4Time = 1004;
|
||||||
@@ -330,15 +330,15 @@ public class EditorTouchStateTest {
|
|||||||
long event2Time = 1002;
|
long event2Time = 1002;
|
||||||
MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 90f);
|
MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 90f);
|
||||||
mTouchState.update(event2, mConfig);
|
mTouchState.update(event2, mConfig);
|
||||||
assertDrag(mTouchState, 0f, 0f, 0, 0, false);
|
assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 90f);
|
||||||
|
|
||||||
// Simulate another ACTION_MOVE event that is vertical from the original down event.
|
// Simulate another ACTION_MOVE event that is vertical from the original down event.
|
||||||
// The value of `isDragCloseToVertical` should NOT change since it should only reflect the
|
// The drag direction ratio should NOT change since it should only reflect the initial
|
||||||
// initial direction of movement.
|
// direction of movement.
|
||||||
long event3Time = 1003;
|
long event3Time = 1003;
|
||||||
MotionEvent event3 = moveEvent(event1Time, event3Time, 0f, 200f);
|
MotionEvent event3 = moveEvent(event1Time, event3Time, 0f, 200f);
|
||||||
mTouchState.update(event3, mConfig);
|
mTouchState.update(event3, mConfig);
|
||||||
assertDrag(mTouchState, 0f, 0f, 0, 0, false);
|
assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 90f);
|
||||||
|
|
||||||
// Simulate an ACTION_UP event.
|
// Simulate an ACTION_UP event.
|
||||||
long event4Time = 1004;
|
long event4Time = 1004;
|
||||||
@@ -374,7 +374,7 @@ public class EditorTouchStateTest {
|
|||||||
long event2Time = 1002;
|
long event2Time = 1002;
|
||||||
MotionEvent event2 = moveEvent(event2Time, event2Time, 200f, 30f);
|
MotionEvent event2 = moveEvent(event2Time, event2Time, 200f, 30f);
|
||||||
mTouchState.update(event2, mConfig);
|
mTouchState.update(event2, mConfig);
|
||||||
assertDrag(mTouchState, 20f, 30f, 0, 0, false);
|
assertDrag(mTouchState, 20f, 30f, 0, 0, Float.MAX_VALUE);
|
||||||
|
|
||||||
// Simulate an ACTION_CANCEL event.
|
// Simulate an ACTION_CANCEL event.
|
||||||
long event3Time = 1003;
|
long event3Time = 1003;
|
||||||
@@ -411,6 +411,84 @@ public class EditorTouchStateTest {
|
|||||||
assertSingleTap(mTouchState, 22f, 33f, 20f, 30f);
|
assertSingleTap(mTouchState, 22f, 33f, 20f, 30f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetXYRatio() throws Exception {
|
||||||
|
doTestGetXYRatio(-1, 0.0f);
|
||||||
|
doTestGetXYRatio(0, 0.0f);
|
||||||
|
doTestGetXYRatio(30, 0.58f);
|
||||||
|
doTestGetXYRatio(45, 1.0f);
|
||||||
|
doTestGetXYRatio(60, 1.73f);
|
||||||
|
doTestGetXYRatio(90, Float.MAX_VALUE);
|
||||||
|
doTestGetXYRatio(91, Float.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestGetXYRatio(int angleFromVerticalInDegrees, float expectedXYRatioRounded) {
|
||||||
|
float result = EditorTouchState.getXYRatio(angleFromVerticalInDegrees);
|
||||||
|
String msg = String.format(
|
||||||
|
"%d deg should give an x/y ratio of %f; actual unrounded result is %f",
|
||||||
|
angleFromVerticalInDegrees, expectedXYRatioRounded, result);
|
||||||
|
float roundedResult = (result == 0.0f || result == Float.MAX_VALUE) ? result :
|
||||||
|
Math.round(result * 100) / 100f;
|
||||||
|
assertThat(msg, roundedResult, is(expectedXYRatioRounded));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdate_dragDirection() throws Exception {
|
||||||
|
// Simulate moving straight up.
|
||||||
|
doTestDragDirection(100f, 100f, 100f, 50f, 0f);
|
||||||
|
|
||||||
|
// Simulate moving straight down.
|
||||||
|
doTestDragDirection(100f, 100f, 100f, 150f, 0f);
|
||||||
|
|
||||||
|
// Simulate moving straight left.
|
||||||
|
doTestDragDirection(100f, 100f, 50f, 100f, Float.MAX_VALUE);
|
||||||
|
|
||||||
|
// Simulate moving straight right.
|
||||||
|
doTestDragDirection(100f, 100f, 150f, 100f, Float.MAX_VALUE);
|
||||||
|
|
||||||
|
// Simulate moving up and right, < 45 deg from vertical.
|
||||||
|
doTestDragDirection(100f, 100f, 110f, 50f, 10f / 50f);
|
||||||
|
|
||||||
|
// Simulate moving up and right, > 45 deg from vertical.
|
||||||
|
doTestDragDirection(100f, 100f, 150f, 90f, 50f / 10f);
|
||||||
|
|
||||||
|
// Simulate moving down and right, < 45 deg from vertical.
|
||||||
|
doTestDragDirection(100f, 100f, 110f, 150f, 10f / 50f);
|
||||||
|
|
||||||
|
// Simulate moving down and right, > 45 deg from vertical.
|
||||||
|
doTestDragDirection(100f, 100f, 150f, 110f, 50f / 10f);
|
||||||
|
|
||||||
|
// Simulate moving down and left, < 45 deg from vertical.
|
||||||
|
doTestDragDirection(100f, 100f, 90f, 150f, 10f / 50f);
|
||||||
|
|
||||||
|
// Simulate moving down and left, > 45 deg from vertical.
|
||||||
|
doTestDragDirection(100f, 100f, 50f, 110f, 50f / 10f);
|
||||||
|
|
||||||
|
// Simulate moving up and left, < 45 deg from vertical.
|
||||||
|
doTestDragDirection(100f, 100f, 90f, 50f, 10f / 50f);
|
||||||
|
|
||||||
|
// Simulate moving up and left, > 45 deg from vertical.
|
||||||
|
doTestDragDirection(100f, 100f, 50f, 90f, 50f / 10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestDragDirection(float downX, float downY, float moveX, float moveY,
|
||||||
|
float expectedInitialDragDirectionXYRatio) {
|
||||||
|
EditorTouchState touchState = new EditorTouchState();
|
||||||
|
|
||||||
|
// Simulate an ACTION_DOWN event.
|
||||||
|
long event1Time = 1001;
|
||||||
|
MotionEvent event1 = downEvent(event1Time, event1Time, downX, downY);
|
||||||
|
touchState.update(event1, mConfig);
|
||||||
|
|
||||||
|
// Simulate an ACTION_MOVE event.
|
||||||
|
long event2Time = 1002;
|
||||||
|
MotionEvent event2 = moveEvent(event1Time, event2Time, moveX, moveY);
|
||||||
|
touchState.update(event2, mConfig);
|
||||||
|
String msg = String.format("(%.0f,%.0f)=>(%.0f,%.0f)", downX, downY, moveX, moveY);
|
||||||
|
assertThat(msg, touchState.getInitialDragDirectionXYRatio(),
|
||||||
|
is(expectedInitialDragDirectionXYRatio));
|
||||||
|
}
|
||||||
|
|
||||||
private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
|
private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
|
||||||
return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
|
return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
|
||||||
}
|
}
|
||||||
@@ -441,7 +519,7 @@ public class EditorTouchStateTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void assertDrag(EditorTouchState touchState, float lastDownX,
|
private static void assertDrag(EditorTouchState touchState, float lastDownX,
|
||||||
float lastDownY, float lastUpX, float lastUpY, boolean isDragCloseToVertical) {
|
float lastDownY, float lastUpX, float lastUpY, float initialDragDirectionXYRatio) {
|
||||||
assertThat(touchState.getLastDownX(), is(lastDownX));
|
assertThat(touchState.getLastDownX(), is(lastDownX));
|
||||||
assertThat(touchState.getLastDownY(), is(lastDownY));
|
assertThat(touchState.getLastDownY(), is(lastDownY));
|
||||||
assertThat(touchState.getLastUpX(), is(lastUpX));
|
assertThat(touchState.getLastUpX(), is(lastUpX));
|
||||||
@@ -451,7 +529,7 @@ public class EditorTouchStateTest {
|
|||||||
assertThat(touchState.isMultiTap(), is(false));
|
assertThat(touchState.isMultiTap(), is(false));
|
||||||
assertThat(touchState.isMultiTapInSameArea(), is(false));
|
assertThat(touchState.isMultiTapInSameArea(), is(false));
|
||||||
assertThat(touchState.isMovedEnoughForDrag(), is(true));
|
assertThat(touchState.isMovedEnoughForDrag(), is(true));
|
||||||
assertThat(touchState.isDragCloseToVertical(), is(isDragCloseToVertical));
|
assertThat(touchState.getInitialDragDirectionXYRatio(), is(initialDragDirectionXYRatio));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertMultiTap(EditorTouchState touchState,
|
private static void assertMultiTap(EditorTouchState touchState,
|
||||||
@@ -467,6 +545,5 @@ public class EditorTouchStateTest {
|
|||||||
|| multiTapStatus == MultiTapStatus.TRIPLE_CLICK));
|
|| multiTapStatus == MultiTapStatus.TRIPLE_CLICK));
|
||||||
assertThat(touchState.isMultiTapInSameArea(), is(isMultiTapInSameArea));
|
assertThat(touchState.isMultiTapInSameArea(), is(isMultiTapInSameArea));
|
||||||
assertThat(touchState.isMovedEnoughForDrag(), is(false));
|
assertThat(touchState.isMovedEnoughForDrag(), is(false));
|
||||||
assertThat(touchState.isDragCloseToVertical(), is(false));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,10 @@ final class CoreSettingsObserver extends ContentObserver {
|
|||||||
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
|
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
|
||||||
WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, boolean.class,
|
WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, boolean.class,
|
||||||
WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT));
|
WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT));
|
||||||
|
sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
|
||||||
|
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL,
|
||||||
|
WidgetFlags.KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL, int.class,
|
||||||
|
WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT));
|
||||||
sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
|
sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
|
||||||
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.FINGER_TO_CURSOR_DISTANCE,
|
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.FINGER_TO_CURSOR_DISTANCE,
|
||||||
WidgetFlags.KEY_FINGER_TO_CURSOR_DISTANCE, int.class,
|
WidgetFlags.KEY_FINGER_TO_CURSOR_DISTANCE, int.class,
|
||||||
|
|||||||
Reference in New Issue
Block a user