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();