From 095b3d31dbe1bb5614880a801b7c31c2facb3645 Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Wed, 8 Dec 2021 18:20:55 +0000 Subject: [PATCH] Introduce media and alarm vibration intensity settings Introduce new setting keys for media and alarm vibration intensity. Merge all default vibration intensity getters into a helper class that receives the VibrationAttributes usage int and applies the default logic to all usages. Also update the usage of boolean settings for haptic feedback and ringtone to disable vibrations in VibrationSettings. Bug: 198346559 Bug: 207477604 Test: VibratorTest & VibrationSettingsTest Change-Id: I69ba05a8bc35657637b1f351f4c19d2d96efc9e3 --- core/api/test-current.txt | 8 + core/java/android/os/VibrationAttributes.java | 22 +- core/java/android/os/Vibrator.java | 89 ++--- .../android/os/vibrator/VibrationConfig.java | 175 +++++++++ core/java/android/provider/Settings.java | 39 +- .../android/providers/settings/system.proto | 6 + .../vibrator/vibratormanagerservice.proto | 8 +- core/res/res/values/config.xml | 8 + core/res/res/values/symbols.xml | 2 + .../src/android/os/VibratorTest.java | 18 +- .../settings/backup/SystemSettings.java | 2 + .../validators/SystemSettingsValidators.java | 2 + .../settings/SettingsProtoDumpUtil.java | 12 + .../server/vibrator/VibrationSettings.java | 268 ++++++------- .../android/server/vibrator/FakeVibrator.java | 34 +- .../server/vibrator/VibrationScalerTest.java | 147 ++++---- .../vibrator/VibrationSettingsTest.java | 353 +++++++++--------- .../server/vibrator/VibrationThreadTest.java | 34 +- .../vibrator/VibratorManagerServiceTest.java | 93 +++-- 19 files changed, 768 insertions(+), 552 deletions(-) create mode 100644 core/java/android/os/vibrator/VibrationConfig.java diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 6586ae044d161..34ee0aa55e51a 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1829,6 +1829,14 @@ package android.os { method @NonNull public android.os.VibrationEffect build(int); } + public abstract class Vibrator { + method public int getDefaultVibrationIntensity(int); + field public static final int VIBRATION_INTENSITY_HIGH = 3; // 0x3 + field public static final int VIBRATION_INTENSITY_LOW = 1; // 0x1 + field public static final int VIBRATION_INTENSITY_MEDIUM = 2; // 0x2 + field public static final int VIBRATION_INTENSITY_OFF = 0; // 0x0 + } + public class VintfObject { method public static String[] getHalNamesAndVersions(); method @NonNull public static String getPlatformSepolicyVersion(); diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java index 58315736f37f0..8834725cc3e97 100644 --- a/core/java/android/os/VibrationAttributes.java +++ b/core/java/android/os/VibrationAttributes.java @@ -32,32 +32,30 @@ import java.util.Objects; public final class VibrationAttributes implements Parcelable { private static final String TAG = "VibrationAttributes"; - /** - * @hide - */ + /** @hide */ @IntDef(prefix = { "USAGE_CLASS_" }, value = { USAGE_CLASS_UNKNOWN, USAGE_CLASS_ALARM, USAGE_CLASS_FEEDBACK, }) @Retention(RetentionPolicy.SOURCE) - public @interface UsageClass{} + public @interface UsageClass {} - /** - * @hide - */ + /** @hide */ @IntDef(prefix = { "USAGE_" }, value = { USAGE_UNKNOWN, + USAGE_ACCESSIBILITY, USAGE_ALARM, - USAGE_RINGTONE, - USAGE_NOTIFICATION, USAGE_COMMUNICATION_REQUEST, - USAGE_TOUCH, - USAGE_PHYSICAL_EMULATION, USAGE_HARDWARE_FEEDBACK, + USAGE_MEDIA, + USAGE_NOTIFICATION, + USAGE_PHYSICAL_EMULATION, + USAGE_RINGTONE, + USAGE_TOUCH, }) @Retention(RetentionPolicy.SOURCE) - public @interface Usage{} + public @interface Usage {} /** * Vibration usage filter value to match all usages. diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index d71ead724f7a3..eba9ff1bb4f8a 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -23,11 +23,14 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.res.Resources; import android.hardware.vibrator.IVibrator; import android.media.AudioAttributes; +import android.os.vibrator.VibrationConfig; import android.util.Log; import java.lang.annotation.Retention; @@ -49,6 +52,7 @@ public abstract class Vibrator { * * @hide */ + @TestApi public static final int VIBRATION_INTENSITY_OFF = 0; /** @@ -56,6 +60,7 @@ public abstract class Vibrator { * * @hide */ + @TestApi public static final int VIBRATION_INTENSITY_LOW = 1; /** @@ -63,6 +68,7 @@ public abstract class Vibrator { * * @hide */ + @TestApi public static final int VIBRATION_INTENSITY_MEDIUM = 2; /** @@ -70,6 +76,7 @@ public abstract class Vibrator { * * @hide */ + @TestApi public static final int VIBRATION_INTENSITY_HIGH = 3; /** @@ -115,16 +122,12 @@ public abstract class Vibrator { } private final String mPackageName; - // The default vibration intensity level for haptic feedback. - @VibrationIntensity - private int mDefaultHapticFeedbackIntensity; - // The default vibration intensity level for notifications. - @VibrationIntensity - private int mDefaultNotificationVibrationIntensity; - // The default vibration intensity level for ringtones. - @VibrationIntensity - private int mDefaultRingVibrationIntensity; - private float mHapticChannelMaxVibrationAmplitude; + @Nullable + private final Resources mResources; + + // This is lazily loaded only for the few clients that need this (e. Settings app). + @Nullable + private volatile VibrationConfig mVibrationConfig; /** * @hide to prevent subclassing from outside of the framework @@ -132,8 +135,7 @@ public abstract class Vibrator { @UnsupportedAppUsage public Vibrator() { mPackageName = ActivityThread.currentPackageName(); - final Context ctx = ActivityThread.currentActivityThread().getSystemContext(); - loadVibrationConfig(ctx); + mResources = null; } /** @@ -141,26 +143,7 @@ public abstract class Vibrator { */ protected Vibrator(Context context) { mPackageName = context.getOpPackageName(); - loadVibrationConfig(context); - } - - private void loadVibrationConfig(Context context) { - mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context, - com.android.internal.R.integer.config_defaultHapticFeedbackIntensity); - mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context, - com.android.internal.R.integer.config_defaultNotificationVibrationIntensity); - mDefaultRingVibrationIntensity = loadDefaultIntensity(context, - com.android.internal.R.integer.config_defaultRingVibrationIntensity); - mHapticChannelMaxVibrationAmplitude = loadFloat(context, - com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude, 0); - } - - private int loadDefaultIntensity(Context ctx, int resId) { - return ctx != null ? ctx.getResources().getInteger(resId) : VIBRATION_INTENSITY_MEDIUM; - } - - private float loadFloat(Context ctx, int resId, float defaultValue) { - return ctx != null ? ctx.getResources().getFloat(resId) : defaultValue; + mResources = context.getResources(); } /** @@ -172,31 +155,30 @@ public abstract class Vibrator { return VibratorInfo.EMPTY_VIBRATOR_INFO; } - /** - * Get the default vibration intensity for haptic feedback. - * - * @hide - */ - public int getDefaultHapticFeedbackIntensity() { - return mDefaultHapticFeedbackIntensity; + /** Get the static vibrator configuration from config.xml. */ + private VibrationConfig getConfig() { + if (mVibrationConfig == null) { + Resources resources = mResources; + if (resources == null) { + final Context ctx = ActivityThread.currentActivityThread().getSystemContext(); + resources = ctx != null ? ctx.getResources() : null; + } + // This might be constructed more than once, but it only loads static config data from a + // xml file, so it would be ok. + mVibrationConfig = new VibrationConfig(resources); + } + return mVibrationConfig; } /** - * Get the default vibration intensity for notifications. + * Get the default vibration intensity for given usage. * * @hide */ - public int getDefaultNotificationVibrationIntensity() { - return mDefaultNotificationVibrationIntensity; - } - - /** - * Get the default vibration intensity for ringtones. - * - * @hide - */ - public int getDefaultRingVibrationIntensity() { - return mDefaultRingVibrationIntensity; + @TestApi + @VibrationIntensity + public int getDefaultVibrationIntensity(@VibrationAttributes.Usage int usage) { + return getConfig().getDefaultVibrationIntensity(usage); } /** @@ -280,10 +262,7 @@ public abstract class Vibrator { * @hide */ public float getHapticChannelMaximumAmplitude() { - if (mHapticChannelMaxVibrationAmplitude <= 0) { - return Float.NaN; - } - return mHapticChannelMaxVibrationAmplitude; + return getConfig().getHapticChannelMaximumAmplitude(); } /** diff --git a/core/java/android/os/vibrator/VibrationConfig.java b/core/java/android/os/vibrator/VibrationConfig.java new file mode 100644 index 0000000000000..4a61472e6205a --- /dev/null +++ b/core/java/android/os/vibrator/VibrationConfig.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2022 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 android.os.vibrator; + +import static android.os.VibrationAttributes.USAGE_ACCESSIBILITY; +import static android.os.VibrationAttributes.USAGE_ALARM; +import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST; +import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK; +import static android.os.VibrationAttributes.USAGE_MEDIA; +import static android.os.VibrationAttributes.USAGE_NOTIFICATION; +import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION; +import static android.os.VibrationAttributes.USAGE_RINGTONE; +import static android.os.VibrationAttributes.USAGE_TOUCH; +import static android.os.VibrationAttributes.USAGE_UNKNOWN; + +import android.annotation.Nullable; +import android.content.res.Resources; +import android.os.VibrationAttributes; +import android.os.Vibrator; +import android.os.Vibrator.VibrationIntensity; + +/** + * List of device-specific internal vibration configuration loaded from platform config.xml. + * + *

This should not be public, but some individual values are exposed by {@link Vibrator} by + * hidden methods, made available to Settings, SysUI and other platform client code. They can also + * be individually exposed with the necessary permissions by the {@link Vibrator} service. + * + * @hide + */ +public class VibrationConfig { + + // TODO(b/191150049): move these to vibrator static config file + private final float mHapticChannelMaxVibrationAmplitude; + private final int mRampStepDurationMs; + private final int mRampDownDurationMs; + + @VibrationIntensity + private final int mDefaultAlarmVibrationIntensity; + @VibrationIntensity + private final int mDefaultHapticFeedbackIntensity; + @VibrationIntensity + private final int mDefaultMediaVibrationIntensity; + @VibrationIntensity + private final int mDefaultNotificationVibrationIntensity; + @VibrationIntensity + private final int mDefaultRingVibrationIntensity; + + /** @hide */ + public VibrationConfig(@Nullable Resources resources) { + mHapticChannelMaxVibrationAmplitude = loadFloat(resources, + com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude, 0); + mRampDownDurationMs = loadInteger(resources, + com.android.internal.R.integer.config_vibrationWaveformRampDownDuration, 0); + mRampStepDurationMs = loadInteger(resources, + com.android.internal.R.integer.config_vibrationWaveformRampStepDuration, 0); + + mDefaultAlarmVibrationIntensity = loadDefaultIntensity(resources, + com.android.internal.R.integer.config_defaultAlarmVibrationIntensity); + mDefaultHapticFeedbackIntensity = loadDefaultIntensity(resources, + com.android.internal.R.integer.config_defaultHapticFeedbackIntensity); + mDefaultMediaVibrationIntensity = loadDefaultIntensity(resources, + com.android.internal.R.integer.config_defaultMediaVibrationIntensity); + mDefaultNotificationVibrationIntensity = loadDefaultIntensity(resources, + com.android.internal.R.integer.config_defaultNotificationVibrationIntensity); + mDefaultRingVibrationIntensity = loadDefaultIntensity(resources, + com.android.internal.R.integer.config_defaultRingVibrationIntensity); + } + + @VibrationIntensity + private static int loadDefaultIntensity(@Nullable Resources res, int resId) { + int defaultIntensity = Vibrator.VIBRATION_INTENSITY_MEDIUM; + int value = loadInteger(res, resId, defaultIntensity); + if (value < Vibrator.VIBRATION_INTENSITY_OFF || value > Vibrator.VIBRATION_INTENSITY_HIGH) { + return defaultIntensity; + } + return value; + } + + private static float loadFloat(@Nullable Resources res, int resId, float defaultValue) { + return res != null ? res.getFloat(resId) : defaultValue; + } + + private static int loadInteger(@Nullable Resources res, int resId, int defaultValue) { + return res != null ? res.getInteger(resId) : defaultValue; + } + + /** + * Return the maximum amplitude the vibrator can play using the audio haptic channels. + * + * @return a positive value representing the maximum absolute value the device can play signals + * from audio haptic channels, or {@link Float#NaN NaN} if it's unknown. + */ + public float getHapticChannelMaximumAmplitude() { + if (mHapticChannelMaxVibrationAmplitude <= 0) { + return Float.NaN; + } + return mHapticChannelMaxVibrationAmplitude; + } + + /** + * The duration, in milliseconds, that should be applied to the ramp to turn off the vibrator + * when a vibration is cancelled or finished at non-zero amplitude. + */ + public int getRampDownDurationMs() { + if (mRampDownDurationMs < 0) { + return 0; + } + return mRampDownDurationMs; + } + + /** + * The duration, in milliseconds, that should be applied to convert vibration effect's + * {@link android.os.vibrator.RampSegment} to a {@link android.os.vibrator.StepSegment} on + * devices without PWLE support. + */ + public int getRampStepDurationMs() { + if (mRampStepDurationMs < 0) { + return 0; + } + return mRampStepDurationMs; + } + + /** Get the default vibration intensity for given usage. */ + @VibrationIntensity + public int getDefaultVibrationIntensity(@VibrationAttributes.Usage int usage) { + switch (usage) { + case USAGE_ALARM: + return mDefaultAlarmVibrationIntensity; + case USAGE_NOTIFICATION: + case USAGE_COMMUNICATION_REQUEST: + return mDefaultNotificationVibrationIntensity; + case USAGE_RINGTONE: + return mDefaultRingVibrationIntensity; + case USAGE_TOUCH: + case USAGE_HARDWARE_FEEDBACK: + case USAGE_PHYSICAL_EMULATION: + case USAGE_ACCESSIBILITY: + return mDefaultHapticFeedbackIntensity; + case USAGE_MEDIA: + case USAGE_UNKNOWN: + // fall through + default: + return mDefaultMediaVibrationIntensity; + } + } + + @Override + public String toString() { + return "VibrationConfig{" + + "mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude + + ", mRampStepDurationMs=" + mRampStepDurationMs + + ", mRampDownDurationMs=" + mRampDownDurationMs + + ", mDefaultAlarmIntensity=" + mDefaultAlarmVibrationIntensity + + ", mDefaultHapticFeedbackIntensity=" + mDefaultHapticFeedbackIntensity + + ", mDefaultMediaIntensity=" + mDefaultMediaVibrationIntensity + + ", mDefaultNotificationIntensity=" + mDefaultNotificationVibrationIntensity + + ", mDefaultRingIntensity=" + mDefaultRingVibrationIntensity + + "}"; + } +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a97d4609539b3..a2692f159f374 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -4602,6 +4602,43 @@ public final class Settings { @Readable public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices"; + /** + * The intensity of alarm vibrations, if configurable. + * + * Not all devices are capable of changing their vibration intensity; on these devices + * there will likely be no difference between the various vibration intensities except for + * intensity 0 (off) and the rest. + * + * Values:
+ * 0 - Vibration is disabled
+ * 1 - Weak vibrations
+ * 2 - Medium vibrations
+ * 3 - Strong vibrations + * @hide + */ + public static final String ALARM_VIBRATION_INTENSITY = + "alarm_vibration_intensity"; + + /** + * The intensity of media vibrations, if configurable. + * + * This includes any vibration that is part of media, such as music, movie, soundtrack, + * game or animations. + * + * Not all devices are capable of changing their vibration intensity; on these devices + * there will likely be no difference between the various vibration intensities except for + * intensity 0 (off) and the rest. + * + * Values:
+ * 0 - Vibration is disabled
+ * 1 - Weak vibrations
+ * 2 - Medium vibrations
+ * 3 - Strong vibrations + * @hide + */ + public static final String MEDIA_VIBRATION_INTENSITY = + "media_vibration_intensity"; + /** * The intensity of notification vibrations, if configurable. * @@ -4619,6 +4656,7 @@ public final class Settings { @Readable public static final String NOTIFICATION_VIBRATION_INTENSITY = "notification_vibration_intensity"; + /** * The intensity of ringtone vibrations, if configurable. * @@ -4670,7 +4708,6 @@ public final class Settings { * 3 - Strong vibrations * @hide */ - @Readable public static final String HARDWARE_HAPTIC_FEEDBACK_INTENSITY = "hardware_haptic_feedback_intensity"; diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto index 73d6a17799d9d..e56d55e940e45 100644 --- a/core/proto/android/providers/settings/system.proto +++ b/core/proto/android/providers/settings/system.proto @@ -212,6 +212,12 @@ message SystemSettingsProto { // DatabaseHelper. optional SettingProto in_silent = 3 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto when_ringing = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; + + optional SettingProto alarm_intensity = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto media_intensity = 6 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto ring_intensity = 7 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // notification_intensity is already logged at Notification.vibration_intensity + // haptic_feedback_intensity is already logged at HapticFeedback.intensity } optional Vibrate vibrate = 32; diff --git a/core/proto/android/server/vibrator/vibratormanagerservice.proto b/core/proto/android/server/vibrator/vibratormanagerservice.proto index 7b97524d05105..fbe2170ea51c9 100644 --- a/core/proto/android/server/vibrator/vibratormanagerservice.proto +++ b/core/proto/android/server/vibrator/vibratormanagerservice.proto @@ -97,7 +97,7 @@ message VibrationProto { optional int32 status = 6; } -// Next id: 18 +// Next id: 24 message VibratorManagerServiceDumpProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; repeated int32 vibrator_ids = 1; @@ -106,8 +106,14 @@ message VibratorManagerServiceDumpProto { optional VibrationProto current_external_vibration = 4; optional bool vibrator_under_external_control = 5; optional bool low_power_mode = 6; + optional int32 alarm_intensity = 18; + optional int32 alarm_default_intensity = 19; optional int32 haptic_feedback_intensity = 7; optional int32 haptic_feedback_default_intensity = 8; + optional int32 hardware_feedback_intensity = 22; + optional int32 hardware_feedback_default_intensity = 23; + optional int32 media_intensity = 20; + optional int32 media_default_intensity = 21; optional int32 notification_intensity = 9; optional int32 notification_default_intensity = 10; optional int32 ring_intensity = 11; diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 7d8bceaf89e94..5470e33df12a2 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1179,10 +1179,18 @@ + + 2 2 + + 2 diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ba4aa81766e0e..a4b5d3caaabfd 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3867,7 +3867,9 @@ + + diff --git a/core/tests/coretests/src/android/os/VibratorTest.java b/core/tests/coretests/src/android/os/VibratorTest.java index bdd76a5c162a2..981086d6b1529 100644 --- a/core/tests/coretests/src/android/os/VibratorTest.java +++ b/core/tests/coretests/src/android/os/VibratorTest.java @@ -27,14 +27,22 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.content.ContentResolver; +import android.content.Context; +import android.content.ContextWrapper; import android.hardware.vibrator.IVibrator; import android.media.AudioAttributes; import android.platform.test.annotations.Presubmit; 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.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -50,11 +58,19 @@ import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class VibratorTest { + @Rule + public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); + + private Context mContextSpy; private Vibrator mVibratorSpy; @Before public void setUp() { - mVibratorSpy = spy(InstrumentationRegistry.getContext().getSystemService(Vibrator.class)); + mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); + + ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); + when(mContextSpy.getContentResolver()).thenReturn(contentResolver); + mVibratorSpy = spy(new SystemVibrator(mContextSpy)); } @Test diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java index 71accc4164164..00b5f50194858 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java @@ -78,6 +78,8 @@ public class SystemSettings { Settings.System.NOTIFICATION_SOUND, Settings.System.ACCELEROMETER_ROTATION, Settings.System.SHOW_BATTERY_PERCENT, + Settings.System.ALARM_VIBRATION_INTENSITY, + Settings.System.MEDIA_VIBRATION_INTENSITY, Settings.System.NOTIFICATION_VIBRATION_INTENSITY, Settings.System.RING_VIBRATION_INTENSITY, Settings.System.HAPTIC_FEEDBACK_INTENSITY, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java index 84e9d28092050..6bcb7695cd226 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java @@ -118,6 +118,8 @@ public class SystemSettingsValidators { VALIDATORS.put(System.MUTE_STREAMS_AFFECTED, NON_NEGATIVE_INTEGER_VALIDATOR); VALIDATORS.put(System.VIBRATE_ON, BOOLEAN_VALIDATOR); VALIDATORS.put(System.APPLY_RAMPING_RINGER, BOOLEAN_VALIDATOR); + VALIDATORS.put(System.ALARM_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR); + VALIDATORS.put(System.MEDIA_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR); VALIDATORS.put(System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR); VALIDATORS.put(System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR); VALIDATORS.put(System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 00cdc9b0a0586..c5f027b829d9c 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -2916,6 +2916,18 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.System.VIBRATE_WHEN_RINGING, SystemSettingsProto.Vibrate.WHEN_RINGING); + + // NOTIFICATION_VIBRATION_INTENSITY is already logged at Notification.vibration_intensity + // HAPTIC_FEEDBACK_INTENSITY is already logged at HapticFeedback.intensity + dumpSetting(s, p, + Settings.System.ALARM_VIBRATION_INTENSITY, + SystemSettingsProto.Vibrate.ALARM_INTENSITY); + dumpSetting(s, p, + Settings.System.MEDIA_VIBRATION_INTENSITY, + SystemSettingsProto.Vibrate.MEDIA_INTENSITY); + dumpSetting(s, p, + Settings.System.RING_VIBRATION_INTENSITY, + SystemSettingsProto.Vibrate.RING_INTENSITY); p.end(vibrateToken); final long volumeToken = p.start(SystemSettingsProto.VOLUME); diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java index 1ee115dd28f28..df6ffa2bd0098 100644 --- a/services/core/java/com/android/server/vibrator/VibrationSettings.java +++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java @@ -16,13 +16,16 @@ package com.android.server.vibrator; +import static android.os.VibrationAttributes.USAGE_ACCESSIBILITY; import static android.os.VibrationAttributes.USAGE_ALARM; import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST; import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK; +import static android.os.VibrationAttributes.USAGE_MEDIA; import static android.os.VibrationAttributes.USAGE_NOTIFICATION; import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION; import static android.os.VibrationAttributes.USAGE_RINGTONE; import static android.os.VibrationAttributes.USAGE_TOUCH; +import static android.os.VibrationAttributes.USAGE_UNKNOWN; import android.annotation.Nullable; import android.app.ActivityManager; @@ -44,8 +47,11 @@ import android.os.UserHandle; import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; +import android.os.Vibrator.VibrationIntensity; +import android.os.vibrator.VibrationConfig; import android.provider.Settings; import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; @@ -109,12 +115,8 @@ final class VibrationSettings { private final List mListeners = new ArrayList<>(); private final SparseArray mFallbackEffects; - private final int mRampStepDuration; - private final int mRampDownDuration; + private final VibrationConfig mVibrationConfig; - @GuardedBy("mLock") - @Nullable - private Vibrator mVibrator; @GuardedBy("mLock") @Nullable private AudioManager mAudioManager; @@ -122,40 +124,22 @@ final class VibrationSettings { @GuardedBy("mLock") private boolean mVibrateInputDevices; @GuardedBy("mLock") - private boolean mVibrateWhenRinging; - @GuardedBy("mLock") - private boolean mApplyRampingRinger; - @GuardedBy("mLock") - private int mHapticFeedbackIntensity; - @GuardedBy("mLock") - private int mHardwareFeedbackIntensity; - @GuardedBy("mLock") - private int mNotificationIntensity; - @GuardedBy("mLock") - private int mRingIntensity; + private SparseIntArray mCurrentVibrationIntensities = new SparseIntArray(); @GuardedBy("mLock") private boolean mBatterySaverMode; VibrationSettings(Context context, Handler handler) { - this(context, handler, - context.getResources().getInteger( - com.android.internal.R.integer.config_vibrationWaveformRampDownDuration), - context.getResources().getInteger( - com.android.internal.R.integer.config_vibrationWaveformRampStepDuration)); + this(context, handler, new VibrationConfig(context.getResources())); } @VisibleForTesting - VibrationSettings(Context context, Handler handler, int rampDownDuration, - int rampStepDuration) { + VibrationSettings(Context context, Handler handler, VibrationConfig config) { mContext = context; + mVibrationConfig = config; mSettingObserver = new SettingsObserver(handler); mUidObserver = new UidObserver(); mUserReceiver = new UserObserver(); - // TODO(b/191150049): move these to vibrator static config file - mRampDownDuration = rampDownDuration; - mRampStepDuration = rampStepDuration; - VibrationEffect clickEffect = createEffectFromResource( com.android.internal.R.array.config_virtualKeyVibePattern); VibrationEffect doubleClickEffect = createEffectFromResource( @@ -179,7 +163,6 @@ final class VibrationSettings { public void onSystemReady() { synchronized (mLock) { - mVibrator = mContext.getSystemService(Vibrator.class); mAudioManager = mContext.getSystemService(AudioManager.class); } try { @@ -214,11 +197,20 @@ final class VibrationSettings { IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(mUserReceiver, filter, Context.RECEIVER_NOT_EXPORTED); + // Listen to all settings that might affect the result of Vibrator.getVibrationIntensity. 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.System.getUriFor( + Settings.System.HAPTIC_FEEDBACK_ENABLED)); + registerSettingsObserver( + Settings.System.getUriFor(Settings.System.ALARM_VIBRATION_INTENSITY)); registerSettingsObserver( Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY)); + registerSettingsObserver( + Settings.System.getUriFor(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY)); + registerSettingsObserver( + Settings.System.getUriFor(Settings.System.MEDIA_VIBRATION_INTENSITY)); registerSettingsObserver( Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY)); registerSettingsObserver( @@ -253,7 +245,7 @@ final class VibrationSettings { * devices without PWLE support. */ public int getRampStepDuration() { - return mRampStepDuration; + return mVibrationConfig.getRampStepDurationMs(); } /** @@ -261,7 +253,7 @@ final class VibrationSettings { * when a vibration is cancelled or finished at non-zero amplitude. */ public int getRampDownDuration() { - return mRampDownDuration; + return mVibrationConfig.getRampDownDurationMs(); } /** @@ -270,25 +262,8 @@ final class VibrationSettings { * @param usageHint one of VibrationAttributes.USAGE_* * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_* */ - public int getDefaultIntensity(int usageHint) { - if (usageHint == USAGE_ALARM) { - return Vibrator.VIBRATION_INTENSITY_HIGH; - } - synchronized (mLock) { - if (mVibrator != null) { - switch (usageHint) { - case USAGE_RINGTONE: - return mVibrator.getDefaultRingVibrationIntensity(); - case USAGE_NOTIFICATION: - return mVibrator.getDefaultNotificationVibrationIntensity(); - case USAGE_TOUCH: - case USAGE_HARDWARE_FEEDBACK: - case USAGE_PHYSICAL_EMULATION: - return mVibrator.getDefaultHapticFeedbackIntensity(); - } - } - } - return Vibrator.VIBRATION_INTENSITY_MEDIUM; + public int getDefaultIntensity(@VibrationAttributes.Usage int usageHint) { + return mVibrationConfig.getDefaultVibrationIntensity(usageHint); } /** @@ -297,23 +272,10 @@ final class VibrationSettings { * @param usageHint one of VibrationAttributes.USAGE_* * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_* */ - public int getCurrentIntensity(int usageHint) { + public int getCurrentIntensity(@VibrationAttributes.Usage int usageHint) { + int defaultIntensity = getDefaultIntensity(usageHint); synchronized (mLock) { - switch (usageHint) { - case USAGE_RINGTONE: - return mRingIntensity; - case USAGE_NOTIFICATION: - return mNotificationIntensity; - case USAGE_TOUCH: - return mHapticFeedbackIntensity; - case USAGE_HARDWARE_FEEDBACK: - case USAGE_PHYSICAL_EMULATION: - return mHardwareFeedbackIntensity; - case USAGE_ALARM: - return Vibrator.VIBRATION_INTENSITY_HIGH; - default: - return Vibrator.VIBRATION_INTENSITY_MEDIUM; - } + return mCurrentVibrationIntensities.get(usageHint, defaultIntensity); } } @@ -371,7 +333,7 @@ final class VibrationSettings { * for touch and ringtone usages only. All other usages are allowed by this method. */ @GuardedBy("mLock") - private boolean shouldVibrateForRingerModeLocked(int usageHint) { + private boolean shouldVibrateForRingerModeLocked(@VibrationAttributes.Usage int usageHint) { // If audio manager was not loaded yet then assume most restrictive mode. int ringerMode = (mAudioManager == null) ? AudioManager.RINGER_MODE_SILENT @@ -379,18 +341,9 @@ final class VibrationSettings { 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; - } + // Touch feedback and ringtone disabled when phone is on silent mode. + return ringerMode != AudioManager.RINGER_MODE_SILENT; default: // All other usages ignore ringer mode settings. return true; @@ -401,64 +354,89 @@ final class VibrationSettings { @VisibleForTesting void updateSettings() { synchronized (mLock) { - mVibrateWhenRinging = getSystemSetting(Settings.System.VIBRATE_WHEN_RINGING, 0) != 0; - mApplyRampingRinger = getSystemSetting(Settings.System.APPLY_RAMPING_RINGER, 0) != 0; - mHapticFeedbackIntensity = getSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, - getDefaultIntensity(USAGE_TOUCH)); - mHardwareFeedbackIntensity = getSystemSetting( - Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, - getHardwareFeedbackIntensityWhenSettingIsMissing(mHapticFeedbackIntensity)); - mNotificationIntensity = getSystemSetting( - Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - getDefaultIntensity(USAGE_NOTIFICATION)); - mRingIntensity = getSystemSetting(Settings.System.RING_VIBRATION_INTENSITY, + mVibrateInputDevices = loadSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0; + + int alarmIntensity = toIntensity( + loadSystemSetting(Settings.System.ALARM_VIBRATION_INTENSITY, -1), + getDefaultIntensity(USAGE_ALARM)); + int defaultHapticFeedbackIntensity = getDefaultIntensity(USAGE_TOUCH); + int hapticFeedbackIntensity = toIntensity( + loadSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, -1), + defaultHapticFeedbackIntensity); + int positiveHapticFeedbackIntensity = toPositiveIntensity( + hapticFeedbackIntensity, defaultHapticFeedbackIntensity); + int hardwareFeedbackIntensity = toIntensity( + loadSystemSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, -1), + positiveHapticFeedbackIntensity); + int mediaIntensity = toIntensity( + loadSystemSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, -1), + getDefaultIntensity(USAGE_MEDIA)); + int defaultNotificationIntensity = getDefaultIntensity(USAGE_NOTIFICATION); + int notificationIntensity = toIntensity( + loadSystemSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, -1), + defaultNotificationIntensity); + int positiveNotificationIntensity = toPositiveIntensity( + notificationIntensity, defaultNotificationIntensity); + int ringIntensity = toIntensity( + loadSystemSetting(Settings.System.RING_VIBRATION_INTENSITY, -1), getDefaultIntensity(USAGE_RINGTONE)); - mVibrateInputDevices = getSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0; + + + mCurrentVibrationIntensities.clear(); + mCurrentVibrationIntensities.put(USAGE_ALARM, alarmIntensity); + mCurrentVibrationIntensities.put(USAGE_NOTIFICATION, notificationIntensity); + mCurrentVibrationIntensities.put(USAGE_MEDIA, mediaIntensity); + mCurrentVibrationIntensities.put(USAGE_UNKNOWN, mediaIntensity); + + // Communication request is not disabled by the notification setting. + mCurrentVibrationIntensities.put(USAGE_COMMUNICATION_REQUEST, + positiveNotificationIntensity); + + if (!loadBooleanSetting(Settings.System.VIBRATE_WHEN_RINGING) + && !loadBooleanSetting(Settings.System.APPLY_RAMPING_RINGER)) { + // Make sure deprecated boolean setting still disables ringtone vibrations. + mCurrentVibrationIntensities.put(USAGE_RINGTONE, Vibrator.VIBRATION_INTENSITY_OFF); + } else { + mCurrentVibrationIntensities.put(USAGE_RINGTONE, ringIntensity); + } + + // This should adapt the behavior preceding the introduction of this new setting + // key, which is to apply HAPTIC_FEEDBACK_INTENSITY, unless it's disabled. + mCurrentVibrationIntensities.put(USAGE_HARDWARE_FEEDBACK, hardwareFeedbackIntensity); + mCurrentVibrationIntensities.put(USAGE_PHYSICAL_EMULATION, hardwareFeedbackIntensity); + + if (!loadBooleanSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED)) { + // Make sure deprecated boolean setting still disables touch vibrations. + mCurrentVibrationIntensities.put(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_OFF); + } else { + mCurrentVibrationIntensities.put(USAGE_TOUCH, hapticFeedbackIntensity); + } + + // A11y is not disabled by any haptic feedback setting. + mCurrentVibrationIntensities.put(USAGE_ACCESSIBILITY, positiveHapticFeedbackIntensity); } notifyListeners(); } - /** - * Return the value to be used for {@link Settings.System#HARDWARE_HAPTIC_FEEDBACK_INTENSITY} - * when the value was not set by the user. - * - *

This should adapt the behavior preceding the introduction of this new setting key, which - * is to apply {@link Settings.System#HAPTIC_FEEDBACK_INTENSITY} unless it's disabled. - */ - private int getHardwareFeedbackIntensityWhenSettingIsMissing(int hapticFeedbackIntensity) { - if (hapticFeedbackIntensity == Vibrator.VIBRATION_INTENSITY_OFF) { - return getDefaultIntensity(USAGE_HARDWARE_FEEDBACK); - } - return hapticFeedbackIntensity; - } - @Override public String toString() { synchronized (mLock) { + StringBuilder vibrationIntensitiesString = new StringBuilder("{"); + for (int i = 0; i < mCurrentVibrationIntensities.size(); i++) { + int usage = mCurrentVibrationIntensities.keyAt(i); + int intensity = mCurrentVibrationIntensities.valueAt(i); + vibrationIntensitiesString.append(VibrationAttributes.usageToString(usage)) + .append("=(").append(intensityToString(intensity)) + .append(",default:").append(intensityToString(getDefaultIntensity(usage))) + .append("), "); + } + vibrationIntensitiesString.append('}'); return "VibrationSettings{" - + "mVibrateInputDevices=" + mVibrateInputDevices - + ", mVibrateWhenRinging=" + mVibrateWhenRinging - + ", mApplyRampingRinger=" + mApplyRampingRinger + + "mVibratorConfig=" + mVibrationConfig + + ", mVibrateInputDevices=" + mVibrateInputDevices + ", 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)) + + ", mVibrationIntensities=" + vibrationIntensitiesString + '}'; } } @@ -466,16 +444,28 @@ final class VibrationSettings { /** Write current settings into given {@link ProtoOutputStream}. */ public void dumpProto(ProtoOutputStream proto) { synchronized (mLock) { + proto.write(VibratorManagerServiceDumpProto.ALARM_INTENSITY, + getCurrentIntensity(USAGE_ALARM)); + proto.write(VibratorManagerServiceDumpProto.ALARM_DEFAULT_INTENSITY, + getDefaultIntensity(USAGE_ALARM)); + proto.write(VibratorManagerServiceDumpProto.HARDWARE_FEEDBACK_INTENSITY, + getCurrentIntensity(USAGE_HARDWARE_FEEDBACK)); + proto.write(VibratorManagerServiceDumpProto.HARDWARE_FEEDBACK_DEFAULT_INTENSITY, + getDefaultIntensity(USAGE_HARDWARE_FEEDBACK)); proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY, - mHapticFeedbackIntensity); + getCurrentIntensity(USAGE_TOUCH)); proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_DEFAULT_INTENSITY, getDefaultIntensity(USAGE_TOUCH)); + proto.write(VibratorManagerServiceDumpProto.MEDIA_INTENSITY, + getCurrentIntensity(USAGE_MEDIA)); + proto.write(VibratorManagerServiceDumpProto.MEDIA_DEFAULT_INTENSITY, + getDefaultIntensity(USAGE_MEDIA)); proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_INTENSITY, - mNotificationIntensity); + getCurrentIntensity(USAGE_NOTIFICATION)); proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_DEFAULT_INTENSITY, getDefaultIntensity(USAGE_NOTIFICATION)); proto.write(VibratorManagerServiceDumpProto.RING_INTENSITY, - mRingIntensity); + getCurrentIntensity(USAGE_RINGTONE)); proto.write(VibratorManagerServiceDumpProto.RING_DEFAULT_INTENSITY, getDefaultIntensity(USAGE_RINGTONE)); } @@ -506,13 +496,29 @@ final class VibrationSettings { } } - private float getHapticChannelMaxVibrationAmplitude() { - synchronized (mLock) { - return mVibrator == null ? Float.NaN : mVibrator.getHapticChannelMaximumAmplitude(); + @VibrationIntensity + private int toPositiveIntensity(int value, @VibrationIntensity int defaultValue) { + if (value == Vibrator.VIBRATION_INTENSITY_OFF) { + return defaultValue; } + return toIntensity(value, defaultValue); } - private int getSystemSetting(String settingName, int defaultValue) { + @VibrationIntensity + private int toIntensity(int value, @VibrationIntensity int defaultValue) { + if ((value < Vibrator.VIBRATION_INTENSITY_OFF) + || (value > Vibrator.VIBRATION_INTENSITY_HIGH)) { + return defaultValue; + } + return value; + } + + private boolean loadBooleanSetting(String settingKey) { + return Settings.System.getIntForUser(mContext.getContentResolver(), + settingKey, 0, UserHandle.USER_CURRENT) != 0; + } + + private int loadSystemSetting(String settingName, int defaultValue) { return Settings.System.getIntForUser(mContext.getContentResolver(), settingName, defaultValue, UserHandle.USER_CURRENT); } diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java index e2a348efa4096..4556a4a47017c 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibrator.java @@ -17,6 +17,7 @@ package com.android.server.vibrator; import android.annotation.NonNull; +import android.content.Context; import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; @@ -24,37 +25,8 @@ import android.os.Vibrator; /** Fake implementation of {@link Vibrator} for service tests. */ final class FakeVibrator extends Vibrator { - private int mDefaultHapticFeedbackIntensity = Vibrator.VIBRATION_INTENSITY_MEDIUM; - private int mDefaultNotificationIntensity = Vibrator.VIBRATION_INTENSITY_MEDIUM; - private int mDefaultRingIntensity = Vibrator.VIBRATION_INTENSITY_MEDIUM; - - @Override - public int getDefaultHapticFeedbackIntensity() { - return mDefaultHapticFeedbackIntensity; - } - - @Override - public int getDefaultNotificationVibrationIntensity() { - return mDefaultNotificationIntensity; - } - - @Override - public int getDefaultRingVibrationIntensity() { - return mDefaultRingIntensity; - } - - public void setDefaultHapticFeedbackIntensity( - @VibrationIntensity int defaultHapticFeedbackIntensity) { - mDefaultHapticFeedbackIntensity = defaultHapticFeedbackIntensity; - } - - public void setDefaultNotificationVibrationIntensity( - @VibrationIntensity int defaultNotificationIntensity) { - mDefaultNotificationIntensity = defaultNotificationIntensity; - } - - public void setDefaultRingVibrationIntensity(@VibrationIntensity int defaultRingIntensity) { - mDefaultRingIntensity = defaultRingIntensity; + FakeVibrator(Context context) { + super(context); } @Override diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java index 59c0b0e96fcde..6369dbc6b171b 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java @@ -16,6 +16,14 @@ package com.android.server.vibrator; +import static android.os.VibrationAttributes.USAGE_NOTIFICATION; +import static android.os.VibrationAttributes.USAGE_RINGTONE; +import static android.os.VibrationAttributes.USAGE_TOUCH; +import static android.os.Vibrator.VIBRATION_INTENSITY_HIGH; +import static android.os.Vibrator.VIBRATION_INTENSITY_LOW; +import static android.os.Vibrator.VIBRATION_INTENSITY_MEDIUM; +import static android.os.Vibrator.VIBRATION_INTENSITY_OFF; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; @@ -24,7 +32,6 @@ 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; @@ -37,6 +44,7 @@ import android.os.test.TestLooper; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.StepSegment; +import android.os.vibrator.VibrationConfig; import android.os.vibrator.VibrationEffectSegment; import android.platform.test.annotations.Presubmit; import android.provider.Settings; @@ -68,29 +76,31 @@ public class VibrationScalerTest { @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); @Mock private PowerManagerInternal mPowerManagerInternalMock; + @Mock private VibrationConfig mVibrationConfigMock; private TestLooper mTestLooper; private ContextWrapper mContextSpy; - private FakeVibrator mFakeVibrator; private VibrationSettings mVibrationSettings; private VibrationScaler mVibrationScaler; @Before public void setUp() throws Exception { mTestLooper = new TestLooper(); - mFakeVibrator = new FakeVibrator(); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); when(mContextSpy.getContentResolver()).thenReturn(contentResolver); - when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mFakeVibrator); LocalServices.removeServiceForTest(PowerManagerInternal.class); LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock); + Settings.System.putInt(contentResolver, Settings.System.HAPTIC_FEEDBACK_ENABLED, 1); + Settings.System.putInt(contentResolver, Settings.System.VIBRATE_WHEN_RINGING, 1); + mVibrationSettings = new VibrationSettings( - mContextSpy, new Handler(mTestLooper.getLooper())); + mContextSpy, new Handler(mTestLooper.getLooper()), mVibrationConfigMock); mVibrationScaler = new VibrationScaler(mContextSpy, mVibrationSettings); + mVibrationSettings.onSystemReady(); } @@ -101,91 +111,80 @@ public class VibrationScalerTest { @Test public void testGetExternalVibrationScale() { - mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_LOW); - setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, - Vibrator.VIBRATION_INTENSITY_HIGH); + setDefaultIntensity(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH); assertEquals(IExternalVibratorService.SCALE_VERY_HIGH, - mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH)); + mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); - setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, - Vibrator.VIBRATION_INTENSITY_MEDIUM); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_MEDIUM); assertEquals(IExternalVibratorService.SCALE_HIGH, - mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH)); + mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); - setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, - Vibrator.VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_LOW); assertEquals(IExternalVibratorService.SCALE_NONE, - mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH)); + mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); - mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM); + setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_MEDIUM); assertEquals(IExternalVibratorService.SCALE_LOW, - mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH)); + mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); - mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH); + setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_HIGH); assertEquals(IExternalVibratorService.SCALE_VERY_LOW, - mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH)); + mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); - setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, - Vibrator.VIBRATION_INTENSITY_OFF); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); // Unexpected vibration intensity will be treated as SCALE_NONE. assertEquals(IExternalVibratorService.SCALE_NONE, - mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH)); + mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH)); } @Test public void scale_withPrebakedSegment_setsEffectStrengthBasedOnSettings() { - setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_HIGH); + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH); PrebakedSegment effect = new PrebakedSegment(VibrationEffect.EFFECT_CLICK, /* shouldFallback= */ false, VibrationEffect.EFFECT_STRENGTH_MEDIUM); - PrebakedSegment scaled = mVibrationScaler.scale( - effect, VibrationAttributes.USAGE_NOTIFICATION); + PrebakedSegment scaled = mVibrationScaler.scale(effect, 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); + VIBRATION_INTENSITY_MEDIUM); + scaled = mVibrationScaler.scale(effect, 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); + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); + scaled = mVibrationScaler.scale(effect, 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); + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); + scaled = mVibrationScaler.scale(effect, USAGE_NOTIFICATION); // Unexpected intensity setting will be mapped to STRONG. assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG); } @Test public void scale_withPrebakedEffect_setsEffectStrengthBasedOnSettings() { - setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_HIGH); + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH); VibrationEffect effect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK); PrebakedSegment scaled = getFirstSegment(mVibrationScaler.scale( - effect, VibrationAttributes.USAGE_NOTIFICATION)); + effect, USAGE_NOTIFICATION)); assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_MEDIUM); + VIBRATION_INTENSITY_MEDIUM); scaled = getFirstSegment(mVibrationScaler.scale( - effect, VibrationAttributes.USAGE_NOTIFICATION)); + effect, USAGE_NOTIFICATION)); assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_MEDIUM); - setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); scaled = getFirstSegment(mVibrationScaler.scale( - effect, VibrationAttributes.USAGE_NOTIFICATION)); + effect, USAGE_NOTIFICATION)); assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_LIGHT); - setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_OFF); + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); scaled = getFirstSegment(mVibrationScaler.scale( - effect, VibrationAttributes.USAGE_NOTIFICATION)); + effect, USAGE_NOTIFICATION)); // Unexpected intensity setting will be mapped to STRONG. assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG); } @@ -193,81 +192,77 @@ public class VibrationScalerTest { @Test public void scale_withOneShotAndWaveform_resolvesAmplitude() { // No scale, default amplitude still resolved - mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW); - setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_LOW); + setDefaultIntensity(USAGE_RINGTONE, VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); StepSegment resolved = getFirstSegment(mVibrationScaler.scale( VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE), - VibrationAttributes.USAGE_RINGTONE)); + USAGE_RINGTONE)); assertTrue(resolved.getAmplitude() > 0); resolved = getFirstSegment(mVibrationScaler.scale( VibrationEffect.createWaveform(new long[]{10}, new int[]{VibrationEffect.DEFAULT_AMPLITUDE}, -1), - VibrationAttributes.USAGE_RINGTONE)); + USAGE_RINGTONE)); assertTrue(resolved.getAmplitude() > 0); } @Test public void scale_withOneShotAndWaveform_scalesAmplitude() { - mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW); - setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_HIGH); - mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH); - setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_LOW); - mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM); - setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, - Vibrator.VIBRATION_INTENSITY_MEDIUM); + setDefaultIntensity(USAGE_RINGTONE, VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH); + setDefaultIntensity(USAGE_NOTIFICATION, VIBRATION_INTENSITY_HIGH); + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); + setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_MEDIUM); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_MEDIUM); StepSegment scaled = getFirstSegment(mVibrationScaler.scale( - VibrationEffect.createOneShot(128, 128), VibrationAttributes.USAGE_RINGTONE)); + VibrationEffect.createOneShot(128, 128), USAGE_RINGTONE)); // Ringtone scales up. assertTrue(scaled.getAmplitude() > 0.5); scaled = getFirstSegment(mVibrationScaler.scale( VibrationEffect.createWaveform(new long[]{128}, new int[]{128}, -1), - VibrationAttributes.USAGE_NOTIFICATION)); + USAGE_NOTIFICATION)); // Notification scales down. assertTrue(scaled.getAmplitude() < 0.5); scaled = getFirstSegment(mVibrationScaler.scale(VibrationEffect.createOneShot(128, 128), - VibrationAttributes.USAGE_TOUCH)); + USAGE_TOUCH)); // Haptic feedback does not scale. assertEquals(128f / 255, scaled.getAmplitude(), 1e-5); } @Test public void scale_withComposed_scalesPrimitives() { - mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW); - setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_HIGH); - mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH); - setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_LOW); - mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM); - setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, - Vibrator.VIBRATION_INTENSITY_MEDIUM); + setDefaultIntensity(USAGE_RINGTONE, VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH); + setDefaultIntensity(USAGE_NOTIFICATION, VIBRATION_INTENSITY_HIGH); + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); + setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_MEDIUM); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_MEDIUM); VibrationEffect composed = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f).compose(); - PrimitiveSegment scaled = getFirstSegment(mVibrationScaler.scale(composed, - VibrationAttributes.USAGE_RINGTONE)); + PrimitiveSegment scaled = getFirstSegment(mVibrationScaler.scale(composed, USAGE_RINGTONE)); // Ringtone scales up. assertTrue(scaled.getScale() > 0.5f); - scaled = getFirstSegment(mVibrationScaler.scale(composed, - VibrationAttributes.USAGE_NOTIFICATION)); + scaled = getFirstSegment(mVibrationScaler.scale(composed, USAGE_NOTIFICATION)); // Notification scales down. assertTrue(scaled.getScale() < 0.5f); - scaled = getFirstSegment(mVibrationScaler.scale(composed, VibrationAttributes.USAGE_TOUCH)); + scaled = getFirstSegment(mVibrationScaler.scale(composed, USAGE_TOUCH)); // Haptic feedback does not scale. assertEquals(0.5, scaled.getScale(), 1e-5); } + private void setDefaultIntensity(@VibrationAttributes.Usage int usage, + @Vibrator.VibrationIntensity int intensity) { + when(mVibrationConfigMock.getDefaultVibrationIntensity(eq(usage))).thenReturn(intensity); + } + private T getFirstSegment(VibrationEffect.Composed effect) { return (T) effect.getSegments().get(0); } 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 ab9fbb5814167..ff59d0f22c3c5 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java @@ -16,9 +16,11 @@ package com.android.server.vibrator; +import static android.os.VibrationAttributes.USAGE_ACCESSIBILITY; import static android.os.VibrationAttributes.USAGE_ALARM; import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST; import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK; +import static android.os.VibrationAttributes.USAGE_MEDIA; import static android.os.VibrationAttributes.USAGE_NOTIFICATION; import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION; import static android.os.VibrationAttributes.USAGE_RINGTONE; @@ -35,6 +37,7 @@ 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.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.spy; @@ -45,7 +48,6 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.content.ContentResolver; -import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.media.AudioManager; @@ -55,7 +57,9 @@ import android.os.PowerSaveState; import android.os.UserHandle; import android.os.VibrationAttributes; import android.os.VibrationEffect; +import android.os.Vibrator; import android.os.test.TestLooper; +import android.os.vibrator.VibrationConfig; import android.platform.test.annotations.Presubmit; import android.provider.Settings; @@ -87,6 +91,19 @@ public class VibrationSettingsTest { private static final PowerSaveState LOW_POWER_STATE = new PowerSaveState.Builder() .setBatterySaverEnabled(true).build(); + private static final int[] ALL_USAGES = new int[] { + USAGE_UNKNOWN, + USAGE_ACCESSIBILITY, + USAGE_ALARM, + USAGE_COMMUNICATION_REQUEST, + USAGE_HARDWARE_FEEDBACK, + USAGE_MEDIA, + USAGE_NOTIFICATION, + USAGE_PHYSICAL_EMULATION, + USAGE_RINGTONE, + USAGE_TOUCH, + }; + @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @Rule @@ -96,23 +113,23 @@ public class VibrationSettingsTest { private VibrationSettings.OnVibratorSettingsChanged mListenerMock; @Mock private PowerManagerInternal mPowerManagerInternalMock; + @Mock + private VibrationConfig mVibrationConfigMock; private TestLooper mTestLooper; private ContextWrapper mContextSpy; private AudioManager mAudioManager; - private FakeVibrator mFakeVibrator; private VibrationSettings mVibrationSettings; private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener; @Before public void setUp() throws Exception { mTestLooper = new TestLooper(); - mFakeVibrator = new FakeVibrator(); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); when(mContextSpy.getContentResolver()).thenReturn(contentResolver); - when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mFakeVibrator); + doAnswer(invocation -> { mRegisteredPowerModeListener = invocation.getArgument(0); return null; @@ -121,16 +138,18 @@ public class VibrationSettingsTest { LocalServices.removeServiceForTest(PowerManagerInternal.class); LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock); + setDefaultIntensity(VIBRATION_INTENSITY_MEDIUM); mAudioManager = mContextSpy.getSystemService(AudioManager.class); mVibrationSettings = new VibrationSettings(mContextSpy, - new Handler(mTestLooper.getLooper())); - mVibrationSettings.onSystemReady(); + new Handler(mTestLooper.getLooper()), mVibrationConfigMock); // Simulate System defaults. + setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1); setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1); setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0); setRingerMode(AudioManager.RINGER_MODE_NORMAL); + mVibrationSettings.onSystemReady(); } @After @@ -145,12 +164,15 @@ public class VibrationSettingsTest { setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0); setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0); + setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); + setUserSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 0); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); - verify(mListenerMock, times(7)).onChange(); + verify(mListenerMock, times(10)).onChange(); } @Test @@ -192,9 +214,7 @@ public class VibrationSettingsTest { 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))); + assertVibrationNotIgnoredForUsage(usage); } } @@ -209,10 +229,7 @@ public class VibrationSettingsTest { 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))); + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_BACKGROUND); } } @@ -221,10 +238,9 @@ public class VibrationSettingsTest { mVibrationSettings.mUidObserver.onUidStateChanged( UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0); - assertNull(mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(USAGE_TOUCH))); - assertNull(mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(USAGE_ALARM))); + for (int usage : ALL_USAGES) { + assertVibrationNotIgnoredForUsage(usage); + } } @Test @@ -238,9 +254,7 @@ public class VibrationSettingsTest { mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); for (int usage : expectedAllowedVibrations) { - assertNull("Error for usage " + VibrationAttributes.usageToString(usage), - mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(usage))); + assertVibrationNotIgnoredForUsage(usage); } } @@ -257,10 +271,7 @@ public class VibrationSettingsTest { mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE); for (int usage : expectedIgnoredVibrations) { - assertEquals("Error for usage " + VibrationAttributes.usageToString(usage), - Vibration.Status.IGNORED_FOR_POWER, - mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(usage))); + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_POWER); } } @@ -268,130 +279,130 @@ public class VibrationSettingsTest { public void shouldIgnoreVibration_notInBatterySaverMode_allowsAnyUsage() { mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); - assertNull(mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(USAGE_TOUCH))); - assertNull(mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(USAGE_COMMUNICATION_REQUEST))); + for (int usage : ALL_USAGES) { + assertVibrationNotIgnoredForUsage(usage); + } } @Test public void shouldIgnoreVibration_withRingerModeSilent_ignoresRingtoneAndTouch() { // Vibrating settings on are overruled by ringer mode. + setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1); - setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0); + setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 1); 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))); + for (int usage : ALL_USAGES) { + if (usage == USAGE_RINGTONE || usage == USAGE_TOUCH) { + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_RINGER_MODE); + } else { + assertVibrationNotIgnoredForUsage(usage); + } + } } @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); - 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))); + for (int usage : ALL_USAGES) { + assertVibrationNotIgnoredForUsage(usage); + } } @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); + public void shouldIgnoreVibration_withRingerModeNormal_allowsAllVibrations() { 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))); + for (int usage : ALL_USAGES) { + assertVibrationNotIgnoredForUsage(usage); + } } @Test - public void shouldIgnoreVibration_withRingerModeNormalAndRingSettingsOn_allowsAllVibrations() { + public void shouldIgnoreVibration_withRingSettingsOff_disableRingtoneVibrations() { + setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0); + setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0); + + for (int usage : ALL_USAGES) { + if (usage == USAGE_RINGTONE) { + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS); + } else { + assertVibrationNotIgnoredForUsage(usage); + } + } + } + + @Test + public void shouldIgnoreVibration_withRingSettingsOn_allowsAllVibrations() { setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1); setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0); - setRingerMode(AudioManager.RINGER_MODE_NORMAL); - assertNull(mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(USAGE_TOUCH))); - assertNull(mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(USAGE_RINGTONE))); - assertNull(mVibrationSettings.shouldIgnoreVibration(UID, - VibrationAttributes.createForUsage(USAGE_ALARM))); + for (int usage : ALL_USAGES) { + assertVibrationNotIgnoredForUsage(usage); + } } @Test - public void shouldIgnoreVibration_withRingerModeNormalAndRampingRingerOn_allowsAllVibrations() { + public void shouldIgnoreVibration_withRampingRingerOn_allowsAllVibrations() { setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0); setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 1); - setRingerMode(AudioManager.RINGER_MODE_NORMAL); - 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))); + for (int usage : ALL_USAGES) { + assertVibrationNotIgnoredForUsage(usage); + } + } + + @Test + public void shouldIgnoreVibration_withHapticFeedbackDisabled_ignoresTouchVibration() { + setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 0); + + for (int usage : ALL_USAGES) { + if (usage == USAGE_TOUCH) { + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS); + } else { + assertVibrationNotIgnoredForUsage(usage); + } + } } @Test public void shouldIgnoreVibration_withHapticFeedbackSettingsOff_ignoresTouchVibration() { setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); - 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))); + for (int usage : ALL_USAGES) { + if (usage == USAGE_TOUCH) { + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS); + } else { + assertVibrationNotIgnoredForUsage(usage); + } + } } @Test public void shouldIgnoreVibration_withHardwareFeedbackSettingsOff_ignoresHardwareVibrations() { setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); - 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))); + for (int usage : ALL_USAGES) { + if (usage == USAGE_HARDWARE_FEEDBACK || usage == USAGE_PHYSICAL_EMULATION) { + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS); + } else { + assertVibrationNotIgnoredForUsage(usage); + } + } } @Test public void shouldIgnoreVibration_withNotificationSettingsOff_ignoresNotificationVibrations() { setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); - 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))); + for (int usage : ALL_USAGES) { + if (usage == USAGE_NOTIFICATION) { + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS); + } else { + assertVibrationNotIgnoredForUsage(usage); + } + } } @Test @@ -402,15 +413,13 @@ public class VibrationSettingsTest { setRingerMode(AudioManager.RINGER_MODE_VIBRATE); setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); - 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))); + for (int usage : ALL_USAGES) { + if (usage == USAGE_RINGTONE) { + assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS); + } else { + assertVibrationNotIgnoredForUsage(usage); + } + } } @Test @@ -423,90 +432,40 @@ public class VibrationSettingsTest { } @Test - public void getDefaultIntensity_beforeSystemReady_returnsMediumToAllExceptAlarm() { - mFakeVibrator.setDefaultHapticFeedbackIntensity(VIBRATION_INTENSITY_HIGH); - mFakeVibrator.setDefaultNotificationVibrationIntensity(VIBRATION_INTENSITY_HIGH); - mFakeVibrator.setDefaultRingVibrationIntensity(VIBRATION_INTENSITY_HIGH); - - setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); - setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); + public void getDefaultIntensity_returnsIntensityFromVibratorConfig() { + setDefaultIntensity(VIBRATION_INTENSITY_HIGH); + setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); - - VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy, - new Handler(mTestLooper.getLooper())); - - assertEquals(VIBRATION_INTENSITY_HIGH, - vibrationSettings.getDefaultIntensity(USAGE_ALARM)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - vibrationSettings.getDefaultIntensity(USAGE_TOUCH)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - vibrationSettings.getDefaultIntensity(USAGE_HARDWARE_FEEDBACK)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - vibrationSettings.getDefaultIntensity(USAGE_PHYSICAL_EMULATION)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - vibrationSettings.getDefaultIntensity(USAGE_NOTIFICATION)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - vibrationSettings.getDefaultIntensity(USAGE_UNKNOWN)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - vibrationSettings.getDefaultIntensity(USAGE_RINGTONE)); - } - - @Test - public void getDefaultIntensity_returnsIntensityFromVibratorService() { - mFakeVibrator.setDefaultHapticFeedbackIntensity(VIBRATION_INTENSITY_HIGH); - mFakeVibrator.setDefaultNotificationVibrationIntensity(VIBRATION_INTENSITY_MEDIUM); - mFakeVibrator.setDefaultRingVibrationIntensity(VIBRATION_INTENSITY_LOW); - setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); + setUserSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF); - setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); - assertEquals(VIBRATION_INTENSITY_HIGH, - mVibrationSettings.getDefaultIntensity(USAGE_ALARM)); - assertEquals(VIBRATION_INTENSITY_HIGH, - mVibrationSettings.getDefaultIntensity(USAGE_TOUCH)); - assertEquals(VIBRATION_INTENSITY_HIGH, - mVibrationSettings.getDefaultIntensity(USAGE_HARDWARE_FEEDBACK)); - assertEquals(VIBRATION_INTENSITY_HIGH, - mVibrationSettings.getDefaultIntensity(USAGE_PHYSICAL_EMULATION)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - mVibrationSettings.getDefaultIntensity(USAGE_NOTIFICATION)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - mVibrationSettings.getDefaultIntensity(USAGE_UNKNOWN)); - assertEquals(VIBRATION_INTENSITY_LOW, - mVibrationSettings.getDefaultIntensity(USAGE_RINGTONE)); + for (int usage : ALL_USAGES) { + assertEquals(VIBRATION_INTENSITY_HIGH, mVibrationSettings.getDefaultIntensity(usage)); + } } @Test public void getCurrentIntensity_returnsIntensityFromSettings() { - mFakeVibrator.setDefaultHapticFeedbackIntensity(VIBRATION_INTENSITY_OFF); - mFakeVibrator.setDefaultNotificationVibrationIntensity(VIBRATION_INTENSITY_OFF); - mFakeVibrator.setDefaultRingVibrationIntensity(VIBRATION_INTENSITY_OFF); - - setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH); + setDefaultIntensity(VIBRATION_INTENSITY_OFF); + setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_LOW); setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_LOW); - setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - VIBRATION_INTENSITY_MEDIUM); + setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); + setUserSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW); - assertEquals(VIBRATION_INTENSITY_HIGH, mVibrationSettings.getCurrentIntensity(USAGE_ALARM)); - assertEquals(VIBRATION_INTENSITY_HIGH, mVibrationSettings.getCurrentIntensity(USAGE_TOUCH)); - assertEquals(VIBRATION_INTENSITY_LOW, - mVibrationSettings.getCurrentIntensity(USAGE_HARDWARE_FEEDBACK)); - assertEquals(VIBRATION_INTENSITY_LOW, - mVibrationSettings.getCurrentIntensity(USAGE_PHYSICAL_EMULATION)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - mVibrationSettings.getCurrentIntensity(USAGE_NOTIFICATION)); - assertEquals(VIBRATION_INTENSITY_MEDIUM, - mVibrationSettings.getCurrentIntensity(USAGE_UNKNOWN)); - assertEquals(VIBRATION_INTENSITY_LOW, - mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE)); + for (int usage : ALL_USAGES) { + assertEquals(errorMessageForUsage(usage), + VIBRATION_INTENSITY_LOW, + mVibrationSettings.getCurrentIntensity(usage)); + } } @Test public void getCurrentIntensity_updateTriggeredAfterUserSwitched() { - mFakeVibrator.setDefaultRingVibrationIntensity(VIBRATION_INTENSITY_OFF); + setDefaultIntensity(USAGE_RINGTONE, VIBRATION_INTENSITY_OFF); setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH); assertEquals(VIBRATION_INTENSITY_HIGH, mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE)); @@ -524,8 +483,9 @@ public class VibrationSettingsTest { @Test public void getCurrentIntensity_noHardwareFeedbackValueUsesHapticFeedbackValue() { - mFakeVibrator.setDefaultHapticFeedbackIntensity(VIBRATION_INTENSITY_MEDIUM); + setDefaultIntensity(USAGE_HARDWARE_FEEDBACK, VIBRATION_INTENSITY_MEDIUM); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); + mVibrationSettings.updateSettings(); assertEquals(VIBRATION_INTENSITY_OFF, mVibrationSettings.getCurrentIntensity(USAGE_TOUCH)); // If haptic feedback is off, fallback to default value. assertEquals(VIBRATION_INTENSITY_MEDIUM, @@ -533,15 +493,11 @@ public class VibrationSettingsTest { assertEquals(VIBRATION_INTENSITY_MEDIUM, mVibrationSettings.getCurrentIntensity(USAGE_PHYSICAL_EMULATION)); - // Switching user is not working with FakeSettingsProvider. - // Testing the broadcast flow manually. - Settings.System.putIntForUser(mContextSpy.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH, - UserHandle.USER_CURRENT); - mVibrationSettings.mUserReceiver.onReceive(mContextSpy, - new Intent(Intent.ACTION_USER_SWITCHED)); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH); + mVibrationSettings.updateSettings(); assertEquals(VIBRATION_INTENSITY_HIGH, mVibrationSettings.getCurrentIntensity(USAGE_TOUCH)); + // If haptic feedback is on, fallback to that value. assertEquals(VIBRATION_INTENSITY_HIGH, mVibrationSettings.getCurrentIntensity(USAGE_HARDWARE_FEEDBACK)); assertEquals(VIBRATION_INTENSITY_HIGH, @@ -557,6 +513,33 @@ public class VibrationSettingsTest { assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_DOUBLE_CLICK)); } + private void assertVibrationIgnoredForUsage(@VibrationAttributes.Usage int usage, + Vibration.Status expectedStatus) { + assertEquals(errorMessageForUsage(usage), + expectedStatus, + mVibrationSettings.shouldIgnoreVibration(UID, + VibrationAttributes.createForUsage(usage))); + } + + private void assertVibrationNotIgnoredForUsage(@VibrationAttributes.Usage int usage) { + assertNull(errorMessageForUsage(usage), + mVibrationSettings.shouldIgnoreVibration(UID, + VibrationAttributes.createForUsage(usage))); + } + + private String errorMessageForUsage(int usage) { + return "Error for usage " + VibrationAttributes.usageToString(usage); + } + + private void setDefaultIntensity(@Vibrator.VibrationIntensity int intensity) { + when(mVibrationConfigMock.getDefaultVibrationIntensity(anyInt())).thenReturn(intensity); + } + + private void setDefaultIntensity(@VibrationAttributes.Usage int usage, + @Vibrator.VibrationIntensity int intensity) { + when(mVibrationConfigMock.getDefaultVibrationIntensity(eq(usage))).thenReturn(intensity); + } + private void setUserSetting(String settingName, int value) { Settings.System.putIntForUser( mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT); diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java index bfceb9abba2e8..5dd44ffc664fc 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java @@ -44,11 +44,13 @@ import android.os.Process; import android.os.SystemClock; import android.os.VibrationAttributes; import android.os.VibrationEffect; +import android.os.Vibrator; import android.os.test.TestLooper; import android.os.vibrator.PrebakedSegment; import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.RampSegment; import android.os.vibrator.StepSegment; +import android.os.vibrator.VibrationConfig; import android.os.vibrator.VibrationEffectSegment; import android.platform.test.annotations.LargeTest; import android.platform.test.annotations.Presubmit; @@ -101,6 +103,8 @@ public class VibrationThreadTest { private IBinder mVibrationToken; @Mock private IBatteryStats mIBatteryStatsMock; + @Mock + private VibrationConfig mVibrationConfigMock; private final Map mVibratorProviders = new HashMap<>(); private VibrationSettings mVibrationSettings; @@ -113,9 +117,13 @@ public class VibrationThreadTest { public void setUp() throws Exception { mTestLooper = new TestLooper(); + when(mVibrationConfigMock.getDefaultVibrationIntensity(anyInt())) + .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM); + when(mVibrationConfigMock.getRampStepDurationMs()).thenReturn(TEST_RAMP_STEP_DURATION); + Context context = InstrumentationRegistry.getContext(); mVibrationSettings = new VibrationSettings(context, new Handler(mTestLooper.getLooper()), - /* rampDownDuration= */ 0, TEST_RAMP_STEP_DURATION); + mVibrationConfigMock); mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings); mWakeLock = context.getSystemService( PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*"); @@ -1111,9 +1119,7 @@ public class VibrationThreadTest { @Test public void vibrate_waveformWithRampDown_addsRampDownAfterVibrationCompleted() { - int rampDownDuration = 15; - mVibrationSettings = new VibrationSettings(InstrumentationRegistry.getContext(), - new Handler(mTestLooper.getLooper()), rampDownDuration, TEST_RAMP_STEP_DURATION); + when(mVibrationConfigMock.getRampDownDurationMs()).thenReturn(15); mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings); mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); @@ -1139,9 +1145,7 @@ public class VibrationThreadTest { @Test public void vibrate_waveformWithRampDown_triggersCallbackWhenOriginalVibrationEnds() { - int rampDownDuration = 10_000; - mVibrationSettings = new VibrationSettings(InstrumentationRegistry.getContext(), - new Handler(mTestLooper.getLooper()), rampDownDuration, TEST_RAMP_STEP_DURATION); + when(mVibrationConfigMock.getRampDownDurationMs()).thenReturn(10_000); mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings); mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); @@ -1174,9 +1178,7 @@ public class VibrationThreadTest { @Test public void vibrate_waveformCancelledWithRampDown_addsRampDownAfterVibrationCancelled() throws Exception { - int rampDownDuration = 15; - mVibrationSettings = new VibrationSettings(InstrumentationRegistry.getContext(), - new Handler(mTestLooper.getLooper()), rampDownDuration, TEST_RAMP_STEP_DURATION); + when(mVibrationConfigMock.getRampDownDurationMs()).thenReturn(15); mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings); mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); @@ -1202,9 +1204,7 @@ public class VibrationThreadTest { @Test public void vibrate_predefinedWithRampDown_doesNotAddRampDown() { - int rampDownDuration = 15; - mVibrationSettings = new VibrationSettings(InstrumentationRegistry.getContext(), - new Handler(mTestLooper.getLooper()), rampDownDuration, TEST_RAMP_STEP_DURATION); + when(mVibrationConfigMock.getRampDownDurationMs()).thenReturn(15); mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings); mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); mVibratorProviders.get(VIBRATOR_ID).setSupportedEffects(VibrationEffect.EFFECT_CLICK); @@ -1224,9 +1224,7 @@ public class VibrationThreadTest { @Test public void vibrate_composedWithRampDown_doesNotAddRampDown() { - int rampDownDuration = 15; - mVibrationSettings = new VibrationSettings(InstrumentationRegistry.getContext(), - new Handler(mTestLooper.getLooper()), rampDownDuration, TEST_RAMP_STEP_DURATION); + when(mVibrationConfigMock.getRampDownDurationMs()).thenReturn(15); mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings); mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL, IVibrator.CAP_COMPOSE_EFFECTS); @@ -1251,9 +1249,7 @@ public class VibrationThreadTest { @Test public void vibrate_pwleWithRampDown_doesNotAddRampDown() { - int rampDownDuration = 15; - mVibrationSettings = new VibrationSettings(InstrumentationRegistry.getContext(), - new Handler(mTestLooper.getLooper()), rampDownDuration, TEST_RAMP_STEP_DURATION); + when(mVibrationConfigMock.getRampDownDurationMs()).thenReturn(15); mEffectAdapter = new DeviceVibrationEffectAdapter(mVibrationSettings); FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID); fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL, diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java index c0f75966bcf24..b0bdaf084b1a1 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -19,6 +19,7 @@ package com.android.server.vibrator; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -155,12 +156,13 @@ public class VibratorManagerServiceTest { @Before public void setUp() throws Exception { mTestLooper = new TestLooper(); - mVibrator = new FakeVibrator(); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); InputManager inputManager = InputManager.resetInstance(mIInputManagerMock); ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); when(mContextSpy.getContentResolver()).thenReturn(contentResolver); + + mVibrator = new FakeVibrator(mContextSpy); when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibrator); when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager); when(mContextSpy.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManagerMock); @@ -175,8 +177,13 @@ public class VibratorManagerServiceTest { }).when(mPowerManagerInternalMock).registerLowPowerModeObserver(any()); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1); + setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1); + setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY, + Vibrator.VIBRATION_INTENSITY_MEDIUM); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM); + setUserSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, + Vibrator.VIBRATION_INTENSITY_MEDIUM); setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, @@ -437,7 +444,7 @@ public class VibratorManagerServiceTest { UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); PrebakedSegment expected = new PrebakedSegment( - VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG); + VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_MEDIUM); // Only vibrators 1 and 3 have always-on capabilities. assertEquals(mVibratorProviders.get(1).getAlwaysOnEffect(1), expected); @@ -461,10 +468,10 @@ public class VibratorManagerServiceTest { UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS)); PrebakedSegment expectedClick = new PrebakedSegment( - VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG); + VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_MEDIUM); PrebakedSegment expectedTick = new PrebakedSegment( - VibrationEffect.EFFECT_TICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG); + VibrationEffect.EFFECT_TICK, false, VibrationEffect.EFFECT_STRENGTH_MEDIUM); // Enables click on vibrator 1 and tick on vibrator 2 only. assertEquals(mVibratorProviders.get(1).getAlwaysOnEffect(1), expectedClick); @@ -539,7 +546,6 @@ public class VibratorManagerServiceTest { public void vibrate_withRingtone_usesRingtoneSettings() throws Exception { mockVibrators(1); FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); - mVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM); fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_HEAVY_CLICK, VibrationEffect.EFFECT_DOUBLE_CLICK); @@ -932,55 +938,67 @@ public class VibratorManagerServiceTest { @Test public void vibrate_withIntensitySettings_appliesSettingsToScaleVibrations() throws Exception { - mVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_LOW); + int defaultNotificationIntensity = + mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_NOTIFICATION); setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_HIGH); + defaultNotificationIntensity < Vibrator.VIBRATION_INTENSITY_HIGH + ? defaultNotificationIntensity + 1 + : defaultNotificationIntensity); + + int defaultTouchIntensity = + mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_TOUCH); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, - Vibrator.VIBRATION_INTENSITY_LOW); - setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, - Vibrator.VIBRATION_INTENSITY_OFF); + defaultTouchIntensity > Vibrator.VIBRATION_INTENSITY_LOW + ? defaultTouchIntensity - 1 + : defaultTouchIntensity); + + setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY, + mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_ALARM)); + setUserSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, + Vibrator.VIBRATION_INTENSITY_HIGH); + setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF); mockVibrators(1); FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL, IVibrator.CAP_COMPOSE_EFFECTS); - fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK); VibratorManagerService service = createSystemReadyService(); vibrate(service, CombinedVibration.startSequential() - .addNext(1, VibrationEffect.createOneShot(20, 100)) + .addNext(1, VibrationEffect.createOneShot(100, 125)) .combine(), NOTIFICATION_ATTRS); assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 1, service, TEST_TIMEOUT_MILLIS)); vibrate(service, VibrationEffect.startComposition() - .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f) .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f) .compose(), HAPTIC_FEEDBACK_ATTRS); + assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 2, + service, TEST_TIMEOUT_MILLIS)); + + vibrate(service, VibrationEffect.startComposition() + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f) + .compose(), ALARM_ATTRS); assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 3, service, TEST_TIMEOUT_MILLIS)); - vibrate(service, CombinedVibration.startParallel() - .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK)) - .combine(), ALARM_ATTRS); - assertTrue(waitUntil(s -> fakeVibrator.getEffectSegments().size() == 4, + vibrate(service, VibrationEffect.createOneShot(100, 125), RINGTONE_ATTRS); + assertFalse(waitUntil(s -> fakeVibrator.getEffectSegments().size() > 3, service, TEST_TIMEOUT_MILLIS)); - vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), RINGTONE_ATTRS); + assertEquals(3, fakeVibrator.getEffectSegments().size()); - assertEquals(4, fakeVibrator.getEffectSegments().size()); + // Notification vibrations will be scaled with SCALE_HIGH or none if default is high. + assertEquals(defaultNotificationIntensity < Vibrator.VIBRATION_INTENSITY_HIGH, + 0.6 < fakeVibrator.getAmplitudes().get(0)); - // Notification vibrations will be scaled with SCALE_VERY_HIGH. - assertTrue(0.6 < fakeVibrator.getAmplitudes().get(0)); + // Haptic feedback vibrations will be scaled with SCALE_LOW or none if default is low. + assertEquals(defaultTouchIntensity > Vibrator.VIBRATION_INTENSITY_LOW, + 0.5 > ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(1)).getScale()); - // Haptic feedback vibrations will be scaled with SCALE_LOW. - assertTrue(0.5 < ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(1)).getScale()); - assertTrue(0.5 > ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(2)).getScale()); - - // Alarm vibration is always VIBRATION_INTENSITY_HIGH. - PrebakedSegment expected = new PrebakedSegment( - VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG); - assertEquals(expected, fakeVibrator.getEffectSegments().get(3)); + // Alarm vibration will be scaled with SCALE_NONE. + assertEquals(1f, + ((PrimitiveSegment) fakeVibrator.getEffectSegments().get(2)).getScale(), 1e-5); // Ring vibrations have intensity OFF and are not played. } @@ -1100,7 +1118,7 @@ public class VibratorManagerServiceTest { int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); mExternalVibratorService.onExternalVibrationStop(externalVibration); - assertEquals(IExternalVibratorService.SCALE_NONE, scale); + assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); assertEquals(Arrays.asList(false, true, false), mVibratorProviders.get(1).getExternalControlStates()); } @@ -1127,8 +1145,8 @@ public class VibratorManagerServiceTest { ringtoneAudioAttrs, secondController); int secondScale = mExternalVibratorService.onExternalVibrationStart(secondVibration); - assertEquals(IExternalVibratorService.SCALE_NONE, firstScale); - assertEquals(IExternalVibratorService.SCALE_NONE, secondScale); + assertNotEquals(IExternalVibratorService.SCALE_MUTE, firstScale); + assertNotEquals(IExternalVibratorService.SCALE_MUTE, secondScale); verify(firstController).mute(); verify(secondController, never()).mute(); // Set external control called only once. @@ -1151,7 +1169,7 @@ public class VibratorManagerServiceTest { ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS, mock(IExternalVibrationController.class)); int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertEquals(IExternalVibratorService.SCALE_NONE, scale); + assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); // Vibration is cancelled. assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); @@ -1163,7 +1181,6 @@ public class VibratorManagerServiceTest { public void onExternalVibration_withRingtone_usesRingerModeSettings() { mockVibrators(1); mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL); - mVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM); AudioAttributes audioAttrs = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) .build(); @@ -1181,13 +1198,13 @@ public class VibratorManagerServiceTest { setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 1); createSystemReadyService(); scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertEquals(IExternalVibratorService.SCALE_NONE, scale); + assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1); setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0); createSystemReadyService(); scale = mExternalVibratorService.onExternalVibrationStart(externalVibration); - assertEquals(IExternalVibratorService.SCALE_NONE, scale); + assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale); } private VibrationEffectSegment expectedPrebaked(int effectId) { @@ -1235,10 +1252,6 @@ public class VibratorManagerServiceTest { mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT); } - private void setGlobalSetting(String settingName, int value) { - Settings.Global.putInt(mContextSpy.getContentResolver(), settingName, value); - } - private void vibrate(VibratorManagerService service, VibrationEffect effect, VibrationAttributes attrs) { vibrate(service, CombinedVibration.createParallel(effect), attrs);