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 0c8afa3ed9701..72e28630da40d 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);