blob: b4be5281a0c4472ded1ef3d270b624917520b36b [file] [log] [blame]
Lais Andrade141b5bb2021-11-23 18:39:06 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.accessibility;
18
Lais Andrade8919e0e2022-01-19 14:03:05 +000019import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
20
Lais Andrade76b2cd62022-01-14 16:58:48 +000021import android.content.BroadcastReceiver;
Lais Andrade141b5bb2021-11-23 18:39:06 +000022import android.content.ContentResolver;
23import android.content.Context;
Lais Andrade76b2cd62022-01-14 16:58:48 +000024import android.content.Intent;
25import android.content.IntentFilter;
Lais Andrade141b5bb2021-11-23 18:39:06 +000026import android.database.ContentObserver;
Lais Andrade76b2cd62022-01-14 16:58:48 +000027import android.media.AudioManager;
Lais Andrade141b5bb2021-11-23 18:39:06 +000028import android.net.Uri;
29import android.os.Handler;
30import android.os.VibrationAttributes;
31import android.os.VibrationEffect;
32import android.os.Vibrator;
33import android.provider.Settings;
34
Lais Andrade76b2cd62022-01-14 16:58:48 +000035import androidx.annotation.Nullable;
Lais Andrade141b5bb2021-11-23 18:39:06 +000036import androidx.preference.Preference;
37
Lais Andrade76b2cd62022-01-14 16:58:48 +000038import com.android.settings.R;
Lais Andrade141b5bb2021-11-23 18:39:06 +000039import com.android.settingslib.core.AbstractPreferenceController;
40
41/**
42 * Vibration intensity settings configuration to be shared between different preference
43 * controllers that handle the same setting key.
44 */
45public abstract class VibrationPreferenceConfig {
46
Lais Andrade8919e0e2022-01-19 14:03:05 +000047 /**
48 * SettingsProvider key for the main "Vibration & haptics" toggle preference, that can disable
49 * all device vibrations.
50 */
51 public static final String MAIN_SWITCH_SETTING_KEY = Settings.System.VIBRATE_ON;
Lais Andradeb8272212022-03-18 16:41:33 +000052 private static final VibrationEffect PREVIEW_VIBRATION_EFFECT =
53 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
Lais Andrade8919e0e2022-01-19 14:03:05 +000054
Lais Andrade141b5bb2021-11-23 18:39:06 +000055 protected final ContentResolver mContentResolver;
Lais Andrade76b2cd62022-01-14 16:58:48 +000056 private final AudioManager mAudioManager;
Lais Andrade141b5bb2021-11-23 18:39:06 +000057 private final Vibrator mVibrator;
58 private final String mSettingKey;
Lais Andrade76b2cd62022-01-14 16:58:48 +000059 private final String mRingerModeSilentSummary;
Lais Andrade141b5bb2021-11-23 18:39:06 +000060 private final int mDefaultIntensity;
Lais Andradeb8272212022-03-18 16:41:33 +000061 private final VibrationAttributes mPreviewVibrationAttributes;
Lais Andrade141b5bb2021-11-23 18:39:06 +000062
Lais Andrade8919e0e2022-01-19 14:03:05 +000063 /** Returns true if the user setting for enabling device vibrations is enabled. */
64 public static boolean isMainVibrationSwitchEnabled(ContentResolver contentResolver) {
65 return Settings.System.getInt(contentResolver, MAIN_SWITCH_SETTING_KEY, ON) == ON;
66 }
67
Lais Andradeb8272212022-03-18 16:41:33 +000068 /** Play a vibration effect with intensity just selected by the user. */
69 public static void playVibrationPreview(Vibrator vibrator,
70 @VibrationAttributes.Usage int vibrationUsage) {
71 vibrator.vibrate(PREVIEW_VIBRATION_EFFECT,
72 createPreviewVibrationAttributes(vibrationUsage));
73 }
74
75 public VibrationPreferenceConfig(Context context, String settingKey,
76 @VibrationAttributes.Usage int vibrationUsage) {
Lais Andrade141b5bb2021-11-23 18:39:06 +000077 mContentResolver = context.getContentResolver();
78 mVibrator = context.getSystemService(Vibrator.class);
Lais Andrade76b2cd62022-01-14 16:58:48 +000079 mAudioManager = context.getSystemService(AudioManager.class);
80 mRingerModeSilentSummary = context.getString(
81 R.string.accessibility_vibration_setting_disabled_for_silent_mode_summary);
Lais Andrade141b5bb2021-11-23 18:39:06 +000082 mSettingKey = settingKey;
83 mDefaultIntensity = mVibrator.getDefaultVibrationIntensity(vibrationUsage);
Lais Andradeb8272212022-03-18 16:41:33 +000084 mPreviewVibrationAttributes = createPreviewVibrationAttributes(vibrationUsage);
Lais Andrade141b5bb2021-11-23 18:39:06 +000085 }
86
Lais Andrade8919e0e2022-01-19 14:03:05 +000087 /** Returns the setting key for this setting preference. */
Lais Andrade141b5bb2021-11-23 18:39:06 +000088 public String getSettingKey() {
89 return mSettingKey;
90 }
91
Lais Andrade76b2cd62022-01-14 16:58:48 +000092 /** Returns the summary string for this setting preference. */
93 @Nullable
94 public CharSequence getSummary() {
95 return isRestrictedByRingerModeSilent() && isRingerModeSilent()
96 ? mRingerModeSilentSummary : null;
97 }
98
Lais Andrade8919e0e2022-01-19 14:03:05 +000099 /** Returns true if this setting preference is enabled for user update. */
100 public boolean isPreferenceEnabled() {
Lais Andrade76b2cd62022-01-14 16:58:48 +0000101 return isMainVibrationSwitchEnabled(mContentResolver)
102 && (!isRestrictedByRingerModeSilent() || !isRingerModeSilent());
103 }
104
105 /**
106 * Returns true if this setting preference should be disabled when the device is in silent mode.
107 */
108 public boolean isRestrictedByRingerModeSilent() {
109 return false;
Lais Andrade8919e0e2022-01-19 14:03:05 +0000110 }
111
Lais Andrade141b5bb2021-11-23 18:39:06 +0000112 /** Returns the default intensity to be displayed when the setting value is not set. */
113 public int getDefaultIntensity() {
114 return mDefaultIntensity;
115 }
116
117 /** Reads setting value for corresponding {@link VibrationPreferenceConfig} */
118 public int readIntensity() {
119 return Settings.System.getInt(mContentResolver, mSettingKey, mDefaultIntensity);
120 }
121
122 /** Update setting value for corresponding {@link VibrationPreferenceConfig} */
123 public boolean updateIntensity(int intensity) {
124 return Settings.System.putInt(mContentResolver, mSettingKey, intensity);
125 }
126
127 /** Play a vibration effect with intensity just selected by the user. */
128 public void playVibrationPreview() {
Lais Andradeb8272212022-03-18 16:41:33 +0000129 mVibrator.vibrate(PREVIEW_VIBRATION_EFFECT, mPreviewVibrationAttributes);
Lais Andrade141b5bb2021-11-23 18:39:06 +0000130 }
131
Lais Andrade76b2cd62022-01-14 16:58:48 +0000132 private boolean isRingerModeSilent() {
133 // AudioManager.isSilentMode() also returns true when ringer mode is VIBRATE.
134 // The vibration preferences are only disabled when the ringer mode is SILENT.
135 return mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT;
136 }
137
Lais Andradeb8272212022-03-18 16:41:33 +0000138 private static VibrationAttributes createPreviewVibrationAttributes(
139 @VibrationAttributes.Usage int vibrationUsage) {
140 return new VibrationAttributes.Builder()
141 .setUsage(vibrationUsage)
142 // Enforce fresh settings to be applied for the preview vibration, as they
143 // are played immediately after the new user values are set.
144 .setFlags(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)
145 .build();
146 }
147
Lais Andrade141b5bb2021-11-23 18:39:06 +0000148 /** {@link ContentObserver} for a setting described by a {@link VibrationPreferenceConfig}. */
149 public static final class SettingObserver extends ContentObserver {
Lais Andrade8919e0e2022-01-19 14:03:05 +0000150 private static final Uri MAIN_SWITCH_SETTING_URI =
151 Settings.System.getUriFor(MAIN_SWITCH_SETTING_KEY);
Lais Andrade76b2cd62022-01-14 16:58:48 +0000152 private static final IntentFilter INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER =
153 new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
Lais Andrade8919e0e2022-01-19 14:03:05 +0000154
Lais Andrade141b5bb2021-11-23 18:39:06 +0000155 private final Uri mUri;
Lais Andrade76b2cd62022-01-14 16:58:48 +0000156 @Nullable
157 private final BroadcastReceiver mRingerModeChangeReceiver;
158
Lais Andrade141b5bb2021-11-23 18:39:06 +0000159 private AbstractPreferenceController mPreferenceController;
160 private Preference mPreference;
161
162 /** Creates observer for given preference. */
163 public SettingObserver(VibrationPreferenceConfig preferenceConfig) {
164 super(new Handler(/* async= */ true));
165 mUri = Settings.System.getUriFor(preferenceConfig.getSettingKey());
Lais Andrade76b2cd62022-01-14 16:58:48 +0000166
167 if (preferenceConfig.isRestrictedByRingerModeSilent()) {
168 // If this preference is restricted by AudioManager.getRingerModeInternal() result
169 // for the device mode, then listen to changes in that value using the broadcast
170 // intent action INTERNAL_RINGER_MODE_CHANGED_ACTION.
171 mRingerModeChangeReceiver = new BroadcastReceiver() {
172 @Override
173 public void onReceive(Context context, Intent intent) {
174 final String action = intent.getAction();
175 if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
176 notifyChange();
177 }
178 }
179 };
180 } else {
181 // No need to register a receiver if this preference is not affected by ringer mode.
182 mRingerModeChangeReceiver = null;
183 }
Lais Andrade141b5bb2021-11-23 18:39:06 +0000184 }
185
186 @Override
187 public void onChange(boolean selfChange, Uri uri) {
Lais Andrade8919e0e2022-01-19 14:03:05 +0000188 if (mUri.equals(uri) || MAIN_SWITCH_SETTING_URI.equals(uri)) {
Lais Andrade76b2cd62022-01-14 16:58:48 +0000189 notifyChange();
190 }
191 }
192
193 private void notifyChange() {
194 if (mPreferenceController != null && mPreference != null) {
Lais Andrade141b5bb2021-11-23 18:39:06 +0000195 mPreferenceController.updateState(mPreference);
196 }
197 }
198
199 /**
Lais Andrade76b2cd62022-01-14 16:58:48 +0000200 * Register this observer to given {@link Context}, to be called from lifecycle
Lais Andrade141b5bb2021-11-23 18:39:06 +0000201 * {@code onStart} method.
202 */
Lais Andrade76b2cd62022-01-14 16:58:48 +0000203 public void register(Context context) {
204 if (mRingerModeChangeReceiver != null) {
205 context.registerReceiver(mRingerModeChangeReceiver,
206 INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER);
207 }
208 context.getContentResolver().registerContentObserver(
209 mUri, /* notifyForDescendants= */ false, this);
210 context.getContentResolver().registerContentObserver(
211 MAIN_SWITCH_SETTING_URI, /* notifyForDescendants= */ false, this);
Lais Andrade141b5bb2021-11-23 18:39:06 +0000212 }
213
214 /**
Lais Andrade76b2cd62022-01-14 16:58:48 +0000215 * Unregister this observer from given {@link Context}, to be called from lifecycle
Lais Andrade141b5bb2021-11-23 18:39:06 +0000216 * {@code onStop} method.
217 */
Lais Andrade76b2cd62022-01-14 16:58:48 +0000218 public void unregister(Context context) {
219 if (mRingerModeChangeReceiver != null) {
220 context.unregisterReceiver(mRingerModeChangeReceiver);
221 }
222 context.getContentResolver().unregisterContentObserver(this);
Lais Andrade141b5bb2021-11-23 18:39:06 +0000223 }
224
225 /**
226 * Binds this observer to given controller and preference, once it has been displayed to the
227 * user.
228 */
229 public void onDisplayPreference(AbstractPreferenceController controller,
230 Preference preference) {
231 mPreferenceController = controller;
232 mPreference = preference;
233 }
234 }
235}