package com.android.launcher3; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; /** * Helper for identifying when a stylus touches a view while the primary stylus button is pressed. * This can occur in {@value MotionEvent#ACTION_DOWN} or {@value MotionEvent#ACTION_MOVE}. */ public class StylusEventHelper { /** * Implement this interface to receive callbacks for a stylus button press and release. */ public interface StylusButtonListener { /** * Called when the stylus button is pressed. * * @param event The MotionEvent that the button press occurred for. * @return Whether the event was handled. */ public boolean onPressed(MotionEvent event); /** * Called when the stylus button is released after a button press. This is also called if * the event is canceled or the stylus is lifted off the screen. * * @param event The MotionEvent the button release occurred for. * @return Whether the event was handled. */ public boolean onReleased(MotionEvent event); } private boolean mIsButtonPressed; private View mView; private StylusButtonListener mListener; private final float mSlop; /** * Constructs a helper for listening to stylus button presses and releases. Ensure that { * {@link #onMotionEvent(MotionEvent)} and {@link #onGenericMotionEvent(MotionEvent)} are called on * the helper to correctly identify stylus events. * * @param listener The listener to call for stylus events. * @param view Optional view associated with the touch events. */ public StylusEventHelper(StylusButtonListener listener, View view) { mListener = listener; mView = view; if (mView != null) { mSlop = ViewConfiguration.get(mView.getContext()).getScaledTouchSlop(); } else { mSlop = ViewConfiguration.getTouchSlop(); } } public boolean onMotionEvent(MotionEvent event) { final boolean stylusButtonPressed = isStylusButtonPressed(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mIsButtonPressed = stylusButtonPressed; if (mIsButtonPressed) { return mListener.onPressed(event); } break; case MotionEvent.ACTION_MOVE: if (!Utilities.pointInView(mView, event.getX(), event.getY(), mSlop)) { return false; } if (!mIsButtonPressed && stylusButtonPressed) { mIsButtonPressed = true; return mListener.onPressed(event); } else if (mIsButtonPressed && !stylusButtonPressed) { mIsButtonPressed = false; return mListener.onReleased(event); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (mIsButtonPressed) { mIsButtonPressed = false; return mListener.onReleased(event); } break; } return false; } /** * Whether a stylus button press is occurring. */ public boolean inStylusButtonPressed() { return mIsButtonPressed; } /** * Identifies if the provided {@link MotionEvent} is a stylus with the primary stylus button * pressed. * * @param event The event to check. * @return Whether a stylus button press occurred. */ private static boolean isStylusButtonPressed(MotionEvent event) { return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS && ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) == MotionEvent.BUTTON_SECONDARY); } }