Merge "Introduce media and alarm vibration intensity settings"

This commit is contained in:
Lais Andrade
2022-01-11 15:16:28 +00:00
committed by Android (Google) Code Review
19 changed files with 768 additions and 552 deletions

View File

@@ -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();

View File

@@ -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.

View File

@@ -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();
}
/**

View File

@@ -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.
*
* <p>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
+ "}";
}
}

View File

@@ -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.
*
* <b>Values:</b><br/>
* 0 - Vibration is disabled<br/>
* 1 - Weak vibrations<br/>
* 2 - Medium vibrations<br/>
* 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.
*
* <b>Values:</b><br/>
* 0 - Vibration is disabled<br/>
* 1 - Weak vibrations<br/>
* 2 - Medium vibrations<br/>
* 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";

View File

@@ -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;

View File

@@ -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;

View File

@@ -1179,10 +1179,18 @@
<string-array translatable="false" name="config_ringtoneEffectUris">
</string-array>
<!-- The default intensity level for alarm vibrations. See
Settings.System.ALARM_VIBRATION_INTENSITY more details on the constant values and
meanings. -->
<integer name="config_defaultAlarmVibrationIntensity">2</integer>
<!-- The default intensity level for haptic feedback. See
Settings.System.HAPTIC_FEEDBACK_INTENSITY more details on the constant values and
meanings. -->
<integer name="config_defaultHapticFeedbackIntensity">2</integer>
<!-- The default intensity level for media vibrations. See
Settings.System.MEDIA_VIBRATION_INTENSITY more details on the constant values and
meanings. -->
<integer name="config_defaultMediaVibrationIntensity">2</integer>
<!-- The default intensity level for notification vibrations. See
Settings.System.NOTIFICATION_VIBRATION_INTENSITY more details on the constant values and
meanings. -->

View File

@@ -3867,7 +3867,9 @@
<java-symbol type="drawable" name="ic_arrow_forward" />
<java-symbol type="drawable" name="ic_permission" />
<java-symbol type="integer" name="config_defaultAlarmVibrationIntensity" />
<java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
<java-symbol type="integer" name="config_defaultMediaVibrationIntensity" />
<java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
<java-symbol type="integer" name="config_defaultRingVibrationIntensity" />

View File

@@ -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

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
private final SparseArray<VibrationEffect> 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.
*
* <p>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);
}

View File

@@ -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

View File

@@ -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 extends VibrationEffectSegment> T getFirstSegment(VibrationEffect.Composed effect) {
return (T) effect.getSegments().get(0);
}

View File

@@ -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);

View File

@@ -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<Integer, FakeVibratorControllerProvider> 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,

View File

@@ -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);