diff --git a/core/proto/android/server/vibrator/vibratormanagerservice.proto b/core/proto/android/server/vibrator/vibratormanagerservice.proto index fbe2170ea51c9..2f2158d4d5a0b 100644 --- a/core/proto/android/server/vibrator/vibratormanagerservice.proto +++ b/core/proto/android/server/vibrator/vibratormanagerservice.proto @@ -97,7 +97,7 @@ message VibrationProto { optional int32 status = 6; } -// Next id: 24 +// Next id: 25 message VibratorManagerServiceDumpProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; repeated int32 vibrator_ids = 1; @@ -106,6 +106,7 @@ message VibratorManagerServiceDumpProto { optional VibrationProto current_external_vibration = 4; optional bool vibrator_under_external_control = 5; optional bool low_power_mode = 6; + optional bool vibrate_on = 24; optional int32 alarm_intensity = 18; optional int32 alarm_default_intensity = 19; optional int32 haptic_feedback_intensity = 7; diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java index c54d490b51628..6c5d9520151bf 100644 --- a/services/core/java/com/android/server/vibrator/VibrationSettings.java +++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java @@ -97,6 +97,15 @@ final class VibrationSettings { USAGE_ALARM, USAGE_COMMUNICATION_REQUEST)); + /** + * Usage allowed for vibrations when {@link Settings.System#VIBRATE_ON} is disabled. + * + *

The only allowed usage is accessibility, which is applied when the user enables talkback. + * Other usages that must ignore this setting should use + * {@link VibrationAttributes#FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF}. + */ + private static final int VIBRATE_ON_DISABLED_USAGE_ALLOWED = USAGE_ACCESSIBILITY; + /** Listener for changes on vibration settings. */ interface OnVibratorSettingsChanged { /** Callback triggered when any of the vibrator settings change. */ @@ -127,6 +136,8 @@ final class VibrationSettings { private SparseIntArray mCurrentVibrationIntensities = new SparseIntArray(); @GuardedBy("mLock") private boolean mBatterySaverMode; + @GuardedBy("mLock") + private boolean mVibrateOn; VibrationSettings(Context context, Handler handler) { this(context, handler, new VibrationConfig(context.getResources())); @@ -199,6 +210,7 @@ final class VibrationSettings { // Listen to all settings that might affect the result of Vibrator.getVibrationIntensity. registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES)); + registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_ON)); registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING)); registerSettingsObserver(Settings.System.getUriFor(Settings.System.APPLY_RAMPING_RINGER)); registerSettingsObserver(Settings.System.getUriFor( @@ -314,11 +326,14 @@ final class VibrationSettings { return Vibration.Status.IGNORED_FOR_POWER; } - int intensity = getCurrentIntensity(usage); - if ((intensity == Vibrator.VIBRATION_INTENSITY_OFF) - && !attrs.isFlagSet( - VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)) { - return Vibration.Status.IGNORED_FOR_SETTINGS; + if (!attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)) { + if (!mVibrateOn && (VIBRATE_ON_DISABLED_USAGE_ALLOWED != usage)) { + return Vibration.Status.IGNORED_FOR_SETTINGS; + } + + if (getCurrentIntensity(usage) == Vibrator.VIBRATION_INTENSITY_OFF) { + return Vibration.Status.IGNORED_FOR_SETTINGS; + } } if (!shouldVibrateForRingerModeLocked(usage)) { @@ -357,6 +372,7 @@ final class VibrationSettings { void updateSettings() { synchronized (mLock) { mVibrateInputDevices = loadSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0; + mVibrateOn = loadSystemSetting(Settings.System.VIBRATE_ON, 1) > 0; int alarmIntensity = toIntensity( loadSystemSetting(Settings.System.ALARM_VIBRATION_INTENSITY, -1), @@ -437,8 +453,9 @@ final class VibrationSettings { + "mVibratorConfig=" + mVibrationConfig + ", mVibrateInputDevices=" + mVibrateInputDevices + ", mBatterySaverMode=" + mBatterySaverMode - + ", mProcStatesCache=" + mUidObserver.mProcStatesCache + + ", mVibrateOn=" + mVibrateOn + ", mVibrationIntensities=" + vibrationIntensitiesString + + ", mProcStatesCache=" + mUidObserver.mProcStatesCache + '}'; } } @@ -446,6 +463,8 @@ final class VibrationSettings { /** Write current settings into given {@link ProtoOutputStream}. */ public void dumpProto(ProtoOutputStream proto) { synchronized (mLock) { + proto.write(VibratorManagerServiceDumpProto.VIBRATE_ON, mVibrateOn); + proto.write(VibratorManagerServiceDumpProto.LOW_POWER_MODE, mBatterySaverMode); proto.write(VibratorManagerServiceDumpProto.ALARM_INTENSITY, getCurrentIntensity(USAGE_ALARM)); proto.write(VibratorManagerServiceDumpProto.ALARM_DEFAULT_INTENSITY, 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 2c22419d13728..5d4ffbb6aca25 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java @@ -319,6 +319,34 @@ public class VibrationSettingsTest { } } + + @Test + public void shouldIgnoreVibration_vibrateOnDisabled_ignoresUsagesNotAccessibility() { + setUserSetting(Settings.System.VIBRATE_ON, 0); + + for (int usage : ALL_USAGES) { + if (usage == USAGE_ACCESSIBILITY) { + assertVibrationNotIgnoredForUsage(usage); + } else { + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS); + } + assertVibrationNotIgnoredForUsageAndFlags(usage, + VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF); + } + } + + @Test + public void shouldIgnoreVibration_vibrateOnEnabledOrUnset_allowsAnyUsage() { + deleteUserSetting(Settings.System.VIBRATE_ON); + for (int usage : ALL_USAGES) { + assertVibrationNotIgnoredForUsage(usage); + } + + setUserSetting(Settings.System.VIBRATE_ON, 1); + for (int usage : ALL_USAGES) { + assertVibrationNotIgnoredForUsage(usage); + } + } @Test public void shouldIgnoreVibration_withRingSettingsOff_disableRingtoneVibrations() { setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0); @@ -560,10 +588,17 @@ public class VibrationSettingsTest { when(mVibrationConfigMock.getDefaultVibrationIntensity(eq(usage))).thenReturn(intensity); } + private void deleteUserSetting(String settingName) { + Settings.System.putStringForUser( + mContextSpy.getContentResolver(), settingName, null, UserHandle.USER_CURRENT); + // FakeSettingsProvider doesn't support testing triggering ContentObserver yet. + mVibrationSettings.updateSettings(); + } + private void setUserSetting(String settingName, int value) { Settings.System.putIntForUser( mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT); - // FakeSettingsProvider don't support testing triggering ContentObserver yet. + // FakeSettingsProvider doesn't support testing triggering ContentObserver yet. mVibrationSettings.updateSettings(); }