Resolve vibration effect default amplitude when scale is bypassed
Fix vibrator manager service to still apply the device default amplitude
when the requested vibration is bypassing scale.
Bug: 325204954
Test: atest VibratorManagerServiceTest
Change-Id: I5285a046a79686fad0fafafdf11e4c3a66e60b93
diff --git a/services/core/java/com/android/server/vibrator/HalVibration.java b/services/core/java/com/android/server/vibrator/HalVibration.java
index 743d02d..70e2e27 100644
--- a/services/core/java/com/android/server/vibrator/HalVibration.java
+++ b/services/core/java/com/android/server/vibrator/HalVibration.java
@@ -102,6 +102,23 @@
}
/**
+ * Resolves the default vibration amplitude of {@link #getEffectToPlay()} and each fallback.
+ *
+ * @param defaultAmplitude An integer in [1,255] representing the device default amplitude to
+ * replace the {@link VibrationEffect#DEFAULT_AMPLITUDE}.
+ */
+ public void resolveEffects(int defaultAmplitude) {
+ CombinedVibration newEffect =
+ mEffectToPlay.transform(VibrationEffect::resolve, defaultAmplitude);
+ if (!Objects.equals(mEffectToPlay, newEffect)) {
+ mEffectToPlay = newEffect;
+ }
+ for (int i = 0; i < mFallbacks.size(); i++) {
+ mFallbacks.setValueAt(i, mFallbacks.valueAt(i).resolve(defaultAmplitude));
+ }
+ }
+
+ /**
* Scales the {@link #getEffectToPlay()} and each fallback effect with a scaling transformation.
*
* @param scaler A {@link VibrationEffect.Transformation<Integer>} that takes one of the
diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java
index c9805c7..ceeed7a 100644
--- a/services/core/java/com/android/server/vibrator/VibrationScaler.java
+++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java
@@ -73,6 +73,13 @@
}
/**
+ * Returns the default vibration amplitude configured for this device, value in [1,255].
+ */
+ public int getDefaultVibrationAmplitude() {
+ return mDefaultVibrationAmplitude;
+ }
+
+ /**
* Calculates the scale to be applied to external vibration with given usage.
*
* @param usageHint one of VibrationAttributes.USAGE_*
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index 9cf942e..f6af9ad 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -160,7 +160,10 @@
if (Flags.adaptiveHapticsEnabled()) {
waitForVibrationParamsIfRequired();
}
+ // Scale resolves the default amplitudes from the effect before scaling them.
mVibration.scaleEffects(mVibrationScaler::scale);
+ } else {
+ mVibration.resolveEffects(mVibrationScaler.getDefaultVibrationAmplitude());
}
mVibration.adaptToDevice(mDeviceAdapter);
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 759450b..bef4d63 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -883,8 +883,10 @@
private Vibration.EndInfo startVibrationOnInputDevicesLocked(HalVibration vib) {
if (!vib.callerInfo.attrs.isFlagSet(
VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)) {
- // Scale effect before dispatching it to the input devices.
+ // Scale resolves the default amplitudes from the effect before scaling them.
vib.scaleEffects(mVibrationScaler::scale);
+ } else {
+ vib.resolveEffects(mVibrationScaler.getDefaultVibrationAmplitude());
}
mInputDeviceDelegate.vibrateIfAvailable(vib.callerInfo, vib.getEffectToPlay());
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 7db707a..e7571ef 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -1421,6 +1421,7 @@
public void vibrate_withIntensitySettings_appliesSettingsToScaleVibrations() throws Exception {
int defaultNotificationIntensity =
mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_NOTIFICATION);
+ // This will scale up notification vibrations.
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
defaultNotificationIntensity < Vibrator.VIBRATION_INTENSITY_HIGH
? defaultNotificationIntensity + 1
@@ -1428,6 +1429,7 @@
int defaultTouchIntensity =
mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_TOUCH);
+ // This will scale down touch vibrations.
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
defaultTouchIntensity > Vibrator.VIBRATION_INTENSITY_LOW
? defaultTouchIntensity - 1
@@ -1482,6 +1484,42 @@
}
@Test
+ public void vibrate_withBypassScaleFlag_ignoresIntensitySettingsAndResolvesAmplitude()
+ throws Exception {
+ // Permission needed for bypassing user settings
+ grantPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
+
+ int defaultTouchIntensity =
+ mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_TOUCH);
+ // This will scale down touch vibrations.
+ setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+ defaultTouchIntensity > Vibrator.VIBRATION_INTENSITY_LOW
+ ? defaultTouchIntensity - 1
+ : defaultTouchIntensity);
+
+ int defaultAmplitude = mContextSpy.getResources().getInteger(
+ com.android.internal.R.integer.config_defaultVibrationAmplitude);
+
+ mockVibrators(1);
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+ fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+
+ vibrateAndWaitUntilFinished(service,
+ VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE),
+ new VibrationAttributes.Builder()
+ .setUsage(VibrationAttributes.USAGE_TOUCH)
+ .setFlags(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)
+ .build());
+
+ assertEquals(1, fakeVibrator.getAllEffectSegments().size());
+
+ assertEquals(defaultAmplitude / 255f, fakeVibrator.getAmplitudes().get(0), 1e-5);
+
+ cancelVibrate(service); // Clean up long-ish effect.
+ }
+
+ @Test
public void vibrate_withPowerModeChange_cancelVibrationIfNotAllowed() throws Exception {
mockVibrators(1, 2);
VibratorManagerService service = createSystemReadyService();
@@ -1879,6 +1917,9 @@
@Test
public void onExternalVibration_withBypassMuteAudioFlag_ignoresUserSettings() {
+ // Permission needed for bypassing user settings
+ grantPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
+
mockVibrators(1);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY,
@@ -1892,12 +1933,12 @@
.build();
createSystemReadyService();
- int scale = mExternalVibratorService.onExternalVibrationStart(
- new ExternalVibration(UID, PACKAGE_NAME, audioAttrs,
- mock(IExternalVibrationController.class)));
+ ExternalVibration vib = new ExternalVibration(UID, PACKAGE_NAME, audioAttrs,
+ mock(IExternalVibrationController.class));
+ int scale = mExternalVibratorService.onExternalVibrationStart(vib);
assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
- createSystemReadyService();
+ mExternalVibratorService.onExternalVibrationStop(vib);
scale = mExternalVibratorService.onExternalVibrationStart(
new ExternalVibration(UID, PACKAGE_NAME, flaggedAudioAttrs,
mock(IExternalVibrationController.class)));
@@ -1912,7 +1953,6 @@
Vibrator.VIBRATION_INTENSITY_OFF);
AudioAttributes flaggedAudioAttrs = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_UNKNOWN)
- .setFlags(AudioAttributes.FLAG_BYPASS_MUTE)
.build();
createSystemReadyService();