Merge "Allow medium-long-press to initiate drag-to-open menus" into lmp-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ef7ebbdff1
@@ -1186,15 +1186,27 @@ public class ListPopupWindow {
|
||||
/** Timeout before disallowing intercept on the source's parent. */
|
||||
private final int mTapTimeout;
|
||||
|
||||
/** Timeout before accepting a long-press to start forwarding. */
|
||||
private final int mLongPressTimeout;
|
||||
|
||||
/** Source view from which events are forwarded. */
|
||||
private final View mSrc;
|
||||
|
||||
/** Runnable used to prevent conflicts with scrolling parents. */
|
||||
private Runnable mDisallowIntercept;
|
||||
|
||||
/** Runnable used to trigger forwarding on long-press. */
|
||||
private Runnable mTriggerLongPress;
|
||||
|
||||
/** Whether this listener is currently forwarding touch events. */
|
||||
private boolean mForwarding;
|
||||
|
||||
/**
|
||||
* Whether forwarding was initiated by a long-press. If so, we won't
|
||||
* force the window to dismiss when the touch stream ends.
|
||||
*/
|
||||
private boolean mWasLongPress;
|
||||
|
||||
/** The id of the first pointer down in the current event stream. */
|
||||
private int mActivePointerId;
|
||||
|
||||
@@ -1203,6 +1215,9 @@ public class ListPopupWindow {
|
||||
mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
|
||||
mTapTimeout = ViewConfiguration.getTapTimeout();
|
||||
|
||||
// Use a medium-press timeout. Halfway between tap and long-press.
|
||||
mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
|
||||
|
||||
src.addOnAttachStateChangeListener(this);
|
||||
}
|
||||
|
||||
@@ -1223,7 +1238,14 @@ public class ListPopupWindow {
|
||||
final boolean wasForwarding = mForwarding;
|
||||
final boolean forwarding;
|
||||
if (wasForwarding) {
|
||||
forwarding = onTouchForwarded(event) || !onForwardingStopped();
|
||||
if (mWasLongPress) {
|
||||
// If we started forwarding as a result of a long-press,
|
||||
// just silently stop forwarding events so that the window
|
||||
// stays open.
|
||||
forwarding = onTouchForwarded(event);
|
||||
} else {
|
||||
forwarding = onTouchForwarded(event) || !onForwardingStopped();
|
||||
}
|
||||
} else {
|
||||
forwarding = onTouchObserved(event) && onForwardingStarted();
|
||||
|
||||
@@ -1305,21 +1327,29 @@ public class ListPopupWindow {
|
||||
switch (actionMasked) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mActivePointerId = srcEvent.getPointerId(0);
|
||||
mWasLongPress = false;
|
||||
|
||||
if (mDisallowIntercept == null) {
|
||||
mDisallowIntercept = new DisallowIntercept();
|
||||
}
|
||||
src.postDelayed(mDisallowIntercept, mTapTimeout);
|
||||
|
||||
if (mTriggerLongPress == null) {
|
||||
mTriggerLongPress = new TriggerLongPress();
|
||||
}
|
||||
src.postDelayed(mTriggerLongPress, mLongPressTimeout);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId);
|
||||
if (activePointerIndex >= 0) {
|
||||
final float x = srcEvent.getX(activePointerIndex);
|
||||
final float y = srcEvent.getY(activePointerIndex);
|
||||
|
||||
// Has the pointer has moved outside of the view?
|
||||
if (!src.pointInView(x, y, mScaledTouchSlop)) {
|
||||
// The pointer has moved outside of the view.
|
||||
if (mDisallowIntercept != null) {
|
||||
src.removeCallbacks(mDisallowIntercept);
|
||||
}
|
||||
clearCallbacks();
|
||||
|
||||
// Don't let the parent intercept our events.
|
||||
src.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
return true;
|
||||
}
|
||||
@@ -1327,15 +1357,48 @@ public class ListPopupWindow {
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mDisallowIntercept != null) {
|
||||
src.removeCallbacks(mDisallowIntercept);
|
||||
}
|
||||
clearCallbacks();
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void clearCallbacks() {
|
||||
if (mTriggerLongPress != null) {
|
||||
mSrc.removeCallbacks(mTriggerLongPress);
|
||||
}
|
||||
|
||||
if (mDisallowIntercept != null) {
|
||||
mSrc.removeCallbacks(mDisallowIntercept);
|
||||
}
|
||||
}
|
||||
|
||||
private void onLongPress() {
|
||||
clearCallbacks();
|
||||
|
||||
final View src = mSrc;
|
||||
if (!src.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!onForwardingStarted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't let the parent intercept our events.
|
||||
mSrc.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
|
||||
// Make sure we cancel any ongoing source event stream.
|
||||
final long now = SystemClock.uptimeMillis();
|
||||
final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
|
||||
mSrc.onTouchEvent(e);
|
||||
e.recycle();
|
||||
|
||||
mForwarding = true;
|
||||
mWasLongPress = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handled forwarded motion events and determines when to stop
|
||||
* forwarding.
|
||||
@@ -1379,6 +1442,13 @@ public class ListPopupWindow {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
|
||||
private class TriggerLongPress implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
onLongPress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user