Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 34070be4 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix external vibration behavior on system update" into main

parents e2820723 5c00c97a
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -155,3 +155,13 @@ flag {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
    namespace: "haptics"
    name: "fix_external_vibration_system_update_aware"
    description: "Fix the audio-coupled haptics handling of system updates."
    bug: "372241975"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}
+26 −12
Original line number Diff line number Diff line
@@ -1015,9 +1015,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                updateAlwaysOnLocked(mAlwaysOnEffects.valueAt(i));
            }

            // TODO(b/372241975): investigate why external vibrations were not handled here before
            if (mCurrentSession == null
                    || (mCurrentSession instanceof ExternalVibrationSession)) {
            if (mCurrentSession == null) {
                return;
            }

            if (!Flags.fixExternalVibrationSystemUpdateAware()
                    && (mCurrentSession instanceof ExternalVibrationSession)) {
                return;
            }

@@ -1025,7 +1028,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            if (inputDevicesChanged || (ignoreStatus != null)) {
                if (DEBUG) {
                    Slog.d(TAG, "Canceling vibration because settings changed: "
                            + (inputDevicesChanged ? "input devices changed" : ignoreStatus));
                            + (ignoreStatus == null ? "input devices changed" : ignoreStatus));
                }
                mCurrentSession.requestEnd(Status.CANCELLED_BY_SETTINGS_UPDATE);
            }
@@ -2334,7 +2337,14 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
    @GuardedBy("mLock")
    private void maybeClearCurrentAndNextSessionsLocked(
            Predicate<VibrationSession> shouldEndSessionPredicate, Status endStatus) {
        // TODO(b/372241975): investigate why external vibrations were not handled here before
        if (Flags.fixExternalVibrationSystemUpdateAware()) {
            if (shouldEndSessionPredicate.test(mNextSession)) {
                clearNextSessionLocked(endStatus);
            }
            if (shouldEndSessionPredicate.test(mCurrentSession)) {
                mCurrentSession.requestEnd(endStatus);
            }
        } else {
            if (!(mNextSession instanceof ExternalVibrationSession)
                    && shouldEndSessionPredicate.test(mNextSession)) {
                clearNextSessionLocked(endStatus);
@@ -2344,6 +2354,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                mCurrentSession.requestEnd(endStatus);
            }
        }
    }

    /**
     * Waits until the current vibration finished processing, timing out after the given
@@ -2535,6 +2546,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                            Slog.d(TAG, "Stopping external vibration: " + vib);
                        }
                        mCurrentSession.requestEnd(Status.FINISHED);
                    } else if (Build.IS_DEBUGGABLE) {
                        Slog.wtf(TAG, "VibrationSession invalid on external vibration stop."
                                + " currentSession=" + mCurrentSession + ", received=" + vib);
                    }
                }
            } finally {
+127 −6
Original line number Diff line number Diff line
@@ -147,6 +147,9 @@ public class VibratorManagerServiceTest {
            new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ALARM).build();
    private static final AudioAttributes AUDIO_NOTIFICATION_ATTRS =
            new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build();
    private static final AudioAttributes AUDIO_HAPTIC_FEEDBACK_ATTRS =
            new AudioAttributes.Builder().setUsage(
                    AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).build();
    private static final VibrationAttributes ALARM_ATTRS =
            new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_ALARM).build();
    private static final VibrationAttributes HAPTIC_FEEDBACK_ATTRS =
@@ -2674,7 +2677,8 @@ public class VibratorManagerServiceTest {
    }

    @Test
    public void onExternalVibration_thenDeniedAppOps_doNotCancelVibration() throws Throwable {
    @DisableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_legacyDeniedAppOps_doNotCancelVibration() throws Throwable {
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        VibratorManagerService service = createSystemReadyService();
@@ -2697,10 +2701,11 @@ public class VibratorManagerServiceTest {
    }

    @Test
    public void onExternalVibration_thenPowerModeChanges_doNotCancelVibration() throws Exception {
    @EnableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_thenDeniedAppOps_cancelVibration() throws Throwable {
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        createSystemReadyService();
        VibratorManagerService service = createSystemReadyService();

        IExternalVibrationController externalVibrationControllerMock =
                mock(IExternalVibrationController.class);
@@ -2711,13 +2716,59 @@ public class VibratorManagerServiceTest {

        assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);

        when(mAppOpsManagerMock.checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
                eq(AudioAttributes.USAGE_ALARM), anyInt(), anyString()))
                .thenReturn(AppOpsManager.MODE_IGNORED);
        service.mAppOpsChangeListener.onOpChanged(AppOpsManager.OP_VIBRATE, null);

        verify(externalVibrationControllerMock).mute();
    }

    @Test
    @DisableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_legacyPowerModeChanges_doNotCancelVibration() throws Exception {
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        createSystemReadyService();

        IExternalVibrationController externalVibrationControllerMock =
                mock(IExternalVibrationController.class);
        ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                AUDIO_HAPTIC_FEEDBACK_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
        ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
                externalVibration);

        assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);

        mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);

        verify(externalVibrationControllerMock, never()).mute();
    }

    @Test
    public void onExternalVibration_thenSettingsChange_doNotCancelVibration() throws Exception {
    @EnableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_thenPowerModeChanges_cancelVibration() throws Exception {
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        createSystemReadyService();

        IExternalVibrationController externalVibrationControllerMock =
                mock(IExternalVibrationController.class);
        ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                AUDIO_HAPTIC_FEEDBACK_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
        ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
                externalVibration);

        assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);

        mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);

        verify(externalVibrationControllerMock).mute();
    }

    @Test
    @DisableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_legacySettingsChange_doNotCancelVibration() throws Exception {
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        VibratorManagerService service = createSystemReadyService();
@@ -2739,7 +2790,31 @@ public class VibratorManagerServiceTest {
    }

    @Test
    public void onExternalVibration_thenScreenTurnsOff_doNotCancelVibration() throws Throwable {
    @EnableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_thenSettingsChange_cancelVibration() throws Exception {
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        VibratorManagerService service = createSystemReadyService();

        IExternalVibrationController externalVibrationControllerMock =
                mock(IExternalVibrationController.class);
        ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                AUDIO_ALARM_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
        ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
                externalVibration);

        assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);

        setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF);
        service.mVibrationSettings.mSettingObserver.onChange(false);
        service.updateServiceState();

        verify(externalVibrationControllerMock).mute();
    }

    @Test
    @DisableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_legacyScreenTurnsOff_doNotCancelVibration() throws Exception {
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        VibratorManagerService service = createSystemReadyService();
@@ -2759,7 +2834,30 @@ public class VibratorManagerServiceTest {
    }

    @Test
    public void onExternalVibration_thenFgUserRequestsMute_doNotCancelVibration() throws Throwable {
    @EnableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_thenScreenTurnsOff_cancelVibration() throws Exception {
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        VibratorManagerService service = createSystemReadyService();

        IExternalVibrationController externalVibrationControllerMock =
                mock(IExternalVibrationController.class);
        ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                AUDIO_ALARM_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
        ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
                externalVibration);

        assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);

        service.mIntentReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_SCREEN_OFF));

        verify(externalVibrationControllerMock).mute();
    }

    @Test
    @DisableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_legacyFgUserRequestsMute_doNotCancelVibration()
            throws Exception {
        assumeTrue(UserManagerInternal.shouldShowNotificationForBackgroundUserSounds());
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
@@ -2780,6 +2878,29 @@ public class VibratorManagerServiceTest {
        verify(externalVibrationControllerMock, never()).mute();
    }

    @Test
    @EnableFlags(android.os.vibrator.Flags.FLAG_FIX_EXTERNAL_VIBRATION_SYSTEM_UPDATE_AWARE)
    public void onExternalVibration_thenFgUserRequestsMute_cancelVibration() throws Exception {
        assumeTrue(UserManagerInternal.shouldShowNotificationForBackgroundUserSounds());
        mockVibrators(1);
        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
        VibratorManagerService service = createSystemReadyService();

        IExternalVibrationController externalVibrationControllerMock =
                mock(IExternalVibrationController.class);
        ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                AUDIO_ALARM_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
        ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
                externalVibration);

        assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);

        service.mIntentReceiver.onReceive(mContextSpy, new Intent(
                BackgroundUserSoundNotifier.ACTION_MUTE_SOUND));

        verify(externalVibrationControllerMock).mute();
    }

    @Test
    @DisableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
    public void startVibrationSession_withoutFeatureFlag_throwsException() throws Exception {