summaryrefslogtreecommitdiffstats
path: root/core/java/android/view
diff options
context:
space:
mode:
authorMichael Wright <michaelwr@google.com>2015-05-14 13:31:24 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-05-14 13:31:29 +0000
commit07b83f1c9e8a7692a985aa2d13ac13fc5521aa4b (patch)
tree057cd12608c83a809c155a1b3b7469f39b2e26ef /core/java/android/view
parentbe752b1f28f1f3724b235e3f0a77b4c07c40e631 (diff)
parentec0ce51b733f10c620cb9447b074f022d042e31d (diff)
downloadframeworks_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.java71
-rw-r--r--core/java/android/view/MotionEvent.java93
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java17
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;