• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.settings.accessibility;
18 
19 import android.content.Context;
20 import android.database.ContentObserver;
21 import android.media.AudioManager;
22 import android.net.Uri;
23 import android.os.Handler;
24 import android.os.Looper;
25 import android.os.Vibrator;
26 import android.provider.DeviceConfig;
27 import android.provider.Settings;
28 
29 import androidx.preference.Preference;
30 import androidx.preference.PreferenceScreen;
31 
32 import com.android.settings.R;
33 import com.android.settings.Utils;
34 import com.android.settings.core.TogglePreferenceController;
35 import com.android.settingslib.core.lifecycle.LifecycleObserver;
36 import com.android.settingslib.core.lifecycle.events.OnStart;
37 import com.android.settingslib.core.lifecycle.events.OnStop;
38 
39 /**
40  * Preference controller for the ramping ringer setting key, controlled via {@link AudioManager}.
41  *
42  * <p>This preference depends on the {@link Settings.System#RING_VIBRATION_INTENSITY}, and it will
43  * be disabled and display the unchecked state when the ring intensity is set to OFF. The actual
44  * ramping ringer setting will not be overwritten when the ring intensity is turned off, so the
45  * user original value will be naturally restored when the ring intensity is enabled again.
46  */
47 public class VibrationRampingRingerTogglePreferenceController
48         extends TogglePreferenceController implements LifecycleObserver, OnStart, OnStop {
49 
50     /** Wrapper around static {@link DeviceConfig} accessor for testing. */
51     protected static class DeviceConfigProvider {
isRampingRingerEnabledOnTelephonyConfig()52         public boolean isRampingRingerEnabledOnTelephonyConfig() {
53             return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY,
54                     "ramping_ringer_enabled", false);
55         }
56     }
57 
58     private final DeviceConfigProvider mDeviceConfigProvider;
59     private final ContentObserver mSettingObserver;
60     private final AudioManager mAudioManager;
61     private final VibrationPreferenceConfig mRingVibrationPreferenceConfig;
62     private final VibrationPreferenceConfig.SettingObserver mRingSettingObserver;
63 
64     private Preference mPreference;
65 
VibrationRampingRingerTogglePreferenceController(Context context, String preferenceKey)66     public VibrationRampingRingerTogglePreferenceController(Context context, String preferenceKey) {
67         this(context, preferenceKey, new DeviceConfigProvider());
68     }
69 
VibrationRampingRingerTogglePreferenceController(Context context, String preferenceKey, DeviceConfigProvider deviceConfigProvider)70     protected VibrationRampingRingerTogglePreferenceController(Context context,
71             String preferenceKey, DeviceConfigProvider deviceConfigProvider) {
72         super(context, preferenceKey);
73         mDeviceConfigProvider = deviceConfigProvider;
74         mAudioManager = context.getSystemService(AudioManager.class);
75         mRingVibrationPreferenceConfig = new RingVibrationPreferenceConfig(context);
76         mRingSettingObserver = new VibrationPreferenceConfig.SettingObserver(
77                 mRingVibrationPreferenceConfig);
78         Handler handler = Looper.myLooper() != null ? new Handler(/* async= */ true) : null;
79         mSettingObserver = new ContentObserver(handler) {
80             @Override
81             public void onChange(boolean selfChange, Uri uri) {
82                 updateState(mPreference);
83             }
84         };
85     }
86 
87     @Override
getAvailabilityStatus()88     public int getAvailabilityStatus() {
89         final boolean rampingRingerEnabledOnTelephonyConfig =
90                 mDeviceConfigProvider.isRampingRingerEnabledOnTelephonyConfig();
91         return (Utils.isVoiceCapable(mContext) && !rampingRingerEnabledOnTelephonyConfig)
92                 ? AVAILABLE
93                 : UNSUPPORTED_ON_DEVICE;
94     }
95 
96     @Override
onStart()97     public void onStart() {
98         mRingSettingObserver.register(mContext);
99         mContext.getContentResolver().registerContentObserver(
100                 Settings.System.getUriFor(Settings.System.APPLY_RAMPING_RINGER),
101                 /* notifyForDescendants= */ false,
102                 mSettingObserver);
103     }
104 
105     @Override
onStop()106     public void onStop() {
107         mRingSettingObserver.unregister(mContext);
108         mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
109     }
110 
111     @Override
displayPreference(PreferenceScreen screen)112     public void displayPreference(PreferenceScreen screen) {
113         super.displayPreference(screen);
114         mPreference = screen.findPreference(getPreferenceKey());
115         mRingSettingObserver.onDisplayPreference(this, mPreference);
116         mPreference.setEnabled(isRingVibrationEnabled());
117     }
118 
119     @Override
isChecked()120     public boolean isChecked() {
121         return isRingVibrationEnabled() && mAudioManager.isRampingRingerEnabled();
122     }
123 
124     @Override
setChecked(boolean isChecked)125     public boolean setChecked(boolean isChecked) {
126         if (isRingVibrationEnabled()) {
127             // Don't update ramping ringer setting value if ring vibration is disabled.
128             mAudioManager.setRampingRingerEnabled(isChecked);
129 
130             if (isChecked) {
131                 // Vibrate when toggle is enabled for consistency with all the other toggle/slides
132                 // in the same screen.
133                 mRingVibrationPreferenceConfig.playVibrationPreview();
134             }
135         }
136         return true;
137     }
138 
139     @Override
getSliceHighlightMenuRes()140     public int getSliceHighlightMenuRes() {
141         return R.string.menu_key_accessibility;
142     }
143 
144     @Override
updateState(Preference preference)145     public void updateState(Preference preference) {
146         super.updateState(preference);
147         if (preference != null) {
148             preference.setEnabled(isRingVibrationEnabled());
149         }
150     }
151 
isRingVibrationEnabled()152     private boolean isRingVibrationEnabled() {
153         return mRingVibrationPreferenceConfig.isPreferenceEnabled()
154                 && (mRingVibrationPreferenceConfig.readIntensity()
155                 != Vibrator.VIBRATION_INTENSITY_OFF);
156     }
157 }
158