• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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;
18 
19 import com.android.settings.bluetooth.DockEventReceiver;
20 
21 import android.app.AlertDialog;
22 import android.app.Dialog;
23 import android.bluetooth.BluetoothDevice;
24 import android.content.BroadcastReceiver;
25 import android.content.ContentResolver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ResolveInfo;
31 import android.database.Cursor;
32 import android.database.sqlite.SQLiteException;
33 import android.media.AudioManager;
34 import android.media.RingtoneManager;
35 import android.media.audiofx.AudioEffect;
36 import android.net.Uri;
37 import android.os.Bundle;
38 import android.os.Handler;
39 import android.os.Message;
40 import android.os.Vibrator;
41 import android.preference.CheckBoxPreference;
42 import android.preference.ListPreference;
43 import android.preference.Preference;
44 import android.preference.PreferenceGroup;
45 import android.preference.PreferenceScreen;
46 import android.provider.MediaStore;
47 import android.provider.Settings;
48 import android.telephony.TelephonyManager;
49 import android.util.Log;
50 
51 import java.util.List;
52 
53 public class SoundSettings extends SettingsPreferenceFragment implements
54         Preference.OnPreferenceChangeListener {
55     private static final String TAG = "SoundSettings";
56 
57     private static final int DIALOG_NOT_DOCKED = 1;
58 
59     /** If there is no setting in the provider, use this. */
60     private static final int FALLBACK_EMERGENCY_TONE_VALUE = 0;
61 
62     private static final String KEY_VIBRATE = "vibrate_when_ringing";
63     private static final String KEY_RING_VOLUME = "ring_volume";
64     private static final String KEY_MUSICFX = "musicfx";
65     private static final String KEY_DTMF_TONE = "dtmf_tone";
66     private static final String KEY_SOUND_EFFECTS = "sound_effects";
67     private static final String KEY_HAPTIC_FEEDBACK = "haptic_feedback";
68     private static final String KEY_EMERGENCY_TONE = "emergency_tone";
69     private static final String KEY_SOUND_SETTINGS = "sound_settings";
70     private static final String KEY_LOCK_SOUNDS = "lock_sounds";
71     private static final String KEY_RINGTONE = "ringtone";
72     private static final String KEY_NOTIFICATION_SOUND = "notification_sound";
73     private static final String KEY_CATEGORY_CALLS = "category_calls_and_notification";
74     private static final String KEY_DOCK_CATEGORY = "dock_category";
75     private static final String KEY_DOCK_AUDIO_SETTINGS = "dock_audio";
76     private static final String KEY_DOCK_SOUNDS = "dock_sounds";
77     private static final String KEY_DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled";
78 
79     private static final String[] NEED_VOICE_CAPABILITY = {
80             KEY_RINGTONE, KEY_DTMF_TONE, KEY_CATEGORY_CALLS,
81             KEY_EMERGENCY_TONE, KEY_VIBRATE
82     };
83 
84     private static final int MSG_UPDATE_RINGTONE_SUMMARY = 1;
85     private static final int MSG_UPDATE_NOTIFICATION_SUMMARY = 2;
86 
87     private CheckBoxPreference mVibrateWhenRinging;
88     private CheckBoxPreference mDtmfTone;
89     private CheckBoxPreference mSoundEffects;
90     private CheckBoxPreference mHapticFeedback;
91     private Preference mMusicFx;
92     private CheckBoxPreference mLockSounds;
93     private Preference mRingtonePreference;
94     private Preference mNotificationPreference;
95 
96     private Runnable mRingtoneLookupRunnable;
97 
98     private AudioManager mAudioManager;
99 
100     private Preference mDockAudioSettings;
101     private CheckBoxPreference mDockSounds;
102     private Intent mDockIntent;
103     private CheckBoxPreference mDockAudioMediaEnabled;
104 
105     private Handler mHandler = new Handler() {
106         public void handleMessage(Message msg) {
107             switch (msg.what) {
108             case MSG_UPDATE_RINGTONE_SUMMARY:
109                 mRingtonePreference.setSummary((CharSequence) msg.obj);
110                 break;
111             case MSG_UPDATE_NOTIFICATION_SUMMARY:
112                 mNotificationPreference.setSummary((CharSequence) msg.obj);
113                 break;
114             }
115         }
116     };
117 
118     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
119         @Override
120         public void onReceive(Context context, Intent intent) {
121             if (intent.getAction().equals(Intent.ACTION_DOCK_EVENT)) {
122                 handleDockChange(intent);
123             }
124         }
125     };
126 
127     private PreferenceGroup mSoundSettings;
128 
129     @Override
onCreate(Bundle savedInstanceState)130     public void onCreate(Bundle savedInstanceState) {
131         super.onCreate(savedInstanceState);
132         ContentResolver resolver = getContentResolver();
133         int activePhoneType = TelephonyManager.getDefault().getCurrentPhoneType();
134 
135         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
136 
137         addPreferencesFromResource(R.xml.sound_settings);
138 
139         if (TelephonyManager.PHONE_TYPE_CDMA != activePhoneType) {
140             // device is not CDMA, do not display CDMA emergency_tone
141             getPreferenceScreen().removePreference(findPreference(KEY_EMERGENCY_TONE));
142         }
143 
144         if (!getResources().getBoolean(R.bool.has_silent_mode)) {
145             findPreference(KEY_RING_VOLUME).setDependency(null);
146         }
147 
148         if (getResources().getBoolean(com.android.internal.R.bool.config_useFixedVolume)) {
149             // device with fixed volume policy, do not display volumes submenu
150             getPreferenceScreen().removePreference(findPreference(KEY_RING_VOLUME));
151         }
152 
153         mVibrateWhenRinging = (CheckBoxPreference) findPreference(KEY_VIBRATE);
154         mVibrateWhenRinging.setPersistent(false);
155         mVibrateWhenRinging.setChecked(Settings.System.getInt(resolver,
156                 Settings.System.VIBRATE_WHEN_RINGING, 0) != 0);
157 
158         mDtmfTone = (CheckBoxPreference) findPreference(KEY_DTMF_TONE);
159         mDtmfTone.setPersistent(false);
160         mDtmfTone.setChecked(Settings.System.getInt(resolver,
161                 Settings.System.DTMF_TONE_WHEN_DIALING, 1) != 0);
162         mSoundEffects = (CheckBoxPreference) findPreference(KEY_SOUND_EFFECTS);
163         mSoundEffects.setPersistent(false);
164         mSoundEffects.setChecked(Settings.System.getInt(resolver,
165                 Settings.System.SOUND_EFFECTS_ENABLED, 1) != 0);
166         mHapticFeedback = (CheckBoxPreference) findPreference(KEY_HAPTIC_FEEDBACK);
167         mHapticFeedback.setPersistent(false);
168         mHapticFeedback.setChecked(Settings.System.getInt(resolver,
169                 Settings.System.HAPTIC_FEEDBACK_ENABLED, 1) != 0);
170         mLockSounds = (CheckBoxPreference) findPreference(KEY_LOCK_SOUNDS);
171         mLockSounds.setPersistent(false);
172         mLockSounds.setChecked(Settings.System.getInt(resolver,
173                 Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) != 0);
174 
175         mRingtonePreference = findPreference(KEY_RINGTONE);
176         mNotificationPreference = findPreference(KEY_NOTIFICATION_SOUND);
177 
178         Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
179         if (vibrator == null || !vibrator.hasVibrator()) {
180             removePreference(KEY_VIBRATE);
181             removePreference(KEY_HAPTIC_FEEDBACK);
182         }
183 
184         if (TelephonyManager.PHONE_TYPE_CDMA == activePhoneType) {
185             ListPreference emergencyTonePreference =
186                 (ListPreference) findPreference(KEY_EMERGENCY_TONE);
187             emergencyTonePreference.setValue(String.valueOf(Settings.Global.getInt(
188                 resolver, Settings.Global.EMERGENCY_TONE, FALLBACK_EMERGENCY_TONE_VALUE)));
189             emergencyTonePreference.setOnPreferenceChangeListener(this);
190         }
191 
192         mSoundSettings = (PreferenceGroup) findPreference(KEY_SOUND_SETTINGS);
193 
194         mMusicFx = mSoundSettings.findPreference(KEY_MUSICFX);
195         Intent i = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
196         PackageManager p = getPackageManager();
197         List<ResolveInfo> ris = p.queryIntentActivities(i, PackageManager.GET_DISABLED_COMPONENTS);
198         if (ris.size() <= 2) {
199             // no need to show the item if there is no choice for the user to make
200             // note: the built in musicfx panel has two activities (one being a
201             // compatibility shim that launches either the other activity, or a
202             // third party one), hence the check for <=2. If the implementation
203             // of the compatbility layer changes, this check may need to be updated.
204             mSoundSettings.removePreference(mMusicFx);
205         }
206 
207         if (!Utils.isVoiceCapable(getActivity())) {
208             for (String prefKey : NEED_VOICE_CAPABILITY) {
209                 Preference pref = findPreference(prefKey);
210                 if (pref != null) {
211                     getPreferenceScreen().removePreference(pref);
212                 }
213             }
214         }
215 
216         mRingtoneLookupRunnable = new Runnable() {
217             public void run() {
218                 if (mRingtonePreference != null) {
219                     updateRingtoneName(RingtoneManager.TYPE_RINGTONE, mRingtonePreference,
220                             MSG_UPDATE_RINGTONE_SUMMARY);
221                 }
222                 if (mNotificationPreference != null) {
223                     updateRingtoneName(RingtoneManager.TYPE_NOTIFICATION, mNotificationPreference,
224                             MSG_UPDATE_NOTIFICATION_SUMMARY);
225                 }
226             }
227         };
228 
229         initDockSettings();
230     }
231 
232     @Override
onResume()233     public void onResume() {
234         super.onResume();
235 
236         lookupRingtoneNames();
237 
238         IntentFilter filter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
239         getActivity().registerReceiver(mReceiver, filter);
240     }
241 
242     @Override
onPause()243     public void onPause() {
244         super.onPause();
245 
246         getActivity().unregisterReceiver(mReceiver);
247     }
248 
updateRingtoneName(int type, Preference preference, int msg)249     private void updateRingtoneName(int type, Preference preference, int msg) {
250         if (preference == null) return;
251         Context context = getActivity();
252         if (context == null) return;
253         Uri ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
254         CharSequence summary = context.getString(com.android.internal.R.string.ringtone_unknown);
255         // Is it a silent ringtone?
256         if (ringtoneUri == null) {
257             summary = context.getString(com.android.internal.R.string.ringtone_silent);
258         } else {
259             // Fetch the ringtone title from the media provider
260             try {
261                 Cursor cursor = context.getContentResolver().query(ringtoneUri,
262                         new String[] { MediaStore.Audio.Media.TITLE }, null, null, null);
263                 if (cursor != null) {
264                     if (cursor.moveToFirst()) {
265                         summary = cursor.getString(0);
266                     }
267                     cursor.close();
268                 }
269             } catch (SQLiteException sqle) {
270                 // Unknown title for the ringtone
271             }
272         }
273         mHandler.sendMessage(mHandler.obtainMessage(msg, summary));
274     }
275 
lookupRingtoneNames()276     private void lookupRingtoneNames() {
277         new Thread(mRingtoneLookupRunnable).start();
278     }
279 
280     @Override
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)281     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
282         if (preference == mVibrateWhenRinging) {
283             Settings.System.putInt(getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING,
284                     mVibrateWhenRinging.isChecked() ? 1 : 0);
285         } else if (preference == mDtmfTone) {
286             Settings.System.putInt(getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING,
287                     mDtmfTone.isChecked() ? 1 : 0);
288 
289         } else if (preference == mSoundEffects) {
290             if (mSoundEffects.isChecked()) {
291                 mAudioManager.loadSoundEffects();
292             } else {
293                 mAudioManager.unloadSoundEffects();
294             }
295             Settings.System.putInt(getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED,
296                     mSoundEffects.isChecked() ? 1 : 0);
297 
298         } else if (preference == mHapticFeedback) {
299             Settings.System.putInt(getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED,
300                     mHapticFeedback.isChecked() ? 1 : 0);
301 
302         } else if (preference == mLockSounds) {
303             Settings.System.putInt(getContentResolver(), Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
304                     mLockSounds.isChecked() ? 1 : 0);
305 
306         } else if (preference == mMusicFx) {
307             // let the framework fire off the intent
308             return false;
309         } else if (preference == mDockAudioSettings) {
310             int dockState = mDockIntent != null
311                     ? mDockIntent.getIntExtra(Intent.EXTRA_DOCK_STATE, 0)
312                     : Intent.EXTRA_DOCK_STATE_UNDOCKED;
313 
314             if (dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
315                 showDialog(DIALOG_NOT_DOCKED);
316             } else {
317                 boolean isBluetooth = mDockIntent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) != null;
318 
319                 if (isBluetooth) {
320                     Intent i = new Intent(mDockIntent);
321                     i.setAction(DockEventReceiver.ACTION_DOCK_SHOW_UI);
322                     i.setClass(getActivity(), DockEventReceiver.class);
323                     getActivity().sendBroadcast(i);
324                 } else {
325                     PreferenceScreen ps = (PreferenceScreen)mDockAudioSettings;
326                     Bundle extras = ps.getExtras();
327                     extras.putBoolean("checked",
328                             Settings.Global.getInt(getContentResolver(),
329                                     Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1);
330                     super.onPreferenceTreeClick(ps, ps);
331                 }
332             }
333         } else if (preference == mDockSounds) {
334             Settings.Global.putInt(getContentResolver(), Settings.Global.DOCK_SOUNDS_ENABLED,
335                     mDockSounds.isChecked() ? 1 : 0);
336         } else if (preference == mDockAudioMediaEnabled) {
337             Settings.Global.putInt(getContentResolver(), Settings.Global.DOCK_AUDIO_MEDIA_ENABLED,
338                     mDockAudioMediaEnabled.isChecked() ? 1 : 0);
339         }
340         return true;
341     }
342 
onPreferenceChange(Preference preference, Object objValue)343     public boolean onPreferenceChange(Preference preference, Object objValue) {
344         final String key = preference.getKey();
345         if (KEY_EMERGENCY_TONE.equals(key)) {
346             try {
347                 int value = Integer.parseInt((String) objValue);
348                 Settings.Global.putInt(getContentResolver(),
349                         Settings.Global.EMERGENCY_TONE, value);
350             } catch (NumberFormatException e) {
351                 Log.e(TAG, "could not persist emergency tone setting", e);
352             }
353         }
354 
355         return true;
356     }
357 
358     @Override
getHelpResource()359     protected int getHelpResource() {
360         return R.string.help_url_sound;
361     }
362 
needsDockSettings()363     private boolean needsDockSettings() {
364         return getResources().getBoolean(R.bool.has_dock_settings);
365     }
366 
initDockSettings()367     private void initDockSettings() {
368         ContentResolver resolver = getContentResolver();
369 
370         if (needsDockSettings()) {
371             mDockSounds = (CheckBoxPreference) findPreference(KEY_DOCK_SOUNDS);
372             mDockSounds.setPersistent(false);
373             mDockSounds.setChecked(Settings.Global.getInt(resolver,
374                     Settings.Global.DOCK_SOUNDS_ENABLED, 0) != 0);
375             mDockAudioSettings = findPreference(KEY_DOCK_AUDIO_SETTINGS);
376             mDockAudioSettings.setEnabled(false);
377         } else {
378             getPreferenceScreen().removePreference(findPreference(KEY_DOCK_CATEGORY));
379             getPreferenceScreen().removePreference(findPreference(KEY_DOCK_AUDIO_SETTINGS));
380             getPreferenceScreen().removePreference(findPreference(KEY_DOCK_SOUNDS));
381             Settings.Global.putInt(resolver, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 1);
382         }
383     }
384 
handleDockChange(Intent intent)385     private void handleDockChange(Intent intent) {
386         if (mDockAudioSettings != null) {
387             int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 0);
388 
389             boolean isBluetooth =
390                     intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) != null;
391 
392             mDockIntent = intent;
393 
394             if (dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
395                 // remove undocked dialog if currently showing.
396                 try {
397                     removeDialog(DIALOG_NOT_DOCKED);
398                 } catch (IllegalArgumentException iae) {
399                     // Maybe it was already dismissed
400                 }
401 
402                 if (isBluetooth) {
403                     mDockAudioSettings.setEnabled(true);
404                 } else {
405                     if (dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) {
406                         ContentResolver resolver = getContentResolver();
407                         mDockAudioSettings.setEnabled(true);
408                         if (Settings.Global.getInt(resolver,
409                                 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, -1) == -1) {
410                             Settings.Global.putInt(resolver,
411                                     Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0);
412                         }
413                         mDockAudioMediaEnabled =
414                                 (CheckBoxPreference) findPreference(KEY_DOCK_AUDIO_MEDIA_ENABLED);
415                         mDockAudioMediaEnabled.setPersistent(false);
416                         mDockAudioMediaEnabled.setChecked(
417                                 Settings.Global.getInt(resolver,
418                                         Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) != 0);
419                     } else {
420                         mDockAudioSettings.setEnabled(false);
421                     }
422                 }
423             } else {
424                 mDockAudioSettings.setEnabled(false);
425             }
426         }
427     }
428 
429     @Override
onCreateDialog(int id)430     public Dialog onCreateDialog(int id) {
431         if (id == DIALOG_NOT_DOCKED) {
432             return createUndockedMessage();
433         }
434         return null;
435     }
436 
createUndockedMessage()437     private Dialog createUndockedMessage() {
438         final AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
439         ab.setTitle(R.string.dock_not_found_title);
440         ab.setMessage(R.string.dock_not_found_text);
441         ab.setPositiveButton(android.R.string.ok, null);
442         return ab.create();
443     }
444 }
445 
446