Loading services/core/java/com/android/server/vibrator/AbstractVibratorStep.java +8 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,14 @@ abstract class AbstractVibratorStep extends Step { } protected void stopVibrating() { if (conductor.isInSession) { if (VibrationThread.DEBUG) { Slog.d(VibrationThread.TAG, "Vibration in session, skipping request to turn off vibrator " + getVibratorId()); } return; } if (VibrationThread.DEBUG) { Slog.d(VibrationThread.TAG, "Turning off vibrator " + getVibratorId()); Loading services/core/java/com/android/server/vibrator/VibrationStepConductor.java +8 −3 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ final class VibrationStepConductor { // Used within steps. public final VibrationSettings vibrationSettings; public final VibrationThread.VibratorManagerHooks vibratorManagerHooks; public final boolean isInSession; private final DeviceAdapter mDeviceAdapter; private final VibrationScaler mVibrationScaler; Loading Loading @@ -105,12 +106,13 @@ final class VibrationStepConductor { private int mRemainingStartSequentialEffectSteps; private int mSuccessfulVibratorOnSteps; VibrationStepConductor(HalVibration vib, VibrationSettings vibrationSettings, DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler, VibratorFrameworkStatsLogger statsLogger, VibrationStepConductor(HalVibration vib, boolean isInSession, VibrationSettings vibrationSettings, DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler, VibratorFrameworkStatsLogger statsLogger, CompletableFuture<Void> requestVibrationParamsFuture, VibrationThread.VibratorManagerHooks vibratorManagerHooks) { this.mVibration = vib; this.isInSession = isInSession; this.vibrationSettings = vibrationSettings; this.mDeviceAdapter = deviceAdapter; mVibrationScaler = vibrationScaler; Loading Loading @@ -286,6 +288,9 @@ final class VibrationStepConductor { if (nextStep == null) { return true; // Finished } if (isInSession) { return true; // Don't wait to play session vibration steps } long waitMillis = nextStep.calculateWaitTime(); if (waitMillis <= 0) { return true; // Regular step ready Loading services/core/java/com/android/server/vibrator/VibratorManagerService.java +3 −2 Original line number Diff line number Diff line Loading @@ -1114,8 +1114,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { mVibrationSettings.getRequestVibrationParamsTimeoutMs()); } return new VibrationStepConductor(vib, mVibrationSettings, mDeviceAdapter, mVibrationScaler, mFrameworkStatsLogger, requestVibrationParamsFuture, mVibrationThreadCallbacks); return new VibrationStepConductor(vib, /* isInSession= */ false, mVibrationSettings, mDeviceAdapter, mVibrationScaler, mFrameworkStatsLogger, requestVibrationParamsFuture, mVibrationThreadCallbacks); } private Status startVibrationOnInputDevicesLocked(HalVibration vib) { Loading services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java +62 −5 Original line number Diff line number Diff line Loading @@ -1913,6 +1913,55 @@ public class VibrationThreadTest { fakeVibrator.getEffectSegments(vibration5.id)); } @Test public void vibrate_multipleVibratorsSequentialInSession_runsInOrderWithoutDelaysAndNoOffs() { mockVibrators(1, 2, 3); mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); mVibratorProviders.get(2).setSupportedPrimitives( VibrationEffect.Composition.PRIMITIVE_CLICK); mVibratorProviders.get(3).setSupportedEffects(VibrationEffect.EFFECT_CLICK); CombinedVibration effect = CombinedVibration.startSequential() .addNext(3, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), /* delay= */ TEST_TIMEOUT_MILLIS) .addNext(1, VibrationEffect.createWaveform( new long[] {TEST_TIMEOUT_MILLIS, TEST_TIMEOUT_MILLIS}, /* repeat= */ -1), /* delay= */ TEST_TIMEOUT_MILLIS) .addNext(2, VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, /* delay= */ TEST_TIMEOUT_MILLIS) .compose(), /* delay= */ TEST_TIMEOUT_MILLIS) .combine(); HalVibration vibration = startThreadAndDispatcher(effect, /* isInSession= */ true); // Should not timeout as delays will not affect in session playback time. waitForCompletion(); // Vibrating state remains ON until session resets it. verifyCallbacksTriggered(vibration, Status.FINISHED); assertTrue(mControllers.get(1).isVibrating()); assertTrue(mControllers.get(2).isVibrating()); assertTrue(mControllers.get(3).isVibrating()); assertEquals(0, mVibratorProviders.get(1).getOffCount()); assertEquals(0, mVibratorProviders.get(2).getOffCount()); assertEquals(0, mVibratorProviders.get(3).getOffCount()); assertEquals(Arrays.asList(expectedOneShot(TEST_TIMEOUT_MILLIS)), mVibratorProviders.get(1).getEffectSegments(vibration.id)); assertEquals(expectedAmplitudes(255), mVibratorProviders.get(1).getAmplitudes()); assertEquals(Arrays.asList(expectedPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, 1, TEST_TIMEOUT_MILLIS)), mVibratorProviders.get(2).getEffectSegments(vibration.id)); assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)), mVibratorProviders.get(3).getEffectSegments(vibration.id)); } private void mockVibrators(int... vibratorIds) { for (int vibratorId : vibratorIds) { mVibratorProviders.put(vibratorId, Loading @@ -1935,8 +1984,14 @@ public class VibrationThreadTest { return startThreadAndDispatcher(createVibration(effect)); } private HalVibration startThreadAndDispatcher(CombinedVibration effect, boolean isInSession) { return startThreadAndDispatcher(createVibration(effect), isInSession, /* requestVibrationParamsFuture= */ null); } private HalVibration startThreadAndDispatcher(HalVibration vib) { return startThreadAndDispatcher(vib, /* requestVibrationParamsFuture= */ null); return startThreadAndDispatcher(vib, /* isInSession= */ false, /* requestVibrationParamsFuture= */ null); } private HalVibration startThreadAndDispatcher(VibrationEffect effect, Loading @@ -1947,15 +2002,17 @@ public class VibrationThreadTest { HalVibration vib = new HalVibration( new CallerInfo(attrs, UID, DEVICE_ID, PACKAGE_NAME, "reason"), CombinedVibration.createParallel(effect)); return startThreadAndDispatcher(vib, requestVibrationParamsFuture); return startThreadAndDispatcher(vib, /* isInSession= */ false, requestVibrationParamsFuture); } private HalVibration startThreadAndDispatcher(HalVibration vib, private HalVibration startThreadAndDispatcher(HalVibration vib, boolean isInSession, CompletableFuture<Void> requestVibrationParamsFuture) { mControllers = createVibratorControllers(); DeviceAdapter deviceAdapter = new DeviceAdapter(mVibrationSettings, mControllers); mVibrationConductor = new VibrationStepConductor(vib, mVibrationSettings, deviceAdapter, mVibrationScaler, mStatsLoggerMock, requestVibrationParamsFuture, mManagerHooks); mVibrationConductor = new VibrationStepConductor(vib, isInSession, mVibrationSettings, deviceAdapter, mVibrationScaler, mStatsLoggerMock, requestVibrationParamsFuture, mManagerHooks); assertTrue(mThread.runVibrationOnVibrationThread(mVibrationConductor)); return mVibrationConductor.getVibration(); } Loading Loading
services/core/java/com/android/server/vibrator/AbstractVibratorStep.java +8 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,14 @@ abstract class AbstractVibratorStep extends Step { } protected void stopVibrating() { if (conductor.isInSession) { if (VibrationThread.DEBUG) { Slog.d(VibrationThread.TAG, "Vibration in session, skipping request to turn off vibrator " + getVibratorId()); } return; } if (VibrationThread.DEBUG) { Slog.d(VibrationThread.TAG, "Turning off vibrator " + getVibratorId()); Loading
services/core/java/com/android/server/vibrator/VibrationStepConductor.java +8 −3 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ final class VibrationStepConductor { // Used within steps. public final VibrationSettings vibrationSettings; public final VibrationThread.VibratorManagerHooks vibratorManagerHooks; public final boolean isInSession; private final DeviceAdapter mDeviceAdapter; private final VibrationScaler mVibrationScaler; Loading Loading @@ -105,12 +106,13 @@ final class VibrationStepConductor { private int mRemainingStartSequentialEffectSteps; private int mSuccessfulVibratorOnSteps; VibrationStepConductor(HalVibration vib, VibrationSettings vibrationSettings, DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler, VibratorFrameworkStatsLogger statsLogger, VibrationStepConductor(HalVibration vib, boolean isInSession, VibrationSettings vibrationSettings, DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler, VibratorFrameworkStatsLogger statsLogger, CompletableFuture<Void> requestVibrationParamsFuture, VibrationThread.VibratorManagerHooks vibratorManagerHooks) { this.mVibration = vib; this.isInSession = isInSession; this.vibrationSettings = vibrationSettings; this.mDeviceAdapter = deviceAdapter; mVibrationScaler = vibrationScaler; Loading Loading @@ -286,6 +288,9 @@ final class VibrationStepConductor { if (nextStep == null) { return true; // Finished } if (isInSession) { return true; // Don't wait to play session vibration steps } long waitMillis = nextStep.calculateWaitTime(); if (waitMillis <= 0) { return true; // Regular step ready Loading
services/core/java/com/android/server/vibrator/VibratorManagerService.java +3 −2 Original line number Diff line number Diff line Loading @@ -1114,8 +1114,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { mVibrationSettings.getRequestVibrationParamsTimeoutMs()); } return new VibrationStepConductor(vib, mVibrationSettings, mDeviceAdapter, mVibrationScaler, mFrameworkStatsLogger, requestVibrationParamsFuture, mVibrationThreadCallbacks); return new VibrationStepConductor(vib, /* isInSession= */ false, mVibrationSettings, mDeviceAdapter, mVibrationScaler, mFrameworkStatsLogger, requestVibrationParamsFuture, mVibrationThreadCallbacks); } private Status startVibrationOnInputDevicesLocked(HalVibration vib) { Loading
services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java +62 −5 Original line number Diff line number Diff line Loading @@ -1913,6 +1913,55 @@ public class VibrationThreadTest { fakeVibrator.getEffectSegments(vibration5.id)); } @Test public void vibrate_multipleVibratorsSequentialInSession_runsInOrderWithoutDelaysAndNoOffs() { mockVibrators(1, 2, 3); mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); mVibratorProviders.get(2).setSupportedPrimitives( VibrationEffect.Composition.PRIMITIVE_CLICK); mVibratorProviders.get(3).setSupportedEffects(VibrationEffect.EFFECT_CLICK); CombinedVibration effect = CombinedVibration.startSequential() .addNext(3, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), /* delay= */ TEST_TIMEOUT_MILLIS) .addNext(1, VibrationEffect.createWaveform( new long[] {TEST_TIMEOUT_MILLIS, TEST_TIMEOUT_MILLIS}, /* repeat= */ -1), /* delay= */ TEST_TIMEOUT_MILLIS) .addNext(2, VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, /* delay= */ TEST_TIMEOUT_MILLIS) .compose(), /* delay= */ TEST_TIMEOUT_MILLIS) .combine(); HalVibration vibration = startThreadAndDispatcher(effect, /* isInSession= */ true); // Should not timeout as delays will not affect in session playback time. waitForCompletion(); // Vibrating state remains ON until session resets it. verifyCallbacksTriggered(vibration, Status.FINISHED); assertTrue(mControllers.get(1).isVibrating()); assertTrue(mControllers.get(2).isVibrating()); assertTrue(mControllers.get(3).isVibrating()); assertEquals(0, mVibratorProviders.get(1).getOffCount()); assertEquals(0, mVibratorProviders.get(2).getOffCount()); assertEquals(0, mVibratorProviders.get(3).getOffCount()); assertEquals(Arrays.asList(expectedOneShot(TEST_TIMEOUT_MILLIS)), mVibratorProviders.get(1).getEffectSegments(vibration.id)); assertEquals(expectedAmplitudes(255), mVibratorProviders.get(1).getAmplitudes()); assertEquals(Arrays.asList(expectedPrimitive( VibrationEffect.Composition.PRIMITIVE_CLICK, 1, TEST_TIMEOUT_MILLIS)), mVibratorProviders.get(2).getEffectSegments(vibration.id)); assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)), mVibratorProviders.get(3).getEffectSegments(vibration.id)); } private void mockVibrators(int... vibratorIds) { for (int vibratorId : vibratorIds) { mVibratorProviders.put(vibratorId, Loading @@ -1935,8 +1984,14 @@ public class VibrationThreadTest { return startThreadAndDispatcher(createVibration(effect)); } private HalVibration startThreadAndDispatcher(CombinedVibration effect, boolean isInSession) { return startThreadAndDispatcher(createVibration(effect), isInSession, /* requestVibrationParamsFuture= */ null); } private HalVibration startThreadAndDispatcher(HalVibration vib) { return startThreadAndDispatcher(vib, /* requestVibrationParamsFuture= */ null); return startThreadAndDispatcher(vib, /* isInSession= */ false, /* requestVibrationParamsFuture= */ null); } private HalVibration startThreadAndDispatcher(VibrationEffect effect, Loading @@ -1947,15 +2002,17 @@ public class VibrationThreadTest { HalVibration vib = new HalVibration( new CallerInfo(attrs, UID, DEVICE_ID, PACKAGE_NAME, "reason"), CombinedVibration.createParallel(effect)); return startThreadAndDispatcher(vib, requestVibrationParamsFuture); return startThreadAndDispatcher(vib, /* isInSession= */ false, requestVibrationParamsFuture); } private HalVibration startThreadAndDispatcher(HalVibration vib, private HalVibration startThreadAndDispatcher(HalVibration vib, boolean isInSession, CompletableFuture<Void> requestVibrationParamsFuture) { mControllers = createVibratorControllers(); DeviceAdapter deviceAdapter = new DeviceAdapter(mVibrationSettings, mControllers); mVibrationConductor = new VibrationStepConductor(vib, mVibrationSettings, deviceAdapter, mVibrationScaler, mStatsLoggerMock, requestVibrationParamsFuture, mManagerHooks); mVibrationConductor = new VibrationStepConductor(vib, isInSession, mVibrationSettings, deviceAdapter, mVibrationScaler, mStatsLoggerMock, requestVibrationParamsFuture, mManagerHooks); assertTrue(mThread.runVibrationOnVibrationThread(mVibrationConductor)); return mVibrationConductor.getVibration(); } Loading