diff --git a/api/current.txt b/api/current.txt index be6e8736b0177..884a046d88e4d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34644,6 +34644,7 @@ package android.view { ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler); ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler, boolean); method public boolean isLongpressEnabled(); + method public boolean onGenericMotionEvent(android.view.MotionEvent); method public boolean onTouchEvent(android.view.MotionEvent); method public void setIsLongpressEnabled(boolean); method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener); diff --git a/api/system-current.txt b/api/system-current.txt index a072bd7bad4b7..04acd18f50c43 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -36902,6 +36902,7 @@ package android.view { ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler); ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler, boolean); method public boolean isLongpressEnabled(); + method public boolean onGenericMotionEvent(android.view.MotionEvent); method public boolean onTouchEvent(android.view.MotionEvent); method public void setIsLongpressEnabled(boolean); method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener); diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java index b8544c65a788f..ff0af6bc49a49 100644 --- a/core/java/android/view/GestureDetector.java +++ b/core/java/android/view/GestureDetector.java @@ -32,6 +32,9 @@ import android.os.Message; *
  • In the {@link View#onTouchEvent(MotionEvent)} method ensure you call * {@link #onTouchEvent(MotionEvent)}. The methods defined in your callback * will be executed when the events occur. + *
  • If listening for {@link OnStylusButtonPressListener#onStylusButtonPress(MotionEvent)} + * you must call {@link #onGenericMotionEvent(MotionEvent)} + * in {@link View#onGenericMotionEvent(MotionEvent)}. * */ public class GestureDetector { @@ -149,12 +152,14 @@ public class GestureDetector { } /** - * The listener that is used to notify when a stylus button press occurs. + * The listener that is used to notify when a stylus button press occurs. When listening for a + * stylus button press ensure that you call {@link #onGenericMotionEvent(MotionEvent)} in + * {@link View#onGenericMotionEvent(MotionEvent)}. */ public interface OnStylusButtonPressListener { /** * Notified when a stylus button press occurs. This is when the stylus - * is touching the screen and the {@value MotionEvent#BUTTON_SECONDARY} + * is touching the screen and the {@value MotionEvent#BUTTON_STYLUS_PRIMARY} * is pressed. * * @param e The motion event that occurred during the stylus button @@ -241,6 +246,7 @@ public class GestureDetector { private boolean mInStylusButtonPress; private boolean mAlwaysInTapRegion; private boolean mAlwaysInBiggerTapRegion; + private boolean mIgnoreNextUpEvent; private MotionEvent mCurrentDownEvent; private MotionEvent mPreviousUpEvent; @@ -552,18 +558,7 @@ public class GestureDetector { break; case MotionEvent.ACTION_DOWN: - if (mStylusButtonListener != null - && ev.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS - && (ev.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { - if (mStylusButtonListener.onStylusButtonPress(ev)) { - mInStylusButtonPress = true; - handled = true; - mHandler.removeMessages(LONG_PRESS); - mHandler.removeMessages(TAP); - } - } - - if (mDoubleTapListener != null && !mInStylusButtonPress) { + if (mDoubleTapListener != null) { boolean hadTapMessage = mHandler.hasMessages(TAP); if (hadTapMessage) mHandler.removeMessages(TAP); if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage && @@ -592,7 +587,7 @@ public class GestureDetector { mInLongPress = false; mDeferConfirmSingleTap = false; - if (mIsLongpressEnabled && !mInStylusButtonPress) { + if (mIsLongpressEnabled) { mHandler.removeMessages(LONG_PRESS); mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT + LONGPRESS_TIMEOUT); @@ -602,16 +597,6 @@ public class GestureDetector { break; case MotionEvent.ACTION_MOVE: - if (mStylusButtonListener != null && !mInStylusButtonPress && !mInLongPress - && ev.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS - && (ev.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { - if (mStylusButtonListener.onStylusButtonPress(ev)) { - mInStylusButtonPress = true; - handled = true; - mHandler.removeMessages(LONG_PRESS); - mHandler.removeMessages(TAP); - } - } if (mInLongPress || mInStylusButtonPress) { break; } @@ -652,15 +637,12 @@ public class GestureDetector { } else if (mInLongPress) { mHandler.removeMessages(TAP); mInLongPress = false; - } else if (mInStylusButtonPress) { - mHandler.removeMessages(TAP); - mInStylusButtonPress = false; - } else if (mAlwaysInTapRegion) { + } else if (mAlwaysInTapRegion && !mIgnoreNextUpEvent) { handled = mListener.onSingleTapUp(ev); if (mDeferConfirmSingleTap && mDoubleTapListener != null) { mDoubleTapListener.onSingleTapConfirmed(ev); } - } else { + } else if (!mIgnoreNextUpEvent) { // A fling must travel the minimum tap distance final VelocityTracker velocityTracker = mVelocityTracker; @@ -687,6 +669,7 @@ public class GestureDetector { } mIsDoubleTapping = false; mDeferConfirmSingleTap = false; + mIgnoreNextUpEvent = false; mHandler.removeMessages(SHOW_PRESS); mHandler.removeMessages(LONG_PRESS); break; @@ -702,6 +685,43 @@ public class GestureDetector { return handled; } + /** + * Analyzes the given generic motion event and if applicable triggers the + * appropriate callbacks on the {@link OnGestureListener} supplied. + * + * @param ev The current motion event. + * @return true if the {@link OnGestureListener} consumed the event, + * else false. + */ + public boolean onGenericMotionEvent(MotionEvent ev) { + if (mInputEventConsistencyVerifier != null) { + mInputEventConsistencyVerifier.onGenericMotionEvent(ev, 0); + } + + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_BUTTON_PRESS: + if (mStylusButtonListener != null && !mInStylusButtonPress && !mInLongPress + && ev.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { + if (mStylusButtonListener.onStylusButtonPress(ev)) { + mInStylusButtonPress = true; + mHandler.removeMessages(LONG_PRESS); + mHandler.removeMessages(TAP); + return true; + } + } + break; + + case MotionEvent.ACTION_BUTTON_RELEASE: + if (mInStylusButtonPress + && ev.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { + mInStylusButtonPress = false; + mIgnoreNextUpEvent = true; + } + break; + } + return false; + } + private void cancel() { mHandler.removeMessages(SHOW_PRESS); mHandler.removeMessages(LONG_PRESS); @@ -715,6 +735,7 @@ public class GestureDetector { mDeferConfirmSingleTap = false; mInLongPress = false; mInStylusButtonPress = false; + mIgnoreNextUpEvent = false; } private void cancelTaps() { @@ -727,6 +748,7 @@ public class GestureDetector { mDeferConfirmSingleTap = false; mInLongPress = false; mInStylusButtonPress = false; + mIgnoreNextUpEvent = false; } private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp,