diff --git a/core/api/current.txt b/core/api/current.txt index 8837813d4adfb..ff000703c33ff 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -49759,16 +49759,24 @@ package android.view { field public static final int CLOCK_TICK = 4; // 0x4 field public static final int CONFIRM = 16; // 0x10 field public static final int CONTEXT_CLICK = 6; // 0x6 + field public static final int DRAG_START = 25; // 0x19 field @Deprecated public static final int FLAG_IGNORE_GLOBAL_SETTING = 2; // 0x2 field public static final int FLAG_IGNORE_VIEW_SETTING = 1; // 0x1 field public static final int GESTURE_END = 13; // 0xd field public static final int GESTURE_START = 12; // 0xc + field public static final int GESTURE_THRESHOLD_ACTIVATE = 23; // 0x17 + field public static final int GESTURE_THRESHOLD_DEACTIVATE = 24; // 0x18 field public static final int KEYBOARD_PRESS = 3; // 0x3 field public static final int KEYBOARD_RELEASE = 7; // 0x7 field public static final int KEYBOARD_TAP = 3; // 0x3 field public static final int LONG_PRESS = 0; // 0x0 + field public static final int NO_HAPTICS = -1; // 0xffffffff field public static final int REJECT = 17; // 0x11 + field public static final int SEGMENT_FREQUENT_TICK = 27; // 0x1b + field public static final int SEGMENT_TICK = 26; // 0x1a field public static final int TEXT_HANDLE_MOVE = 9; // 0x9 + field public static final int TOGGLE_OFF = 22; // 0x16 + field public static final int TOGGLE_ON = 21; // 0x15 field public static final int VIRTUAL_KEY = 1; // 0x1 field public static final int VIRTUAL_KEY_RELEASE = 8; // 0x8 } diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java index 45b65e551305a..6551a1884af05 100644 --- a/core/java/android/view/HapticFeedbackConstants.java +++ b/core/java/android/view/HapticFeedbackConstants.java @@ -24,6 +24,13 @@ public class HapticFeedbackConstants { private HapticFeedbackConstants() {} + /** + * No haptic feedback should be performed. Applications may use this value to indicate skipping + * a call to {@link View#performHapticFeedback} entirely, or else rely that it will immediately + * return {@code false}. + */ + public static final int NO_HAPTICS = -1; + /** * The user has performed a long press on an object that is resulting * in an action being performed. @@ -144,6 +151,64 @@ public class HapticFeedbackConstants { */ public static final int ROTARY_SCROLL_LIMIT = 20; + /** + * The user has toggled a switch or button into the on position. + */ + public static final int TOGGLE_ON = 21; + + /** + * The user has toggled a switch or button into the off position. + */ + public static final int TOGGLE_OFF = 22; + + /** + * The user is executing a swipe/drag-style gesture, such as pull-to-refresh, where the + * gesture action is “eligible” at a certain threshold of movement, and can be cancelled by + * moving back past the threshold. This constant indicates that the user's motion has just + * passed the threshold for the action to be activated on release. + * + * @see #GESTURE_THRESHOLD_DEACTIVATE + */ + public static final int GESTURE_THRESHOLD_ACTIVATE = 23; + + /** + * The user is executing a swipe/drag-style gesture, such as pull-to-refresh, where the + * gesture action is “eligible” at a certain threshold of movement, and can be cancelled by + * moving back past the threshold. This constant indicates that the user's motion has just + * re-crossed back "under" the threshold for the action to be activated, meaning the gesture is + * currently in a cancelled state. + * + * @see #GESTURE_THRESHOLD_ACTIVATE + */ + public static final int GESTURE_THRESHOLD_DEACTIVATE = 24; + + /** + * The user has started a drag-and-drop gesture. The drag target has just been "picked up". + */ + public static final int DRAG_START = 25; + + /** + * The user is switching between a series of potential choices, for example items in a list + * or discrete points on a slider. + * + *

See also {@link #SEGMENT_FREQUENT_TICK} for cases where density of choices is high, and + * the haptics should be lighter or suppressed for a better user experience. + */ + public static final int SEGMENT_TICK = 26; + + /** + * The user is switching between a series of many potential choices, for example minutes on a + * clock face, or individual percentages. This constant is expected to be very soft, so as + * not to be uncomfortable when performed a lot in quick succession. If the device can’t make + * a suitably soft vibration, then it may not make any vibration. + * + *

Some specializations of this constant exist for specific actions, notably + * {@link #CLOCK_TICK} and {@link #TEXT_HANDLE_MOVE}. + * + *

See also {@link #SEGMENT_TICK}. + */ + public static final int SEGMENT_FREQUENT_TICK = 27; + /** * The phone has booted with safe mode enabled. * This is a private constant. Feel free to renumber as desired. diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 508c6bd64a4c1..d5adb236c34f1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -27271,7 +27271,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param flags Additional flags as per {@link HapticFeedbackConstants}. */ public boolean performHapticFeedback(int feedbackConstant, int flags) { - if (mAttachInfo == null) { + if (feedbackConstant == HapticFeedbackConstants.NO_HAPTICS + || mAttachInfo == null) { return false; } //noinspection SimplifiableIfStatement diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5a0c3443078d8..85c682fb5e94a 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5722,44 +5722,53 @@ public class PhoneWindowManager implements WindowManagerPolicy { switch (effectId) { case HapticFeedbackConstants.CONTEXT_CLICK: case HapticFeedbackConstants.GESTURE_END: + case HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE: case HapticFeedbackConstants.ROTARY_SCROLL_TICK: + case HapticFeedbackConstants.SEGMENT_TICK: return VibrationEffect.get(VibrationEffect.EFFECT_TICK); + case HapticFeedbackConstants.TEXT_HANDLE_MOVE: if (!mHapticTextHandleEnabled) { return null; } // fallthrough case HapticFeedbackConstants.CLOCK_TICK: + case HapticFeedbackConstants.SEGMENT_FREQUENT_TICK: return VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK); + case HapticFeedbackConstants.KEYBOARD_RELEASE: case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE: case HapticFeedbackConstants.ENTRY_BUMP: case HapticFeedbackConstants.DRAG_CROSSING: return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false); + case HapticFeedbackConstants.KEYBOARD_TAP: // == KEYBOARD_PRESS case HapticFeedbackConstants.VIRTUAL_KEY: case HapticFeedbackConstants.EDGE_RELEASE: + case HapticFeedbackConstants.CALENDAR_DATE: case HapticFeedbackConstants.CONFIRM: case HapticFeedbackConstants.GESTURE_START: case HapticFeedbackConstants.ROTARY_SCROLL_ITEM_FOCUS: case HapticFeedbackConstants.ROTARY_SCROLL_LIMIT: return VibrationEffect.get(VibrationEffect.EFFECT_CLICK); + case HapticFeedbackConstants.LONG_PRESS: case HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON: + case HapticFeedbackConstants.DRAG_START: case HapticFeedbackConstants.EDGE_SQUEEZE: return VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK); + case HapticFeedbackConstants.REJECT: return VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK); - case HapticFeedbackConstants.CALENDAR_DATE: - return VibrationEffect.get(VibrationEffect.EFFECT_CLICK); case HapticFeedbackConstants.SAFE_MODE_ENABLED: pattern = mSafeModeEnabledVibePattern; break; case HapticFeedbackConstants.ASSISTANT_BUTTON: if (mVibrator.areAllPrimitivesSupported( - VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)) { + VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, + VibrationEffect.Composition.PRIMITIVE_TICK)) { // quiet ramp, short pause, then sharp tick return VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, 0.25f) @@ -5769,6 +5778,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { // fallback for devices without composition support return VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK); + case HapticFeedbackConstants.GESTURE_THRESHOLD_DEACTIVATE: + return getScaledPrimitiveOrElseEffect( + VibrationEffect.Composition.PRIMITIVE_TICK, 0.4f, + VibrationEffect.EFFECT_TEXTURE_TICK); + + case HapticFeedbackConstants.TOGGLE_ON: + return getScaledPrimitiveOrElseEffect( + VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f, + VibrationEffect.EFFECT_TICK); + + case HapticFeedbackConstants.TOGGLE_OFF: + return getScaledPrimitiveOrElseEffect( + VibrationEffect.Composition.PRIMITIVE_LOW_TICK, 0.2f, + VibrationEffect.EFFECT_TEXTURE_TICK); + + case HapticFeedbackConstants.NO_HAPTICS: default: return null; } @@ -5784,6 +5809,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private VibrationEffect getScaledPrimitiveOrElseEffect(int primitiveId, float scale, + int elseEffectId) { + if (mVibrator.areAllPrimitivesSupported(primitiveId)) { + return VibrationEffect.startComposition() + .addPrimitive(primitiveId, scale) + .compose(); + } else { + return VibrationEffect.get(elseEffectId); + } + } + private VibrationAttributes getVibrationAttributes(int effectId) { switch (effectId) { case HapticFeedbackConstants.EDGE_SQUEEZE: