1 /* 2 * Copyright (C) 2014 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.notification; 18 19 import android.content.ContentResolver; 20 import android.content.Context; 21 import android.content.res.Resources; 22 import android.database.ContentObserver; 23 import android.media.AudioManager; 24 import android.net.Uri; 25 import android.os.AsyncTask; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.os.Vibrator; 29 import android.provider.SearchIndexableResource; 30 import android.provider.Settings.Global; 31 import android.provider.Settings.System; 32 import android.telephony.TelephonyManager; 33 34 import com.android.internal.logging.MetricsProto.MetricsEvent; 35 import com.android.settings.R; 36 import com.android.settings.SettingsPreferenceFragment; 37 import com.android.settings.Utils; 38 import com.android.settings.search.BaseSearchIndexProvider; 39 import com.android.settings.search.Indexable; 40 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.List; 44 45 import static com.android.settings.notification.SettingPref.TYPE_GLOBAL; 46 import static com.android.settings.notification.SettingPref.TYPE_SYSTEM; 47 48 public class OtherSoundSettings extends SettingsPreferenceFragment implements Indexable { 49 private static final String TAG = "OtherSoundSettings"; 50 51 private static final int DEFAULT_ON = 1; 52 53 private static final int EMERGENCY_TONE_SILENT = 0; 54 private static final int EMERGENCY_TONE_ALERT = 1; 55 private static final int EMERGENCY_TONE_VIBRATE = 2; 56 private static final int DEFAULT_EMERGENCY_TONE = EMERGENCY_TONE_SILENT; 57 58 private static final int DOCK_AUDIO_MEDIA_DISABLED = 0; 59 private static final int DOCK_AUDIO_MEDIA_ENABLED = 1; 60 private static final int DEFAULT_DOCK_AUDIO_MEDIA = DOCK_AUDIO_MEDIA_DISABLED; 61 62 private static final String KEY_DIAL_PAD_TONES = "dial_pad_tones"; 63 private static final String KEY_SCREEN_LOCKING_SOUNDS = "screen_locking_sounds"; 64 private static final String KEY_CHARGING_SOUNDS = "charging_sounds"; 65 private static final String KEY_DOCKING_SOUNDS = "docking_sounds"; 66 private static final String KEY_TOUCH_SOUNDS = "touch_sounds"; 67 private static final String KEY_VIBRATE_ON_TOUCH = "vibrate_on_touch"; 68 private static final String KEY_DOCK_AUDIO_MEDIA = "dock_audio_media"; 69 private static final String KEY_EMERGENCY_TONE = "emergency_tone"; 70 71 private static final SettingPref PREF_DIAL_PAD_TONES = new SettingPref( 72 TYPE_SYSTEM, KEY_DIAL_PAD_TONES, System.DTMF_TONE_WHEN_DIALING, DEFAULT_ON) { 73 @Override 74 public boolean isApplicable(Context context) { 75 return Utils.isVoiceCapable(context); 76 } 77 }; 78 79 private static final SettingPref PREF_SCREEN_LOCKING_SOUNDS = new SettingPref( 80 TYPE_SYSTEM, KEY_SCREEN_LOCKING_SOUNDS, System.LOCKSCREEN_SOUNDS_ENABLED, DEFAULT_ON); 81 82 private static final SettingPref PREF_CHARGING_SOUNDS = new SettingPref( 83 TYPE_GLOBAL, KEY_CHARGING_SOUNDS, Global.CHARGING_SOUNDS_ENABLED, DEFAULT_ON); 84 85 private static final SettingPref PREF_DOCKING_SOUNDS = new SettingPref( 86 TYPE_GLOBAL, KEY_DOCKING_SOUNDS, Global.DOCK_SOUNDS_ENABLED, DEFAULT_ON) { 87 @Override 88 public boolean isApplicable(Context context) { 89 return hasDockSettings(context); 90 } 91 }; 92 93 private static final SettingPref PREF_TOUCH_SOUNDS = new SettingPref( 94 TYPE_SYSTEM, KEY_TOUCH_SOUNDS, System.SOUND_EFFECTS_ENABLED, DEFAULT_ON) { 95 @Override 96 protected boolean setSetting(final Context context, final int value) { 97 AsyncTask.execute(new Runnable() { 98 @Override 99 public void run() { 100 final AudioManager am = 101 (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 102 if (value != 0) { 103 am.loadSoundEffects(); 104 } else { 105 am.unloadSoundEffects(); 106 } 107 } 108 }); 109 return super.setSetting(context, value); 110 } 111 }; 112 113 private static final SettingPref PREF_VIBRATE_ON_TOUCH = new SettingPref( 114 TYPE_SYSTEM, KEY_VIBRATE_ON_TOUCH, System.HAPTIC_FEEDBACK_ENABLED, DEFAULT_ON) { 115 @Override 116 public boolean isApplicable(Context context) { 117 return hasHaptic(context); 118 } 119 }; 120 121 private static final SettingPref PREF_DOCK_AUDIO_MEDIA = new SettingPref( 122 TYPE_GLOBAL, KEY_DOCK_AUDIO_MEDIA, Global.DOCK_AUDIO_MEDIA_ENABLED, 123 DEFAULT_DOCK_AUDIO_MEDIA, DOCK_AUDIO_MEDIA_DISABLED, DOCK_AUDIO_MEDIA_ENABLED) { 124 @Override 125 public boolean isApplicable(Context context) { 126 return hasDockSettings(context); 127 } 128 129 @Override 130 protected String getCaption(Resources res, int value) { 131 switch(value) { 132 case DOCK_AUDIO_MEDIA_DISABLED: 133 return res.getString(R.string.dock_audio_media_disabled); 134 case DOCK_AUDIO_MEDIA_ENABLED: 135 return res.getString(R.string.dock_audio_media_enabled); 136 default: 137 throw new IllegalArgumentException(); 138 } 139 } 140 }; 141 142 private static final SettingPref PREF_EMERGENCY_TONE = new SettingPref( 143 TYPE_GLOBAL, KEY_EMERGENCY_TONE, Global.EMERGENCY_TONE, DEFAULT_EMERGENCY_TONE, 144 EMERGENCY_TONE_ALERT, EMERGENCY_TONE_VIBRATE, EMERGENCY_TONE_SILENT) { 145 @Override 146 public boolean isApplicable(Context context) { 147 final int activePhoneType = TelephonyManager.getDefault().getCurrentPhoneType(); 148 return activePhoneType == TelephonyManager.PHONE_TYPE_CDMA; 149 } 150 151 @Override 152 protected String getCaption(Resources res, int value) { 153 switch(value) { 154 case EMERGENCY_TONE_SILENT: 155 return res.getString(R.string.emergency_tone_silent); 156 case EMERGENCY_TONE_ALERT: 157 return res.getString(R.string.emergency_tone_alert); 158 case EMERGENCY_TONE_VIBRATE: 159 return res.getString(R.string.emergency_tone_vibrate); 160 default: 161 throw new IllegalArgumentException(); 162 } 163 } 164 }; 165 166 private static final SettingPref[] PREFS = { 167 PREF_DIAL_PAD_TONES, 168 PREF_SCREEN_LOCKING_SOUNDS, 169 PREF_CHARGING_SOUNDS, 170 PREF_DOCKING_SOUNDS, 171 PREF_TOUCH_SOUNDS, 172 PREF_VIBRATE_ON_TOUCH, 173 PREF_DOCK_AUDIO_MEDIA, 174 PREF_EMERGENCY_TONE, 175 }; 176 177 private final SettingsObserver mSettingsObserver = new SettingsObserver(); 178 179 private Context mContext; 180 181 @Override getMetricsCategory()182 protected int getMetricsCategory() { 183 return MetricsEvent.NOTIFICATION_OTHER_SOUND; 184 } 185 186 @Override getHelpResource()187 protected int getHelpResource() { 188 return R.string.help_uri_other_sounds; 189 } 190 191 @Override onCreate(Bundle savedInstanceState)192 public void onCreate(Bundle savedInstanceState) { 193 super.onCreate(savedInstanceState); 194 195 addPreferencesFromResource(R.xml.other_sound_settings); 196 197 mContext = getActivity(); 198 199 for (SettingPref pref : PREFS) { 200 pref.init(this); 201 } 202 } 203 204 @Override onResume()205 public void onResume() { 206 super.onResume(); 207 mSettingsObserver.register(true); 208 } 209 210 @Override onPause()211 public void onPause() { 212 super.onPause(); 213 mSettingsObserver.register(false); 214 } 215 hasDockSettings(Context context)216 private static boolean hasDockSettings(Context context) { 217 return context.getResources().getBoolean(R.bool.has_dock_settings); 218 } 219 hasHaptic(Context context)220 private static boolean hasHaptic(Context context) { 221 final Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 222 return vibrator != null && vibrator.hasVibrator(); 223 } 224 225 // === Callbacks === 226 227 private final class SettingsObserver extends ContentObserver { SettingsObserver()228 public SettingsObserver() { 229 super(new Handler()); 230 } 231 register(boolean register)232 public void register(boolean register) { 233 final ContentResolver cr = getContentResolver(); 234 if (register) { 235 for (SettingPref pref : PREFS) { 236 cr.registerContentObserver(pref.getUri(), false, this); 237 } 238 } else { 239 cr.unregisterContentObserver(this); 240 } 241 } 242 243 @Override onChange(boolean selfChange, Uri uri)244 public void onChange(boolean selfChange, Uri uri) { 245 super.onChange(selfChange, uri); 246 for (SettingPref pref : PREFS) { 247 if (pref.getUri().equals(uri)) { 248 pref.update(mContext); 249 return; 250 } 251 } 252 } 253 } 254 255 // === Indexing === 256 257 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 258 new BaseSearchIndexProvider() { 259 260 public List<SearchIndexableResource> getXmlResourcesToIndex( 261 Context context, boolean enabled) { 262 final SearchIndexableResource sir = new SearchIndexableResource(context); 263 sir.xmlResId = R.xml.other_sound_settings; 264 return Arrays.asList(sir); 265 } 266 267 public List<String> getNonIndexableKeys(Context context) { 268 final ArrayList<String> rt = new ArrayList<String>(); 269 for (SettingPref pref : PREFS) { 270 if (!pref.isApplicable(context)) { 271 rt.add(pref.getKey()); 272 } 273 } 274 return rt; 275 } 276 }; 277 } 278