diff options
| author | Michael Wright <michaelwr@google.com> | 2015-05-08 20:08:04 +0100 |
|---|---|---|
| committer | Michael Wright <michaelwr@google.com> | 2015-05-14 14:18:05 +0100 |
| commit | ec0ce51b733f10c620cb9447b074f022d042e31d (patch) | |
| tree | b1fb669f40ae6038e271f7c1a81ca46c7a19fb0b /core/java | |
| parent | fbb34dd8df7bc89ae972c545130e76c5bbb4176e (diff) | |
| download | frameworks_base-ec0ce51b733f10c620cb9447b074f022d042e31d.zip frameworks_base-ec0ce51b733f10c620cb9447b074f022d042e31d.tar.gz frameworks_base-ec0ce51b733f10c620cb9447b074f022d042e31d.tar.bz2 | |
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
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/view/InputEventConsistencyVerifier.java | 71 | ||||
| -rw-r--r-- | core/java/android/view/MotionEvent.java | 93 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 4 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 17 |
4 files changed, 166 insertions, 19 deletions
diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java index c5e4c21..46ef379 100644 --- a/core/java/android/view/InputEventConsistencyVerifier.java +++ b/core/java/android/view/InputEventConsistencyVerifier.java @@ -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) { diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 5df596a..4394cd8 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -303,6 +303,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 * down by {@link #ACTION_POINTER_INDEX_SHIFT} provides the actual pointer @@ -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,12 +2254,36 @@ 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 * on the screen, before it had been adjusted for the containing window @@ -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) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 75dc0a2..f4202bc 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -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()); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index fda6e63..c4a8776 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -40,6 +40,7 @@ import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.media.AudioManager; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.Handler; @@ -5320,7 +5321,7 @@ public final class ViewRootImpl implements ViewParent, //Log.d(TAG, ">>>>>> CALLING relayout"); if (params != null && mOrigWindowType != params.type) { // For compatibility with old apps, don't crash here. - if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { Slog.w(TAG, "Window type can not be changed after " + "the window is added; ignoring change of " + mView); params.type = mOrigWindowType; @@ -5745,6 +5746,7 @@ public final class ViewRootImpl implements ViewParent, void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { + adjustInputEventForCompatibility(event); QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); // Always enqueue the input event in order, regardless of its time stamp. @@ -5850,6 +5852,19 @@ public final class ViewRootImpl implements ViewParent, recycleQueuedInputEvent(q); } + private void adjustInputEventForCompatibility(InputEvent e) { + if (mTargetSdkVersion < Build.VERSION_CODES.MNC && e instanceof MotionEvent) { + MotionEvent motion = (MotionEvent) e; + final int mask = + MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY; + final int buttonState = motion.getButtonState(); + final int compatButtonState = (buttonState & mask) >> 4; + if (compatButtonState != 0) { + motion.setButtonState(buttonState | compatButtonState); + } + } + } + static boolean isTerminalInputEvent(InputEvent event) { if (event instanceof KeyEvent) { final KeyEvent keyEvent = (KeyEvent)event; |
