summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/input/InputDeviceVibrator.java5
-rw-r--r--core/java/android/hardware/input/InputDeviceVibratorManager.java5
-rw-r--r--core/java/android/os/IVibratorManagerService.aidl2
-rw-r--r--core/java/android/os/NullVibrator.java4
-rw-r--r--core/java/android/os/SystemVibrator.java9
-rw-r--r--core/java/android/os/SystemVibratorManager.java67
-rw-r--r--core/java/android/os/Vibrator.java10
-rw-r--r--core/java/android/os/VibratorManager.java10
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java46
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java44
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java35
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java8
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java2
14 files changed, 159 insertions, 92 deletions
diff --git a/core/java/android/hardware/input/InputDeviceVibrator.java b/core/java/android/hardware/input/InputDeviceVibrator.java
index a4817ae27fa5..1ab183626d2e 100644
--- a/core/java/android/hardware/input/InputDeviceVibrator.java
+++ b/core/java/android/hardware/input/InputDeviceVibrator.java
@@ -175,4 +175,9 @@ final class InputDeviceVibrator extends Vibrator {
public void cancel() {
mInputManager.cancelVibrate(mDeviceId, mToken);
}
+
+ @Override
+ public void cancel(int usageFilter) {
+ cancel();
+ }
}
diff --git a/core/java/android/hardware/input/InputDeviceVibratorManager.java b/core/java/android/hardware/input/InputDeviceVibratorManager.java
index ed0efffbb346..7caff7209cc5 100644
--- a/core/java/android/hardware/input/InputDeviceVibratorManager.java
+++ b/core/java/android/hardware/input/InputDeviceVibratorManager.java
@@ -134,4 +134,9 @@ public class InputDeviceVibratorManager extends VibratorManager
public void cancel() {
mInputManager.cancelVibrate(mDeviceId, mToken);
}
+
+ @Override
+ public void cancel(int usageFilter) {
+ cancel();
+ }
}
diff --git a/core/java/android/os/IVibratorManagerService.aidl b/core/java/android/os/IVibratorManagerService.aidl
index c58cc4f9988f..a0d6ce1ba108 100644
--- a/core/java/android/os/IVibratorManagerService.aidl
+++ b/core/java/android/os/IVibratorManagerService.aidl
@@ -32,5 +32,5 @@ interface IVibratorManagerService {
in CombinedVibration vibration, in VibrationAttributes attributes);
void vibrate(int uid, String opPkg, in CombinedVibration vibration,
in VibrationAttributes attributes, String reason, IBinder token);
- void cancelVibrate(IBinder token);
+ void cancelVibrate(int usageFilter, IBinder token);
}
diff --git a/core/java/android/os/NullVibrator.java b/core/java/android/os/NullVibrator.java
index 6bb016519a84..7859b5cfe5df 100644
--- a/core/java/android/os/NullVibrator.java
+++ b/core/java/android/os/NullVibrator.java
@@ -54,4 +54,8 @@ public class NullVibrator extends Vibrator {
@Override
public void cancel() {
}
+
+ @Override
+ public void cancel(int usageFilter) {
+ }
}
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index 2e8ecb59b0d3..70808594225f 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -256,6 +256,15 @@ public class SystemVibrator extends Vibrator {
mVibratorManager.cancel();
}
+ @Override
+ public void cancel(int usageFilter) {
+ if (mVibratorManager == null) {
+ Log.w(TAG, "Failed to cancel vibrate; no vibrator manager.");
+ return;
+ }
+ mVibratorManager.cancel(usageFilter);
+ }
+
/**
* Tries to unregister individual {@link android.os.Vibrator.OnVibratorStateChangedListener}
* that were left registered to vibrators after failures to register them to all vibrators.
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index 84a1016e3364..ba86c6f9ec1a 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -146,12 +146,21 @@ public class SystemVibratorManager extends VibratorManager {
@Override
public void cancel() {
+ cancelVibration(/* usageFilter= */ -1);
+ }
+
+ @Override
+ public void cancel(int usageFilter) {
+ cancelVibration(usageFilter);
+ }
+
+ private void cancelVibration(int usageFilter) {
if (mService == null) {
Log.w(TAG, "Failed to cancel vibration; no vibrator manager service.");
return;
}
try {
- mService.cancelVibrate(mToken);
+ mService.cancelVibrate(usageFilter, mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to cancel vibration.", e);
}
@@ -232,54 +241,32 @@ public class SystemVibratorManager extends VibratorManager {
@Override
public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId,
@Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) {
- if (mService == null) {
- Log.w(TAG, "Failed to set always-on effect on vibrator " + mVibratorInfo.getId()
- + "; no vibrator manager service.");
- return false;
- }
- try {
- VibrationAttributes attr = new VibrationAttributes.Builder(
- attributes, effect).build();
- CombinedVibration combined = CombinedVibration.startParallel()
- .addVibrator(mVibratorInfo.getId(), effect)
- .combine();
- return mService.setAlwaysOnEffect(uid, opPkg, alwaysOnId, combined, attr);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to set always-on effect on vibrator " + mVibratorInfo.getId());
- }
- return false;
+ VibrationAttributes attr = new VibrationAttributes.Builder(
+ attributes, effect).build();
+ CombinedVibration combined = CombinedVibration.startParallel()
+ .addVibrator(mVibratorInfo.getId(), effect)
+ .combine();
+ return SystemVibratorManager.this.setAlwaysOnEffect(uid, opPkg, alwaysOnId, combined,
+ attr);
}
@Override
public void vibrate(int uid, String opPkg, @NonNull VibrationEffect vibe, String reason,
@NonNull VibrationAttributes attributes) {
- if (mService == null) {
- Log.w(TAG, "Failed to vibrate on vibrator " + mVibratorInfo.getId()
- + "; no vibrator manager service.");
- return;
- }
- try {
- CombinedVibration combined = CombinedVibration.startParallel()
- .addVibrator(mVibratorInfo.getId(), vibe)
- .combine();
- mService.vibrate(uid, opPkg, combined, attributes, reason, mToken);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to vibrate.", e);
- }
+ CombinedVibration combined = CombinedVibration.startParallel()
+ .addVibrator(mVibratorInfo.getId(), vibe)
+ .combine();
+ SystemVibratorManager.this.vibrate(uid, opPkg, combined, reason, attributes);
}
@Override
public void cancel() {
- if (mService == null) {
- Log.w(TAG, "Failed to cancel vibration on vibrator " + mVibratorInfo.getId()
- + "; no vibrator manager service.");
- return;
- }
- try {
- mService.cancelVibrate(mToken);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to cancel vibration on vibrator " + mVibratorInfo.getId(), e);
- }
+ SystemVibratorManager.this.cancel();
+ }
+
+ @Override
+ public void cancel(int usageFilter) {
+ SystemVibratorManager.this.cancel(usageFilter);
}
@Override
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index a0f70c8fa526..54cb83f7caf1 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -494,6 +494,16 @@ public abstract class Vibrator {
public abstract void cancel();
/**
+ * Cancel specific types of ongoing vibrations.
+ *
+ * @param usageFilter The type of vibration to be cancelled, represented as a bitwise
+ * combination of {@link VibrationAttributes.Usage} values.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.VIBRATE)
+ public abstract void cancel(int usageFilter);
+
+ /**
* Check whether the vibrator is vibrating.
*
* @return True if the hardware is vibrating, otherwise false.
diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java
index 7c911160dfa6..01cece39b922 100644
--- a/core/java/android/os/VibratorManager.java
+++ b/core/java/android/os/VibratorManager.java
@@ -136,4 +136,14 @@ public abstract class VibratorManager {
*/
@RequiresPermission(android.Manifest.permission.VIBRATE)
public abstract void cancel();
+
+ /**
+ * Cancel specific types of ongoing vibrations.
+ *
+ * @param usageFilter The type of vibration to be cancelled, represented as a bitwise
+ * combination of {@link VibrationAttributes.Usage} values.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.VIBRATE)
+ public abstract void cancel(int usageFilter);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bd442bdf9d63..21b93a74655f 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -212,6 +212,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.DeviceConfig;
@@ -1076,23 +1077,8 @@ public class NotificationManagerService extends SystemService {
(status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
if (disableNotificationEffects(null) != null) {
// cancel whatever's going on
- final long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
- if (player != null) {
- player.stopAsync();
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- final long identity2 = Binder.clearCallingIdentity();
- try {
- mVibrator.cancel();
- } finally {
- Binder.restoreCallingIdentity(identity2);
- }
+ clearSoundLocked();
+ clearVibrateLocked();
}
}
}
@@ -1582,7 +1568,10 @@ public class NotificationManagerService extends SystemService {
mVibrateNotificationKey = null;
final long identity = Binder.clearCallingIdentity();
try {
- mVibrator.cancel();
+ // Stop all vibrations with usage of class alarm (ringtone, alarm, notification usages).
+ int usageFilter =
+ VibrationAttributes.USAGE_CLASS_ALARM | ~VibrationAttributes.USAGE_CLASS_MASK;
+ mVibrator.cancel(usageFilter);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -8301,29 +8290,12 @@ public class NotificationManagerService extends SystemService {
// sound
if (canceledKey.equals(mSoundNotificationKey)) {
- mSoundNotificationKey = null;
- final long identity = Binder.clearCallingIdentity();
- try {
- final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
- if (player != null) {
- player.stopAsync();
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ clearSoundLocked();
}
// vibrate
if (canceledKey.equals(mVibrateNotificationKey)) {
- mVibrateNotificationKey = null;
- final long identity = Binder.clearCallingIdentity();
- try {
- mVibrator.cancel();
- }
- finally {
- Binder.restoreCallingIdentity(identity);
- }
+ clearVibrateLocked();
}
// light
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 5d2b1b169c4e..06a5077bec82 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -383,7 +383,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
@Override // Binder call
- public void cancelVibrate(IBinder token) {
+ public void cancelVibrate(int usageFilter, IBinder token) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "cancelVibrate");
try {
mContext.enforceCallingOrSelfPermission(
@@ -392,16 +392,24 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
synchronized (mLock) {
if (DEBUG) {
- Slog.d(TAG, "Canceling vibration.");
+ Slog.d(TAG, "Canceling vibration");
}
final long ident = Binder.clearCallingIdentity();
try {
- mNextVibration = null;
+ if (mNextVibration != null
+ && shouldCancelVibration(mNextVibration.getVibration(),
+ usageFilter, token)) {
+ mNextVibration = null;
+ }
if (mCurrentVibration != null
- && mCurrentVibration.getVibration().token == token) {
+ && shouldCancelVibration(mCurrentVibration.getVibration(),
+ usageFilter, token)) {
mCurrentVibration.cancel();
}
- if (mCurrentExternalVibration != null) {
+ if (mCurrentExternalVibration != null
+ && shouldCancelVibration(
+ mCurrentExternalVibration.externalVibration.getVibrationAttributes(),
+ usageFilter)) {
mCurrentExternalVibration.end(Vibration.Status.CANCELLED);
mVibratorManagerRecords.record(mCurrentExternalVibration);
mCurrentExternalVibration.externalVibration.mute();
@@ -693,6 +701,30 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
/**
+ * Return true if the vibration has the same token and usage belongs to given usage class.
+ *
+ * @param vib The ongoing or pending vibration to be cancelled.
+ * @param usageFilter The vibration usages to be cancelled, any bitwise combination of
+ * VibrationAttributes.USAGE_* values.
+ * @param token The binder token to identify the vibration origin. Only vibrations
+ * started with the same token can be cancelled with it.
+ */
+ private boolean shouldCancelVibration(Vibration vib, int usageFilter, IBinder token) {
+ return (vib.token == token) && shouldCancelVibration(vib.attrs, usageFilter);
+ }
+
+ /**
+ * Return true if the external vibration usage belongs to given usage class.
+ *
+ * @param attrs The attributes of an ongoing or pending vibration to be cancelled.
+ * @param usageFilter The vibration usages to be cancelled, any bitwise combination of
+ * VibrationAttributes.USAGE_* values.
+ */
+ private boolean shouldCancelVibration(VibrationAttributes attrs, int usageFilter) {
+ return (usageFilter & attrs.getUsage()) == attrs.getUsage();
+ }
+
+ /**
* Check which mode should be set for a vibration with given {@code uid}, {@code opPkg} and
* {@code attrs}. This will return one of the AppOpsManager.MODE_*.
*/
@@ -1501,7 +1533,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
private int runCancel() {
- cancelVibrate(mToken);
+ cancelVibrate(/* usageFilter= */ -1, mToken);
return 0;
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java
index 014bfd2d40e4..e739a7658a95 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java
@@ -76,4 +76,8 @@ final class FakeVibrator extends Vibrator {
@Override
public void cancel() {
}
+
+ @Override
+ public void cancel(int usageFilter) {
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index e367b7448299..b4c1de1c68f5 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -234,7 +234,7 @@ public class VibratorManagerServiceTest {
CombinedVibration effect = CombinedVibration.createParallel(
VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
- service.cancelVibrate(service);
+ service.cancelVibrate(/* usageFilter= */ -1, service);
assertTrue(service.setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
@@ -880,17 +880,42 @@ public class VibratorManagerServiceTest {
}
@Test
- public void cancelVibrate_stopsVibrating() throws Exception {
+ public void cancelVibrate_withoutUsageFilter_stopsVibrating() throws Exception {
mockVibrators(1);
VibratorManagerService service = createSystemReadyService();
- service.cancelVibrate(service);
+ service.cancelVibrate(/* usageFilter= */ -1, service);
assertFalse(service.isVibrating(1));
- vibrate(service, VibrationEffect.createOneShot(10_000, 100), ALARM_ATTRS);
+ vibrate(service, VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100), ALARM_ATTRS);
assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
- service.cancelVibrate(service);
+ service.cancelVibrate(/* usageFilter= */ -1, service);
+ assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
+ }
+
+ @Test
+ public void cancelVibrate_withFilter_onlyCancelsVibrationWithFilteredUsage() throws Exception {
+ mockVibrators(1);
+ VibratorManagerService service = createSystemReadyService();
+
+ vibrate(service, VibrationEffect.createOneShot(10 * TEST_TIMEOUT_MILLIS, 100), ALARM_ATTRS);
+ assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
+
+ // Vibration is not cancelled with a different usage.
+ service.cancelVibrate(VibrationAttributes.USAGE_RINGTONE, service);
+ assertFalse(waitUntil(s -> !s.isVibrating(1), service, /* timeout= */ 50));
+
+ // Vibration is not cancelled with a different usage class used as filter.
+ service.cancelVibrate(
+ VibrationAttributes.USAGE_CLASS_FEEDBACK | ~VibrationAttributes.USAGE_CLASS_MASK,
+ service);
+ assertFalse(waitUntil(s -> !s.isVibrating(1), service, /* timeout= */ 50));
+
+ // Vibration is cancelled with usage class as filter.
+ service.cancelVibrate(
+ VibrationAttributes.USAGE_CLASS_ALARM | ~VibrationAttributes.USAGE_CLASS_MASK,
+ service);
assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index ff881748cfea..00eb0f284719 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -64,6 +64,7 @@ import android.os.Handler;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
@@ -444,11 +445,14 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
}
private void verifyStopVibrate() {
- verify(mVibrator, times(1)).cancel();
+ int alarmClassUsageFilter =
+ VibrationAttributes.USAGE_CLASS_ALARM | ~VibrationAttributes.USAGE_CLASS_MASK;
+ verify(mVibrator, times(1)).cancel(eq(alarmClassUsageFilter));
}
- private void verifyNeverStopVibrate() throws RemoteException {
+ private void verifyNeverStopVibrate() {
verify(mVibrator, never()).cancel();
+ verify(mVibrator, never()).cancel(anyInt());
}
private void verifyNeverLights() {
diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
index 7cd2c23162fb..e0f3f03e9cb7 100644
--- a/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
+++ b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
@@ -140,7 +140,7 @@ public class VibratorManagerServicePermissionTest {
@Test
public void testCancelVibrateFails() throws RemoteException {
expectSecurityException("VIBRATE");
- mVibratorService.cancelVibrate(new Binder());
+ mVibratorService.cancelVibrate(/* usageFilter= */ -1, new Binder());
}
private void expectSecurityException(String expectedPermission) {