Merge "Update vibration cancellation policy for notifications" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
88efc6f72e
@@ -61,12 +61,11 @@ final class Vibration {
|
|||||||
IGNORED_BACKGROUND,
|
IGNORED_BACKGROUND,
|
||||||
IGNORED_UNKNOWN_VIBRATION,
|
IGNORED_UNKNOWN_VIBRATION,
|
||||||
IGNORED_UNSUPPORTED,
|
IGNORED_UNSUPPORTED,
|
||||||
IGNORED_FOR_ALARM,
|
|
||||||
IGNORED_FOR_EXTERNAL,
|
IGNORED_FOR_EXTERNAL,
|
||||||
|
IGNORED_FOR_HIGHER_IMPORTANCE,
|
||||||
IGNORED_FOR_ONGOING,
|
IGNORED_FOR_ONGOING,
|
||||||
IGNORED_FOR_POWER,
|
IGNORED_FOR_POWER,
|
||||||
IGNORED_FOR_RINGER_MODE,
|
IGNORED_FOR_RINGER_MODE,
|
||||||
IGNORED_FOR_RINGTONE,
|
|
||||||
IGNORED_FOR_SETTINGS,
|
IGNORED_FOR_SETTINGS,
|
||||||
IGNORED_SUPERSEDED,
|
IGNORED_SUPERSEDED,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -713,16 +713,17 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
|||||||
case IGNORED_ERROR_APP_OPS:
|
case IGNORED_ERROR_APP_OPS:
|
||||||
Slog.w(TAG, "Would be an error: vibrate from uid " + uid);
|
Slog.w(TAG, "Would be an error: vibrate from uid " + uid);
|
||||||
break;
|
break;
|
||||||
case IGNORED_FOR_ALARM:
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case IGNORED_FOR_EXTERNAL:
|
case IGNORED_FOR_EXTERNAL:
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
|
Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case IGNORED_FOR_HIGHER_IMPORTANCE:
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Ignoring incoming vibration in favor of ongoing vibration"
|
||||||
|
+ " with higher importance");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case IGNORED_FOR_ONGOING:
|
case IGNORED_FOR_ONGOING:
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "Ignoring incoming vibration in favor of repeating vibration");
|
Slog.d(TAG, "Ignoring incoming vibration in favor of repeating vibration");
|
||||||
@@ -734,12 +735,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
|||||||
+ attrs);
|
+ attrs);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IGNORED_FOR_RINGTONE:
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "Ignoring incoming vibration in favor of ringtone vibration");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "Vibration for uid=" + uid + " and with attrs=" + attrs
|
Slog.d(TAG, "Vibration for uid=" + uid + " and with attrs=" + attrs
|
||||||
@@ -812,20 +807,43 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentVibration.attrs.getUsage() == VibrationAttributes.USAGE_ALARM) {
|
int currentUsage = currentVibration.attrs.getUsage();
|
||||||
return Vibration.Status.IGNORED_FOR_ALARM;
|
int newUsage = vib.attrs.getUsage();
|
||||||
}
|
if (getVibrationImportance(currentUsage) > getVibrationImportance(newUsage)) {
|
||||||
|
// Current vibration has higher importance than this one and should not be cancelled.
|
||||||
if (currentVibration.attrs.getUsage() == VibrationAttributes.USAGE_RINGTONE) {
|
return Vibration.Status.IGNORED_FOR_HIGHER_IMPORTANCE;
|
||||||
return Vibration.Status.IGNORED_FOR_RINGTONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentVibration.isRepeating()) {
|
if (currentVibration.isRepeating()) {
|
||||||
|
// Current vibration is repeating, assume it's more important.
|
||||||
return Vibration.Status.IGNORED_FOR_ONGOING;
|
return Vibration.Status.IGNORED_FOR_ONGOING;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int getVibrationImportance(@VibrationAttributes.Usage int usage) {
|
||||||
|
switch (usage) {
|
||||||
|
case VibrationAttributes.USAGE_RINGTONE:
|
||||||
|
return 5;
|
||||||
|
case VibrationAttributes.USAGE_ALARM:
|
||||||
|
return 4;
|
||||||
|
case VibrationAttributes.USAGE_NOTIFICATION:
|
||||||
|
return 3;
|
||||||
|
case VibrationAttributes.USAGE_COMMUNICATION_REQUEST:
|
||||||
|
case VibrationAttributes.USAGE_ACCESSIBILITY:
|
||||||
|
return 2;
|
||||||
|
case VibrationAttributes.USAGE_HARDWARE_FEEDBACK:
|
||||||
|
case VibrationAttributes.USAGE_PHYSICAL_EMULATION:
|
||||||
|
return 1;
|
||||||
|
case VibrationAttributes.USAGE_MEDIA:
|
||||||
|
case VibrationAttributes.USAGE_TOUCH:
|
||||||
|
case VibrationAttributes.USAGE_UNKNOWN:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if given vibration should be ignored by this service.
|
* Check if given vibration should be ignored by this service.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -778,8 +778,7 @@ public class VibratorManagerServiceTest {
|
|||||||
assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
|
assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
|
||||||
service, TEST_TIMEOUT_MILLIS));
|
service, TEST_TIMEOUT_MILLIS));
|
||||||
|
|
||||||
vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
|
vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), HAPTIC_FEEDBACK_ATTRS);
|
||||||
HAPTIC_FEEDBACK_ATTRS);
|
|
||||||
|
|
||||||
// Wait before checking it never played a second effect.
|
// Wait before checking it never played a second effect.
|
||||||
assertFalse(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1,
|
assertFalse(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1,
|
||||||
@@ -793,49 +792,78 @@ public class VibratorManagerServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void vibrate_withOngoingAlarmVibration_ignoresEffect() throws Exception {
|
public void vibrate_withNewRepeatingVibration_cancelsOngoingEffect() throws Exception {
|
||||||
mockVibrators(1);
|
mockVibrators(1);
|
||||||
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
|
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||||
VibratorManagerService service = createSystemReadyService();
|
VibratorManagerService service = createSystemReadyService();
|
||||||
|
|
||||||
VibrationEffect alarmEffect = VibrationEffect.createWaveform(
|
VibrationEffect alarmEffect = VibrationEffect.createWaveform(
|
||||||
new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
|
new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
|
||||||
vibrate(service, alarmEffect, new VibrationAttributes.Builder().setUsage(
|
vibrate(service, alarmEffect, ALARM_ATTRS);
|
||||||
VibrationAttributes.USAGE_ALARM).build());
|
|
||||||
|
|
||||||
// VibrationThread will start this vibration async, so wait before checking it started.
|
// VibrationThread will start this vibration async, so wait before checking it started.
|
||||||
assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
|
assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
|
||||||
service, TEST_TIMEOUT_MILLIS));
|
service, TEST_TIMEOUT_MILLIS));
|
||||||
|
|
||||||
vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
|
VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
|
||||||
HAPTIC_FEEDBACK_ATTRS);
|
new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
|
||||||
|
vibrate(service, repeatingEffect, NOTIFICATION_ATTRS);
|
||||||
|
|
||||||
// Wait before checking it never played a second effect.
|
// VibrationThread will start this vibration async, so wait before checking it started.
|
||||||
assertFalse(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1,
|
assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1,
|
||||||
service, /* timeout= */ 50));
|
service, TEST_TIMEOUT_MILLIS));
|
||||||
|
|
||||||
|
// The second vibration should have recorded that the vibrators were turned on.
|
||||||
|
verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void vibrate_withOngoingRingtoneVibration_ignoresEffect() throws Exception {
|
public void vibrate_withOngoingHigherImportanceVibration_ignoresEffect() throws Exception {
|
||||||
mockVibrators(1);
|
mockVibrators(1);
|
||||||
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
|
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||||
VibratorManagerService service = createSystemReadyService();
|
VibratorManagerService service = createSystemReadyService();
|
||||||
|
|
||||||
VibrationEffect alarmEffect = VibrationEffect.createWaveform(
|
VibrationEffect effect = VibrationEffect.createWaveform(
|
||||||
new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
|
new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
|
||||||
vibrate(service, alarmEffect, new VibrationAttributes.Builder().setUsage(
|
vibrate(service, effect, ALARM_ATTRS);
|
||||||
VibrationAttributes.USAGE_RINGTONE).build());
|
|
||||||
|
|
||||||
// VibrationThread will start this vibration async, so wait before checking it started.
|
// VibrationThread will start this vibration async, so wait before checking it started.
|
||||||
assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
|
assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
|
||||||
service, TEST_TIMEOUT_MILLIS));
|
service, TEST_TIMEOUT_MILLIS));
|
||||||
|
|
||||||
vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
|
vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
|
||||||
HAPTIC_FEEDBACK_ATTRS);
|
|
||||||
|
|
||||||
// Wait before checking it never played a second effect.
|
// Wait before checking it never played a second effect.
|
||||||
assertFalse(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1,
|
assertFalse(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1,
|
||||||
service, /* timeout= */ 50));
|
service, /* timeout= */ 50));
|
||||||
|
|
||||||
|
// The second vibration shouldn't have recorded that the vibrators were turned on.
|
||||||
|
verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void vibrate_withOngoingLowerImportanceVibration_cancelsOngoingEffect()
|
||||||
|
throws Exception {
|
||||||
|
mockVibrators(1);
|
||||||
|
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||||
|
VibratorManagerService service = createSystemReadyService();
|
||||||
|
|
||||||
|
VibrationEffect effect = VibrationEffect.createWaveform(
|
||||||
|
new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
|
||||||
|
vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
|
||||||
|
|
||||||
|
// VibrationThread will start this vibration async, so wait before checking it started.
|
||||||
|
assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
|
||||||
|
service, TEST_TIMEOUT_MILLIS));
|
||||||
|
|
||||||
|
vibrate(service, effect, RINGTONE_ATTRS);
|
||||||
|
|
||||||
|
// VibrationThread will start this vibration async, so wait before checking it started.
|
||||||
|
assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() > 1,
|
||||||
|
service, TEST_TIMEOUT_MILLIS));
|
||||||
|
|
||||||
|
// The second vibration should have recorded that the vibrators were turned on.
|
||||||
|
verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1052,15 +1080,15 @@ public class VibratorManagerServiceTest {
|
|||||||
IVibrator.CAP_COMPOSE_EFFECTS);
|
IVibrator.CAP_COMPOSE_EFFECTS);
|
||||||
VibratorManagerService service = createSystemReadyService();
|
VibratorManagerService service = createSystemReadyService();
|
||||||
|
|
||||||
vibrate(service, CombinedVibration.startSequential()
|
|
||||||
.addNext(1, VibrationEffect.createOneShot(100, 125))
|
|
||||||
.combine(), NOTIFICATION_ATTRS);
|
|
||||||
assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 1,
|
|
||||||
service, TEST_TIMEOUT_MILLIS));
|
|
||||||
|
|
||||||
vibrate(service, VibrationEffect.startComposition()
|
vibrate(service, VibrationEffect.startComposition()
|
||||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
|
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
|
||||||
.compose(), HAPTIC_FEEDBACK_ATTRS);
|
.compose(), HAPTIC_FEEDBACK_ATTRS);
|
||||||
|
assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 1,
|
||||||
|
service, TEST_TIMEOUT_MILLIS));
|
||||||
|
|
||||||
|
vibrate(service, CombinedVibration.startSequential()
|
||||||
|
.addNext(1, VibrationEffect.createOneShot(100, 125))
|
||||||
|
.combine(), NOTIFICATION_ATTRS);
|
||||||
assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 2,
|
assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 2,
|
||||||
service, TEST_TIMEOUT_MILLIS));
|
service, TEST_TIMEOUT_MILLIS));
|
||||||
|
|
||||||
@@ -1070,25 +1098,25 @@ public class VibratorManagerServiceTest {
|
|||||||
assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 3,
|
assertTrue(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() == 3,
|
||||||
service, TEST_TIMEOUT_MILLIS));
|
service, TEST_TIMEOUT_MILLIS));
|
||||||
|
|
||||||
|
// Ring vibrations have intensity OFF and are not played.
|
||||||
vibrate(service, VibrationEffect.createOneShot(100, 125), RINGTONE_ATTRS);
|
vibrate(service, VibrationEffect.createOneShot(100, 125), RINGTONE_ATTRS);
|
||||||
assertFalse(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() > 3,
|
assertFalse(waitUntil(s -> fakeVibrator.getAllEffectSegments().size() > 3,
|
||||||
service, TEST_TIMEOUT_MILLIS));
|
service, /* timeout= */ 50));
|
||||||
|
|
||||||
|
// Only 3 effects played successfully.
|
||||||
assertEquals(3, fakeVibrator.getAllEffectSegments().size());
|
assertEquals(3, fakeVibrator.getAllEffectSegments().size());
|
||||||
|
|
||||||
|
// Haptic feedback vibrations will be scaled with SCALE_LOW or none if default is low.
|
||||||
|
assertEquals(defaultTouchIntensity > Vibrator.VIBRATION_INTENSITY_LOW,
|
||||||
|
0.5 > ((PrimitiveSegment) fakeVibrator.getAllEffectSegments().get(0)).getScale());
|
||||||
|
|
||||||
// Notification vibrations will be scaled with SCALE_HIGH or none if default is high.
|
// Notification vibrations will be scaled with SCALE_HIGH or none if default is high.
|
||||||
assertEquals(defaultNotificationIntensity < Vibrator.VIBRATION_INTENSITY_HIGH,
|
assertEquals(defaultNotificationIntensity < Vibrator.VIBRATION_INTENSITY_HIGH,
|
||||||
0.6 < fakeVibrator.getAmplitudes().get(0));
|
0.6 < fakeVibrator.getAmplitudes().get(0));
|
||||||
|
|
||||||
// Haptic feedback vibrations will be scaled with SCALE_LOW or none if default is low.
|
|
||||||
assertEquals(defaultTouchIntensity > Vibrator.VIBRATION_INTENSITY_LOW,
|
|
||||||
0.5 > ((PrimitiveSegment) fakeVibrator.getAllEffectSegments().get(1)).getScale());
|
|
||||||
|
|
||||||
// Alarm vibration will be scaled with SCALE_NONE.
|
// Alarm vibration will be scaled with SCALE_NONE.
|
||||||
assertEquals(1f,
|
assertEquals(1f,
|
||||||
((PrimitiveSegment) fakeVibrator.getAllEffectSegments().get(2)).getScale(), 1e-5);
|
((PrimitiveSegment) fakeVibrator.getAllEffectSegments().get(2)).getScale(), 1e-5);
|
||||||
|
|
||||||
// Ring vibrations have intensity OFF and are not played.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user