diff options
author | Michael Wright <michaelwr@google.com> | 2015-05-14 13:31:24 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-05-14 13:31:29 +0000 |
commit | 07b83f1c9e8a7692a985aa2d13ac13fc5521aa4b (patch) | |
tree | 057cd12608c83a809c155a1b3b7469f39b2e26ef /core/java/android/view | |
parent | be752b1f28f1f3724b235e3f0a77b4c07c40e631 (diff) | |
parent | ec0ce51b733f10c620cb9447b074f022d042e31d (diff) | |
download | frameworks_base-07b83f1c9e8a7692a985aa2d13ac13fc5521aa4b.zip frameworks_base-07b83f1c9e8a7692a985aa2d13ac13fc5521aa4b.tar.gz frameworks_base-07b83f1c9e8a7692a985aa2d13ac13fc5521aa4b.tar.bz2 |
Merge "Add new MotionEvent actions for button press and release." into mnc-dev
Diffstat (limited to 'core/java/android/view')
-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 9e16b4b..6ca320a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5221,8 +5221,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 7c635b9..1cbd886 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; @@ -5352,7 +5353,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; @@ -5777,6 +5778,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. @@ -5882,6 +5884,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; |