diff options
| author | 2022-01-19 17:24:40 +0000 | |
|---|---|---|
| committer | 2022-01-19 17:24:40 +0000 | |
| commit | 41fd16dfb790d048ed70c984f195f810af10bbac (patch) | |
| tree | 01672eebdf30a28e224dbef445dd2dbd9ae12702 | |
| parent | cfb5200a1bb4315bb1921477ebc13947665263c0 (diff) | |
| parent | a01a1f6993558249df3d74bffd4561c9fc7a1c1f (diff) | |
Merge "Deprecate boolean settings for haptic feedback and vibrate when ringing"
22 files changed, 162 insertions, 196 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 3234e162e5fa..83abc07751c5 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -36231,7 +36231,7 @@ package android.provider { field public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone"; field public static final String END_BUTTON_BEHAVIOR = "end_button_behavior"; field public static final String FONT_SCALE = "font_scale"; - field public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled"; + field @Deprecated public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled"; field @Deprecated public static final String HTTP_PROXY = "http_proxy"; field @Deprecated public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; field @Deprecated public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed"; @@ -36275,7 +36275,7 @@ package android.provider { field public static final String USER_ROTATION = "user_rotation"; field @Deprecated public static final String USE_GOOGLE_MAIL = "use_google_mail"; field public static final String VIBRATE_ON = "vibrate_on"; - field public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing"; + field @Deprecated public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing"; field @Deprecated public static final String WAIT_FOR_DEBUGGER = "wait_for_debugger"; field @Deprecated public static final String WALLPAPER_ACTIVITY = "wallpaper_activity"; field @Deprecated public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"; @@ -48473,7 +48473,7 @@ 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 FLAG_IGNORE_GLOBAL_SETTING = 2; // 0x2 + 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 diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java index 8834725cc3e9..8bc219b7dc57 100644 --- a/core/java/android/os/VibrationAttributes.java +++ b/core/java/android/os/VibrationAttributes.java @@ -136,6 +136,7 @@ public final class VibrationAttributes implements Parcelable { */ @IntDef(prefix = { "FLAG_" }, flag = true, value = { FLAG_BYPASS_INTERRUPTION_POLICY, + FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF }) @Retention(RetentionPolicy.SOURCE) public @interface Flag{} @@ -146,10 +147,22 @@ public final class VibrationAttributes implements Parcelable { public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1; /** + * Flag requesting vibration effect to be played even when user settings are disabling it. + * + * <p>Flag introduced to represent + * {@link android.view.HapticFeedbackConstants#FLAG_IGNORE_GLOBAL_SETTING} and + * {@link AudioAttributes#FLAG_BYPASS_MUTE}. + * + * @hide + */ + public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 0x2; + + /** * All flags supported by vibrator service, update it when adding new flag. * @hide */ - public static final int FLAG_ALL_SUPPORTED = FLAG_BYPASS_INTERRUPTION_POLICY; + public static final int FLAG_ALL_SUPPORTED = + FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF; /** Creates a new {@link VibrationAttributes} instance with given usage. */ public static @NonNull VibrationAttributes createForUsage(int usage) { @@ -397,6 +410,11 @@ public final class VibrationAttributes implements Parcelable { if ((audio.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { mFlags |= FLAG_BYPASS_INTERRUPTION_POLICY; } + if ((audio.getAllFlags() & AudioAttributes.FLAG_BYPASS_MUTE) != 0) { + // Muted audio stream translates to vibration usage having the value + // Vibrator.VIBRATION_INTENSITY_OFF set in the user setting. + mFlags |= FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF; + } } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5cdb1fdf64ce..a50f38e73136 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5120,7 +5120,12 @@ public final class Settings { * It was about AudioManager's setting and thus affected all the applications which * relied on the setting, while this is purely about the vibration setting for incoming * calls. + * + * @deprecated Replaced by using {@link android.os.VibrationAttributes#USAGE_RINGTONE} on + * vibrations for incoming calls. User settings are applied automatically by the service and + * should not be applied by individual apps. */ + @Deprecated @Readable public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing"; @@ -5181,7 +5186,12 @@ public final class Settings { /** * Whether haptic feedback (Vibrate on tap) is enabled. The value is * boolean (1 or 0). + * + * @deprecated Replaced by using {@link android.os.VibrationAttributes#USAGE_TOUCH} on + * vibrations. User settings are applied automatically by the service and should not be + * applied by individual apps. */ + @Deprecated @Readable public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled"; diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java index c5bc99d042d7..45b65e551305 100644 --- a/core/java/android/view/HapticFeedbackConstants.java +++ b/core/java/android/view/HapticFeedbackConstants.java @@ -177,6 +177,10 @@ public class HapticFeedbackConstants { * Flag for {@link View#performHapticFeedback(int, int) * View.performHapticFeedback(int, int)}: Ignore the global setting * for whether to perform haptic feedback, do it always. + * + * @deprecated Starting from {@link android.os.Build.VERSION_CODES#TIRAMISU} only privileged + * apps can ignore user settings for touch feedback. */ + @Deprecated public static final int FLAG_IGNORE_GLOBAL_SETTING = 0x0002; } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index f91776eaf259..f8ccde4cf4d9 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1028,15 +1028,6 @@ public class LockPatternUtils { } /** - * @return Whether tactile feedback for the pattern is enabled. - */ - @UnsupportedAppUsage - public boolean isTactileFeedbackEnabled() { - return Settings.System.getIntForUser(mContentResolver, - Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0; - } - - /** * Set and store the lockout deadline, meaning the user can't attempt their unlock * pattern until the deadline has passed. * @return the chosen deadline. diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 3994fbdca2df..2b6b933c6886 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -139,7 +139,6 @@ public class LockPatternView extends View { private boolean mInputEnabled = true; @UnsupportedAppUsage private boolean mInStealthMode = false; - private boolean mEnableHapticFeedback = true; @UnsupportedAppUsage private boolean mPatternInProgress = false; private boolean mFadePattern = true; @@ -401,13 +400,6 @@ public class LockPatternView extends View { } /** - * @return Whether the view has tactile feedback enabled. - */ - public boolean isTactileFeedbackEnabled() { - return mEnableHapticFeedback; - } - - /** * Set whether the view is in stealth mode. If true, there will be no * visible feedback as the user enters the pattern. * @@ -427,17 +419,6 @@ public class LockPatternView extends View { } /** - * Set whether the view will use tactile feedback. If true, there will be - * tactile feedback as the user enters the pattern. - * - * @param tactileFeedbackEnabled Whether tactile feedback is enabled - */ - @UnsupportedAppUsage - public void setTactileFeedbackEnabled(boolean tactileFeedbackEnabled) { - mEnableHapticFeedback = tactileFeedbackEnabled; - } - - /** * Set the call back for pattern detection. * @param onPatternListener The call back. */ @@ -783,11 +764,9 @@ public class LockPatternView extends View { addCellToPattern(fillInGapCell); } addCellToPattern(cell); - if (mEnableHapticFeedback) { - performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING - | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } + performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING + | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); return cell; } return null; @@ -1462,7 +1441,7 @@ public class LockPatternView extends View { return new SavedState(superState, patternString, mPatternDisplayMode.ordinal(), - mInputEnabled, mInStealthMode, mEnableHapticFeedback); + mInputEnabled, mInStealthMode); } @Override @@ -1475,7 +1454,6 @@ public class LockPatternView extends View { mPatternDisplayMode = DisplayMode.values()[ss.getDisplayMode()]; mInputEnabled = ss.isInputEnabled(); mInStealthMode = ss.isInStealthMode(); - mEnableHapticFeedback = ss.isTactileFeedbackEnabled(); } /** @@ -1487,20 +1465,18 @@ public class LockPatternView extends View { private final int mDisplayMode; private final boolean mInputEnabled; private final boolean mInStealthMode; - private final boolean mTactileFeedbackEnabled; /** * Constructor called from {@link LockPatternView#onSaveInstanceState()} */ @UnsupportedAppUsage private SavedState(Parcelable superState, String serializedPattern, int displayMode, - boolean inputEnabled, boolean inStealthMode, boolean tactileFeedbackEnabled) { + boolean inputEnabled, boolean inStealthMode) { super(superState); mSerializedPattern = serializedPattern; mDisplayMode = displayMode; mInputEnabled = inputEnabled; mInStealthMode = inStealthMode; - mTactileFeedbackEnabled = tactileFeedbackEnabled; } /** @@ -1513,7 +1489,6 @@ public class LockPatternView extends View { mDisplayMode = in.readInt(); mInputEnabled = (Boolean) in.readValue(null); mInStealthMode = (Boolean) in.readValue(null); - mTactileFeedbackEnabled = (Boolean) in.readValue(null); } public String getSerializedPattern() { @@ -1532,10 +1507,6 @@ public class LockPatternView extends View { return mInStealthMode; } - public boolean isTactileFeedbackEnabled(){ - return mTactileFeedbackEnabled; - } - @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); @@ -1543,7 +1514,6 @@ public class LockPatternView extends View { dest.writeInt(mDisplayMode); dest.writeValue(mInputEnabled); dest.writeValue(mInStealthMode); - dest.writeValue(mTactileFeedbackEnabled); } @SuppressWarnings({ "unused", "hiding" }) // Found using reflection diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java index 5e6f3a46de7d..11566d9a026d 100644 --- a/core/java/com/android/internal/widget/SlidingTab.java +++ b/core/java/com/android/internal/widget/SlidingTab.java @@ -22,10 +22,9 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.media.AudioAttributes; -import android.os.UserHandle; +import android.os.VibrationAttributes; +import android.os.VibrationEffect; import android.os.Vibrator; -import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; @@ -68,10 +67,8 @@ public class SlidingTab extends ViewGroup { private boolean mHoldLeftOnTransition = true; private boolean mHoldRightOnTransition = true; - private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) - .build(); + private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES = + VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH); private OnTriggerListener mOnTriggerListener; private int mGrabbedState = OnTriggerListener.NO_HANDLE; @@ -834,16 +831,12 @@ public class SlidingTab extends ViewGroup { * Triggers haptic feedback. */ private synchronized void vibrate(long duration) { - final boolean hapticEnabled = Settings.System.getIntForUser( - mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, - UserHandle.USER_CURRENT) != 0; - if (hapticEnabled) { - if (mVibrator == null) { - mVibrator = (android.os.Vibrator) getContext() - .getSystemService(Context.VIBRATOR_SERVICE); - } - mVibrator.vibrate(duration, VIBRATION_ATTRIBUTES); + if (mVibrator == null) { + mVibrator = getContext().getSystemService(Vibrator.class); } + mVibrator.vibrate( + VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE), + TOUCH_VIBRATION_ATTRIBUTES); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt index 9e012598554b..aac1d0626d30 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt @@ -17,13 +17,10 @@ package com.android.wm.shell.common.magnetictarget import android.annotation.SuppressLint import android.content.Context -import android.database.ContentObserver import android.graphics.PointF -import android.os.Handler -import android.os.UserHandle +import android.os.VibrationAttributes import android.os.VibrationEffect import android.os.Vibrator -import android.provider.Settings import android.view.MotionEvent import android.view.VelocityTracker import android.view.View @@ -147,6 +144,8 @@ abstract class MagnetizedObject<T : Any>( private val velocityTracker: VelocityTracker = VelocityTracker.obtain() private val vibrator: Vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator + private val vibrationAttributes: VibrationAttributes = VibrationAttributes.createForUsage( + VibrationAttributes.USAGE_TOUCH) private var touchDown = PointF() private var touchSlop = 0 @@ -268,10 +267,6 @@ abstract class MagnetizedObject<T : Any>( */ var flungIntoTargetSpringConfig = springConfig - init { - initHapticSettingObserver(context) - } - /** * Adds the provided MagneticTarget to this object. The object will now be attracted to the * target if it strays within its magnetic field or is flung towards it. @@ -468,8 +463,8 @@ abstract class MagnetizedObject<T : Any>( /** Plays the given vibration effect if haptics are enabled. */ @SuppressLint("MissingPermission") private fun vibrateIfEnabled(effectId: Int) { - if (hapticsEnabled && systemHapticsEnabled) { - vibrator.vibrate(VibrationEffect.createPredefined(effectId)) + if (hapticsEnabled) { + vibrator.vibrate(VibrationEffect.createPredefined(effectId), vibrationAttributes) } } @@ -622,44 +617,6 @@ abstract class MagnetizedObject<T : Any>( } companion object { - - /** - * Whether the HAPTIC_FEEDBACK_ENABLED setting is true. - * - * We put it in the companion object because we need to register a settings observer and - * [MagnetizedObject] doesn't have an obvious lifecycle so we don't have a good time to - * remove that observer. Since this settings is shared among all instances we just let all - * instances read from this value. - */ - private var systemHapticsEnabled = false - private var hapticSettingObserverInitialized = false - - private fun initHapticSettingObserver(context: Context) { - if (hapticSettingObserverInitialized) { - return - } - - val hapticSettingObserver = - object : ContentObserver(Handler.getMain()) { - override fun onChange(selfChange: Boolean) { - systemHapticsEnabled = - Settings.System.getIntForUser( - context.contentResolver, - Settings.System.HAPTIC_FEEDBACK_ENABLED, - 0, - UserHandle.USER_CURRENT) != 0 - } - } - - context.contentResolver.registerContentObserver( - Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), - true /* notifyForDescendants */, hapticSettingObserver) - - // Trigger the observer once to initialize systemHapticsEnabled. - hapticSettingObserver.onChange(false /* selfChange */) - hapticSettingObserverInitialized = true - } - /** * Magnetizes the given view. Magnetized views are attracted to one or more magnetic * targets. Magnetic targets attract objects that are dragged near them, and hold them there diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index cc6df45c598f..d02b8752469a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -30,7 +30,6 @@ import com.android.systemui.R; */ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView { protected View mEcaView; - protected boolean mEnableHaptics; // To avoid accidental lockout due to events while the device in in the pocket, ignore // any passwords with length less than or equal to this length. @@ -45,10 +44,6 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView { super(context, attrs); } - void setEnableHaptics(boolean enableHaptics) { - mEnableHaptics = enableHaptics; - } - protected abstract int getPasswordTextViewId(); protected abstract void resetState(); @@ -80,11 +75,9 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView { // Cause a VIRTUAL_KEY vibration public void doHapticKeyClick() { - if (mEnableHaptics) { - performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING - | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } + performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING + | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } public void setKeyDownListener(KeyDownListener keyDownListener) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 1c4559eb0364..f86d08de87fc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -98,7 +98,6 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey protected void onViewAttached() { super.onViewAttached(); mView.setKeyDownListener(mKeyDownListener); - mView.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled()); mEmergencyButtonController.setEmergencyButtonCallback(mEmergencyButtonCallback); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 94e07b713915..238acd5db621 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -224,8 +224,6 @@ public class KeyguardPatternViewController mLockPatternView.setSaveEnabled(false); mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled( KeyguardUpdateMonitor.getCurrentUser())); - // vibrate mode will be the same for the life of this screen - mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); mLockPatternView.setOnTouchListener((v, event) -> { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { mFalsingCollector.avoidGesture(); diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java index e79ea9a44843..a5a3f80d07b9 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java @@ -213,10 +213,8 @@ public class NumPadKey extends ViewGroup { // Cause a VIRTUAL_KEY vibration public void doHapticKeyClick() { - if (mLockPatternUtils.isTactileFeedbackEnabled()) { - performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING - | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } + performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING + | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java index ab8162f9464d..11498dbc0b83 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java @@ -107,6 +107,5 @@ public class AuthCredentialPatternView extends AuthCredentialView { mLockPatternView.setOnPatternListener(new UnlockPatternListener()); mLockPatternView.setInStealthMode( !mLockPatternUtils.isVisiblePatternEnabled(mUserId)); - mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java index ea90bdd940a7..6c3a9093fa98 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java @@ -17,14 +17,10 @@ package com.android.systemui.statusbar; import android.content.Context; -import android.database.ContentObserver; -import android.media.AudioAttributes; import android.os.AsyncTask; -import android.os.Handler; -import android.os.UserHandle; +import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; -import android.provider.Settings; import com.android.systemui.dagger.SysUISingleton; @@ -37,19 +33,8 @@ public class VibratorHelper { private final Vibrator mVibrator; private final Context mContext; - private boolean mHapticFeedbackEnabled; - private static final AudioAttributes STATUS_BAR_VIBRATION_ATTRIBUTES = - new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) - .build(); - - final private ContentObserver mVibrationObserver = new ContentObserver(Handler.getMain()) { - @Override - public void onChange(boolean selfChange) { - updateHapticFeedBackEnabled(); - } - }; + private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES = + VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH); /** */ @@ -57,23 +42,11 @@ public class VibratorHelper { public VibratorHelper(Context context) { mContext = context; mVibrator = context.getSystemService(Vibrator.class); - - mContext.getContentResolver().registerContentObserver( - Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), true, - mVibrationObserver); - mVibrationObserver.onChange(false /* selfChange */); } public void vibrate(final int effectId) { - if (mHapticFeedbackEnabled) { - AsyncTask.execute(() -> - mVibrator.vibrate(VibrationEffect.get(effectId, false /* fallback */), - STATUS_BAR_VIBRATION_ATTRIBUTES)); - } - } - - private void updateHapticFeedBackEnabled() { - mHapticFeedbackEnabled = Settings.System.getIntForUser(mContext.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) != 0; + AsyncTask.execute(() -> + mVibrator.vibrate(VibrationEffect.get(effectId, false /* fallback */), + TOUCH_VIBRATION_ATTRIBUTES)); } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 57ae36ed906b..0ea936e35a37 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4384,12 +4384,6 @@ public class AudioService extends IAudioService.Stub if (!mHasVibrator) { return false; } - final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0; - if (hapticsDisabled) { - return false; - } - if (effect == null) { return false; } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 28f65cf6d1a0..7dd942507a16 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5401,18 +5401,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!mVibrator.hasVibrator()) { return false; } - final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0; - if (hapticsDisabled && !always) { - return false; - } - VibrationEffect effect = getVibrationEffect(effectId); if (effect == null) { return false; } - - mVibrator.vibrate(uid, packageName, effect, reason, getVibrationAttributes(effectId)); + VibrationAttributes attrs = getVibrationAttributes(effectId); + if (always) { + attrs = new VibrationAttributes.Builder(attrs) + .setFlags(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF, + VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF) + .build(); + } + mVibrator.vibrate(uid, packageName, effect, reason, attrs); return true; } diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java index f481772d7a7f..a528f063e875 100644 --- a/services/core/java/com/android/server/vibrator/VibrationScaler.java +++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java @@ -74,6 +74,12 @@ final class VibrationScaler { public int getExternalVibrationScale(int usageHint) { int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint); int currentIntensity = mSettingsController.getCurrentIntensity(usageHint); + + if (currentIntensity == Vibrator.VIBRATION_INTENSITY_OFF) { + // Bypassing user settings, or it has changed between checking and scaling. Use default. + return SCALE_NONE; + } + int scaleLevel = currentIntensity - defaultIntensity; if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) { @@ -97,6 +103,12 @@ final class VibrationScaler { public <T extends VibrationEffect> T scale(VibrationEffect effect, int usageHint) { int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint); int currentIntensity = mSettingsController.getCurrentIntensity(usageHint); + + if (currentIntensity == Vibrator.VIBRATION_INTENSITY_OFF) { + // Bypassing user settings, or it has changed between checking and scaling. Use default. + currentIntensity = defaultIntensity; + } + int newEffectStrength = intensityToEffectStrength(currentIntensity); effect = effect.applyEffectStrength(newEffectStrength).resolve(mDefaultVibrationAmplitude); ScaleLevel scale = mScaleLevels.get(currentIntensity - defaultIntensity); @@ -121,6 +133,12 @@ final class VibrationScaler { */ public PrebakedSegment scale(PrebakedSegment prebaked, int usageHint) { int currentIntensity = mSettingsController.getCurrentIntensity(usageHint); + + if (currentIntensity == Vibrator.VIBRATION_INTENSITY_OFF) { + // Bypassing user settings, or it has changed between checking and scaling. Use default. + currentIntensity = mSettingsController.getDefaultIntensity(usageHint); + } + int newEffectStrength = intensityToEffectStrength(currentIntensity); return prebaked.applyEffectStrength(newEffectStrength); } diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java index df6ffa2bd009..c54d490b5162 100644 --- a/services/core/java/com/android/server/vibrator/VibrationSettings.java +++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java @@ -315,7 +315,9 @@ final class VibrationSettings { } int intensity = getCurrentIntensity(usage); - if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { + if ((intensity == Vibrator.VIBRATION_INTENSITY_OFF) + && !attrs.isFlagSet( + VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)) { return Vibration.Status.IGNORED_FOR_SETTINGS; } diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index 27566b301a6e..a95b6c955d63 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -80,6 +80,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private static final boolean DEBUG = false; private static final VibrationAttributes DEFAULT_ATTRIBUTES = new VibrationAttributes.Builder().build(); + private static final int ATTRIBUTES_ALL_BYPASS_FLAGS = + VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY + | VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF; /** Lifecycle responsible for initializing this class at the right system server phases. */ public static class Lifecycle extends SystemService { @@ -975,12 +978,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { usage = VibrationAttributes.USAGE_TOUCH; } int flags = attrs.getFlags(); - if (attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)) { + if ((flags & ATTRIBUTES_ALL_BYPASS_FLAGS) != 0) { if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE) || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) { - // Remove bypass policy flag from attributes if the app does not have permissions. - flags &= ~VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; + // Remove bypass flags from attributes if the app does not have permissions. + flags &= ~ATTRIBUTES_ALL_BYPASS_FLAGS; } } if ((usage == attrs.getUsage()) && (flags == attrs.getFlags())) { diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java index 6369dbc6b171..81677101c139 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java @@ -133,13 +133,14 @@ public class VibrationScalerTest { mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); - // Unexpected vibration intensity will be treated as SCALE_NONE. + // Vibration setting being bypassed will use default setting and not scale. assertEquals(IExternalVibratorService.SCALE_NONE, mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); } @Test public void scale_withPrebakedSegment_setsEffectStrengthBasedOnSettings() { + setDefaultIntensity(USAGE_NOTIFICATION, VIBRATION_INTENSITY_MEDIUM); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH); PrebakedSegment effect = new PrebakedSegment(VibrationEffect.EFFECT_CLICK, /* shouldFallback= */ false, VibrationEffect.EFFECT_STRENGTH_MEDIUM); @@ -158,35 +159,33 @@ public class VibrationScalerTest { setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); scaled = mVibrationScaler.scale(effect, USAGE_NOTIFICATION); - // Unexpected intensity setting will be mapped to STRONG. - assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG); + // Vibration setting being bypassed will use default setting. + assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_MEDIUM); } @Test public void scale_withPrebakedEffect_setsEffectStrengthBasedOnSettings() { + setDefaultIntensity(USAGE_NOTIFICATION, VIBRATION_INTENSITY_LOW); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH); VibrationEffect effect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK); - PrebakedSegment scaled = getFirstSegment(mVibrationScaler.scale( - effect, USAGE_NOTIFICATION)); + PrebakedSegment scaled = + getFirstSegment(mVibrationScaler.scale(effect, USAGE_NOTIFICATION)); assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_MEDIUM); - scaled = getFirstSegment(mVibrationScaler.scale( - effect, USAGE_NOTIFICATION)); + scaled = getFirstSegment(mVibrationScaler.scale(effect, USAGE_NOTIFICATION)); assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_MEDIUM); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); - scaled = getFirstSegment(mVibrationScaler.scale( - effect, USAGE_NOTIFICATION)); + scaled = getFirstSegment(mVibrationScaler.scale(effect, USAGE_NOTIFICATION)); assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_LIGHT); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); - scaled = getFirstSegment(mVibrationScaler.scale( - effect, USAGE_NOTIFICATION)); - // Unexpected intensity setting will be mapped to STRONG. - assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG); + scaled = getFirstSegment(mVibrationScaler.scale(effect, USAGE_NOTIFICATION)); + // Vibration setting being bypassed will use default setting. + assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_LIGHT); } @Test diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java index ff59d0f22c3c..2c22419d1372 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java @@ -330,6 +330,8 @@ public class VibrationSettingsTest { } else { assertVibrationNotIgnoredForUsage(usage); } + assertVibrationNotIgnoredForUsageAndFlags(usage, + VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF); } } @@ -363,6 +365,8 @@ public class VibrationSettingsTest { } else { assertVibrationNotIgnoredForUsage(usage); } + assertVibrationNotIgnoredForUsageAndFlags(usage, + VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF); } } @@ -376,6 +380,8 @@ public class VibrationSettingsTest { } else { assertVibrationNotIgnoredForUsage(usage); } + assertVibrationNotIgnoredForUsageAndFlags(usage, + VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF); } } @@ -389,6 +395,8 @@ public class VibrationSettingsTest { } else { assertVibrationNotIgnoredForUsage(usage); } + assertVibrationNotIgnoredForUsageAndFlags(usage, + VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF); } } @@ -402,6 +410,8 @@ public class VibrationSettingsTest { } else { assertVibrationNotIgnoredForUsage(usage); } + assertVibrationNotIgnoredForUsageAndFlags(usage, + VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF); } } @@ -419,6 +429,8 @@ public class VibrationSettingsTest { } else { assertVibrationNotIgnoredForUsage(usage); } + assertVibrationNotIgnoredForUsageAndFlags(usage, + VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF); } } @@ -522,9 +534,17 @@ public class VibrationSettingsTest { } private void assertVibrationNotIgnoredForUsage(@VibrationAttributes.Usage int usage) { + assertVibrationNotIgnoredForUsageAndFlags(usage, /* flags= */ 0); + } + + private void assertVibrationNotIgnoredForUsageAndFlags(@VibrationAttributes.Usage int usage, + @VibrationAttributes.Flag int flags) { assertNull(errorMessageForUsage(usage), mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(usage))); + new VibrationAttributes.Builder() + .setUsage(usage) + .setFlags(flags, VibrationAttributes.FLAG_ALL_SUPPORTED) + .build())); } private String errorMessageForUsage(int usage) { diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index b0bdaf084b1a..ab86e295e28a 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -1207,6 +1207,33 @@ public class VibratorManagerServiceTest { assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); } + @Test + public void onExternalVibration_withBypassMuteAudioFlag_ignoresUserSettings() { + mockVibrators(1); + mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL); + setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY, + Vibrator.VIBRATION_INTENSITY_OFF); + AudioAttributes audioAttrs = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .build(); + AudioAttributes flaggedAudioAttrs = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_ALARM) + .setFlags(AudioAttributes.FLAG_BYPASS_MUTE) + .build(); + createSystemReadyService(); + + int scale = mExternalVibratorService.onExternalVibrationStart( + new ExternalVibration(UID, PACKAGE_NAME, audioAttrs, + mock(IExternalVibrationController.class))); + assertEquals(IExternalVibratorService.SCALE_MUTE, scale); + + createSystemReadyService(); + scale = mExternalVibratorService.onExternalVibrationStart( + new ExternalVibration(UID, PACKAGE_NAME, flaggedAudioAttrs, + mock(IExternalVibrationController.class))); + assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); + } + private VibrationEffectSegment expectedPrebaked(int effectId) { return new PrebakedSegment(effectId, false, VibrationEffect.EFFECT_STRENGTH_MEDIUM); } |