Extract vibration settings and scaling code from VibratorService
Move the existing logic around vibration settings and ContentObserver to
a separate class, that will be used by VibratiorManagerService once
migration is complete.
Also extract the vibration scaling logic to a separate controller, which
will also be used by the VibratorManagerService after migration.
Bug: 167946816
Bug: 131311651
Test: atest FrameworksServiceTests:VibratorServiceTest
atest FrameworksServiceTests:VibrationSettingsTest
atest FrameworksServiceTests:VibrationScaleTest
Change-Id: Idf081e662aa218e93a38cd3262a1357e2e3faf0d
This commit is contained in:
@@ -413,7 +413,7 @@ public abstract class VibrationEffect implements Parcelable {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract VibrationEffect resolve(int defaultAmplitude);
|
||||
public abstract <T extends VibrationEffect> T resolve(int defaultAmplitude);
|
||||
|
||||
/**
|
||||
* Scale the vibration effect intensity with the given constraints.
|
||||
@@ -425,7 +425,7 @@ public abstract class VibrationEffect implements Parcelable {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract VibrationEffect scale(float scaleFactor);
|
||||
public abstract <T extends VibrationEffect> T scale(float scaleFactor);
|
||||
|
||||
/**
|
||||
* Scale given vibration intensity by the given factor.
|
||||
|
||||
@@ -29,11 +29,8 @@ import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.hardware.vibrator.IVibrator;
|
||||
import android.hardware.vibrator.V1_0.EffectStrength;
|
||||
import android.media.AudioManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.Binder;
|
||||
import android.os.ExternalVibration;
|
||||
@@ -56,14 +53,10 @@ import android.os.ShellCallback;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.WorkSource;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
import android.util.DebugUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
@@ -74,6 +67,8 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.server.vibrator.VibrationScaler;
|
||||
import com.android.server.vibrator.VibrationSettings;
|
||||
|
||||
import libcore.util.NativeAllocationRegistry;
|
||||
|
||||
@@ -97,22 +92,6 @@ public class VibratorService extends IVibratorService.Stub
|
||||
|
||||
private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
|
||||
|
||||
// Scale levels. Each level, except MUTE, is defined as the delta between the current setting
|
||||
// and the default intensity for that type of vibration (i.e. current - default).
|
||||
private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
|
||||
private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
|
||||
private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
|
||||
private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
|
||||
private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
|
||||
private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
|
||||
|
||||
// Scale factors for each level.
|
||||
private static final float SCALE_FACTOR_VERY_LOW = 0.6f;
|
||||
private static final float SCALE_FACTOR_LOW = 0.8f;
|
||||
private static final float SCALE_FACTOR_NONE = 1f;
|
||||
private static final float SCALE_FACTOR_HIGH = 1.2f;
|
||||
private static final float SCALE_FACTOR_VERY_HIGH = 1.4f;
|
||||
|
||||
// Default vibration attributes. Used when vibration is requested without attributes
|
||||
private static final VibrationAttributes DEFAULT_ATTRIBUTES =
|
||||
new VibrationAttributes.Builder().build();
|
||||
@@ -120,11 +99,6 @@ public class VibratorService extends IVibratorService.Stub
|
||||
// Used to generate globally unique vibration ids.
|
||||
private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback
|
||||
|
||||
// A mapping from the intensity adjustment to the scaling to apply, where the intensity
|
||||
// adjustment is defined as the delta between the default intensity level and the user selected
|
||||
// intensity level. It's important that we apply the scaling on the delta between the two so
|
||||
// that the default intensity level applies no scaling to application provided effects.
|
||||
private final SparseArray<ScaleLevel> mScaleLevels;
|
||||
private final LinkedList<VibrationInfo> mPreviousRingVibrations;
|
||||
private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
|
||||
private final LinkedList<VibrationInfo> mPreviousAlarmVibrations;
|
||||
@@ -149,8 +123,8 @@ public class VibratorService extends IVibratorService.Stub
|
||||
private final String mSystemUiPackage;
|
||||
private PowerManagerInternal mPowerManagerInternal;
|
||||
private InputManager mIm;
|
||||
private Vibrator mVibrator;
|
||||
private SettingsObserver mSettingObserver;
|
||||
private VibrationSettings mVibrationSettings;
|
||||
private VibrationScaler mVibrationScaler;
|
||||
|
||||
private final NativeWrapper mNativeWrapper;
|
||||
private volatile VibrateWaveformThread mThread;
|
||||
@@ -172,9 +146,6 @@ public class VibratorService extends IVibratorService.Stub
|
||||
@GuardedBy("mLock")
|
||||
private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
|
||||
new RemoteCallbackList<>();
|
||||
private int mHapticFeedbackIntensity;
|
||||
private int mNotificationIntensity;
|
||||
private int mRingIntensity;
|
||||
private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
|
||||
|
||||
static native long vibratorInit(OnCompleteListener listener);
|
||||
@@ -343,7 +314,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
|
||||
private ExternalVibrationHolder(ExternalVibration externalVibration) {
|
||||
this.externalVibration = externalVibration;
|
||||
this.scale = SCALE_NONE;
|
||||
this.scale = IExternalVibratorService.SCALE_NONE;
|
||||
mStartTimeDebug = System.currentTimeMillis();
|
||||
mStatus = VibrationInfo.Status.RUNNING;
|
||||
}
|
||||
@@ -518,20 +489,6 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents the scale that must be applied to a vibration effect intensity. */
|
||||
private static final class ScaleLevel {
|
||||
public final float factor;
|
||||
|
||||
ScaleLevel(float factor) {
|
||||
this.factor = factor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ScaleLevel{factor=" + factor + "}";
|
||||
}
|
||||
}
|
||||
|
||||
VibratorService(Context context) {
|
||||
this(context, new Injector());
|
||||
}
|
||||
@@ -599,13 +556,6 @@ public class VibratorService extends IVibratorService.Stub
|
||||
mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK,
|
||||
VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
|
||||
|
||||
mScaleLevels = new SparseArray<>();
|
||||
mScaleLevels.put(SCALE_VERY_LOW, new ScaleLevel(SCALE_FACTOR_VERY_LOW));
|
||||
mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_FACTOR_LOW));
|
||||
mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_FACTOR_NONE));
|
||||
mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_FACTOR_HIGH));
|
||||
mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_FACTOR_VERY_HIGH));
|
||||
|
||||
injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
|
||||
}
|
||||
|
||||
@@ -628,8 +578,8 @@ public class VibratorService extends IVibratorService.Stub
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
|
||||
try {
|
||||
mIm = mContext.getSystemService(InputManager.class);
|
||||
mVibrator = mContext.getSystemService(Vibrator.class);
|
||||
mSettingObserver = new SettingsObserver(mH);
|
||||
mVibrationSettings = new VibrationSettings(mContext, mH);
|
||||
mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
|
||||
|
||||
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
|
||||
mPowerManagerInternal.registerLowPowerModeObserver(
|
||||
@@ -645,25 +595,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
});
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
|
||||
true, mSettingObserver, UserHandle.USER_ALL);
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
|
||||
true, mSettingObserver, UserHandle.USER_ALL);
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
|
||||
true, mSettingObserver, UserHandle.USER_ALL);
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
|
||||
true, mSettingObserver, UserHandle.USER_ALL);
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
|
||||
true, mSettingObserver, UserHandle.USER_ALL);
|
||||
mVibrationSettings.addListener(this::updateVibrators);
|
||||
|
||||
mContext.registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
@@ -686,17 +618,6 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private final class SettingsObserver extends ContentObserver {
|
||||
public SettingsObserver(Handler handler) {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean SelfChange) {
|
||||
updateVibrators();
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback for when vibration is complete, to be called by native. */
|
||||
@VisibleForTesting
|
||||
public void onVibrationComplete(long vibrationId) {
|
||||
@@ -1118,11 +1039,10 @@ public class VibratorService extends IVibratorService.Stub
|
||||
private void startVibrationLocked(final Vibration vib) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
|
||||
try {
|
||||
final int intensity = getCurrentIntensityLocked(vib.attrs.getUsage());
|
||||
if (!shouldVibrate(vib, intensity)) {
|
||||
if (!shouldVibrate(vib)) {
|
||||
return;
|
||||
}
|
||||
applyVibrationIntensityScalingLocked(vib, intensity);
|
||||
applyVibrationIntensityScalingLocked(vib);
|
||||
startVibrationInnerLocked(vib);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
|
||||
@@ -1171,73 +1091,12 @@ public class VibratorService extends IVibratorService.Stub
|
||||
|| usage == VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
|
||||
}
|
||||
|
||||
private int getCurrentIntensityLocked(int usageHint) {
|
||||
if (isRingtone(usageHint)) {
|
||||
return mRingIntensity;
|
||||
} else if (isNotification(usageHint)) {
|
||||
return mNotificationIntensity;
|
||||
} else if (isHapticFeedback(usageHint)) {
|
||||
return mHapticFeedbackIntensity;
|
||||
} else if (isAlarm(usageHint)) {
|
||||
return Vibrator.VIBRATION_INTENSITY_HIGH;
|
||||
} else {
|
||||
return Vibrator.VIBRATION_INTENSITY_MEDIUM;
|
||||
}
|
||||
}
|
||||
|
||||
private int getDefaultIntensity(int usageHint) {
|
||||
if (isRingtone(usageHint)) {
|
||||
return mVibrator.getDefaultRingVibrationIntensity();
|
||||
} else if (isNotification(usageHint)) {
|
||||
return mVibrator.getDefaultNotificationVibrationIntensity();
|
||||
} else if (isHapticFeedback(usageHint)) {
|
||||
return mVibrator.getDefaultHapticFeedbackIntensity();
|
||||
} else if (isAlarm(usageHint)) {
|
||||
return Vibrator.VIBRATION_INTENSITY_HIGH;
|
||||
} else {
|
||||
return Vibrator.VIBRATION_INTENSITY_MEDIUM;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale the vibration effect by the intensity as appropriate based its intent.
|
||||
*/
|
||||
private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
|
||||
if (vib.effect instanceof VibrationEffect.Prebaked) {
|
||||
// Prebaked effects are always just a direct translation from intensity to
|
||||
// EffectStrength.
|
||||
VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
|
||||
prebaked.setEffectStrength(intensityToEffectStrength(intensity));
|
||||
return;
|
||||
}
|
||||
|
||||
final int defaultIntensity = getDefaultIntensity(vib.attrs.getUsage());
|
||||
final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
|
||||
if (scale == null) {
|
||||
// We should have scaling levels for all cases, so not being able to scale because of a
|
||||
// missing level is unexpected.
|
||||
Slog.e(TAG, "No configured scaling level!"
|
||||
+ " (current=" + intensity + ", default= " + defaultIntensity + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
vib.originalEffect = vib.effect;
|
||||
vib.effect = vib.effect.resolve(mDefaultVibrationAmplitude).scale(scale.factor);
|
||||
vib.scale = scale.factor;
|
||||
}
|
||||
|
||||
private boolean shouldVibrateForRingtone() {
|
||||
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
|
||||
int ringerMode = audioManager.getRingerModeInternal();
|
||||
// "Also vibrate for calls" Setting in Sound
|
||||
if (Settings.System.getInt(
|
||||
mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
|
||||
return ringerMode != AudioManager.RINGER_MODE_SILENT;
|
||||
} else if (Settings.Global.getInt(
|
||||
mContext.getContentResolver(), Settings.Global.APPLY_RAMPING_RINGER, 0) != 0) {
|
||||
return ringerMode != AudioManager.RINGER_MODE_SILENT;
|
||||
} else {
|
||||
return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
|
||||
/** Scale the vibration effect by the intensity as appropriate based its intent. */
|
||||
private void applyVibrationIntensityScalingLocked(Vibration vib) {
|
||||
VibrationEffect scaled = mVibrationScaler.scale(vib.effect, vib.attrs.getUsage());
|
||||
if (!scaled.equals(vib.effect)) {
|
||||
vib.originalEffect = vib.effect;
|
||||
vib.effect = scaled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1262,18 +1121,19 @@ public class VibratorService extends IVibratorService.Stub
|
||||
return mode;
|
||||
}
|
||||
|
||||
private boolean shouldVibrate(Vibration vib, int intensity) {
|
||||
private boolean shouldVibrate(Vibration vib) {
|
||||
if (!shouldVibrateForPowerModeLocked(vib)) {
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_POWER);
|
||||
return false;
|
||||
}
|
||||
|
||||
int intensity = mVibrationSettings.getCurrentIntensity(vib.attrs.getUsage());
|
||||
if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_SETTINGS);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vib.isRingtone() && !shouldVibrateForRingtone()) {
|
||||
if (vib.isRingtone() && !mVibrationSettings.shouldVibrateForRingtone()) {
|
||||
if (DEBUG) {
|
||||
Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
|
||||
}
|
||||
@@ -1335,7 +1195,6 @@ public class VibratorService extends IVibratorService.Stub
|
||||
synchronized (mLock) {
|
||||
boolean devicesUpdated = updateInputDeviceVibratorsLocked();
|
||||
boolean lowPowerModeUpdated = updateLowPowerModeLocked();
|
||||
updateVibrationIntensityLocked();
|
||||
|
||||
if (devicesUpdated || lowPowerModeUpdated) {
|
||||
// If the state changes out from under us then just reset.
|
||||
@@ -1348,13 +1207,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
|
||||
private boolean updateInputDeviceVibratorsLocked() {
|
||||
boolean changed = false;
|
||||
boolean vibrateInputDevices = false;
|
||||
try {
|
||||
vibrateInputDevices = Settings.System.getIntForUser(
|
||||
mContext.getContentResolver(),
|
||||
Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
|
||||
} catch (SettingNotFoundException snfe) {
|
||||
}
|
||||
boolean vibrateInputDevices = mVibrationSettings.shouldVibrateInputDevices();
|
||||
if (vibrateInputDevices != mVibrateInputDevicesSetting) {
|
||||
changed = true;
|
||||
mVibrateInputDevicesSetting = vibrateInputDevices;
|
||||
@@ -1397,26 +1250,13 @@ public class VibratorService extends IVibratorService.Stub
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateVibrationIntensityLocked() {
|
||||
mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
|
||||
Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
|
||||
mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
|
||||
Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
|
||||
mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
|
||||
Settings.System.RING_VIBRATION_INTENSITY,
|
||||
mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
|
||||
}
|
||||
|
||||
private void updateAlwaysOnLocked(int id, Vibration vib) {
|
||||
final int intensity = getCurrentIntensityLocked(vib.attrs.getUsage());
|
||||
if (!shouldVibrate(vib, intensity)) {
|
||||
if (!shouldVibrate(vib)) {
|
||||
mNativeWrapper.vibratorAlwaysOnDisable(id);
|
||||
} else {
|
||||
final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
|
||||
final int strength = intensityToEffectStrength(intensity);
|
||||
mNativeWrapper.vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
|
||||
VibrationEffect.Prebaked scaled = mVibrationScaler.scale(vib.effect,
|
||||
vib.attrs.getUsage());
|
||||
mNativeWrapper.vibratorAlwaysOnEnable(id, scaled.getId(), scaled.getEffectStrength());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1459,8 +1299,8 @@ public class VibratorService extends IVibratorService.Stub
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
|
||||
try {
|
||||
synchronized (mInputDeviceVibrators) {
|
||||
final VibrationEffect.OneShot oneShot =
|
||||
(VibrationEffect.OneShot) vib.effect.resolve(mDefaultVibrationAmplitude);
|
||||
final VibrationEffect.OneShot oneShot = vib.effect.resolve(
|
||||
mDefaultVibrationAmplitude);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Turning vibrator on for " + oneShot.getDuration() + " ms"
|
||||
+ " with amplitude " + oneShot.getAmplitude() + ".");
|
||||
@@ -1547,9 +1387,8 @@ public class VibratorService extends IVibratorService.Stub
|
||||
vib.opPkg, vib.reason + " (fallback)");
|
||||
// Set current vibration before starting it, so callback will work.
|
||||
mCurrentVibration = fallbackVib;
|
||||
final int intensity = getCurrentIntensityLocked(fallbackVib.attrs.getUsage());
|
||||
linkVibration(fallbackVib);
|
||||
applyVibrationIntensityScalingLocked(fallbackVib, intensity);
|
||||
applyVibrationIntensityScalingLocked(fallbackVib);
|
||||
startVibrationInnerLocked(fallbackVib);
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
|
||||
@@ -1594,25 +1433,6 @@ public class VibratorService extends IVibratorService.Stub
|
||||
return mFallbackEffects.get(effectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current desired effect strength.
|
||||
*
|
||||
* If the returned value is < 0 then the vibration shouldn't be played at all.
|
||||
*/
|
||||
private static int intensityToEffectStrength(int intensity) {
|
||||
switch (intensity) {
|
||||
case Vibrator.VIBRATION_INTENSITY_LOW:
|
||||
return EffectStrength.LIGHT;
|
||||
case Vibrator.VIBRATION_INTENSITY_MEDIUM:
|
||||
return EffectStrength.MEDIUM;
|
||||
case Vibrator.VIBRATION_INTENSITY_HIGH:
|
||||
return EffectStrength.STRONG;
|
||||
default:
|
||||
Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
|
||||
return EffectStrength.STRONG;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isNotification(int usageHint) {
|
||||
return usageHint == VibrationAttributes.USAGE_NOTIFICATION;
|
||||
}
|
||||
@@ -1690,14 +1510,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
pw.println(" mVibratorStateListeners Count="
|
||||
+ mVibratorStateListeners.getRegisteredCallbackCount());
|
||||
pw.println(" mLowPowerMode=" + mLowPowerMode);
|
||||
pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
|
||||
pw.println(" mHapticFeedbackDefaultIntensity="
|
||||
+ mVibrator.getDefaultHapticFeedbackIntensity());
|
||||
pw.println(" mNotificationIntensity=" + mNotificationIntensity);
|
||||
pw.println(" mNotificationDefaultIntensity="
|
||||
+ mVibrator.getDefaultNotificationVibrationIntensity());
|
||||
pw.println(" mRingIntensity=" + mRingIntensity);
|
||||
pw.println(" mRingDefaultIntensity=" + mVibrator.getDefaultRingVibrationIntensity());
|
||||
pw.println(" mVibrationSettings=" + mVibrationSettings);
|
||||
pw.println(" mSupportedEffects=" + mSupportedEffects);
|
||||
pw.println(" mSupportedPrimitives=" + mSupportedPrimitives);
|
||||
pw.println();
|
||||
@@ -1746,15 +1559,17 @@ public class VibratorService extends IVibratorService.Stub
|
||||
mVibratorUnderExternalControl);
|
||||
proto.write(VibratorServiceDumpProto.LOW_POWER_MODE, mLowPowerMode);
|
||||
proto.write(VibratorServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY,
|
||||
mHapticFeedbackIntensity);
|
||||
mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_TOUCH));
|
||||
proto.write(VibratorServiceDumpProto.HAPTIC_FEEDBACK_DEFAULT_INTENSITY,
|
||||
mVibrator.getDefaultHapticFeedbackIntensity());
|
||||
proto.write(VibratorServiceDumpProto.NOTIFICATION_INTENSITY, mNotificationIntensity);
|
||||
mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
|
||||
proto.write(VibratorServiceDumpProto.NOTIFICATION_INTENSITY,
|
||||
mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_NOTIFICATION));
|
||||
proto.write(VibratorServiceDumpProto.NOTIFICATION_DEFAULT_INTENSITY,
|
||||
mVibrator.getDefaultNotificationVibrationIntensity());
|
||||
proto.write(VibratorServiceDumpProto.RING_INTENSITY, mRingIntensity);
|
||||
mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
|
||||
proto.write(VibratorServiceDumpProto.RING_INTENSITY,
|
||||
mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE));
|
||||
proto.write(VibratorServiceDumpProto.RING_DEFAULT_INTENSITY,
|
||||
mVibrator.getDefaultRingVibrationIntensity());
|
||||
mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
|
||||
|
||||
for (VibrationInfo info : mPreviousRingVibrations) {
|
||||
info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_RING_VIBRATIONS);
|
||||
@@ -2080,7 +1895,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
@Override
|
||||
public int onExternalVibrationStart(ExternalVibration vib) {
|
||||
if (!hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
|
||||
return SCALE_MUTE;
|
||||
return IExternalVibratorService.SCALE_MUTE;
|
||||
}
|
||||
if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
|
||||
vib.getUid(), -1 /*owningUid*/, true /*exported*/)
|
||||
@@ -2088,7 +1903,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
|
||||
+ " tried to play externally controlled vibration"
|
||||
+ " without VIBRATE permission, ignoring.");
|
||||
return SCALE_MUTE;
|
||||
return IExternalVibratorService.SCALE_MUTE;
|
||||
}
|
||||
|
||||
int mode = getAppOpMode(vib.getUid(), vib.getPackage(), vib.getVibrationAttributes());
|
||||
@@ -2101,10 +1916,9 @@ public class VibratorService extends IVibratorService.Stub
|
||||
} else {
|
||||
endVibrationLocked(vibHolder, VibrationInfo.Status.IGNORED_APP_OPS);
|
||||
}
|
||||
return SCALE_MUTE;
|
||||
return IExternalVibratorService.SCALE_MUTE;
|
||||
}
|
||||
|
||||
final int scaleLevel;
|
||||
synchronized (mLock) {
|
||||
if (mCurrentExternalVibration != null
|
||||
&& mCurrentExternalVibration.externalVibration.equals(vib)) {
|
||||
@@ -2131,23 +1945,12 @@ public class VibratorService extends IVibratorService.Stub
|
||||
mCurrentExternalVibration = new ExternalVibrationHolder(vib);
|
||||
mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient();
|
||||
vib.linkToDeath(mCurrentExternalDeathRecipient);
|
||||
mCurrentExternalVibration.scale = mVibrationScaler.getExternalVibrationScale(
|
||||
vib.getVibrationAttributes().getUsage());
|
||||
if (DEBUG) {
|
||||
Slog.e(TAG, "Playing external vibration: " + vib);
|
||||
}
|
||||
int usage = vib.getVibrationAttributes().getUsage();
|
||||
int defaultIntensity = getDefaultIntensity(usage);
|
||||
int currentIntensity = getCurrentIntensityLocked(usage);
|
||||
scaleLevel = currentIntensity - defaultIntensity;
|
||||
}
|
||||
if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
|
||||
mCurrentExternalVibration.scale = scaleLevel;
|
||||
return scaleLevel;
|
||||
} else {
|
||||
// Presumably we want to play this but something about our scaling has gone
|
||||
// wrong, so just play with no scaling.
|
||||
Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
|
||||
+ scaleLevel + " for vibration " + vib);
|
||||
return SCALE_NONE;
|
||||
return mCurrentExternalVibration.scale;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2232,21 +2035,12 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
|
||||
private boolean checkDoNotDisturb(CommonOptions opts) {
|
||||
try {
|
||||
final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.ZEN_MODE);
|
||||
if (zenMode != Settings.Global.ZEN_MODE_OFF && !opts.force) {
|
||||
try (PrintWriter pw = getOutPrintWriter();) {
|
||||
pw.print("Ignoring because device is on DND mode ");
|
||||
pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
|
||||
zenMode));
|
||||
return true;
|
||||
}
|
||||
if (mVibrationSettings.isInZenMode() && !opts.force) {
|
||||
try (PrintWriter pw = getOutPrintWriter();) {
|
||||
pw.print("Ignoring because device is on DND mode ");
|
||||
return true;
|
||||
}
|
||||
} catch (SettingNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.vibrator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.vibrator.V1_0.EffectStrength;
|
||||
import android.os.IExternalVibratorService;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
/** Controls vibration scaling. */
|
||||
// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
|
||||
public final class VibrationScaler {
|
||||
private static final String TAG = "VibrationScaler";
|
||||
|
||||
// Scale levels. Each level, except MUTE, is defined as the delta between the current setting
|
||||
// and the default intensity for that type of vibration (i.e. current - default).
|
||||
private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
|
||||
private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
|
||||
private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
|
||||
private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
|
||||
private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
|
||||
private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
|
||||
|
||||
// Scale factors for each level.
|
||||
private static final float SCALE_FACTOR_VERY_LOW = 0.6f;
|
||||
private static final float SCALE_FACTOR_LOW = 0.8f;
|
||||
private static final float SCALE_FACTOR_NONE = 1f;
|
||||
private static final float SCALE_FACTOR_HIGH = 1.2f;
|
||||
private static final float SCALE_FACTOR_VERY_HIGH = 1.4f;
|
||||
|
||||
// A mapping from the intensity adjustment to the scaling to apply, where the intensity
|
||||
// adjustment is defined as the delta between the default intensity level and the user selected
|
||||
// intensity level. It's important that we apply the scaling on the delta between the two so
|
||||
// that the default intensity level applies no scaling to application provided effects.
|
||||
private final SparseArray<ScaleLevel> mScaleLevels;
|
||||
private final VibrationSettings mSettingsController;
|
||||
private final int mDefaultVibrationAmplitude;
|
||||
|
||||
public VibrationScaler(Context context, VibrationSettings settingsController) {
|
||||
mSettingsController = settingsController;
|
||||
mDefaultVibrationAmplitude = context.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_defaultVibrationAmplitude);
|
||||
|
||||
mScaleLevels = new SparseArray<>();
|
||||
mScaleLevels.put(SCALE_VERY_LOW, new ScaleLevel(SCALE_FACTOR_VERY_LOW));
|
||||
mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_FACTOR_LOW));
|
||||
mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_FACTOR_NONE));
|
||||
mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_FACTOR_HIGH));
|
||||
mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_FACTOR_VERY_HIGH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the scale to be applied to external vibration with given usage.
|
||||
*
|
||||
* @param usageHint one of VibrationAttributes.USAGE_*
|
||||
* @return one of IExternalVibratorService.SCALE_*
|
||||
*/
|
||||
public int getExternalVibrationScale(int usageHint) {
|
||||
int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint);
|
||||
int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);
|
||||
int scaleLevel = currentIntensity - defaultIntensity;
|
||||
|
||||
if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
|
||||
return scaleLevel;
|
||||
} else {
|
||||
// Something about our scaling has gone wrong, so just play with no scaling.
|
||||
Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
|
||||
+ scaleLevel + " for vibration with usage " + usageHint);
|
||||
return SCALE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale a {@link VibrationEffect} based on the given usage hint for this vibration.
|
||||
*
|
||||
* @param effect the effect to be scaled
|
||||
* @param usageHint one of VibrationAttributes.USAGE_*
|
||||
* @return The same given effect, if no changes were made, or a new {@link VibrationEffect} with
|
||||
* resolved and scaled amplitude
|
||||
*/
|
||||
public <T extends VibrationEffect> T scale(VibrationEffect effect, int usageHint) {
|
||||
if (effect instanceof VibrationEffect.Prebaked) {
|
||||
// Prebaked effects are always just a direct translation to EffectStrength.
|
||||
int intensity = mSettingsController.getCurrentIntensity(usageHint);
|
||||
int newStrength = intensityToEffectStrength(intensity);
|
||||
VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
|
||||
|
||||
if (prebaked.getEffectStrength() == newStrength) {
|
||||
return (T) prebaked;
|
||||
}
|
||||
|
||||
return (T) new VibrationEffect.Prebaked(
|
||||
prebaked.getId(), prebaked.shouldFallback(), newStrength);
|
||||
}
|
||||
|
||||
effect = effect.resolve(mDefaultVibrationAmplitude);
|
||||
int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint);
|
||||
int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);
|
||||
ScaleLevel scale = mScaleLevels.get(currentIntensity - defaultIntensity);
|
||||
|
||||
if (scale == null) {
|
||||
// Something about our scaling has gone wrong, so just play with no scaling.
|
||||
Slog.e(TAG, "No configured scaling level!"
|
||||
+ " (current=" + currentIntensity + ", default= " + defaultIntensity + ")");
|
||||
return (T) effect;
|
||||
}
|
||||
|
||||
return effect.scale(scale.factor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Mapping of Vibrator.VIBRATION_INTENSITY_* values to {@link EffectStrength}. */
|
||||
private static int intensityToEffectStrength(int intensity) {
|
||||
switch (intensity) {
|
||||
case Vibrator.VIBRATION_INTENSITY_LOW:
|
||||
return EffectStrength.LIGHT;
|
||||
case Vibrator.VIBRATION_INTENSITY_MEDIUM:
|
||||
return EffectStrength.MEDIUM;
|
||||
case Vibrator.VIBRATION_INTENSITY_HIGH:
|
||||
return EffectStrength.STRONG;
|
||||
default:
|
||||
Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
|
||||
return EffectStrength.STRONG;
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents the scale that must be applied to a vibration effect intensity. */
|
||||
private static final class ScaleLevel {
|
||||
public final float factor;
|
||||
|
||||
ScaleLevel(float factor) {
|
||||
this.factor = factor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ScaleLevel{factor=" + factor + "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.vibrator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Controls all the system settings related to vibration. */
|
||||
// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
|
||||
public final class VibrationSettings {
|
||||
private static final String TAG = "VibrationSettings";
|
||||
|
||||
/** Listener for changes on vibration settings. */
|
||||
public interface OnVibratorSettingsChanged {
|
||||
/** Callback triggered when any of the vibrator settings change. */
|
||||
void onChange();
|
||||
}
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final Context mContext;
|
||||
private final Vibrator mVibrator;
|
||||
private final AudioManager mAudioManager;
|
||||
private final SettingsObserver mSettingObserver;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean mVibrateInputDevices;
|
||||
@GuardedBy("mLock")
|
||||
private boolean mVibrateWhenRinging;
|
||||
@GuardedBy("mLock")
|
||||
private boolean mApplyRampingRinger;
|
||||
@GuardedBy("mLock")
|
||||
private int mZenMode;
|
||||
@GuardedBy("mLock")
|
||||
private int mHapticFeedbackIntensity;
|
||||
@GuardedBy("mLock")
|
||||
private int mNotificationIntensity;
|
||||
@GuardedBy("mLock")
|
||||
private int mRingIntensity;
|
||||
|
||||
public VibrationSettings(Context context, Handler handler) {
|
||||
mContext = context;
|
||||
mVibrator = context.getSystemService(Vibrator.class);
|
||||
mAudioManager = context.getSystemService(AudioManager.class);
|
||||
mSettingObserver = new SettingsObserver(handler);
|
||||
|
||||
registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
|
||||
registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING));
|
||||
registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.APPLY_RAMPING_RINGER));
|
||||
registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.ZEN_MODE));
|
||||
registerSettingsObserver(
|
||||
Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY));
|
||||
registerSettingsObserver(
|
||||
Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY));
|
||||
registerSettingsObserver(
|
||||
Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY));
|
||||
|
||||
// Update with current values from settings.
|
||||
updateSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listener to vibrator settings changes. This will trigger the listener with current state
|
||||
* immediately and every time one of the settings change.
|
||||
*/
|
||||
public void addListener(OnVibratorSettingsChanged listener) {
|
||||
synchronized (mLock) {
|
||||
if (!mListeners.contains(listener)) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove listener to vibrator settings. */
|
||||
public void removeListener(OnVibratorSettingsChanged listener) {
|
||||
synchronized (mLock) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return default vibration intensity for given usage.
|
||||
*
|
||||
* @param usageHint one of VibrationAttributes.USAGE_*
|
||||
* @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_*
|
||||
*/
|
||||
public int getDefaultIntensity(int usageHint) {
|
||||
if (isRingtone(usageHint)) {
|
||||
return mVibrator.getDefaultRingVibrationIntensity();
|
||||
} else if (isNotification(usageHint)) {
|
||||
return mVibrator.getDefaultNotificationVibrationIntensity();
|
||||
} else if (isHapticFeedback(usageHint)) {
|
||||
return mVibrator.getDefaultHapticFeedbackIntensity();
|
||||
} else if (isAlarm(usageHint)) {
|
||||
return Vibrator.VIBRATION_INTENSITY_HIGH;
|
||||
} else {
|
||||
return Vibrator.VIBRATION_INTENSITY_MEDIUM;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current vibration intensity set for given usage at the user settings.
|
||||
*
|
||||
* @param usageHint one of VibrationAttributes.USAGE_*
|
||||
* @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_*
|
||||
*/
|
||||
public int getCurrentIntensity(int usageHint) {
|
||||
synchronized (mLock) {
|
||||
if (isRingtone(usageHint)) {
|
||||
return mRingIntensity;
|
||||
} else if (isNotification(usageHint)) {
|
||||
return mNotificationIntensity;
|
||||
} else if (isHapticFeedback(usageHint)) {
|
||||
return mHapticFeedbackIntensity;
|
||||
} else if (isAlarm(usageHint)) {
|
||||
return Vibrator.VIBRATION_INTENSITY_HIGH;
|
||||
} else {
|
||||
return Vibrator.VIBRATION_INTENSITY_MEDIUM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if the device should vibrate for ringtones.
|
||||
*
|
||||
* <p>This checks the current {@link AudioManager#getRingerMode()} against user settings for
|
||||
* vibrations while ringing.
|
||||
*/
|
||||
public boolean shouldVibrateForRingtone() {
|
||||
int ringerMode = mAudioManager.getRingerModeInternal();
|
||||
synchronized (mLock) {
|
||||
if (mVibrateWhenRinging) {
|
||||
return ringerMode != AudioManager.RINGER_MODE_SILENT;
|
||||
} else if (mApplyRampingRinger) {
|
||||
return ringerMode != AudioManager.RINGER_MODE_SILENT;
|
||||
} else {
|
||||
return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 isNotification(int usageHint) {
|
||||
return usageHint == VibrationAttributes.USAGE_NOTIFICATION;
|
||||
}
|
||||
|
||||
private static boolean isRingtone(int usageHint) {
|
||||
return usageHint == VibrationAttributes.USAGE_RINGTONE;
|
||||
}
|
||||
|
||||
private static boolean isHapticFeedback(int usageHint) {
|
||||
return usageHint == VibrationAttributes.USAGE_TOUCH;
|
||||
}
|
||||
|
||||
private static boolean isAlarm(int usageHint) {
|
||||
return usageHint == VibrationAttributes.USAGE_ALARM;
|
||||
}
|
||||
|
||||
/** Updates all vibration settings and triggers registered listeners. */
|
||||
@VisibleForTesting
|
||||
public void updateSettings() {
|
||||
List<OnVibratorSettingsChanged> currentListeners;
|
||||
synchronized (mLock) {
|
||||
mVibrateWhenRinging = getSystemSetting(Settings.System.VIBRATE_WHEN_RINGING, 0) != 0;
|
||||
mApplyRampingRinger = getGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0) != 0;
|
||||
mHapticFeedbackIntensity = getSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
mVibrator.getDefaultHapticFeedbackIntensity());
|
||||
mNotificationIntensity = getSystemSetting(
|
||||
Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
mVibrator.getDefaultNotificationVibrationIntensity());
|
||||
mRingIntensity = getSystemSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
mVibrator.getDefaultRingVibrationIntensity());
|
||||
mVibrateInputDevices = getSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0;
|
||||
mZenMode = getGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
|
||||
currentListeners = new ArrayList<>(mListeners);
|
||||
}
|
||||
|
||||
for (OnVibratorSettingsChanged listener : currentListeners) {
|
||||
listener.onChange();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VibrationSettings{"
|
||||
+ "mVibrateInputDevices=" + mVibrateInputDevices
|
||||
+ ", mVibrateWhenRinging=" + mVibrateWhenRinging
|
||||
+ ", mApplyRampingRinger=" + mApplyRampingRinger
|
||||
+ ", mZenMode=" + Settings.Global.zenModeToString(mZenMode)
|
||||
+ ", mHapticFeedbackIntensity="
|
||||
+ intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_TOUCH))
|
||||
+ ", mHapticFeedbackDefaultIntensity="
|
||||
+ intensityToString(getDefaultIntensity(VibrationAttributes.USAGE_TOUCH))
|
||||
+ ", mNotificationIntensity="
|
||||
+ intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_NOTIFICATION))
|
||||
+ ", mNotificationDefaultIntensity="
|
||||
+ intensityToString(getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION))
|
||||
+ ", mRingIntensity="
|
||||
+ intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE))
|
||||
+ ", mRingDefaultIntensity="
|
||||
+ intensityToString(getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE))
|
||||
+ '}';
|
||||
}
|
||||
|
||||
private static String intensityToString(int intensity) {
|
||||
switch (intensity) {
|
||||
case Vibrator.VIBRATION_INTENSITY_OFF:
|
||||
return "OFF";
|
||||
case Vibrator.VIBRATION_INTENSITY_LOW:
|
||||
return "LOW";
|
||||
case Vibrator.VIBRATION_INTENSITY_MEDIUM:
|
||||
return "MEDIUM";
|
||||
case Vibrator.VIBRATION_INTENSITY_HIGH:
|
||||
return "HIGH";
|
||||
default:
|
||||
return "UNKNOWN INTENSITY " + intensity;
|
||||
}
|
||||
}
|
||||
|
||||
private int getSystemSetting(String settingName, int defaultValue) {
|
||||
return Settings.System.getIntForUser(mContext.getContentResolver(),
|
||||
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,
|
||||
UserHandle.USER_ALL);
|
||||
}
|
||||
|
||||
/** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */
|
||||
private final class SettingsObserver extends ContentObserver {
|
||||
SettingsObserver(Handler handler) {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
updateSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,11 +39,13 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.hardware.vibrator.IVibrator;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.IVibratorStateListener;
|
||||
@@ -61,11 +63,11 @@ import android.os.Vibrator;
|
||||
import android.os.test.TestLooper;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.Settings;
|
||||
import android.test.mock.MockContentResolver;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.internal.util.test.FakeSettingsProviderRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -107,11 +109,13 @@ public class VibratorServiceTest {
|
||||
new VibrationAttributes.Builder().setUsage(
|
||||
VibrationAttributes.USAGE_RINGTONE).build();
|
||||
|
||||
@Rule public MockitoRule rule = MockitoJUnit.rule();
|
||||
@Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||
@Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
|
||||
|
||||
@Mock private PackageManagerInternal mPackageManagerInternalMock;
|
||||
@Mock private PowerManagerInternal mPowerManagerInternalMock;
|
||||
@Mock private PowerSaveState mPowerSaveStateMock;
|
||||
// TODO(b/131311651): replace with a FakeVibrator instead.
|
||||
@Mock private Vibrator mVibratorMock;
|
||||
@Mock private AppOpsManager mAppOpsManagerMock;
|
||||
@Mock private VibratorService.NativeWrapper mNativeWrapperMock;
|
||||
@@ -126,9 +130,7 @@ public class VibratorServiceTest {
|
||||
mTestLooper = new TestLooper();
|
||||
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
|
||||
|
||||
MockContentResolver contentResolver = new MockContentResolver(mContextSpy);
|
||||
contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
|
||||
|
||||
ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
|
||||
when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
|
||||
when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
|
||||
when(mContextSpy.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManagerMock);
|
||||
@@ -144,28 +146,26 @@ public class VibratorServiceTest {
|
||||
when(mPowerManagerInternalMock.getLowPowerState(PowerManager.ServiceType.VIBRATION))
|
||||
.thenReturn(mPowerSaveStateMock);
|
||||
|
||||
setVibrationIntensityUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
|
||||
setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
|
||||
addLocalServiceMock(PackageManagerInternal.class, mPackageManagerInternalMock);
|
||||
addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
LocalServices.removeServiceForTest(PackageManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(PowerManagerInternal.class);
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
|
||||
private VibratorService createService() {
|
||||
return new VibratorService(mContextSpy,
|
||||
VibratorService service = new VibratorService(mContextSpy,
|
||||
new VibratorService.Injector() {
|
||||
@Override
|
||||
VibratorService.NativeWrapper getNativeWrapper() {
|
||||
@@ -182,6 +182,8 @@ public class VibratorServiceTest {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
service.systemReady();
|
||||
return service;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -304,10 +306,30 @@ public class VibratorServiceTest {
|
||||
verify(mNativeWrapperMock, never()).vibratorAlwaysOnEnable(anyLong(), anyLong(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withRingtone_usesRingtoneSettings() {
|
||||
setRingerMode(AudioManager.RINGER_MODE_NORMAL);
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
|
||||
setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
|
||||
vibrate(createService(), VibrationEffect.createOneShot(1, 1), RINGTONE_ATTRS);
|
||||
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
|
||||
setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 1);
|
||||
vibrate(createService(), VibrationEffect.createOneShot(10, 10), RINGTONE_ATTRS);
|
||||
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
|
||||
setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
|
||||
vibrate(createService(), VibrationEffect.createOneShot(100, 100), RINGTONE_ATTRS);
|
||||
|
||||
InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
|
||||
inOrderVerifier.verify(mNativeWrapperMock, never()).vibratorOn(eq(1L), anyLong());
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(10L), anyLong());
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withAudioAttributes_usesOriginalAudioUsageInAppOpsManager() {
|
||||
VibratorService service = createService();
|
||||
service.systemReady();
|
||||
|
||||
VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
|
||||
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
||||
@@ -324,7 +346,6 @@ public class VibratorServiceTest {
|
||||
@Test
|
||||
public void vibrate_withVibrationAttributes_usesCorrespondingAudioUsageInAppOpsManager() {
|
||||
VibratorService service = createService();
|
||||
service.systemReady();
|
||||
|
||||
vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
|
||||
vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), NOTIFICATION_ATTRS);
|
||||
@@ -624,14 +645,13 @@ public class VibratorServiceTest {
|
||||
@Test
|
||||
public void scale_withPrebaked_userIntensitySettingAsEffectStrength() {
|
||||
// Alarm vibration is always VIBRATION_INTENSITY_HIGH.
|
||||
setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
VibratorService service = createService();
|
||||
service.systemReady();
|
||||
|
||||
vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK),
|
||||
ALARM_ATTRS);
|
||||
@@ -659,16 +679,15 @@ public class VibratorServiceTest {
|
||||
public void scale_withOneShotAndWaveform_usesScaleLevelOnAmplitude() throws Exception {
|
||||
when(mVibratorMock.getDefaultNotificationVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
|
||||
mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||
VibratorService service = createService();
|
||||
service.systemReady();
|
||||
|
||||
vibrate(service, VibrationEffect.createOneShot(20, 100), ALARM_ATTRS);
|
||||
vibrate(service, VibrationEffect.createOneShot(20, 100), NOTIFICATION_ATTRS);
|
||||
@@ -694,16 +713,15 @@ public class VibratorServiceTest {
|
||||
public void scale_withComposed_usesScaleLevelOnPrimitiveScaleValues() {
|
||||
when(mVibratorMock.getDefaultNotificationVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
VibratorService service = createService();
|
||||
service.systemReady();
|
||||
|
||||
VibrationEffect effect = VibrationEffect.startComposition()
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
|
||||
@@ -785,8 +803,18 @@ public class VibratorServiceTest {
|
||||
LocalServices.addService(clazz, mock);
|
||||
}
|
||||
|
||||
private void setVibrationIntensityUserSetting(String settingName, int value) {
|
||||
private void setRingerMode(int ringerMode) {
|
||||
AudioManager audioManager = mContextSpy.getSystemService(AudioManager.class);
|
||||
audioManager.setRingerModeInternal(ringerMode);
|
||||
assertEquals(ringerMode, audioManager.getRingerMode());
|
||||
}
|
||||
|
||||
private void setUserSetting(String settingName, int value) {
|
||||
Settings.System.putIntForUser(
|
||||
mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
|
||||
}
|
||||
|
||||
private void setGlobalSetting(String settingName, int value) {
|
||||
Settings.Global.putInt(mContextSpy.getContentResolver(), settingName, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.vibrator;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.os.Handler;
|
||||
import android.os.IExternalVibratorService;
|
||||
import android.os.UserHandle;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.test.TestLooper;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.internal.util.test.FakeSettingsProviderRule;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
/**
|
||||
* Tests for {@link VibrationScaler}.
|
||||
*
|
||||
* Build/Install/Run:
|
||||
* atest FrameworksServicesTests:VibrationScalerTest
|
||||
*/
|
||||
@Presubmit
|
||||
public class VibrationScalerTest {
|
||||
|
||||
@Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||
@Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
|
||||
|
||||
// TODO(b/131311651): replace with a FakeVibrator instead.
|
||||
@Mock private Vibrator mVibratorMock;
|
||||
|
||||
private TestLooper mTestLooper;
|
||||
private ContextWrapper mContextSpy;
|
||||
private VibrationSettings mVibrationSettings;
|
||||
private VibrationScaler mVibrationScaler;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mTestLooper = new TestLooper();
|
||||
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
|
||||
|
||||
ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
|
||||
when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
|
||||
when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
|
||||
|
||||
mVibrationSettings = new VibrationSettings(
|
||||
mContextSpy, new Handler(mTestLooper.getLooper()));
|
||||
mVibrationScaler = new VibrationScaler(mContextSpy, mVibrationSettings);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExternalVibrationScale() {
|
||||
when(mVibratorMock.getDefaultHapticFeedbackIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
assertEquals(IExternalVibratorService.SCALE_VERY_HIGH,
|
||||
mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
|
||||
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
assertEquals(IExternalVibratorService.SCALE_HIGH,
|
||||
mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
|
||||
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
assertEquals(IExternalVibratorService.SCALE_NONE,
|
||||
mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
|
||||
|
||||
when(mVibratorMock.getDefaultHapticFeedbackIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
assertEquals(IExternalVibratorService.SCALE_LOW,
|
||||
mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
|
||||
|
||||
when(mVibratorMock.getDefaultHapticFeedbackIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
assertEquals(IExternalVibratorService.SCALE_VERY_LOW,
|
||||
mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
|
||||
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
// Unexpected vibration intensity will be treated as SCALE_NONE.
|
||||
assertEquals(IExternalVibratorService.SCALE_NONE,
|
||||
mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scale_withPrebaked_setsEffectStrengthBasedOnSettings() {
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
VibrationEffect effect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
|
||||
|
||||
VibrationEffect.Prebaked scaled = mVibrationScaler.scale(
|
||||
effect, VibrationAttributes.USAGE_NOTIFICATION);
|
||||
assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG);
|
||||
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
scaled = mVibrationScaler.scale(effect, VibrationAttributes.USAGE_NOTIFICATION);
|
||||
assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_MEDIUM);
|
||||
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
scaled = mVibrationScaler.scale(effect, VibrationAttributes.USAGE_NOTIFICATION);
|
||||
assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_LIGHT);
|
||||
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
scaled = mVibrationScaler.scale(effect, VibrationAttributes.USAGE_NOTIFICATION);
|
||||
// Unexpected intensity setting will be mapped to STRONG.
|
||||
assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scale_withOneShotAndWaveform_resolvesAmplitude() {
|
||||
// No scale, default amplitude still resolved
|
||||
when(mVibratorMock.getDefaultRingVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
|
||||
VibrationEffect.OneShot oneShot = mVibrationScaler.scale(
|
||||
VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE),
|
||||
VibrationAttributes.USAGE_RINGTONE);
|
||||
assertTrue(oneShot.getAmplitude() > 0);
|
||||
|
||||
VibrationEffect.Waveform waveform = mVibrationScaler.scale(
|
||||
VibrationEffect.createWaveform(new long[]{10},
|
||||
new int[]{VibrationEffect.DEFAULT_AMPLITUDE}, -1),
|
||||
VibrationAttributes.USAGE_RINGTONE);
|
||||
assertTrue(waveform.getAmplitudes()[0] > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scale_withOneShotWaveform_scalesAmplitude() {
|
||||
when(mVibratorMock.getDefaultRingVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
when(mVibratorMock.getDefaultNotificationVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
when(mVibratorMock.getDefaultHapticFeedbackIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
|
||||
VibrationEffect.OneShot oneShot = mVibrationScaler.scale(
|
||||
VibrationEffect.createOneShot(100, 100), VibrationAttributes.USAGE_RINGTONE);
|
||||
// Ringtone scales up.
|
||||
assertTrue(oneShot.getAmplitude() > 100);
|
||||
|
||||
VibrationEffect.Waveform waveform = mVibrationScaler.scale(
|
||||
VibrationEffect.createWaveform(new long[]{100}, new int[]{100}, -1),
|
||||
VibrationAttributes.USAGE_NOTIFICATION);
|
||||
// Notification scales down.
|
||||
assertTrue(waveform.getAmplitudes()[0] < 100);
|
||||
|
||||
oneShot = mVibrationScaler.scale(VibrationEffect.createOneShot(100, 100),
|
||||
VibrationAttributes.USAGE_TOUCH);
|
||||
// Haptic feedback does not scale.
|
||||
assertEquals(100, oneShot.getAmplitude());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scale_withComposed_scalesPrimitives() {
|
||||
when(mVibratorMock.getDefaultRingVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
when(mVibratorMock.getDefaultNotificationVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
when(mVibratorMock.getDefaultHapticFeedbackIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
|
||||
VibrationEffect composed = VibrationEffect.startComposition()
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f).compose();
|
||||
|
||||
VibrationEffect.Composed scaled = mVibrationScaler.scale(composed,
|
||||
VibrationAttributes.USAGE_RINGTONE);
|
||||
// Ringtone scales up.
|
||||
assertTrue(scaled.getPrimitiveEffects().get(0).scale > 0.5f);
|
||||
|
||||
scaled = mVibrationScaler.scale(composed, VibrationAttributes.USAGE_NOTIFICATION);
|
||||
// Notification scales down.
|
||||
assertTrue(scaled.getPrimitiveEffects().get(0).scale < 0.5f);
|
||||
|
||||
scaled = mVibrationScaler.scale(composed, VibrationAttributes.USAGE_TOUCH);
|
||||
// Haptic feedback does not scale.
|
||||
assertEquals(0.5, scaled.getPrimitiveEffects().get(0).scale, 1e-5);
|
||||
}
|
||||
|
||||
private void setUserSetting(String settingName, int value) {
|
||||
Settings.System.putIntForUser(
|
||||
mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
|
||||
// FakeSettingsProvider don't support testing triggering ContentObserver yet.
|
||||
mVibrationSettings.updateSettings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.vibrator;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.Vibrator;
|
||||
import android.os.test.TestLooper;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.internal.util.test.FakeSettingsProviderRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
/**
|
||||
* Tests for {@link VibrationSettings}.
|
||||
*
|
||||
* Build/Install/Run:
|
||||
* atest FrameworksServicesTests:VibrationSettingsTest
|
||||
*/
|
||||
@Presubmit
|
||||
public class VibrationSettingsTest {
|
||||
|
||||
@Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||
@Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
|
||||
|
||||
// TODO(b/131311651): replace with a FakeVibrator instead.
|
||||
@Mock private Vibrator mVibratorMock;
|
||||
@Mock private VibrationSettings.OnVibratorSettingsChanged mListenerMock;
|
||||
|
||||
private TestLooper mTestLooper;
|
||||
private ContextWrapper mContextSpy;
|
||||
private AudioManager mAudioManager;
|
||||
private VibrationSettings mVibrationSettings;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mTestLooper = new TestLooper();
|
||||
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
|
||||
|
||||
ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
|
||||
when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
|
||||
when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
|
||||
when(mVibratorMock.hasVibrator()).thenReturn(true);
|
||||
|
||||
mAudioManager = mContextSpy.getSystemService(AudioManager.class);
|
||||
mVibrationSettings = new VibrationSettings(
|
||||
mContextSpy, new Handler(mTestLooper.getLooper()));
|
||||
|
||||
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0);
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
|
||||
setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
|
||||
setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addListener_settingsChangeTriggerListener() {
|
||||
mVibrationSettings.addListener(mListenerMock);
|
||||
|
||||
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
|
||||
setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
|
||||
setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_ALARMS);
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
|
||||
verify(mListenerMock, times(7)).onChange();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeListener_noMoreCallbacksToListener() {
|
||||
mVibrationSettings.addListener(mListenerMock);
|
||||
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
|
||||
verify(mListenerMock).onChange();
|
||||
|
||||
mVibrationSettings.removeListener(mListenerMock);
|
||||
|
||||
verifyNoMoreInteractions(mListenerMock);
|
||||
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
|
||||
setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_ALARMS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldVibrateForRingtones_withVibrateWhenRinging_onlyIgnoreSettingsForSilentMode() {
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_SILENT);
|
||||
assertEquals(AudioManager.RINGER_MODE_SILENT, mAudioManager.getRingerMode());
|
||||
assertFalse(mVibrationSettings.shouldVibrateForRingtone());
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_MAX);
|
||||
assertEquals(AudioManager.RINGER_MODE_MAX, mAudioManager.getRingerMode());
|
||||
assertTrue(mVibrationSettings.shouldVibrateForRingtone());
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL);
|
||||
assertEquals(AudioManager.RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
|
||||
assertTrue(mVibrationSettings.shouldVibrateForRingtone());
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE);
|
||||
assertEquals(AudioManager.RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
|
||||
assertTrue(mVibrationSettings.shouldVibrateForRingtone());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldVibrateForRingtones_withApplyRampingRinger_onlyIgnoreSettingsForSilentMode() {
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
|
||||
setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 1);
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_SILENT);
|
||||
assertEquals(AudioManager.RINGER_MODE_SILENT, mAudioManager.getRingerMode());
|
||||
assertFalse(mVibrationSettings.shouldVibrateForRingtone());
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_MAX);
|
||||
assertEquals(AudioManager.RINGER_MODE_MAX, mAudioManager.getRingerMode());
|
||||
assertTrue(mVibrationSettings.shouldVibrateForRingtone());
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL);
|
||||
assertEquals(AudioManager.RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
|
||||
assertTrue(mVibrationSettings.shouldVibrateForRingtone());
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE);
|
||||
assertEquals(AudioManager.RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
|
||||
assertTrue(mVibrationSettings.shouldVibrateForRingtone());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldVibrateForRingtones_withAllSettingsOff_onlyVibratesForVibrateMode() {
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
|
||||
setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE);
|
||||
assertEquals(AudioManager.RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
|
||||
assertTrue(mVibrationSettings.shouldVibrateForRingtone());
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_SILENT);
|
||||
assertEquals(AudioManager.RINGER_MODE_SILENT, mAudioManager.getRingerMode());
|
||||
assertFalse(mVibrationSettings.shouldVibrateForRingtone());
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_MAX);
|
||||
assertEquals(AudioManager.RINGER_MODE_MAX, mAudioManager.getRingerMode());
|
||||
assertFalse(mVibrationSettings.shouldVibrateForRingtone());
|
||||
|
||||
mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL);
|
||||
assertEquals(AudioManager.RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
|
||||
assertFalse(mVibrationSettings.shouldVibrateForRingtone());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldVibrateInputDevices_returnsSettingsValue() {
|
||||
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
|
||||
assertTrue(mVibrationSettings.shouldVibrateInputDevices());
|
||||
|
||||
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0);
|
||||
assertFalse(mVibrationSettings.shouldVibrateInputDevices());
|
||||
}
|
||||
|
||||
@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_returnsIntensityFromVibratorService() {
|
||||
when(mVibratorMock.getDefaultHapticFeedbackIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
when(mVibratorMock.getDefaultNotificationVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
when(mVibratorMock.getDefaultRingVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
|
||||
mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_ALARM));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
|
||||
mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
|
||||
mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
|
||||
mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_UNKNOWN));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
|
||||
mVibrationSettings.getDefaultIntensity(
|
||||
VibrationAttributes.USAGE_PHYSICAL_EMULATION));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_LOW,
|
||||
mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrentIntensity_returnsIntensityFromSettings() {
|
||||
when(mVibratorMock.getDefaultHapticFeedbackIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
when(mVibratorMock.getDefaultNotificationVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
when(mVibratorMock.getDefaultRingVibrationIntensity())
|
||||
.thenReturn(Vibrator.VIBRATION_INTENSITY_OFF);
|
||||
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_HIGH);
|
||||
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_MEDIUM);
|
||||
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Vibrator.VIBRATION_INTENSITY_LOW);
|
||||
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
|
||||
mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_ALARM));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
|
||||
mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_TOUCH));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
|
||||
mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_NOTIFICATION));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
|
||||
mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_UNKNOWN));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
|
||||
mVibrationSettings.getCurrentIntensity(
|
||||
VibrationAttributes.USAGE_PHYSICAL_EMULATION));
|
||||
assertEquals(Vibrator.VIBRATION_INTENSITY_LOW,
|
||||
mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE));
|
||||
}
|
||||
|
||||
private void setUserSetting(String settingName, int value) {
|
||||
Settings.System.putIntForUser(
|
||||
mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
|
||||
// FakeSettingsProvider don't support testing triggering ContentObserver yet.
|
||||
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();
|
||||
mAudioManager.reloadAudioSettings();
|
||||
}
|
||||
}
|
||||
@@ -91,6 +91,14 @@ public class FakeSettingsProvider extends MockContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link org.junit.rules.TestRule} that makes sure {@link #clearSettingsProvider()}
|
||||
* is triggered before and after each test.
|
||||
*/
|
||||
public static FakeSettingsProviderRule rule() {
|
||||
return new FakeSettingsProviderRule();
|
||||
}
|
||||
|
||||
/**
|
||||
* This needs to be called before and after using the FakeSettingsProvider class.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.util.test;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.test.mock.MockContentResolver;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
* JUnit Rule helps keeping test {@link FakeSettingsProvider} clean.
|
||||
*
|
||||
* <p>It clears {@link FakeSettingsProvider} before and after each test. Example use:
|
||||
* <pre class="code"><code class="java">
|
||||
* public class ExampleTest {
|
||||
*
|
||||
* @Rule public FakeSettingsProviderRule rule = FakeSettingsProvider.rule();
|
||||
*
|
||||
* @Test
|
||||
* public void shouldDoSomething() {
|
||||
* ContextResolver cr = rule.mockContentResolver(mContext);
|
||||
* Settings.Global.putInt(cr, "my_setting_name", 1);
|
||||
* // Test code relying on my_setting_name value using cr
|
||||
* }
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* @see FakeSettingsProvider
|
||||
*/
|
||||
public final class FakeSettingsProviderRule implements TestRule {
|
||||
|
||||
/** Prevent initialization outside {@link FakeSettingsProvider}. */
|
||||
FakeSettingsProviderRule() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link MockContentResolver} that uses the {@link FakeSettingsProvider} as the
|
||||
* {@link Settings#AUTHORITY} provider.
|
||||
*/
|
||||
public MockContentResolver mockContentResolver(Context context) {
|
||||
MockContentResolver contentResolver = new MockContentResolver(context);
|
||||
contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
|
||||
return contentResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
return new Statement() {
|
||||
public void evaluate() throws Throwable {
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
try {
|
||||
base.evaluate();
|
||||
} finally {
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user