summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alan Viverette <alanv@google.com> 2014-07-24 03:20:55 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2014-07-23 18:56:15 +0000
commitef7ebbdff12c25f033beecf151bf3661716fde13 (patch)
treed2891c2d4c050a052c45f564ada8364f5a5ca912
parentfd4354a9ee0a484fcd310618ec5ad3da3cb689ff (diff)
parentbca05f5ce7716b82f4b3d9221480a807aeb7ff15 (diff)
Merge "Allow medium-long-press to initiate drag-to-open menus" into lmp-dev
-rw-r--r--core/java/android/widget/ListPopupWindow.java86
1 files changed, 78 insertions, 8 deletions
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 84b213bd9b2a..af4644b37208 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -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();
+ }
+ }
}
/**