summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lais Andrade <lsandrade@google.com> 2021-11-23 14:56:11 +0000
committer Lais Andrade <lsandrade@google.com> 2021-12-02 12:09:26 +0000
commit27ca44272fa75cbd4050a3ae2510f82226c3a1ac (patch)
treeaee266044fd6f1608443c8ac3f5d174d27220e49
parent502ab7764e25ca8b40a274e2aef31aea84c82e86 (diff)
Enable hardware feedback in background and disable touch feedback in silent mode
Move method that validates all settings applied to a incoming vibration into VibrationSettings. Modify battery-saver mode and backgound process validation to use allowlist of usage filters. Fix: 207362379 Fix: 165478128 Test: VibrationSettingsTest Change-Id: I8e80c29a872aa000986ed5dbdd169d5550978b66
-rw-r--r--core/java/android/os/VibrationAttributes.java17
-rw-r--r--services/core/java/com/android/server/vibrator/Vibration.java2
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationSettings.java203
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java366
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java292
5 files changed, 512 insertions, 368 deletions
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 9612ca6addcd..58315736f37f 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -136,7 +136,7 @@ public final class VibrationAttributes implements Parcelable {
/**
* @hide
*/
- @IntDef(prefix = { "FLAG_" }, value = {
+ @IntDef(prefix = { "FLAG_" }, flag = true, value = {
FLAG_BYPASS_INTERRUPTION_POLICY,
})
@Retention(RetentionPolicy.SOURCE)
@@ -162,7 +162,8 @@ public final class VibrationAttributes implements Parcelable {
private final int mFlags;
private final int mOriginalAudioUsage;
- private VibrationAttributes(int usage, int audioUsage, int flags) {
+ private VibrationAttributes(@Usage int usage, @AudioAttributes.AttributeUsage int audioUsage,
+ @Flag int flags) {
mUsage = usage;
mOriginalAudioUsage = audioUsage;
mFlags = flags & FLAG_ALL_SUPPORTED;
@@ -172,6 +173,7 @@ public final class VibrationAttributes implements Parcelable {
* Return the vibration usage class.
* @return USAGE_CLASS_ALARM, USAGE_CLASS_FEEDBACK or USAGE_CLASS_UNKNOWN
*/
+ @UsageClass
public int getUsageClass() {
return mUsage & USAGE_CLASS_MASK;
}
@@ -180,6 +182,7 @@ public final class VibrationAttributes implements Parcelable {
* Return the vibration usage.
* @return one of the values that can be set in {@link Builder#setUsage(int)}
*/
+ @Usage
public int getUsage() {
return mUsage;
}
@@ -188,6 +191,7 @@ public final class VibrationAttributes implements Parcelable {
* Return the flags.
* @return a combined mask of all flags
*/
+ @Flag
public int getFlags() {
return mFlags;
}
@@ -196,7 +200,7 @@ public final class VibrationAttributes implements Parcelable {
* Check whether a flag is set
* @return true if a flag is set and false otherwise
*/
- public boolean isFlagSet(int flag) {
+ public boolean isFlagSet(@Flag int flag) {
return (mFlags & flag) > 0;
}
@@ -206,6 +210,7 @@ public final class VibrationAttributes implements Parcelable {
* @hide
*/
@TestApi
+ @AudioAttributes.AttributeUsage
public int getAudioUsage() {
if (mOriginalAudioUsage != AudioAttributes.USAGE_UNKNOWN) {
// Return same audio usage set in the Builder.
@@ -292,7 +297,7 @@ public final class VibrationAttributes implements Parcelable {
}
/** @hide */
- public static String usageToString(int usage) {
+ public static String usageToString(@Usage int usage) {
switch (usage) {
case USAGE_UNKNOWN:
return "UNKNOWN";
@@ -419,7 +424,7 @@ public final class VibrationAttributes implements Parcelable {
* {@link VibrationAttributes#USAGE_MEDIA}.
* @return the same Builder instance.
*/
- public @NonNull Builder setUsage(int usage) {
+ public @NonNull Builder setUsage(@Usage int usage) {
mOriginalAudioUsage = AudioAttributes.USAGE_UNKNOWN;
mUsage = usage;
return this;
@@ -431,7 +436,7 @@ public final class VibrationAttributes implements Parcelable {
* @param mask Bit range that should be changed.
* @return the same Builder instance.
*/
- public @NonNull Builder setFlags(int flags, int mask) {
+ public @NonNull Builder setFlags(@Flag int flags, int mask) {
mask &= FLAG_ALL_SUPPORTED;
mFlags = (mFlags & ~mask) | (flags & mask);
return this;
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index ddac9cd84d05..1d6e1585872d 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -53,13 +53,13 @@ final class Vibration {
IGNORED,
IGNORED_APP_OPS,
IGNORED_BACKGROUND,
- IGNORED_RINGTONE,
IGNORED_UNKNOWN_VIBRATION,
IGNORED_UNSUPPORTED,
IGNORED_FOR_ALARM,
IGNORED_FOR_EXTERNAL,
IGNORED_FOR_ONGOING,
IGNORED_FOR_POWER,
+ IGNORED_FOR_RINGER_MODE,
IGNORED_FOR_SETTINGS,
IGNORED_SUPERSEDED,
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index f82f99d6a253..1ee115dd28f2 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -53,12 +53,44 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/** Controls all the system settings related to vibration. */
final class VibrationSettings {
private static final String TAG = "VibrationSettings";
+ /**
+ * Set of usages allowed for vibrations from background processes.
+ *
+ * <p>Some examples are notification, ringtone or alarm vibrations, that are allowed to vibrate
+ * unexpectedly as they are meant to grab the user's attention. Hardware feedback and physical
+ * emulation are also supported, as the trigger process might still be in the background when
+ * the user interaction wakes the device.
+ */
+ private static final Set<Integer> BACKGROUND_PROCESS_USAGE_ALLOWLIST = new HashSet<>(
+ Arrays.asList(
+ USAGE_RINGTONE,
+ USAGE_ALARM,
+ USAGE_NOTIFICATION,
+ USAGE_COMMUNICATION_REQUEST,
+ USAGE_HARDWARE_FEEDBACK,
+ USAGE_PHYSICAL_EMULATION));
+
+ /**
+ * Set of usages allowed for vibrations in battery saver mode (low power).
+ *
+ * <p>Some examples are ringtone or alarm vibrations, that have high priority and should vibrate
+ * even when the device is saving battery.
+ */
+ private static final Set<Integer> BATTERY_SAVER_USAGE_ALLOWLIST = new HashSet<>(
+ Arrays.asList(
+ USAGE_RINGTONE,
+ USAGE_ALARM,
+ USAGE_COMMUNICATION_REQUEST));
+
/** Listener for changes on vibration settings. */
interface OnVibratorSettingsChanged {
/** Callback triggered when any of the vibrator settings change. */
@@ -94,8 +126,6 @@ final class VibrationSettings {
@GuardedBy("mLock")
private boolean mApplyRampingRinger;
@GuardedBy("mLock")
- private int mZenMode;
- @GuardedBy("mLock")
private int mHapticFeedbackIntensity;
@GuardedBy("mLock")
private int mHardwareFeedbackIntensity;
@@ -104,7 +134,7 @@ final class VibrationSettings {
@GuardedBy("mLock")
private int mRingIntensity;
@GuardedBy("mLock")
- private boolean mLowPowerMode;
+ private boolean mBatterySaverMode;
VibrationSettings(Context context, Handler handler) {
this(context, handler,
@@ -172,8 +202,8 @@ final class VibrationSettings {
public void onLowPowerModeChanged(PowerSaveState result) {
boolean shouldNotifyListeners;
synchronized (mLock) {
- shouldNotifyListeners = result.batterySaverEnabled != mLowPowerMode;
- mLowPowerMode = result.batterySaverEnabled;
+ shouldNotifyListeners = result.batterySaverEnabled != mBatterySaverMode;
+ mBatterySaverMode = result.batterySaverEnabled;
}
if (shouldNotifyListeners) {
notifyListeners();
@@ -187,7 +217,6 @@ final class VibrationSettings {
registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING));
registerSettingsObserver(Settings.System.getUriFor(Settings.System.APPLY_RAMPING_RINGER));
- registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.ZEN_MODE));
registerSettingsObserver(
Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY));
registerSettingsObserver(
@@ -299,71 +328,78 @@ final class VibrationSettings {
return mFallbackEffects.get(effectId);
}
+ /** Return {@code true} if input devices should vibrate instead of this device. */
+ public boolean shouldVibrateInputDevices() {
+ return mVibrateInputDevices;
+ }
+
/**
- * Return {@code true} if the device should vibrate for current ringer mode.
+ * Check if given vibration should be ignored by the service.
*
- * <p>This checks the current {@link AudioManager#getRingerModeInternal()} against user settings
- * for ringtone usage only. All other usages are allowed independently of ringer mode.
+ * @return One of Vibration.Status.IGNORED_* values if the vibration should be ignored,
+ * null otherwise.
*/
- public boolean shouldVibrateForRingerMode(int usageHint) {
- if (usageHint != USAGE_RINGTONE) {
- return true;
- }
+ @Nullable
+ public Vibration.Status shouldIgnoreVibration(int uid, VibrationAttributes attrs) {
+ final int usage = attrs.getUsage();
synchronized (mLock) {
- if (mAudioManager == null) {
- return false;
+ if (!mUidObserver.isUidForeground(uid)
+ && !BACKGROUND_PROCESS_USAGE_ALLOWLIST.contains(usage)) {
+ return Vibration.Status.IGNORED_BACKGROUND;
}
- int ringerMode = mAudioManager.getRingerModeInternal();
- if (mVibrateWhenRinging) {
- return ringerMode != AudioManager.RINGER_MODE_SILENT;
- } else if (mApplyRampingRinger) {
- return ringerMode != AudioManager.RINGER_MODE_SILENT;
- } else {
- return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+
+ if (mBatterySaverMode && !BATTERY_SAVER_USAGE_ALLOWLIST.contains(usage)) {
+ return Vibration.Status.IGNORED_FOR_POWER;
}
- }
- }
- /**
- * Returns {@code true} if this vibration is allowed for given {@code uid}.
- *
- * <p>This checks if the user is aware of this foreground process, or if the vibration usage is
- * allowed to play in the background (i.e. it's a notification, ringtone or alarm vibration).
- */
- public boolean shouldVibrateForUid(int uid, int usageHint) {
- return mUidObserver.isUidForeground(uid) || isClassAlarm(usageHint);
+ int intensity = getCurrentIntensity(usage);
+ if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
+ return Vibration.Status.IGNORED_FOR_SETTINGS;
+ }
+
+ if (!shouldVibrateForRingerModeLocked(usage)) {
+ return Vibration.Status.IGNORED_FOR_RINGER_MODE;
+ }
+ }
+ return null;
}
/**
- * Returns {@code true} if this vibration is allowed for current power mode state.
+ * Return {@code true} if the device should vibrate for current ringer mode.
*
- * <p>This checks if the device is in battery saver mode, in which case only alarm, ringtone and
- * {@link VibrationAttributes#USAGE_COMMUNICATION_REQUEST} usages are allowed to vibrate.
+ * <p>This checks the current {@link AudioManager#getRingerModeInternal()} against user settings
+ * for touch and ringtone usages only. All other usages are allowed by this method.
*/
- public boolean shouldVibrateForPowerMode(int usageHint) {
- synchronized (mLock) {
- return !mLowPowerMode || usageHint == USAGE_RINGTONE || usageHint == USAGE_ALARM
- || usageHint == USAGE_COMMUNICATION_REQUEST;
+ @GuardedBy("mLock")
+ private boolean shouldVibrateForRingerModeLocked(int usageHint) {
+ // If audio manager was not loaded yet then assume most restrictive mode.
+ int ringerMode = (mAudioManager == null)
+ ? AudioManager.RINGER_MODE_SILENT
+ : mAudioManager.getRingerModeInternal();
+
+ switch (usageHint) {
+ case USAGE_TOUCH:
+ // Touch feedback disabled when phone is on silent mode.
+ return ringerMode != AudioManager.RINGER_MODE_SILENT;
+ case USAGE_RINGTONE:
+ switch (ringerMode) {
+ case AudioManager.RINGER_MODE_SILENT:
+ return false;
+ case AudioManager.RINGER_MODE_VIBRATE:
+ return true;
+ default:
+ // Ringtone vibrations also depend on 2 other settings:
+ return mVibrateWhenRinging || mApplyRampingRinger;
+ }
+ default:
+ // All other usages ignore ringer mode settings.
+ return true;
}
}
- /** Return {@code true} if input devices should vibrate instead of this device. */
- public boolean shouldVibrateInputDevices() {
- return mVibrateInputDevices;
- }
-
- /** Return {@code true} if setting for {@link Settings.Global#ZEN_MODE} is not OFF. */
- public boolean isInZenMode() {
- return mZenMode != Settings.Global.ZEN_MODE_OFF;
- }
-
- private static boolean isClassAlarm(int usageHint) {
- return (usageHint & VibrationAttributes.USAGE_CLASS_MASK)
- == VibrationAttributes.USAGE_CLASS_ALARM;
- }
-
/** Updates all vibration settings and triggers registered listeners. */
- public void updateSettings() {
+ @VisibleForTesting
+ void updateSettings() {
synchronized (mLock) {
mVibrateWhenRinging = getSystemSetting(Settings.System.VIBRATE_WHEN_RINGING, 0) != 0;
mApplyRampingRinger = getSystemSetting(Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
@@ -378,7 +414,6 @@ final class VibrationSettings {
mRingIntensity = getSystemSetting(Settings.System.RING_VIBRATION_INTENSITY,
getDefaultIntensity(USAGE_RINGTONE));
mVibrateInputDevices = getSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0;
- mZenMode = getGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
}
notifyListeners();
}
@@ -399,31 +434,33 @@ final class VibrationSettings {
@Override
public String toString() {
- return "VibrationSettings{"
- + "mVibrateInputDevices=" + mVibrateInputDevices
- + ", mVibrateWhenRinging=" + mVibrateWhenRinging
- + ", mApplyRampingRinger=" + mApplyRampingRinger
- + ", mLowPowerMode=" + mLowPowerMode
- + ", mZenMode=" + Settings.Global.zenModeToString(mZenMode)
- + ", mProcStatesCache=" + mUidObserver.mProcStatesCache
- + ", mHapticChannelMaxVibrationAmplitude=" + getHapticChannelMaxVibrationAmplitude()
- + ", mRampStepDuration=" + mRampStepDuration
- + ", mRampDownDuration=" + mRampDownDuration
- + ", mHardwareHapticFeedbackIntensity="
- + intensityToString(getCurrentIntensity(USAGE_HARDWARE_FEEDBACK))
- + ", mHapticFeedbackIntensity="
- + intensityToString(getCurrentIntensity(USAGE_TOUCH))
- + ", mHapticFeedbackDefaultIntensity="
- + intensityToString(getDefaultIntensity(USAGE_TOUCH))
- + ", mNotificationIntensity="
- + intensityToString(getCurrentIntensity(USAGE_NOTIFICATION))
- + ", mNotificationDefaultIntensity="
- + intensityToString(getDefaultIntensity(USAGE_NOTIFICATION))
- + ", mRingIntensity="
- + intensityToString(getCurrentIntensity(USAGE_RINGTONE))
- + ", mRingDefaultIntensity="
- + intensityToString(getDefaultIntensity(USAGE_RINGTONE))
- + '}';
+ synchronized (mLock) {
+ return "VibrationSettings{"
+ + "mVibrateInputDevices=" + mVibrateInputDevices
+ + ", mVibrateWhenRinging=" + mVibrateWhenRinging
+ + ", mApplyRampingRinger=" + mApplyRampingRinger
+ + ", mBatterySaverMode=" + mBatterySaverMode
+ + ", mProcStatesCache=" + mUidObserver.mProcStatesCache
+ + ", mHapticChannelMaxVibrationAmplitude="
+ + getHapticChannelMaxVibrationAmplitude()
+ + ", mRampStepDuration=" + mRampStepDuration
+ + ", mRampDownDuration=" + mRampDownDuration
+ + ", mHardwareHapticFeedbackIntensity="
+ + intensityToString(getCurrentIntensity(USAGE_HARDWARE_FEEDBACK))
+ + ", mHapticFeedbackIntensity="
+ + intensityToString(getCurrentIntensity(USAGE_TOUCH))
+ + ", mHapticFeedbackDefaultIntensity="
+ + intensityToString(getDefaultIntensity(USAGE_TOUCH))
+ + ", mNotificationIntensity="
+ + intensityToString(getCurrentIntensity(USAGE_NOTIFICATION))
+ + ", mNotificationDefaultIntensity="
+ + intensityToString(getDefaultIntensity(USAGE_NOTIFICATION))
+ + ", mRingIntensity="
+ + intensityToString(getCurrentIntensity(USAGE_RINGTONE))
+ + ", mRingDefaultIntensity="
+ + intensityToString(getDefaultIntensity(USAGE_RINGTONE))
+ + '}';
+ }
}
/** Write current settings into given {@link ProtoOutputStream}. */
@@ -480,10 +517,6 @@ final class VibrationSettings {
settingName, defaultValue, UserHandle.USER_CURRENT);
}
- private int getGlobalSetting(String settingName, int defaultValue) {
- return Settings.Global.getInt(mContext.getContentResolver(), settingName, defaultValue);
- }
-
private void registerSettingsObserver(Uri settingUri) {
mContext.getContentResolver().registerContentObserver(
settingUri, /* notifyForDescendants= */ true, mSettingObserver,
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 97172015f9f0..478e86e5f710 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -46,7 +46,6 @@ import android.os.ShellCommand;
import android.os.Trace;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
-import android.os.Vibrator;
import android.os.VibratorInfo;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.VibrationEffectSegment;
@@ -394,13 +393,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
if (DEBUG) {
Slog.d(TAG, "Starting vibrate for vibration " + vib.id);
}
- Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(vib);
- if (ignoreStatus != null) {
- endVibrationLocked(vib, ignoreStatus);
- return vib;
+ Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
+ vib.uid, vib.opPkg, vib.attrs);
+
+ if (ignoreStatus == null) {
+ ignoreStatus = shouldIgnoreVibrationForOngoingLocked(vib);
}
- ignoreStatus = shouldIgnoreVibrationForCurrentLocked(vib);
if (ignoreStatus != null) {
endVibrationLocked(vib, ignoreStatus);
return vib;
@@ -453,8 +452,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
&& shouldCancelVibration(
mCurrentExternalVibration.externalVibration.getVibrationAttributes(),
usageFilter)) {
- mCurrentExternalVibration.end(Vibration.Status.CANCELLED);
- mVibratorManagerRecords.record(mCurrentExternalVibration);
+ endVibrationLocked(mCurrentExternalVibration, Vibration.Status.CANCELLED);
mCurrentExternalVibration.externalVibration.mute();
mCurrentExternalVibration = null;
setExternalControl(false);
@@ -482,15 +480,76 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
try {
if (isDumpProto) {
- mVibratorManagerRecords.dumpProto(fd);
+ dumpProto(fd);
} else {
- mVibratorManagerRecords.dumpText(pw);
+ dumpText(pw);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
+ private void dumpText(PrintWriter pw) {
+ if (DEBUG) {
+ Slog.d(TAG, "Dumping vibrator manager service to text...");
+ }
+ synchronized (mLock) {
+ pw.println("Vibrator Manager Service:");
+ pw.println(" mVibrationSettings:");
+ pw.println(" " + mVibrationSettings);
+ pw.println();
+ pw.println(" mVibratorControllers:");
+ for (int i = 0; i < mVibrators.size(); i++) {
+ pw.println(" " + mVibrators.valueAt(i));
+ }
+ pw.println();
+ pw.println(" mCurrentVibration:");
+ pw.println(" " + (mCurrentVibration == null
+ ? null : mCurrentVibration.getVibration().getDebugInfo()));
+ pw.println();
+ pw.println(" mNextVibration:");
+ pw.println(" " + (mNextVibration == null
+ ? null : mNextVibration.getVibration().getDebugInfo()));
+ pw.println();
+ pw.println(" mCurrentExternalVibration:");
+ pw.println(" " + (mCurrentExternalVibration == null
+ ? null : mCurrentExternalVibration.getDebugInfo()));
+ pw.println();
+ }
+ mVibratorManagerRecords.dumpText(pw);
+ }
+
+ synchronized void dumpProto(FileDescriptor fd) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ if (DEBUG) {
+ Slog.d(TAG, "Dumping vibrator manager service to proto...");
+ }
+ synchronized (mLock) {
+ mVibrationSettings.dumpProto(proto);
+ if (mCurrentVibration != null) {
+ mCurrentVibration.getVibration().getDebugInfo().dumpProto(proto,
+ VibratorManagerServiceDumpProto.CURRENT_VIBRATION);
+ }
+ if (mCurrentExternalVibration != null) {
+ mCurrentExternalVibration.getDebugInfo().dumpProto(proto,
+ VibratorManagerServiceDumpProto.CURRENT_EXTERNAL_VIBRATION);
+ }
+
+ boolean isVibrating = false;
+ boolean isUnderExternalControl = false;
+ for (int i = 0; i < mVibrators.size(); i++) {
+ proto.write(VibratorManagerServiceDumpProto.VIBRATOR_IDS, mVibrators.keyAt(i));
+ isVibrating |= mVibrators.valueAt(i).isVibrating();
+ isUnderExternalControl |= mVibrators.valueAt(i).isUnderExternalControl();
+ }
+ proto.write(VibratorManagerServiceDumpProto.IS_VIBRATING, isVibrating);
+ proto.write(VibratorManagerServiceDumpProto.VIBRATOR_UNDER_EXTERNAL_CONTROL,
+ isUnderExternalControl);
+ }
+ mVibratorManagerRecords.dumpProto(proto);
+ proto.flush();
+ }
+
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback cb, ResultReceiver resultReceiver) {
@@ -515,8 +574,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
return;
}
- if (inputDevicesChanged || !mVibrationSettings.shouldVibrateForPowerMode(
- mCurrentVibration.getVibration().attrs.getUsage())) {
+ Vibration vib = mCurrentVibration.getVibration();
+ Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
+ vib.uid, vib.opPkg, vib.attrs);
+
+ if (inputDevicesChanged || (ignoreStatus != null)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Canceling vibration because settings changed: "
+ + (inputDevicesChanged ? "input devices changed" : ignoreStatus));
+ }
mCurrentVibration.cancel();
}
}
@@ -602,15 +668,56 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
@GuardedBy("mLock")
private void endVibrationLocked(Vibration vib, Vibration.Status status) {
vib.end(status);
+ logVibrationStatus(vib.uid, vib.attrs, status);
mVibratorManagerRecords.record(vib);
}
@GuardedBy("mLock")
private void endVibrationLocked(ExternalVibrationHolder vib, Vibration.Status status) {
vib.end(status);
+ logVibrationStatus(vib.externalVibration.getUid(),
+ vib.externalVibration.getVibrationAttributes(), status);
mVibratorManagerRecords.record(vib);
}
+ private void logVibrationStatus(int uid, VibrationAttributes attrs, Vibration.Status status) {
+ switch (status) {
+ case IGNORED_BACKGROUND:
+ Slog.e(TAG, "Ignoring incoming vibration as process with"
+ + " uid= " + uid + " is background," + " attrs= " + attrs);
+ break;
+ case IGNORED_ERROR_APP_OPS:
+ Slog.w(TAG, "Would be an error: vibrate from uid " + uid);
+ break;
+ case IGNORED_FOR_ALARM:
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
+ }
+ break;
+ case IGNORED_FOR_EXTERNAL:
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
+ }
+ break;
+ case IGNORED_FOR_ONGOING:
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring incoming vibration in favor of repeating vibration");
+ }
+ break;
+ case IGNORED_FOR_RINGER_MODE:
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring incoming vibration because of ringer mode, attrs="
+ + attrs);
+ }
+ break;
+ default:
+ if (DEBUG) {
+ Slog.d(TAG, "Vibration for uid=" + uid + " and with attrs=" + attrs
+ + " ended with status " + status);
+ }
+ }
+ }
+
@GuardedBy("mLock")
private void reportFinishedVibrationLocked(Vibration.Status status) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
@@ -651,90 +758,53 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
/**
- * Check if given vibration should be ignored in favour of one of the vibrations currently
- * running on the same vibrators.
+ * Check if given vibration should be ignored by this service because of the ongoing vibration.
*
- * @return One of Vibration.Status.IGNORED_* values if the vibration should be ignored.
+ * @return One of Vibration.Status.IGNORED_* values if the vibration should be ignored, null
+ * otherwise.
*/
@GuardedBy("mLock")
@Nullable
- private Vibration.Status shouldIgnoreVibrationForCurrentLocked(Vibration vibration) {
- if (vibration.isRepeating()) {
- // Repeating vibrations always take precedence.
- return null;
+ private Vibration.Status shouldIgnoreVibrationForOngoingLocked(Vibration vib) {
+ if (mCurrentExternalVibration != null) {
+ // If something has external control of the vibrator, assume that it's more important.
+ return Vibration.Status.IGNORED_FOR_EXTERNAL;
}
- if (mCurrentVibration != null && !mCurrentVibration.getVibration().hasEnded()) {
- if (mCurrentVibration.getVibration().attrs.getUsage()
- == VibrationAttributes.USAGE_ALARM) {
- if (DEBUG) {
- Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
- }
- return Vibration.Status.IGNORED_FOR_ALARM;
- }
- if (mCurrentVibration.getVibration().isRepeating()) {
- if (DEBUG) {
- Slog.d(TAG, "Ignoring incoming vibration in favor of repeating vibration");
- }
- return Vibration.Status.IGNORED_FOR_ONGOING;
- }
+
+ if (mCurrentVibration == null || vib.isRepeating()) {
+ // Incoming repeating vibrations always take precedence over ongoing vibrations.
+ return null;
}
- return null;
- }
- /**
- * Check if given vibration should be ignored by this service.
- *
- * @return One of Vibration.Status.IGNORED_* values if the vibration should be ignored.
- * @see #shouldIgnoreVibrationLocked(int, String, VibrationAttributes)
- */
- @GuardedBy("mLock")
- @Nullable
- private Vibration.Status shouldIgnoreVibrationLocked(Vibration vib) {
- // If something has external control of the vibrator, assume that it's more important.
- if (mCurrentExternalVibration != null) {
- if (DEBUG) {
- Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
- }
- return Vibration.Status.IGNORED_FOR_EXTERNAL;
+ Vibration currentVibration = mCurrentVibration.getVibration();
+ if (currentVibration.hasEnded()) {
+ // Current vibration is finishing up, it should not block incoming vibrations.
+ return null;
}
- if (!mVibrationSettings.shouldVibrateForUid(vib.uid, vib.attrs.getUsage())) {
- Slog.e(TAG, "Ignoring incoming vibration as process with"
- + " uid= " + vib.uid + " is background,"
- + " attrs= " + vib.attrs);
- return Vibration.Status.IGNORED_BACKGROUND;
+ if (currentVibration.attrs.getUsage() == VibrationAttributes.USAGE_ALARM) {
+ return Vibration.Status.IGNORED_FOR_ALARM;
}
- return shouldIgnoreVibrationLocked(vib.uid, vib.opPkg, vib.attrs);
+ if (currentVibration.isRepeating()) {
+ return Vibration.Status.IGNORED_FOR_ONGOING;
+ }
+ return null;
}
/**
- * Check if a vibration with given {@code uid}, {@code opPkg} and {@code attrs} should be
- * ignored by this service.
+ * Check if given vibration should be ignored by this service.
*
- * @param uid The user id of this vibration
- * @param opPkg The package name of this vibration
- * @param attrs The attributes of this vibration
- * @return One of Vibration.Status.IGNORED_* values if the vibration should be ignored.
+ * @return One of Vibration.Status.IGNORED_* values if the vibration should be ignored, null
+ * otherwise.
*/
@GuardedBy("mLock")
@Nullable
private Vibration.Status shouldIgnoreVibrationLocked(int uid, String opPkg,
VibrationAttributes attrs) {
- if (!mVibrationSettings.shouldVibrateForPowerMode(attrs.getUsage())) {
- return Vibration.Status.IGNORED_FOR_POWER;
- }
-
- int intensity = mVibrationSettings.getCurrentIntensity(attrs.getUsage());
- if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
- return Vibration.Status.IGNORED_FOR_SETTINGS;
- }
-
- if (!mVibrationSettings.shouldVibrateForRingerMode(attrs.getUsage())) {
- if (DEBUG) {
- Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
- }
- return Vibration.Status.IGNORED_RINGTONE;
+ Vibration.Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(uid, attrs);
+ if (statusFromSettings != null) {
+ return statusFromSettings;
}
int mode = checkAppOpModeLocked(uid, opPkg, attrs);
@@ -742,7 +812,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
if (mode == AppOpsManager.MODE_ERRORED) {
// We might be getting calls from within system_server, so we don't actually
// want to throw a SecurityException here.
- Slog.w(TAG, "Would be an error: vibrate from uid " + uid);
return Vibration.Status.IGNORED_ERROR_APP_OPS;
} else {
return Vibration.Status.IGNORED_APP_OPS;
@@ -1236,21 +1305,18 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
/** Keep records of vibrations played and provide debug information for this service. */
- private final class VibratorManagerRecords {
- @GuardedBy("mLock")
+ private static final class VibratorManagerRecords {
private final SparseArray<LinkedList<Vibration.DebugInfo>> mPreviousVibrations =
new SparseArray<>();
- @GuardedBy("mLock")
private final LinkedList<Vibration.DebugInfo> mPreviousExternalVibrations =
new LinkedList<>();
private final int mPreviousVibrationsLimit;
- private VibratorManagerRecords(int limit) {
+ VibratorManagerRecords(int limit) {
mPreviousVibrationsLimit = limit;
}
- @GuardedBy("mLock")
- void record(Vibration vib) {
+ synchronized void record(Vibration vib) {
int usage = vib.attrs.getUsage();
if (!mPreviousVibrations.contains(usage)) {
mPreviousVibrations.put(usage, new LinkedList<>());
@@ -1258,122 +1324,67 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
record(mPreviousVibrations.get(usage), vib.getDebugInfo());
}
- @GuardedBy("mLock")
- void record(ExternalVibrationHolder vib) {
+ synchronized void record(ExternalVibrationHolder vib) {
record(mPreviousExternalVibrations, vib.getDebugInfo());
}
- @GuardedBy("mLock")
- void record(LinkedList<Vibration.DebugInfo> records, Vibration.DebugInfo info) {
+ synchronized void record(LinkedList<Vibration.DebugInfo> records,
+ Vibration.DebugInfo info) {
if (records.size() > mPreviousVibrationsLimit) {
records.removeFirst();
}
records.addLast(info);
}
- void dumpText(PrintWriter pw) {
- pw.println("Vibrator Manager Service:");
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "Dumping vibrator manager service to text...");
- }
- pw.println(" mVibrationSettings:");
- pw.println(" " + mVibrationSettings);
- pw.println();
- pw.println(" mVibratorControllers:");
- for (int i = 0; i < mVibrators.size(); i++) {
- pw.println(" " + mVibrators.valueAt(i));
- }
- pw.println();
- pw.println(" mCurrentVibration:");
- pw.println(" " + (mCurrentVibration == null
- ? null : mCurrentVibration.getVibration().getDebugInfo()));
- pw.println();
- pw.println(" mNextVibration:");
- pw.println(" " + (mNextVibration == null
- ? null : mNextVibration.getVibration().getDebugInfo()));
- pw.println();
- pw.println(" mCurrentExternalVibration:");
- pw.println(" " + (mCurrentExternalVibration == null
- ? null : mCurrentExternalVibration.getDebugInfo()));
- pw.println();
- for (int i = 0; i < mPreviousVibrations.size(); i++) {
- pw.println();
- pw.print(" Previous vibrations for usage ");
- pw.print(VibrationAttributes.usageToString(mPreviousVibrations.keyAt(i)));
- pw.println(":");
- for (Vibration.DebugInfo info : mPreviousVibrations.valueAt(i)) {
- pw.println(" " + info);
- }
- }
-
+ synchronized void dumpText(PrintWriter pw) {
+ for (int i = 0; i < mPreviousVibrations.size(); i++) {
pw.println();
- pw.println(" Previous external vibrations:");
- for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
+ pw.print(" Previous vibrations for usage ");
+ pw.print(VibrationAttributes.usageToString(mPreviousVibrations.keyAt(i)));
+ pw.println(":");
+ for (Vibration.DebugInfo info : mPreviousVibrations.valueAt(i)) {
pw.println(" " + info);
}
}
- }
-
- synchronized void dumpProto(FileDescriptor fd) {
- final ProtoOutputStream proto = new ProtoOutputStream(fd);
-
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "Dumping vibrator manager service to proto...");
- }
- mVibrationSettings.dumpProto(proto);
- if (mCurrentVibration != null) {
- mCurrentVibration.getVibration().getDebugInfo().dumpProto(proto,
- VibratorManagerServiceDumpProto.CURRENT_VIBRATION);
- }
- if (mCurrentExternalVibration != null) {
- mCurrentExternalVibration.getDebugInfo().dumpProto(proto,
- VibratorManagerServiceDumpProto.CURRENT_EXTERNAL_VIBRATION);
- }
- boolean isVibrating = false;
- boolean isUnderExternalControl = false;
- for (int i = 0; i < mVibrators.size(); i++) {
- proto.write(VibratorManagerServiceDumpProto.VIBRATOR_IDS, mVibrators.keyAt(i));
- isVibrating |= mVibrators.valueAt(i).isVibrating();
- isUnderExternalControl |= mVibrators.valueAt(i).isUnderExternalControl();
+ pw.println();
+ pw.println(" Previous external vibrations:");
+ for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
+ pw.println(" " + info);
+ }
+ }
+
+ synchronized void dumpProto(ProtoOutputStream proto) {
+ for (int i = 0; i < mPreviousVibrations.size(); i++) {
+ long fieldId;
+ switch (mPreviousVibrations.keyAt(i)) {
+ case VibrationAttributes.USAGE_RINGTONE:
+ fieldId = VibratorManagerServiceDumpProto.PREVIOUS_RING_VIBRATIONS;
+ break;
+ case VibrationAttributes.USAGE_NOTIFICATION:
+ fieldId = VibratorManagerServiceDumpProto
+ .PREVIOUS_NOTIFICATION_VIBRATIONS;
+ break;
+ case VibrationAttributes.USAGE_ALARM:
+ fieldId = VibratorManagerServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS;
+ break;
+ default:
+ fieldId = VibratorManagerServiceDumpProto.PREVIOUS_VIBRATIONS;
}
- proto.write(VibratorManagerServiceDumpProto.IS_VIBRATING, isVibrating);
- proto.write(VibratorManagerServiceDumpProto.VIBRATOR_UNDER_EXTERNAL_CONTROL,
- isUnderExternalControl);
-
- for (int i = 0; i < mPreviousVibrations.size(); i++) {
- long fieldId;
- switch (mPreviousVibrations.keyAt(i)) {
- case VibrationAttributes.USAGE_RINGTONE:
- fieldId = VibratorManagerServiceDumpProto.PREVIOUS_RING_VIBRATIONS;
- break;
- case VibrationAttributes.USAGE_NOTIFICATION:
- fieldId = VibratorManagerServiceDumpProto
- .PREVIOUS_NOTIFICATION_VIBRATIONS;
- break;
- case VibrationAttributes.USAGE_ALARM:
- fieldId = VibratorManagerServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS;
- break;
- default:
- fieldId = VibratorManagerServiceDumpProto.PREVIOUS_VIBRATIONS;
- }
- for (Vibration.DebugInfo info : mPreviousVibrations.valueAt(i)) {
- info.dumpProto(proto, fieldId);
- }
+ for (Vibration.DebugInfo info : mPreviousVibrations.valueAt(i)) {
+ info.dumpProto(proto, fieldId);
}
+ }
- for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
- info.dumpProto(proto,
- VibratorManagerServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS);
- }
+ for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
+ info.dumpProto(proto,
+ VibratorManagerServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS);
}
- proto.flush();
}
}
/** Clears mNextVibration if set, ending it cleanly */
+ @GuardedBy("mLock")
private void clearNextVibrationLocked(Vibration.Status endStatus) {
if (mNextVibration != null) {
endVibrationLocked(mNextVibration.getVibration(), endStatus);
@@ -1482,6 +1493,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
}
+ @GuardedBy("mLock")
private void stopExternalVibrateLocked(Vibration.Status status) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "stopExternalVibrateLocked");
try {
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index beee2a7520ec..ab9fbb581416 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -32,6 +32,7 @@ import static android.os.Vibrator.VIBRATION_INTENSITY_OFF;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -52,6 +53,7 @@ import android.os.Handler;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.UserHandle;
+import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -124,10 +126,11 @@ public class VibrationSettingsTest {
new Handler(mTestLooper.getLooper()));
mVibrationSettings.onSystemReady();
+ // Simulate System defaults.
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0);
- setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+ setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0);
- setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+ setRingerMode(AudioManager.RINGER_MODE_NORMAL);
}
@After
@@ -142,13 +145,12 @@ public class VibrationSettingsTest {
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0);
- setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_ALARMS);
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
- verify(mListenerMock, times(8)).onChange();
+ verify(mListenerMock, times(7)).onChange();
}
@Test
@@ -173,126 +175,242 @@ public class VibrationSettingsTest {
verifyNoMoreInteractions(mListenerMock);
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
- setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_ALARMS);
}
@Test
- public void shouldVibrateForRingerMode_beforeSystemReady_returnsFalseOnlyForRingtone() {
- setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
- setRingerMode(AudioManager.RINGER_MODE_MAX);
- VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy,
- new Handler(mTestLooper.getLooper()));
+ public void shouldIgnoreVibration_fromBackground_doesNotIgnoreUsagesFromAllowlist() {
+ int[] expectedAllowedVibrations = new int[] {
+ USAGE_RINGTONE,
+ USAGE_ALARM,
+ USAGE_NOTIFICATION,
+ USAGE_COMMUNICATION_REQUEST,
+ USAGE_HARDWARE_FEEDBACK,
+ USAGE_PHYSICAL_EMULATION,
+ };
- assertFalse(vibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_ALARM));
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_TOUCH));
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_NOTIFICATION));
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_COMMUNICATION_REQUEST));
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_HARDWARE_FEEDBACK));
+ mVibrationSettings.mUidObserver.onUidStateChanged(
+ UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
+
+ for (int usage : expectedAllowedVibrations) {
+ assertNull("Error for usage " + VibrationAttributes.usageToString(usage),
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(usage)));
+ }
}
@Test
- public void shouldVibrateForRingerMode_withoutRingtoneUsage_returnsTrue() {
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_ALARM));
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_TOUCH));
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_NOTIFICATION));
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_COMMUNICATION_REQUEST));
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_HARDWARE_FEEDBACK));
+ public void shouldIgnoreVibration_fromBackground_ignoresUsagesNotInAllowlist() {
+ int[] expectedIgnoredVibrations = new int[] {
+ USAGE_TOUCH,
+ USAGE_UNKNOWN,
+ };
+
+ mVibrationSettings.mUidObserver.onUidStateChanged(
+ UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
+
+ for (int usage : expectedIgnoredVibrations) {
+ assertEquals("Error for usage " + VibrationAttributes.usageToString(usage),
+ Vibration.Status.IGNORED_BACKGROUND,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(usage)));
+ }
}
@Test
- public void shouldVibrateForRingerMode_withVibrateWhenRinging_ignoreSettingsForSilentMode() {
- setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+ public void shouldIgnoreVibration_fromForeground_allowsAnyUsage() {
+ mVibrationSettings.mUidObserver.onUidStateChanged(
+ UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
- setRingerMode(AudioManager.RINGER_MODE_SILENT);
- assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_ALARM)));
+ }
- setRingerMode(AudioManager.RINGER_MODE_MAX);
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ @Test
+ public void shouldIgnoreVibration_inBatterySaverMode_doesNotIgnoreUsagesFromAllowlist() {
+ int[] expectedAllowedVibrations = new int[] {
+ USAGE_RINGTONE,
+ USAGE_ALARM,
+ USAGE_COMMUNICATION_REQUEST,
+ };
- setRingerMode(AudioManager.RINGER_MODE_NORMAL);
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
- setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ for (int usage : expectedAllowedVibrations) {
+ assertNull("Error for usage " + VibrationAttributes.usageToString(usage),
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(usage)));
+ }
}
@Test
- public void shouldVibrateForRingerMode_withApplyRampingRinger_ignoreSettingsForSilentMode() {
- setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
- setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 1);
+ public void shouldIgnoreVibration_inBatterySaverMode_ignoresUsagesNotInAllowlist() {
+ int[] expectedIgnoredVibrations = new int[] {
+ USAGE_NOTIFICATION,
+ USAGE_HARDWARE_FEEDBACK,
+ USAGE_PHYSICAL_EMULATION,
+ USAGE_TOUCH,
+ USAGE_UNKNOWN,
+ };
- setRingerMode(AudioManager.RINGER_MODE_SILENT);
- assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
- setRingerMode(AudioManager.RINGER_MODE_MAX);
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ for (int usage : expectedIgnoredVibrations) {
+ assertEquals("Error for usage " + VibrationAttributes.usageToString(usage),
+ Vibration.Status.IGNORED_FOR_POWER,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(usage)));
+ }
+ }
- setRingerMode(AudioManager.RINGER_MODE_NORMAL);
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ @Test
+ public void shouldIgnoreVibration_notInBatterySaverMode_allowsAnyUsage() {
+ mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
- setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_COMMUNICATION_REQUEST)));
}
@Test
- public void shouldVibrateForRingerMode_withAllSettingsOff_onlyVibratesForVibrateMode() {
- setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+ public void shouldIgnoreVibration_withRingerModeSilent_ignoresRingtoneAndTouch() {
+ // Vibrating settings on are overruled by ringer mode.
+ setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0);
+ setRingerMode(AudioManager.RINGER_MODE_SILENT);
+
+ assertEquals(Vibration.Status.IGNORED_FOR_RINGER_MODE,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_RINGTONE)));
+ assertEquals(Vibration.Status.IGNORED_FOR_RINGER_MODE,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_COMMUNICATION_REQUEST)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_HARDWARE_FEEDBACK)));
+ }
+ @Test
+ public void shouldIgnoreVibration_withRingerModeVibrate_allowsAllVibrations() {
+ // Vibrating settings off are overruled by ringer mode.
+ setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+ setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0);
setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
- assertTrue(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
- setRingerMode(AudioManager.RINGER_MODE_SILENT);
- assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_PHYSICAL_EMULATION)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_RINGTONE)));
+ }
- setRingerMode(AudioManager.RINGER_MODE_MAX);
- assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+ @Test
+ public void shouldIgnoreVibration_withRingerModeNormalAndRingSettingsOff_ignoresRingtoneOnly() {
+ // Vibrating settings off are respected for normal ringer mode.
+ setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+ setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0);
+ setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+
+ assertEquals(Vibration.Status.IGNORED_FOR_RINGER_MODE,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_RINGTONE)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_NOTIFICATION)));
+ }
+ @Test
+ public void shouldIgnoreVibration_withRingerModeNormalAndRingSettingsOn_allowsAllVibrations() {
+ setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+ setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0);
setRingerMode(AudioManager.RINGER_MODE_NORMAL);
- assertFalse(mVibrationSettings.shouldVibrateForRingerMode(USAGE_RINGTONE));
+
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_RINGTONE)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_ALARM)));
}
@Test
- public void shouldVibrateForUid_withForegroundOnlyUsage_returnsTrueWhInForeground() {
- assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_TOUCH));
+ public void shouldIgnoreVibration_withRingerModeNormalAndRampingRingerOn_allowsAllVibrations() {
+ setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+ setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 1);
+ setRingerMode(AudioManager.RINGER_MODE_NORMAL);
- mVibrationSettings.mUidObserver.onUidStateChanged(
- UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
- assertFalse(mVibrationSettings.shouldVibrateForUid(UID, USAGE_TOUCH));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_RINGTONE)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_COMMUNICATION_REQUEST)));
}
@Test
- public void shouldVibrateForUid_withBackgroundAllowedUsage_returnTrue() {
- mVibrationSettings.mUidObserver.onUidStateChanged(
- UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
+ public void shouldIgnoreVibration_withHapticFeedbackSettingsOff_ignoresTouchVibration() {
+ setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
- assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_ALARM));
- assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_COMMUNICATION_REQUEST));
- assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_NOTIFICATION));
- assertTrue(mVibrationSettings.shouldVibrateForUid(UID, USAGE_RINGTONE));
+ assertEquals(Vibration.Status.IGNORED_FOR_SETTINGS,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_RINGTONE)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_HARDWARE_FEEDBACK)));
}
@Test
- public void shouldVibrateForPowerMode_withLowPowerAndAllowedUsage_returnTrue() {
- mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
+ public void shouldIgnoreVibration_withHardwareFeedbackSettingsOff_ignoresHardwareVibrations() {
+ setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
- assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_ALARM));
- assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_RINGTONE));
- assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_COMMUNICATION_REQUEST));
+ assertEquals(Vibration.Status.IGNORED_FOR_SETTINGS,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_HARDWARE_FEEDBACK)));
+ assertEquals(Vibration.Status.IGNORED_FOR_SETTINGS,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_PHYSICAL_EMULATION)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_NOTIFICATION)));
}
@Test
- public void shouldVibrateForPowerMode_withRestrictedUsage_returnsFalseWhileInLowPowerMode() {
- mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
+ public void shouldIgnoreVibration_withNotificationSettingsOff_ignoresNotificationVibrations() {
+ setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
- assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_TOUCH));
- assertTrue(mVibrationSettings.shouldVibrateForPowerMode(USAGE_NOTIFICATION));
+ assertEquals(Vibration.Status.IGNORED_FOR_SETTINGS,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_NOTIFICATION)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_ALARM)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_RINGTONE)));
+ }
- mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
+ @Test
+ public void shouldIgnoreVibration_withRingSettingsOff_ignoresRingtoneVibrations() {
+ // Vibrating settings on are overruled by ring intensity setting.
+ setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+ setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 1);
+ setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
+ setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
- assertFalse(mVibrationSettings.shouldVibrateForPowerMode(USAGE_TOUCH));
- assertFalse(mVibrationSettings.shouldVibrateForPowerMode(USAGE_NOTIFICATION));
+ assertEquals(Vibration.Status.IGNORED_FOR_SETTINGS,
+ mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_RINGTONE)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_NOTIFICATION)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_ALARM)));
+ assertNull(mVibrationSettings.shouldIgnoreVibration(UID,
+ VibrationAttributes.createForUsage(USAGE_TOUCH)));
}
@Test
@@ -305,24 +423,6 @@ public class VibrationSettingsTest {
}
@Test
- public void isInZenMode_returnsSettingsValue() {
- setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
- assertFalse(mVibrationSettings.isInZenMode());
-
- setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
- assertTrue(mVibrationSettings.isInZenMode());
- setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_ALARMS);
- assertTrue(mVibrationSettings.isInZenMode());
-
- setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
- assertFalse(mVibrationSettings.isInZenMode());
-
- setGlobalSetting(Settings.Global.ZEN_MODE,
- Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- assertTrue(mVibrationSettings.isInZenMode());
- }
-
- @Test
public void getDefaultIntensity_beforeSystemReady_returnsMediumToAllExceptAlarm() {
mFakeVibrator.setDefaultHapticFeedbackIntensity(VIBRATION_INTENSITY_HIGH);
mFakeVibrator.setDefaultNotificationVibrationIntensity(VIBRATION_INTENSITY_HIGH);
@@ -464,12 +564,6 @@ public class VibrationSettingsTest {
mVibrationSettings.updateSettings();
}
- private void setGlobalSetting(String settingName, int value) {
- Settings.Global.putInt(mContextSpy.getContentResolver(), settingName, value);
- // FakeSettingsProvider don't support testing triggering ContentObserver yet.
- mVibrationSettings.updateSettings();
- }
-
private void setRingerMode(int ringerMode) {
mAudioManager.setRingerModeInternal(ringerMode);
assertEquals(ringerMode, mAudioManager.getRingerModeInternal());