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