Add primary switch for vibration settings screen

This re-lands commit fd54fc34c6.

Add primary switch that updates the VIBRATE_ON user setting. Update all settings in this page to be disabled when this main toggle is
off.

Bug: 30028435
Test: VibrationMainSwitchPreferenceControllerTest
Reason for revert: Re-landing change with fixed tests
Change-Id: If9219e3d81dd698f47219c80cac10b079b63e45d
This commit is contained in:
Lais Andrade
2022-01-19 14:03:05 +00:00
parent 47875a5dff
commit 8919e0ee50
14 changed files with 564 additions and 65 deletions

View File

@@ -16,57 +16,12 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.content.Context;
import android.media.AudioManager;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.provider.Settings;
/** Preference controller for ringtone vibration intensity */
public class RingVibrationIntensityPreferenceController
extends VibrationIntensityPreferenceController {
/** General configuration for ringtone vibration intensity settings. */
public static final class RingVibrationPreferenceConfig extends VibrationPreferenceConfig {
private final AudioManager mAudioManager;
public RingVibrationPreferenceConfig(Context context) {
super(context, Settings.System.RING_VIBRATION_INTENSITY,
VibrationAttributes.USAGE_RINGTONE);
mAudioManager = context.getSystemService(AudioManager.class);
}
@Override
public int readIntensity() {
final int vibrateWhenRinging = Settings.System.getInt(mContentResolver,
Settings.System.VIBRATE_WHEN_RINGING, ON);
if ((vibrateWhenRinging == OFF)
&& !mAudioManager.isRampingRingerEnabled()) {
// VIBRATE_WHEN_RINGING is deprecated but should still be applied if the user has
// turned it off and has not enabled the ramping ringer (old three-state setting).
return Vibrator.VIBRATION_INTENSITY_OFF;
}
return super.readIntensity();
}
@Override
public boolean updateIntensity(int intensity) {
final boolean success = super.updateIntensity(intensity);
// VIBRATE_WHEN_RINGING is deprecated but should still reflect the intensity setting.
// Ramping ringer is independent of the ring intensity and should not be affected.
Settings.System.putInt(mContentResolver, Settings.System.VIBRATE_WHEN_RINGING,
(intensity == Vibrator.VIBRATION_INTENSITY_OFF) ? OFF : ON);
return success;
}
}
public RingVibrationIntensityPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey, new RingVibrationPreferenceConfig(context));
}

View File

@@ -0,0 +1,64 @@
/*
* 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 com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.content.Context;
import android.media.AudioManager;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.provider.Settings;
/** General configuration for ringtone vibration intensity settings. */
public class RingVibrationPreferenceConfig extends VibrationPreferenceConfig {
private final AudioManager mAudioManager;
public RingVibrationPreferenceConfig(Context context) {
super(context, Settings.System.RING_VIBRATION_INTENSITY,
VibrationAttributes.USAGE_RINGTONE);
mAudioManager = context.getSystemService(AudioManager.class);
}
@Override
public int readIntensity() {
final int vibrateWhenRinging = Settings.System.getInt(mContentResolver,
Settings.System.VIBRATE_WHEN_RINGING, ON);
if ((vibrateWhenRinging == OFF)
&& !mAudioManager.isRampingRingerEnabled()) {
// VIBRATE_WHEN_RINGING is deprecated but should still be applied if the user has
// turned it off and has not enabled the ramping ringer (old three-state setting).
return Vibrator.VIBRATION_INTENSITY_OFF;
}
return super.readIntensity();
}
@Override
public boolean updateIntensity(int intensity) {
final boolean success = super.updateIntensity(intensity);
// VIBRATE_WHEN_RINGING is deprecated but should still reflect the intensity setting.
// Ramping ringer is independent of the ring intensity and should not be affected.
Settings.System.putInt(mContentResolver, Settings.System.VIBRATE_WHEN_RINGING,
(intensity == Vibrator.VIBRATION_INTENSITY_OFF) ? OFF : ON);
return success;
}
}

View File

@@ -18,8 +18,6 @@ package com.android.settings.accessibility;
import android.content.Context;
import com.android.settings.accessibility.RingVibrationIntensityPreferenceController.RingVibrationPreferenceConfig;
/** Preference controller for ringtone vibration with only a toggle for on/off states. */
public class RingVibrationTogglePreferenceController extends VibrationTogglePreferenceController {

View File

@@ -19,6 +19,7 @@ package com.android.settings.accessibility;
import android.content.Context;
import android.os.Vibrator;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
@@ -70,13 +71,22 @@ public abstract class VibrationIntensityPreferenceController extends SliderPrefe
super.displayPreference(screen);
final SeekBarPreference preference = screen.findPreference(getPreferenceKey());
mSettingsContentObserver.onDisplayPreference(this, preference);
// TODO: remove this and replace with a different way to play the haptic preview without
// relying on the setting being propagated to the service.
preference.setEnabled(mPreferenceConfig.isPreferenceEnabled());
// TODO: remove setContinuousUpdates and replace with a different way to play the haptic
// preview without relying on the setting being propagated to the service.
preference.setContinuousUpdates(true);
preference.setMin(getMin());
preference.setMax(getMax());
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
if (preference != null) {
preference.setEnabled(mPreferenceConfig.isPreferenceEnabled());
}
}
@Override
public int getMin() {
return Vibrator.VIBRATION_INTENSITY_OFF;
@@ -89,12 +99,19 @@ public abstract class VibrationIntensityPreferenceController extends SliderPrefe
@Override
public int getSliderPosition() {
if (!mPreferenceConfig.isPreferenceEnabled()) {
return getMin();
}
final int position = mPreferenceConfig.readIntensity();
return Math.min(position, getMax());
}
@Override
public boolean setSliderPosition(int position) {
if (!mPreferenceConfig.isPreferenceEnabled()) {
// Ignore slider updates when the preference is disabled.
return false;
}
final int intensity = calculateVibrationIntensity(position);
final boolean success = mPreferenceConfig.updateIntensity(intensity);

View File

@@ -0,0 +1,91 @@
/*
* 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 com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import com.android.settings.R;
import com.android.settings.widget.SettingsMainSwitchPreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
/**
* Preference controller for the main switch setting for vibration and haptics screen.
*
* <p>This preference is controlled by the setting key{@link Settings.System#VIBRATE_ON}, and it
* will disable the entire settings screen once the settings is turned OFF. All device haptics will
* be disabled by this setting, except the flagged alerts and accessibility touch feedback.
*/
public class VibrationMainSwitchPreferenceController extends SettingsMainSwitchPreferenceController
implements LifecycleObserver, OnStart, OnStop {
private final ContentObserver mSettingObserver;
public VibrationMainSwitchPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mSettingObserver = new ContentObserver(new Handler(/* async= */ true)) {
@Override
public void onChange(boolean selfChange, Uri uri) {
updateState(mSwitchPreference);
}
};
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void onStart() {
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY),
/* notifyForDescendants= */ false,
mSettingObserver);
}
@Override
public void onStop() {
mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
}
@Override
public boolean isChecked() {
return VibrationPreferenceConfig.isMainVibrationSwitchEnabled(
mContext.getContentResolver());
}
@Override
public boolean setChecked(boolean isChecked) {
return Settings.System.putInt(mContext.getContentResolver(),
VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY,
isChecked ? ON : OFF);
}
@Override
public int getSliceHighlightMenuRes() {
return R.string.menu_key_accessibility;
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -36,12 +38,23 @@ import com.android.settingslib.core.AbstractPreferenceController;
*/
public abstract class VibrationPreferenceConfig {
/**
* SettingsProvider key for the main "Vibration & haptics" toggle preference, that can disable
* all device vibrations.
*/
public static final String MAIN_SWITCH_SETTING_KEY = Settings.System.VIBRATE_ON;
protected final ContentResolver mContentResolver;
private final Vibrator mVibrator;
private final String mSettingKey;
private final int mDefaultIntensity;
private final VibrationAttributes mVibrationAttributes;
/** Returns true if the user setting for enabling device vibrations is enabled. */
public static boolean isMainVibrationSwitchEnabled(ContentResolver contentResolver) {
return Settings.System.getInt(contentResolver, MAIN_SWITCH_SETTING_KEY, ON) == ON;
}
public VibrationPreferenceConfig(Context context, String settingKey, int vibrationUsage) {
mContentResolver = context.getContentResolver();
mVibrator = context.getSystemService(Vibrator.class);
@@ -52,11 +65,16 @@ public abstract class VibrationPreferenceConfig {
.build();
}
/** Return the setting key for this setting preference. */
/** Returns the setting key for this setting preference. */
public String getSettingKey() {
return mSettingKey;
}
/** Returns true if this setting preference is enabled for user update. */
public boolean isPreferenceEnabled() {
return isMainVibrationSwitchEnabled(mContentResolver);
}
/** Returns the default intensity to be displayed when the setting value is not set. */
public int getDefaultIntensity() {
return mDefaultIntensity;
@@ -80,6 +98,9 @@ public abstract class VibrationPreferenceConfig {
/** {@link ContentObserver} for a setting described by a {@link VibrationPreferenceConfig}. */
public static final class SettingObserver extends ContentObserver {
private static final Uri MAIN_SWITCH_SETTING_URI =
Settings.System.getUriFor(MAIN_SWITCH_SETTING_KEY);
private final Uri mUri;
private AbstractPreferenceController mPreferenceController;
private Preference mPreference;
@@ -92,7 +113,11 @@ public abstract class VibrationPreferenceConfig {
@Override
public void onChange(boolean selfChange, Uri uri) {
if (mUri.equals(uri) && mPreferenceController != null && mPreference != null) {
if (mPreferenceController == null || mPreference == null) {
// onDisplayPreference not triggered yet, nothing to update.
return;
}
if (mUri.equals(uri) || MAIN_SWITCH_SETTING_URI.equals(uri)) {
mPreferenceController.updateState(mPreference);
}
}
@@ -103,6 +128,8 @@ public abstract class VibrationPreferenceConfig {
*/
public void register(ContentResolver contentResolver) {
contentResolver.registerContentObserver(mUri, /* notifyForDescendants= */ false, this);
contentResolver.registerContentObserver(MAIN_SWITCH_SETTING_URI,
/* notifyForDescendants= */ false, this);
}
/**

View File

@@ -21,7 +21,6 @@ import android.database.ContentObserver;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Handler;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -57,8 +56,9 @@ public class VibrationRampingRingerTogglePreferenceController
private final DeviceConfigProvider mDeviceConfigProvider;
private final ContentObserver mSettingObserver;
private final Vibrator mVibrator;
private final AudioManager mAudioManager;
private final VibrationPreferenceConfig mRingVibrationPreferenceConfig;
private final VibrationPreferenceConfig.SettingObserver mRingSettingObserver;
private Preference mPreference;
@@ -70,8 +70,10 @@ public class VibrationRampingRingerTogglePreferenceController
String preferenceKey, DeviceConfigProvider deviceConfigProvider) {
super(context, preferenceKey);
mDeviceConfigProvider = deviceConfigProvider;
mVibrator = context.getSystemService(Vibrator.class);
mAudioManager = context.getSystemService(AudioManager.class);
mRingVibrationPreferenceConfig = new RingVibrationPreferenceConfig(context);
mRingSettingObserver = new VibrationPreferenceConfig.SettingObserver(
mRingVibrationPreferenceConfig);
mSettingObserver = new ContentObserver(new Handler(/* async= */ true)) {
@Override
public void onChange(boolean selfChange, Uri uri) {
@@ -91,18 +93,16 @@ public class VibrationRampingRingerTogglePreferenceController
@Override
public void onStart() {
mRingSettingObserver.register(mContext.getContentResolver());
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.APPLY_RAMPING_RINGER),
/* notifyForDescendants= */ false,
mSettingObserver);
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
/* notifyForDescendants= */ false,
mSettingObserver);
}
@Override
public void onStop() {
mRingSettingObserver.unregister(mContext.getContentResolver());
mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
}
@@ -110,6 +110,7 @@ public class VibrationRampingRingerTogglePreferenceController
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
mRingSettingObserver.onDisplayPreference(this, mPreference);
mPreference.setEnabled(isRingVibrationEnabled());
}
@@ -141,9 +142,8 @@ public class VibrationRampingRingerTogglePreferenceController
}
private boolean isRingVibrationEnabled() {
final int ringIntensity = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.RING_VIBRATION_INTENSITY,
mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_RINGTONE));
return ringIntensity != Vibrator.VIBRATION_INTENSITY_OFF;
return mRingVibrationPreferenceConfig.isPreferenceEnabled()
&& (mRingVibrationPreferenceConfig.readIntensity()
!= Vibrator.VIBRATION_INTENSITY_OFF);
}
}

View File

@@ -58,16 +58,29 @@ public abstract class VibrationTogglePreferenceController extends TogglePreferen
super.displayPreference(screen);
final Preference preference = screen.findPreference(getPreferenceKey());
mSettingsContentObserver.onDisplayPreference(this, preference);
preference.setEnabled(mPreferenceConfig.isPreferenceEnabled());
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
if (preference != null) {
preference.setEnabled(mPreferenceConfig.isPreferenceEnabled());
}
}
@Override
public boolean isChecked() {
final int position = mPreferenceConfig.readIntensity();
return position != Vibrator.VIBRATION_INTENSITY_OFF;
return mPreferenceConfig.isPreferenceEnabled()
&& (mPreferenceConfig.readIntensity() != Vibrator.VIBRATION_INTENSITY_OFF);
}
@Override
public boolean setChecked(boolean isChecked) {
if (!mPreferenceConfig.isPreferenceEnabled()) {
// Ignore toggle updates when the preference is disabled.
return false;
}
final int newIntensity = isChecked
? mPreferenceConfig.getDefaultIntensity()
: Vibrator.VIBRATION_INTENSITY_OFF;