Fix usage filter over UNKNOWN vibration

The usageFilter parameter added to Vibrator.cancel is always cancelling
UNKNOWN vibrations (usage = 0). The filter should only cancel them if
the value is the same usage, or if all usages are being cancelled.

Fix: 182440404
Test: VibratorManagerServiceTest
Change-Id: Ibf33fe24e5253501e751b027cbf4b68564d82929
This commit is contained in:
Lais Andrade
2021-06-16 15:48:51 +01:00
parent a2d7f96154
commit ba57b002d3
4 changed files with 49 additions and 5 deletions

View File

@@ -146,7 +146,7 @@ public class SystemVibratorManager extends VibratorManager {
@Override
public void cancel() {
cancelVibration(/* usageFilter= */ -1);
cancelVibration(VibrationAttributes.USAGE_FILTER_MATCH_ALL);
}
@Override

View File

@@ -62,6 +62,11 @@ public final class VibrationAttributes implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface Usage{}
/**
* Vibration usage filter value to match all usages.
* @hide
*/
public static final int USAGE_FILTER_MATCH_ALL = -1;
/**
* Vibration usage class value to use when the vibration usage class is unknown.
*/

View File

@@ -723,6 +723,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
* VibrationAttributes.USAGE_* values.
*/
private boolean shouldCancelVibration(VibrationAttributes attrs, int usageFilter) {
if (attrs.getUsage() == VibrationAttributes.USAGE_UNKNOWN) {
// Special case, usage UNKNOWN would match all filters. Instead it should only match if
// it's cancelling that usage specifically, or if cancelling all usages.
return usageFilter == VibrationAttributes.USAGE_UNKNOWN
|| usageFilter == VibrationAttributes.USAGE_FILTER_MATCH_ALL;
}
return (usageFilter & attrs.getUsage()) == attrs.getUsage();
}
@@ -1535,7 +1541,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
private int runCancel() {
cancelVibrate(/* usageFilter= */ -1, mToken);
cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, mToken);
return 0;
}

View File

@@ -234,7 +234,7 @@ public class VibratorManagerServiceTest {
CombinedVibration effect = CombinedVibration.createParallel(
VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
service.cancelVibrate(/* usageFilter= */ -1, service);
service.cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, service);
assertTrue(service.setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
@@ -889,13 +889,13 @@ public class VibratorManagerServiceTest {
mockVibrators(1);
VibratorManagerService service = createSystemReadyService();
service.cancelVibrate(/* usageFilter= */ -1, service);
service.cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, service);
assertFalse(service.isVibrating(1));
vibrate(service, VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100), ALARM_ATTRS);
assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
service.cancelVibrate(/* usageFilter= */ -1, service);
service.cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, service);
assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
}
@@ -924,6 +924,39 @@ public class VibratorManagerServiceTest {
assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
}
@Test
public void cancelVibrate_withoutUnknownUsage_onlyStopsIfFilteringUnknownOrAllUsages()
throws Exception {
mockVibrators(1);
VibrationAttributes attrs = new VibrationAttributes.Builder()
.setUsage(VibrationAttributes.USAGE_UNKNOWN)
.build();
VibratorManagerService service = createSystemReadyService();
vibrate(service, VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100), attrs);
assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
// Do not cancel UNKNOWN vibration when filter is being applied for other usages.
service.cancelVibrate(VibrationAttributes.USAGE_RINGTONE, service);
assertFalse(waitUntil(s -> !s.isVibrating(1), service, /* timeout= */ 50));
service.cancelVibrate(
VibrationAttributes.USAGE_CLASS_ALARM | ~VibrationAttributes.USAGE_CLASS_MASK,
service);
assertFalse(waitUntil(s -> !s.isVibrating(1), service, /* timeout= */ 50));
// Cancel UNKNOWN vibration when filtered for that vibration specifically.
service.cancelVibrate(VibrationAttributes.USAGE_UNKNOWN, service);
assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
vibrate(service, VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100), attrs);
assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
// Cancel UNKNOWN vibration when all vibrations are being cancelled.
service.cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, service);
assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
}
private void mockCapabilities(long... capabilities) {
when(mNativeWrapperMock.getCapabilities()).thenReturn(
Arrays.stream(capabilities).reduce(0, (a, b) -> a | b));