/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.notification; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.database.ContentObserver; import android.media.AudioManager; import android.media.RingtoneManager; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceScreen; import android.preference.SeekBarVolumizer; import android.preference.TwoStatePreference; import android.provider.Settings; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.SoundSettings; public class NotificationSettings extends SettingsPreferenceFragment { private static final String TAG = "NotificationSettings"; private static final String KEY_MEDIA_VOLUME = "media_volume"; private static final String KEY_ALARM_VOLUME = "alarm_volume"; private static final String KEY_RING_VOLUME = "ring_volume"; private static final String KEY_RINGER_MODE = "ringer_mode"; private static final String KEY_PHONE_RINGTONE = "ringtone"; private static final String KEY_NOTIFICATION_RINGTONE = "notification_ringtone"; private static final String KEY_VIBRATE_WHEN_RINGING = "vibrate_when_ringing"; private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access"; private static final int SAMPLE_CUTOFF = 2000; // manually cap sample playback at 2 seconds private final VolumePreferenceCallback mVolumeCallback = new VolumePreferenceCallback(); private final H mHandler = new H(); private final SettingsObserver mSettingsObserver = new SettingsObserver(); private Context mContext; private PackageManager mPM; private DropDownPreference mRingerMode; private Preference mPhoneRingtonePreference; private Preference mNotificationRingtonePreference; private TwoStatePreference mVibrateWhenRinging; private Preference mNotificationAccess; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = getActivity(); mPM = mContext.getPackageManager(); addPreferencesFromResource(R.xml.notification_settings); final PreferenceScreen root = getPreferenceScreen(); initVolumePreference(KEY_MEDIA_VOLUME, AudioManager.STREAM_MUSIC); initVolumePreference(KEY_ALARM_VOLUME, AudioManager.STREAM_ALARM); initVolumePreference(KEY_RING_VOLUME, AudioManager.STREAM_RING); initRingerMode(root); initRingtones(root); initVibrateWhenRinging(root); mNotificationAccess = findPreference(KEY_NOTIFICATION_ACCESS); refreshNotificationListeners(); } @Override public void onResume() { super.onResume(); refreshNotificationListeners(); lookupRingtoneNames(); final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); mContext.registerReceiver(mReceiver, filter); mSettingsObserver.register(true); } @Override public void onPause() { super.onPause(); mVolumeCallback.stopSample(); mContext.unregisterReceiver(mReceiver); mSettingsObserver.register(false); } // === Volumes === private void initVolumePreference(String key, int stream) { final VolumeSeekBarPreference volumePref = (VolumeSeekBarPreference) findPreference(key); volumePref.setStream(stream); volumePref.setCallback(mVolumeCallback); } private final class VolumePreferenceCallback implements VolumeSeekBarPreference.Callback { private SeekBarVolumizer mCurrent; @Override public void onSampleStarting(SeekBarVolumizer sbv) { if (mCurrent != null && mCurrent != sbv) { mCurrent.stopSample(); } mCurrent = sbv; if (mCurrent != null) { mHandler.removeMessages(H.STOP_SAMPLE); mHandler.sendEmptyMessageDelayed(H.STOP_SAMPLE, SAMPLE_CUTOFF); } } public void stopSample() { if (mCurrent != null) { mCurrent.stopSample(); } } }; // === Ringer mode === private void initRingerMode(PreferenceScreen root) { mRingerMode = (DropDownPreference) root.findPreference(KEY_RINGER_MODE); if (mRingerMode == null) return; final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mRingerMode.addItem(R.string.ringer_mode_audible, AudioManager.RINGER_MODE_NORMAL); mRingerMode.addItem(R.string.ringer_mode_vibrate, AudioManager.RINGER_MODE_VIBRATE); mRingerMode.addItem(R.string.ringer_mode_silent, AudioManager.RINGER_MODE_SILENT); updateRingerMode(); mRingerMode.setCallback(new DropDownPreference.Callback() { @Override public boolean onItemSelected(int pos, Object value) { final int val = (Integer) value; am.setRingerMode(val); return true; } }); } private void updateRingerMode() { final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mRingerMode.setSelectedValue(am.getRingerMode()); } // === Phone & notification ringtone === private void initRingtones(PreferenceScreen root) { mPhoneRingtonePreference = root.findPreference(KEY_PHONE_RINGTONE); mNotificationRingtonePreference = root.findPreference(KEY_NOTIFICATION_RINGTONE); } private void lookupRingtoneNames() { AsyncTask.execute(mLookupRingtoneNames); } private final Runnable mLookupRingtoneNames = new Runnable() { @Override public void run() { if (mPhoneRingtonePreference != null) { final CharSequence summary = SoundSettings.updateRingtoneName( mContext, RingtoneManager.TYPE_RINGTONE); if (summary != null) { mHandler.obtainMessage(H.UPDATE_PHONE_RINGTONE, summary).sendToTarget(); } } if (mNotificationRingtonePreference != null) { final CharSequence summary = SoundSettings.updateRingtoneName( mContext, RingtoneManager.TYPE_NOTIFICATION); if (summary != null) { mHandler.obtainMessage(H.UPDATE_NOTIFICATION_RINGTONE, summary).sendToTarget(); } } } }; // === Vibrate when ringing === private void initVibrateWhenRinging(PreferenceScreen root) { mVibrateWhenRinging = (TwoStatePreference) findPreference(KEY_VIBRATE_WHEN_RINGING); if (mVibrateWhenRinging == null) return; mVibrateWhenRinging.setPersistent(false); updateVibrateWhenRinging(); mVibrateWhenRinging.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { final boolean val = (Boolean) newValue; return Settings.System.putInt(getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, val ? 1 : 0); } }); } private void updateVibrateWhenRinging() { if (mVibrateWhenRinging == null) return; mVibrateWhenRinging.setChecked(Settings.System.getInt(getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0); } // === Notification listeners === private void refreshNotificationListeners() { if (mNotificationAccess != null) { final int total = NotificationAccessSettings.getListenersCount(mPM); if (total == 0) { getPreferenceScreen().removePreference(mNotificationAccess); } else { final int n = NotificationAccessSettings.getEnabledListenersCount(mContext); if (n == 0) { mNotificationAccess.setSummary(getResources().getString( R.string.manage_notification_access_summary_zero)); } else { mNotificationAccess.setSummary(String.format(getResources().getQuantityString( R.plurals.manage_notification_access_summary_nonzero, n, n))); } } } } // === Callbacks === private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) { updateRingerMode(); } } }; private final class SettingsObserver extends ContentObserver { private final Uri VIBRATE_WHEN_RINGING_URI = Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING); public SettingsObserver() { super(mHandler); } public void register(boolean register) { final ContentResolver cr = getContentResolver(); if (register) { cr.registerContentObserver(VIBRATE_WHEN_RINGING_URI, false, this); } else { cr.unregisterContentObserver(this); } } @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); if (VIBRATE_WHEN_RINGING_URI.equals(uri)) { updateVibrateWhenRinging(); } } } private final class H extends Handler { private static final int UPDATE_PHONE_RINGTONE = 1; private static final int UPDATE_NOTIFICATION_RINGTONE = 2; private static final int STOP_SAMPLE = 3; private H() { super(Looper.getMainLooper()); } @Override public void handleMessage(Message msg) { switch (msg.what) { case UPDATE_PHONE_RINGTONE: mPhoneRingtonePreference.setSummary((CharSequence) msg.obj); break; case UPDATE_NOTIFICATION_RINGTONE: mNotificationRingtonePreference.setSummary((CharSequence) msg.obj); break; case STOP_SAMPLE: mVolumeCallback.stopSample(); break; } } } }