diff options
Diffstat (limited to 'core/java/android')
-rw-r--r-- | core/java/android/app/AssistStructure.java | 11 | ||||
-rw-r--r-- | core/java/android/view/HapticFeedbackConstants.java | 5 | ||||
-rw-r--r-- | core/java/android/view/MotionEvent.java | 12 | ||||
-rw-r--r-- | core/java/android/view/View.java | 181 | ||||
-rw-r--r-- | core/java/android/view/ViewAssistStructure.java | 2 | ||||
-rw-r--r-- | core/java/android/view/accessibility/AccessibilityEvent.java | 14 | ||||
-rw-r--r-- | core/java/android/view/accessibility/AccessibilityNodeInfo.java | 34 |
7 files changed, 251 insertions, 8 deletions
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java index 9946d79..3abbb5b 100644 --- a/core/java/android/app/AssistStructure.java +++ b/core/java/android/app/AssistStructure.java @@ -224,6 +224,7 @@ final public class AssistStructure implements Parcelable { static final int FLAGS_CHECKED = 0x00000200; static final int FLAGS_CLICKABLE = 0x00004000; static final int FLAGS_LONG_CLICKABLE = 0x00200000; + static final int FLAGS_STYLUS_BUTTON_PRESSABLE = 0x00400000; int mFlags; @@ -401,6 +402,10 @@ final public class AssistStructure implements Parcelable { return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0; } + public boolean isStylusButtonPressable() { + return (mFlags&ViewNode.FLAGS_STYLUS_BUTTON_PRESSABLE) != 0; + } + public String getClassName() { return mClassName; } @@ -513,6 +518,12 @@ final public class AssistStructure implements Parcelable { } @Override + public void setStylusButtonPressable(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_STYLUS_BUTTON_PRESSABLE) + | (state ? ViewNode.FLAGS_STYLUS_BUTTON_PRESSABLE : 0); + } + + @Override public void setFocusable(boolean state) { mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE) | (state ? ViewNode.FLAGS_FOCUSABLE : 0); diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java index cc090ad..6651b83 100644 --- a/core/java/android/view/HapticFeedbackConstants.java +++ b/core/java/android/view/HapticFeedbackConstants.java @@ -52,6 +52,11 @@ public class HapticFeedbackConstants { public static final int CALENDAR_DATE = 5; /** + * The user has touched the screen with a stylus and pressed the stylus button. + */ + public static final int STYLUS_BUTTON_PRESS = 6; + + /** * This is a private constant. Feel free to renumber as desired. * @hide */ diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 5e45c8f..5df596a 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -3180,6 +3180,18 @@ 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 b5b7f0f..81ad5ad 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -987,6 +987,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ static final int DUPLICATE_PARENT_STATE = 0x00400000; + /** + * <p> + * Indicates this view can be stylus button pressed. When stylus button + * pressable, a View reacts to stylus button presses by notifiying + * the OnStylusButtonPressListener. + * </p> + * {@hide} + */ + static final int STYLUS_BUTTON_PRESSABLE = 0x00800000; + + /** @hide */ @IntDef({ SCROLLBARS_INSIDE_OVERLAY, @@ -3270,6 +3281,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, protected OnLongClickListener mOnLongClickListener; /** + * Listener used to dispatch stylus touch and button press events. This field should be made + * private, so it is hidden from the SDK. + * {@hide} + */ + protected OnStylusButtonPressListener mOnStylusButtonPressListener; + + /** * Listener used to build the context menu. * This field should be made private, so it is hidden from the SDK. * {@hide} @@ -3360,6 +3378,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private boolean mHasPerformedLongPress; /** + * Whether the stylus button is currently pressed down. This is true when + * the stylus is touching the screen and the button has been pressed, this + * is false once the stylus has been lifted. + */ + private boolean mInStylusButtonPress = false; + + /** * The minimum height of the view. We'll try our best to have the height * of this view to at least this amount. */ @@ -3875,6 +3900,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, viewFlagMasks |= LONG_CLICKABLE; } break; + case com.android.internal.R.styleable.View_stylusButtonPressable: + if (a.getBoolean(attr, false)) { + viewFlagValues |= STYLUS_BUTTON_PRESSABLE; + viewFlagMasks |= STYLUS_BUTTON_PRESSABLE; + } + break; case com.android.internal.R.styleable.View_saveEnabled: if (!a.getBoolean(attr, true)) { viewFlagValues |= SAVE_DISABLED; @@ -4340,6 +4371,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); + out.append((mViewFlags & STYLUS_BUTTON_PRESSABLE) != 0 ? 'S' : '.'); out.append(' '); out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); @@ -4835,6 +4867,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Register a callback to be invoked when this view is touched with a stylus and the button is + * pressed. + * + * @param l The callback that will run + * @see #setStylusButtonPressable(boolean) + */ + public void setOnStylusButtonPressListener(@Nullable OnStylusButtonPressListener l) { + if (!isStylusButtonPressable()) { + setStylusButtonPressable(true); + } + getListenerInfo().mOnStylusButtonPressListener = l; + } + + /** * Register a callback to be invoked when the context menu for this view is * being built. If this view is not long clickable, it becomes long clickable. * @@ -4912,6 +4958,46 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Call this view's OnStylusButtonPressListener, if it is defined. + * + * @return True if there was an assigned OnStylusButtonPressListener that consumed the event, + * false otherwise. + */ + public boolean performStylusButtonPress() { + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_STYLUS_BUTTON_PRESSED); + + boolean handled = false; + ListenerInfo li = mListenerInfo; + if (li != null && li.mOnStylusButtonPressListener != null) { + handled = li.mOnStylusButtonPressListener.onStylusButtonPress(View.this); + } + if (handled) { + performHapticFeedback(HapticFeedbackConstants.STYLUS_BUTTON_PRESS); + } + return handled; + } + + /** + * Checks for a stylus button press and calls the listener. + * + * @param event The event. + * @return True if the event was consumed. + */ + private boolean performStylusActionOnButtonPress(MotionEvent event) { + if (isStylusButtonPressable() && !mInStylusButtonPress + && !mHasPerformedLongPress && event.isStylusButtonPressed()) { + if (performStylusButtonPress()) { + mInStylusButtonPress = true; + setPressed(true, event.getX(), event.getY()); + removeTapCallback(); + removeLongPressCallback(); + return true; + } + } + return false; + } + + /** * Performs button-related actions during a touch down event. * * @param event The event. @@ -5701,6 +5787,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> + * <li>{@link AccessibilityNodeInfo#setStylusButtonPressable(boolean)}</li> * </ul> * <p> * Subclasses should override this method, call the super implementation, @@ -5852,6 +5939,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setChecked(true); } } + if (isStylusButtonPressable()) { + structure.setStylusButtonPressable(true); + } structure.setClassName(getAccessibilityClassName().toString()); structure.setContentDescription(getContentDescription()); } @@ -5909,6 +5999,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setChecked(true); } } + if (info.isStylusButtonPressable()) { + structure.setStylusButtonPressable(true); + } CharSequence cname = info.getClassName(); structure.setClassName(cname != null ? cname.toString() : null); structure.setContentDescription(info.getContentDescription()); @@ -6038,6 +6131,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, info.setAccessibilityFocused(isAccessibilityFocused()); info.setSelected(isSelected()); info.setLongClickable(isLongClickable()); + info.setStylusButtonPressable(isStylusButtonPressable()); info.setLiveRegion(getAccessibilityLiveRegion()); // TODO: These make sense only if we are in an AdapterView but all @@ -6068,6 +6162,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); } + if (isStylusButtonPressable() && isEnabled()) { + info.addAction(AccessibilityAction.ACTION_STYLUS_BUTTON_PRESS); + } + CharSequence text = getIterableTextForAccessibility(); if (text != null && text.length() > 0) { info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); @@ -7442,6 +7540,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Indicates whether this view reacts to stylus button press events or not. + * + * @return true if the view is stylus button pressable, false otherwise + * @see #setStylusButtonPressable(boolean) + * @attr ref android.R.styleable#View_stylusButtonPressable + */ + public boolean isStylusButtonPressable() { + return (mViewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE; + } + + /** + * Enables or disables stylus button press events for this view. When a view is stylus button + * pressable it reacts to the user touching the screen with a stylus and pressing the first + * stylus button. This event can launch the listener. + * + * @param stylusButtonPressable true to make the view react to a stylus button press, false + * otherwise + * @see #isStylusButtonPressable() + * @attr ref android.R.styleable#View_stylusButtonPressable + */ + public void setStylusButtonPressable(boolean stylusButtonPressable) { + setFlags(stylusButtonPressable ? STYLUS_BUTTON_PRESSABLE : 0, STYLUS_BUTTON_PRESSABLE); + } + + /** * Sets the pressed state for this view and provides a touch coordinate for * animation hinting. * @@ -7856,7 +7979,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void addTouchables(ArrayList<View> views) { final int viewFlags = mViewFlags; - if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) + if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE + || (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE) && (viewFlags & ENABLED_MASK) == ENABLED) { views.add(this); } @@ -8571,6 +8695,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return requestRectangleOnScreen(r, true); } } break; + case R.id.accessibilityActionStylusButtonPress: { + if (isStylusButtonPressable()) { + performStylusButtonPress(); + return true; + } + } break; } return false; } @@ -9728,7 +9858,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } return (viewFlags & CLICKABLE) == CLICKABLE - || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; + || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE + || (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE; } /** @@ -9811,15 +9942,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final float x = event.getX(); final float y = event.getY(); final int viewFlags = mViewFlags; + final int action = event.getAction(); if ((viewFlags & ENABLED_MASK) == DISABLED) { - if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { + if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false); } // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. - return (((viewFlags & CLICKABLE) == CLICKABLE || - (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); + return (((viewFlags & CLICKABLE) == CLICKABLE + || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) + || (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE); } if (mTouchDelegate != null) { @@ -9829,9 +9962,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } if (((viewFlags & CLICKABLE) == CLICKABLE || - (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { - switch (event.getAction()) { + (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || + (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE) { + switch (action) { case MotionEvent.ACTION_UP: + if (mInStylusButtonPress) { + mInStylusButtonPress = false; + mHasPerformedLongPress = false; + } boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { // take focus if we don't have it already and we should in @@ -9885,6 +10023,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, case MotionEvent.ACTION_DOWN: mHasPerformedLongPress = false; + mInStylusButtonPress = false; + + if (performStylusActionOnButtonPress(event)) { + break; + } if (performButtonActionOnTouchDown(event)) { break; @@ -9914,6 +10057,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setPressed(false); removeTapCallback(); removeLongPressCallback(); + if (mInStylusButtonPress) { + mInStylusButtonPress = false; + mHasPerformedLongPress = false; + } break; case MotionEvent.ACTION_MOVE: @@ -9929,6 +10076,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setPressed(false); } + } else if (performStylusActionOnButtonPress(event)) { + // Check for stylus button press if we're within the view. + break; } break; } @@ -10216,7 +10366,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (accessibilityEnabled) { if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0 - || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0) { + || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 + || (changed & STYLUS_BUTTON_PRESSABLE) != 0) { if (oldIncludeForAccessibility != includeForAccessibility()) { notifySubtreeAccessibilityStateChangedIfNeeded(); } else { @@ -20782,6 +20933,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Interface definition for a callback to be invoked when a view is touched with a stylus while + * the stylus button is pressed. + */ + public interface OnStylusButtonPressListener { + /** + * Called when a view is touched with a stylus while the stylus button is pressed. + * + * @param v The view that was touched. + * @return true if the callback consumed the stylus button press, false otherwise. + */ + boolean onStylusButtonPress(View v); + } + + /** * Interface definition for a callback to be invoked when the context menu * for this view is being built. */ diff --git a/core/java/android/view/ViewAssistStructure.java b/core/java/android/view/ViewAssistStructure.java index 346b8ec..fccfbb8 100644 --- a/core/java/android/view/ViewAssistStructure.java +++ b/core/java/android/view/ViewAssistStructure.java @@ -40,6 +40,8 @@ public abstract class ViewAssistStructure { public abstract void setLongClickable(boolean state); + public abstract void setStylusButtonPressable(boolean state); + public abstract void setFocusable(boolean state); public abstract void setFocused(boolean state); diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 417e22c..b0dbeca 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -684,6 +684,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par public static final int TYPE_WINDOWS_CHANGED = 0x00400000; /** + * Represents the event of a stylus button press on a {@link android.view.View}. + */ + public static final int TYPE_VIEW_STYLUS_BUTTON_PRESSED = 0x00800000; + + /** * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: * The type of change is not defined. */ @@ -731,6 +736,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par * @see #TYPE_TOUCH_INTERACTION_START * @see #TYPE_TOUCH_INTERACTION_END * @see #TYPE_WINDOWS_CHANGED + * @see #TYPE_VIEW_STYLUS_BUTTON_PRESSED */ public static final int TYPES_ALL_MASK = 0xFFFFFFFF; @@ -1396,6 +1402,14 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par builder.append("TYPE_WINDOWS_CHANGED"); eventTypeCount++; } break; + case TYPE_VIEW_STYLUS_BUTTON_PRESSED: { + if (eventTypeCount > 0) { + builder.append(", "); + } + builder.append("TYPE_VIEW_STYLUS_BUTTON_PRESSED"); + eventTypeCount++; + } + break; } } if (eventTypeCount > 1) { diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 0736ed8..bf4b7ae 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -520,6 +520,8 @@ public class AccessibilityNodeInfo implements Parcelable { private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000; + private static final int BOOLEAN_PROPERTY_STYLUS_BUTTON_PRESSABLE = 0x00020000; + /** * Bits that provide the id of a virtual descendant of a view. */ @@ -1930,6 +1932,30 @@ public class AccessibilityNodeInfo implements Parcelable { } /** + * Gets whether this node is stylus button pressable. + * + * @return True if the node is stylus button pressable. + */ + public boolean isStylusButtonPressable() { + return getBooleanProperty(BOOLEAN_PROPERTY_STYLUS_BUTTON_PRESSABLE); + } + + /** + * Sets whether this node is stylus button pressable. + * <p> + * <strong>Note:</strong> Cannot be called from an + * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable + * before being delivered to an AccessibilityService. + * </p> + * + * @param stylusButtonPressable True if the node is stylus button pressable. + * @throws IllegalStateException If called from an AccessibilityService. + */ + public void setStylusButtonPressable(boolean stylusButtonPressable) { + setBooleanProperty(BOOLEAN_PROPERTY_STYLUS_BUTTON_PRESSABLE, stylusButtonPressable); + } + + /** * Gets the node's live region mode. * <p> * A live region is a node that contains information that is important for @@ -3117,6 +3143,7 @@ public class AccessibilityNodeInfo implements Parcelable { builder.append("; selected: ").append(isSelected()); builder.append("; clickable: ").append(isClickable()); builder.append("; longClickable: ").append(isLongClickable()); + builder.append("; stylusButtonPressable: ").append(isStylusButtonPressable()); builder.append("; enabled: ").append(isEnabled()); builder.append("; password: ").append(isPassword()); builder.append("; scrollable: ").append(isScrollable()); @@ -3472,6 +3499,12 @@ public class AccessibilityNodeInfo implements Parcelable { public static final AccessibilityAction ACTION_SCROLL_TO_POSITION = new AccessibilityAction(R.id.accessibilityActionScrollToPosition, null); + /** + * Action that stylus button presses the node. + */ + public static final AccessibilityAction ACTION_STYLUS_BUTTON_PRESS = + new AccessibilityAction(R.id.accessibilityActionStylusButtonPress, null); + private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>(); static { sStandardActions.add(ACTION_FOCUS); @@ -3498,6 +3531,7 @@ public class AccessibilityNodeInfo implements Parcelable { sStandardActions.add(ACTION_SET_TEXT); sStandardActions.add(ACTION_SHOW_ON_SCREEN); sStandardActions.add(ACTION_SCROLL_TO_POSITION); + sStandardActions.add(ACTION_STYLUS_BUTTON_PRESS); } private final int mActionId; |