Merge "Reconcile drag-to-open and touch event interception" into klp-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9212e350d5
@ -32,6 +32,7 @@ import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.View.OnTouchListener;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
@ -1133,18 +1134,32 @@ public class ListPopupWindow {
|
||||
*
|
||||
* @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. */
|
||||
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. */
|
||||
private boolean mForwarding;
|
||||
|
||||
/** The id of the first pointer down in the current event stream. */
|
||||
private int mActivePointerId;
|
||||
|
||||
public ForwardingListener(Context context) {
|
||||
mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
public ForwardingListener(View src) {
|
||||
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 forwarding;
|
||||
if (wasForwarding) {
|
||||
forwarding = onTouchForwarded(v, event) || !onForwardingStopped();
|
||||
forwarding = onTouchForwarded(event) || !onForwardingStopped();
|
||||
} else {
|
||||
forwarding = onTouchObserved(v, event) && onForwardingStarted();
|
||||
forwarding = onTouchObserved(event) && onForwardingStarted();
|
||||
}
|
||||
|
||||
mForwarding = forwarding;
|
||||
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.
|
||||
* <p>
|
||||
@ -1182,7 +1211,7 @@ public class ListPopupWindow {
|
||||
*
|
||||
* @return true to start forwarding, false otherwise
|
||||
*/
|
||||
public boolean onForwardingStarted() {
|
||||
protected boolean onForwardingStarted() {
|
||||
final ListPopupWindow popup = getPopup();
|
||||
if (popup != null && !popup.isShowing()) {
|
||||
popup.show();
|
||||
@ -1199,7 +1228,7 @@ public class ListPopupWindow {
|
||||
*
|
||||
* @return true to stop forwarding, false otherwise
|
||||
*/
|
||||
public boolean onForwardingStopped() {
|
||||
protected boolean onForwardingStopped() {
|
||||
final ListPopupWindow popup = getPopup();
|
||||
if (popup != null && popup.isShowing()) {
|
||||
popup.dismiss();
|
||||
@ -1210,30 +1239,46 @@ public class ListPopupWindow {
|
||||
/**
|
||||
* 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
|
||||
* @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()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The first pointer down is always the active pointer.
|
||||
final int actionMasked = srcEvent.getActionMasked();
|
||||
if (actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
switch (actionMasked) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
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);
|
||||
if (activePointerIndex >= 0) {
|
||||
final float x = srcEvent.getX(activePointerIndex);
|
||||
final float y = srcEvent.getY(activePointerIndex);
|
||||
if (!src.pointInView(x, y, mScaledTouchSlop)) {
|
||||
// The pointer has moved outside of the view.
|
||||
if (mDisallowIntercept != null) {
|
||||
src.removeCallbacks(mDisallowIntercept);
|
||||
}
|
||||
src.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mDisallowIntercept != null) {
|
||||
src.removeCallbacks(mDisallowIntercept);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1242,11 +1287,11 @@ public class ListPopupWindow {
|
||||
* Handled forwarded motion events and determines when to stop
|
||||
* forwarding.
|
||||
*
|
||||
* @param src view from which the event originated
|
||||
* @param srcEvent motion event in source view coordinates
|
||||
* @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();
|
||||
if (popup == null || !popup.isShowing()) {
|
||||
return false;
|
||||
@ -1267,6 +1312,14 @@ public class ListPopupWindow {
|
||||
dstEvent.recycle();
|
||||
return handled;
|
||||
}
|
||||
|
||||
private class DisallowIntercept implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
final ViewParent parent = mSrc.getParent();
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,7 +198,7 @@ public class Spinner extends AbsSpinner implements OnClickListener {
|
||||
}
|
||||
|
||||
mPopup = popup;
|
||||
mForwardingListener = new ForwardingListener(context) {
|
||||
mForwardingListener = new ForwardingListener(this) {
|
||||
@Override
|
||||
public ListPopupWindow getPopup() {
|
||||
return popup;
|
||||
|
@ -565,7 +565,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter
|
||||
setVisibility(VISIBLE);
|
||||
setEnabled(true);
|
||||
|
||||
setOnTouchListener(new ForwardingListener(context) {
|
||||
setOnTouchListener(new ForwardingListener(this) {
|
||||
@Override
|
||||
public ListPopupWindow getPopup() {
|
||||
if (mOverflowPopup == null) {
|
||||
|
Reference in New Issue
Block a user