Merge "Reconcile drag-to-open and touch event interception" into klp-dev

This commit is contained in:
Alan Viverette
2013-08-26 20:48:58 +00:00
committed by Android (Google) Code Review
3 changed files with 79 additions and 26 deletions

View File

@ -32,6 +32,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.View.MeasureSpec; import android.view.View.MeasureSpec;
import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnTouchListener; import android.view.View.OnTouchListener;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -1133,18 +1134,32 @@ public class ListPopupWindow {
* *
* @hide * @hide
*/ */
public static abstract class ForwardingListener implements View.OnTouchListener { public static abstract class ForwardingListener
implements View.OnTouchListener, View.OnAttachStateChangeListener {
/** Scaled touch slop, used for detecting movement outside bounds. */ /** Scaled touch slop, used for detecting movement outside bounds. */
private final float mScaledTouchSlop; private final float mScaledTouchSlop;
/** Timeout before disallowing intercept on the source's parent. */
private final int mTapTimeout;
/** Source view from which events are forwarded. */
private final View mSrc;
/** Runnable used to prevent conflicts with scrolling parents. */
private Runnable mDisallowIntercept;
/** Whether this listener is currently forwarding touch events. */ /** Whether this listener is currently forwarding touch events. */
private boolean mForwarding; private boolean mForwarding;
/** The id of the first pointer down in the current event stream. */ /** The id of the first pointer down in the current event stream. */
private int mActivePointerId; private int mActivePointerId;
public ForwardingListener(Context context) { public ForwardingListener(View src) {
mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mSrc = src;
mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
mTapTimeout = ViewConfiguration.getTapTimeout();
src.addOnAttachStateChangeListener(this);
} }
/** /**
@ -1164,15 +1179,29 @@ public class ListPopupWindow {
final boolean wasForwarding = mForwarding; final boolean wasForwarding = mForwarding;
final boolean forwarding; final boolean forwarding;
if (wasForwarding) { if (wasForwarding) {
forwarding = onTouchForwarded(v, event) || !onForwardingStopped(); forwarding = onTouchForwarded(event) || !onForwardingStopped();
} else { } else {
forwarding = onTouchObserved(v, event) && onForwardingStarted(); forwarding = onTouchObserved(event) && onForwardingStarted();
} }
mForwarding = forwarding; mForwarding = forwarding;
return forwarding || wasForwarding; return forwarding || wasForwarding;
} }
@Override
public void onViewAttachedToWindow(View v) {
}
@Override
public void onViewDetachedFromWindow(View v) {
mForwarding = false;
mActivePointerId = MotionEvent.INVALID_POINTER_ID;
if (mDisallowIntercept != null) {
mSrc.removeCallbacks(mDisallowIntercept);
}
}
/** /**
* Called when forwarding would like to start. * Called when forwarding would like to start.
* <p> * <p>
@ -1182,7 +1211,7 @@ public class ListPopupWindow {
* *
* @return true to start forwarding, false otherwise * @return true to start forwarding, false otherwise
*/ */
public boolean onForwardingStarted() { protected boolean onForwardingStarted() {
final ListPopupWindow popup = getPopup(); final ListPopupWindow popup = getPopup();
if (popup != null && !popup.isShowing()) { if (popup != null && !popup.isShowing()) {
popup.show(); popup.show();
@ -1199,7 +1228,7 @@ public class ListPopupWindow {
* *
* @return true to stop forwarding, false otherwise * @return true to stop forwarding, false otherwise
*/ */
public boolean onForwardingStopped() { protected boolean onForwardingStopped() {
final ListPopupWindow popup = getPopup(); final ListPopupWindow popup = getPopup();
if (popup != null && popup.isShowing()) { if (popup != null && popup.isShowing()) {
popup.dismiss(); popup.dismiss();
@ -1210,30 +1239,46 @@ public class ListPopupWindow {
/** /**
* Observes motion events and determines when to start forwarding. * Observes motion events and determines when to start forwarding.
* *
* @param src view from which the event originated
* @param srcEvent motion event in source view coordinates * @param srcEvent motion event in source view coordinates
* @return true to start forwarding motion events, false otherwise * @return true to start forwarding motion events, false otherwise
*/ */
private boolean onTouchObserved(View src, MotionEvent srcEvent) { private boolean onTouchObserved(MotionEvent srcEvent) {
final View src = mSrc;
if (!src.isEnabled()) { if (!src.isEnabled()) {
return false; return false;
} }
// The first pointer down is always the active pointer.
final int actionMasked = srcEvent.getActionMasked(); final int actionMasked = srcEvent.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) { switch (actionMasked) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = srcEvent.getPointerId(0); mActivePointerId = srcEvent.getPointerId(0);
if (mDisallowIntercept == null) {
mDisallowIntercept = new DisallowIntercept();
} }
src.postDelayed(mDisallowIntercept, mTapTimeout);
break;
case MotionEvent.ACTION_MOVE:
final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId); final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId);
if (activePointerIndex >= 0) { if (activePointerIndex >= 0) {
final float x = srcEvent.getX(activePointerIndex); final float x = srcEvent.getX(activePointerIndex);
final float y = srcEvent.getY(activePointerIndex); final float y = srcEvent.getY(activePointerIndex);
if (!src.pointInView(x, y, mScaledTouchSlop)) { if (!src.pointInView(x, y, mScaledTouchSlop)) {
// The pointer has moved outside of the view. // The pointer has moved outside of the view.
if (mDisallowIntercept != null) {
src.removeCallbacks(mDisallowIntercept);
}
src.getParent().requestDisallowInterceptTouchEvent(true);
return true; return true;
} }
} }
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mDisallowIntercept != null) {
src.removeCallbacks(mDisallowIntercept);
}
break;
}
return false; return false;
} }
@ -1242,11 +1287,11 @@ public class ListPopupWindow {
* Handled forwarded motion events and determines when to stop * Handled forwarded motion events and determines when to stop
* forwarding. * forwarding.
* *
* @param src view from which the event originated
* @param srcEvent motion event in source view coordinates * @param srcEvent motion event in source view coordinates
* @return true to continue forwarding motion events, false to cancel * @return true to continue forwarding motion events, false to cancel
*/ */
private boolean onTouchForwarded(View src, MotionEvent srcEvent) { private boolean onTouchForwarded(MotionEvent srcEvent) {
final View src = mSrc;
final ListPopupWindow popup = getPopup(); final ListPopupWindow popup = getPopup();
if (popup == null || !popup.isShowing()) { if (popup == null || !popup.isShowing()) {
return false; return false;
@ -1267,6 +1312,14 @@ public class ListPopupWindow {
dstEvent.recycle(); dstEvent.recycle();
return handled; return handled;
} }
private class DisallowIntercept implements Runnable {
@Override
public void run() {
final ViewParent parent = mSrc.getParent();
parent.requestDisallowInterceptTouchEvent(true);
}
}
} }
/** /**

View File

@ -198,7 +198,7 @@ public class Spinner extends AbsSpinner implements OnClickListener {
} }
mPopup = popup; mPopup = popup;
mForwardingListener = new ForwardingListener(context) { mForwardingListener = new ForwardingListener(this) {
@Override @Override
public ListPopupWindow getPopup() { public ListPopupWindow getPopup() {
return popup; return popup;

View File

@ -565,7 +565,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter
setVisibility(VISIBLE); setVisibility(VISIBLE);
setEnabled(true); setEnabled(true);
setOnTouchListener(new ForwardingListener(context) { setOnTouchListener(new ForwardingListener(this) {
@Override @Override
public ListPopupWindow getPopup() { public ListPopupWindow getPopup() {
if (mOverflowPopup == null) { if (mOverflowPopup == null) {