Merge "Add Vibrator.cancel method with usage filters" into sc-dev
This commit is contained in:
@@ -175,4 +175,9 @@ final class InputDeviceVibrator extends Vibrator {
|
||||
public void cancel() {
|
||||
mInputManager.cancelVibrate(mDeviceId, mToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(int usageFilter) {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,4 +134,9 @@ public class InputDeviceVibratorManager extends VibratorManager
|
||||
public void cancel() {
|
||||
mInputManager.cancelVibrate(mDeviceId, mToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(int usageFilter) {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -54,4 +54,8 @@ public class NullVibrator extends Vibrator {
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(int usageFilter) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -493,6 +493,16 @@ public abstract class Vibrator {
|
||||
@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);
|
||||
|
||||
/**
|
||||
* Check whether the vibrator is vibrating.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
@@ -692,6 +700,30 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,4 +76,8 @@ final class FakeVibrator extends Vibrator {
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(int usageFilter) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user