Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec0ce51b authored by Michael Wright's avatar Michael Wright
Browse files

Add new MotionEvent actions for button press and release.

Introduce ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE as actions to
signal a button press or release. If these actions happen
simulanteously with a DOWN or UP event then they're explicitly
ordered to happen after the DOWN or preceding the UP in order to send
them to the most recently targeted view.

Also, introduce new stylus button constants that differ from the
constants we use for mouse buttons.

Bug: 20704355
Change-Id: I5b75e5c5e692171c1c117ee687dd185a0d9dd15c
parent fbb34dd8
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -35617,6 +35617,7 @@ package android.view {
    method public static java.lang.String axisToString(int);
    method public final int findPointerIndex(int);
    method public final int getAction();
    method public final int getActionButton();
    method public final int getActionIndex();
    method public final int getActionMasked();
    method public final float getAxisValue(int);
@@ -35680,7 +35681,6 @@ package android.view {
    method public final float getY(int);
    method public final float getYPrecision();
    method public final boolean isButtonPressed(int);
    method public final boolean isStylusButtonPressed();
    method public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent.PointerProperties[], android.view.MotionEvent.PointerCoords[], int, int, float, float, int, int, int, int);
    method public static deprecated android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent.PointerCoords[], int, float, float, int, int, int, int);
    method public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
@@ -35696,6 +35696,8 @@ package android.view {
    method public final void setSource(int);
    method public final void transform(android.graphics.Matrix);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final int ACTION_BUTTON_PRESS = 11; // 0xb
    field public static final int ACTION_BUTTON_RELEASE = 12; // 0xc
    field public static final int ACTION_CANCEL = 3; // 0x3
    field public static final int ACTION_DOWN = 0; // 0x0
    field public static final int ACTION_HOVER_ENTER = 9; // 0x9
@@ -35764,6 +35766,8 @@ package android.view {
    field public static final int BUTTON_FORWARD = 16; // 0x10
    field public static final int BUTTON_PRIMARY = 1; // 0x1
    field public static final int BUTTON_SECONDARY = 2; // 0x2
    field public static final int BUTTON_STYLUS_PRIMARY = 32; // 0x20
    field public static final int BUTTON_STYLUS_SECONDARY = 64; // 0x40
    field public static final int BUTTON_TERTIARY = 4; // 0x4
    field public static final android.os.Parcelable.Creator<android.view.MotionEvent> CREATOR;
    field public static final int EDGE_BOTTOM = 2; // 0x2
+5 −1
Original line number Diff line number Diff line
@@ -37828,6 +37828,7 @@ package android.view {
    method public static java.lang.String axisToString(int);
    method public final int findPointerIndex(int);
    method public final int getAction();
    method public final int getActionButton();
    method public final int getActionIndex();
    method public final int getActionMasked();
    method public final float getAxisValue(int);
@@ -37891,7 +37892,6 @@ package android.view {
    method public final float getY(int);
    method public final float getYPrecision();
    method public final boolean isButtonPressed(int);
    method public final boolean isStylusButtonPressed();
    method public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent.PointerProperties[], android.view.MotionEvent.PointerCoords[], int, int, float, float, int, int, int, int);
    method public static deprecated android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent.PointerCoords[], int, float, float, int, int, int, int);
    method public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
@@ -37907,6 +37907,8 @@ package android.view {
    method public final void setSource(int);
    method public final void transform(android.graphics.Matrix);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final int ACTION_BUTTON_PRESS = 11; // 0xb
    field public static final int ACTION_BUTTON_RELEASE = 12; // 0xc
    field public static final int ACTION_CANCEL = 3; // 0x3
    field public static final int ACTION_DOWN = 0; // 0x0
    field public static final int ACTION_HOVER_ENTER = 9; // 0x9
@@ -37975,6 +37977,8 @@ package android.view {
    field public static final int BUTTON_FORWARD = 16; // 0x10
    field public static final int BUTTON_PRIMARY = 1; // 0x1
    field public static final int BUTTON_SECONDARY = 2; // 0x2
    field public static final int BUTTON_STYLUS_PRIMARY = 32; // 0x20
    field public static final int BUTTON_STYLUS_SECONDARY = 64; // 0x40
    field public static final int BUTTON_TERTIARY = 4; // 0x4
    field public static final android.os.Parcelable.Creator<android.view.MotionEvent> CREATOR;
    field public static final int EDGE_BOTTOM = 2; // 0x2
+71 −0
Original line number Diff line number Diff line
@@ -97,6 +97,9 @@ public final class InputEventConsistencyVerifier {
    // Set to true if we received hover enter.
    private boolean mHoverEntered;

    // The bitset of buttons which we've received ACTION_BUTTON_PRESS for.
    private int mButtonsPressed;

    // The current violation message.
    private StringBuilder mViolationMessage;

@@ -148,6 +151,7 @@ public final class InputEventConsistencyVerifier {
        mTouchEventStreamIsTainted = false;
        mTouchEventStreamUnhandled = false;
        mHoverEntered = false;
        mButtonsPressed = 0;

        while (mKeyStateList != null) {
            final KeyState state = mKeyStateList;
@@ -466,6 +470,8 @@ public final class InputEventConsistencyVerifier {

            final int action = event.getAction();
            final int source = event.getSource();
            final int buttonState = event.getButtonState();
            final int actionButton = event.getActionButton();
            if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                switch (action) {
                    case MotionEvent.ACTION_HOVER_ENTER:
@@ -486,6 +492,62 @@ public final class InputEventConsistencyVerifier {
                        ensureHistorySizeIsZeroForThisAction(event);
                        ensurePointerCountIsOneForThisAction(event);
                        break;
                    case MotionEvent.ACTION_BUTTON_PRESS:
                        ensureActionButtonIsNonZeroForThisAction(event);
                        if ((mButtonsPressed & actionButton) != 0) {
                            problem("Action button for ACTION_BUTTON_PRESS event is " +
                                    actionButton + ", but it has already been pressed and " +
                                    "has yet to be released.");
                        }

                        mButtonsPressed |= actionButton;
                        // The system will automatically mirror the stylus buttons onto the button
                        // state as the old set of generic buttons for apps targeting pre-M. If
                        // it looks this has happened, go ahead and set the generic buttons as
                        // pressed to prevent spurious errors.
                        if (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY &&
                                (buttonState & MotionEvent.BUTTON_SECONDARY) != 0) {
                            mButtonsPressed |= MotionEvent.BUTTON_SECONDARY;
                        } else if (actionButton == MotionEvent.BUTTON_STYLUS_SECONDARY &&
                                (buttonState & MotionEvent.BUTTON_TERTIARY) != 0) {
                            mButtonsPressed |= MotionEvent.BUTTON_TERTIARY;
                        }

                        if (mButtonsPressed != buttonState) {
                            problem(String.format("Reported button state differs from " +
                                    "expected button state based on press and release events. " +
                                    "Is 0x%08x but expected 0x%08x.",
                                    buttonState, mButtonsPressed));
                        }
                        break;
                    case MotionEvent.ACTION_BUTTON_RELEASE:
                        ensureActionButtonIsNonZeroForThisAction(event);
                        if ((mButtonsPressed & actionButton) != actionButton) {
                            problem("Action button for ACTION_BUTTON_RELEASE event is " +
                                    actionButton + ", but it was either never pressed or has " +
                                    "already been released.");
                        }

                        mButtonsPressed &= ~actionButton;
                        // The system will automatically mirror the stylus buttons onto the button
                        // state as the old set of generic buttons for apps targeting pre-M. If
                        // it looks this has happened, go ahead and set the generic buttons as
                        // released to prevent spurious errors.
                        if (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY &&
                                (buttonState & MotionEvent.BUTTON_SECONDARY) == 0) {
                            mButtonsPressed &= ~MotionEvent.BUTTON_SECONDARY;
                        } else if (actionButton == MotionEvent.BUTTON_STYLUS_SECONDARY &&
                                (buttonState & MotionEvent.BUTTON_TERTIARY) == 0) {
                            mButtonsPressed &= ~MotionEvent.BUTTON_TERTIARY;
                        }

                        if (mButtonsPressed != buttonState) {
                            problem(String.format("Reported button state differs from " +
                                    "expected button state based on press and release events. " +
                                    "Is 0x%08x but expected 0x%08x.",
                                    buttonState, mButtonsPressed));
                        }
                        break;
                    default:
                        problem("Invalid action for generic pointer event.");
                        break;
@@ -563,6 +625,15 @@ public final class InputEventConsistencyVerifier {
        }
    }

    private void ensureActionButtonIsNonZeroForThisAction(MotionEvent event) {
        final int actionButton = event.getActionButton();
        if (actionButton == 0) {
            problem("No action button set. Action button should always be non-zero for " +
                    MotionEvent.actionToString(event.getAction()));

        }
    }

    private void ensureHistorySizeIsZeroForThisAction(MotionEvent event) {
        final int historySize = event.getHistorySize();
        if (historySize != 0) {
+77 −16
Original line number Diff line number Diff line
@@ -302,6 +302,32 @@ public final class MotionEvent extends InputEvent implements Parcelable {
     */
    public static final int ACTION_HOVER_EXIT       = 10;

    /**
     * Constant for {@link #getActionMasked}: A button has been pressed.
     *
     * <p>
     * Use {@link #getActionButton()} to get which button was pressed.
     * </p><p>
     * This action is not a touch event so it is delivered to
     * {@link View#onGenericMotionEvent(MotionEvent)} rather than
     * {@link View#onTouchEvent(MotionEvent)}.
     * </p>
     */
    public static final int ACTION_BUTTON_PRESS   = 11;

    /**
     * Constant for {@link #getActionMasked}: A button has been released.
     *
     * <p>
     * Use {@link #getActionButton()} to get which button was released.
     * </p><p>
     * This action is not a touch event so it is delivered to
     * {@link View#onGenericMotionEvent(MotionEvent)} rather than
     * {@link View#onTouchEvent(MotionEvent)}.
     * </p>
     */
    public static final int ACTION_BUTTON_RELEASE  = 12;

    /**
     * Bits in the action code that represent a pointer index, used with
     * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}.  Shifting
@@ -1174,14 +1200,14 @@ public final class MotionEvent extends InputEvent implements Parcelable {
    public static final int BUTTON_PRIMARY = 1 << 0;

    /**
     * Button constant: Secondary button (right mouse button, stylus first button).
     * Button constant: Secondary button (right mouse button).
     *
     * @see #getButtonState
     */
    public static final int BUTTON_SECONDARY = 1 << 1;

    /**
     * Button constant: Tertiary button (middle mouse button, stylus second button).
     * Button constant: Tertiary button (middle mouse button).
     *
     * @see #getButtonState
     */
@@ -1209,6 +1235,20 @@ public final class MotionEvent extends InputEvent implements Parcelable {
     */
    public static final int BUTTON_FORWARD = 1 << 4;

    /**
     * Button constant: Primary stylus button pressed.
     *
     * @see #getButtonState
     */
    public static final int BUTTON_STYLUS_PRIMARY = 1 << 5;

    /**
     * Button constant: Secondary stylus button pressed.
     *
     * @see #getButtonState
     */
    public static final int BUTTON_STYLUS_SECONDARY = 1 << 6;

    // NOTE: If you add a new axis here you must also add it to:
    //  native/include/android/input.h

@@ -1220,8 +1260,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
        "BUTTON_TERTIARY",
        "BUTTON_BACK",
        "BUTTON_FORWARD",
        "0x00000020",
        "0x00000040",
        "BUTTON_STYLUS_PRIMARY",
        "BUTTON_STYLUS_SECONDARY",
        "0x00000080",
        "0x00000100",
        "0x00000200",
@@ -1357,6 +1397,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
    private static native void nativeSetEdgeFlags(long nativePtr, int action);
    private static native int nativeGetMetaState(long nativePtr);
    private static native int nativeGetButtonState(long nativePtr);
    private static native void nativeSetButtonState(long nativePtr, int buttonState);
    private static native int nativeGetActionButton(long nativePtr);
    private static native void nativeOffsetLocation(long nativePtr, float deltaX, float deltaY);
    private static native float nativeGetXOffset(long nativePtr);
    private static native float nativeGetYOffset(long nativePtr);
@@ -2212,11 +2254,35 @@ public final class MotionEvent extends InputEvent implements Parcelable {
     * @see #BUTTON_TERTIARY
     * @see #BUTTON_FORWARD
     * @see #BUTTON_BACK
     * @see #BUTTON_STYLUS_PRIMARY
     * @see #BUTTON_STYLUS_SECONDARY
     */
    public final int getButtonState() {
        return nativeGetButtonState(mNativePtr);
    }

    /**
     * Sets the bitfield indicating which buttons are pressed.
     *
     * @see #getButtonState()
     * @hide
     */
    public final void setButtonState(int buttonState) {
        nativeSetButtonState(mNativePtr, buttonState);
    }

    /**
     * Gets which button has been modified during a press or release action.
     *
     * For actions other than {@link #ACTION_BUTTON_PRESS} and {@link #ACTION_BUTTON_RELEASE}
     * the returned value is undefined.
     *
     * @see #getButtonState()
     */
    public final int getActionButton() {
        return nativeGetActionButton(mNativePtr);
    }

    /**
     * Returns the original raw X coordinate of this event.  For touch
     * events on the screen, this is the original location of the event
@@ -3013,6 +3079,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
    public String toString() {
        StringBuilder msg = new StringBuilder();
        msg.append("MotionEvent { action=").append(actionToString(getAction()));
        msg.append(", actionButton=").append(buttonStateToString(getActionButton()));

        final int pointerCount = getPointerCount();
        for (int i = 0; i < pointerCount; i++) {
@@ -3066,6 +3133,10 @@ public final class MotionEvent extends InputEvent implements Parcelable {
                return "ACTION_HOVER_ENTER";
            case ACTION_HOVER_EXIT:
                return "ACTION_HOVER_EXIT";
            case ACTION_BUTTON_PRESS:
                return "ACTION_BUTTON_PRESS";
            case ACTION_BUTTON_RELEASE:
                return "ACTION_BUTTON_RELEASE";
        }
        int index = (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
        switch (action & ACTION_MASK) {
@@ -3172,6 +3243,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
     * @see #BUTTON_TERTIARY
     * @see #BUTTON_FORWARD
     * @see #BUTTON_BACK
     * @see #BUTTON_STYLUS_PRIMARY
     * @see #BUTTON_STYLUS_SECONDARY
     */
    public final boolean isButtonPressed(int button) {
        if (button == 0) {
@@ -3180,18 +3253,6 @@ public final class MotionEvent extends InputEvent implements Parcelable {
        return (getButtonState() & button) == button;
    }

    /**
     * Checks if a stylus is being used and if the first stylus button is
     * pressed.
     *
     * @return True if the tool is a stylus and if the first stylus button is
     *         pressed.
     * @see #BUTTON_SECONDARY
     */
    public final boolean isStylusButtonPressed() {
        return (isButtonPressed(BUTTON_SECONDARY) && getToolType(0) == TOOL_TYPE_STYLUS);
    }

    public static final Parcelable.Creator<MotionEvent> CREATOR
            = new Parcelable.Creator<MotionEvent>() {
        public MotionEvent createFromParcel(Parcel in) {
+2 −2
Original line number Diff line number Diff line
@@ -4986,8 +4986,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * @return True if the event was consumed.
     */
    private boolean performStylusActionOnButtonPress(MotionEvent event) {
        if (isStylusButtonPressable() && !mInStylusButtonPress
                && !mHasPerformedLongPress && event.isStylusButtonPressed()) {
        if (isStylusButtonPressable() && !mInStylusButtonPress && !mHasPerformedLongPress
                && event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY)) {
            if (performStylusButtonPress()) {
                mInStylusButtonPress = true;
                setPressed(true, event.getX(), event.getY());
Loading