Commit 81bef1d7 authored by John Spurlock's avatar John Spurlock

VolumeZen: Sound & Notifications settings.

- Add sound settings under the newly combined Sound & Notifications
  top-level settings page.
- New slider preferences for setting audio stream volumes.
- Migrate checkbox prefs to switch prefs.
- New settings subpage for touch sounds.
- New settings subpage for "Showing notifications"
- New setting pref for displaying intercepted notifications in zen mode.
- New tri-state lockscreen notifications pref.
- Add priority + sensitivity options to app notification dialog.
- Remove badges on app notifications row, migrate to subtitle text.
- Migrate strings to common spot in strings.xml
- Remove heads up setting.
- Remove tweaks category (unused).
- Clean up notification settings, separate out into a code section per option.
- Clean up _settings.xml files, prefix each pref with option name.
- Add appropriate indexing data to each settings page.

Depends on f/b change Ic30aa575ae07650cee62c8c1d83b6bc69395cf0d

Change-Id: If700385a7d0057f6c4c4bcf6e648dcf88b8ebff2
parent ba046c03
......@@ -1722,6 +1722,53 @@
android:resource="@id/notification_settings" />
</activity>
<activity android:name="Settings$NotificationDisplaySettingsActivity"
android:label="@string/notification_display_settings"
android:exported="true"
android:taskAffinity=""
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.settings.ACTION_NOTIFICATION_DISPLAY_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.notification.NotificationDisplaySettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/notification_settings" />
</activity>
<activity android:name="Settings$TouchSoundSettingsActivity"
android:label="@string/touch_sound_settings"
android:exported="true"
android:taskAffinity=""
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.settings.ACTION_TOUCH_SOUND_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.notification.TouchSoundSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/notification_settings" />
</activity>
<activity android:name="Settings$AppNotificationSettingsActivity"
android:label="@string/app_notifications_title"
android:exported="true"
android:taskAffinity=""
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.settings.ACTION_APP_NOTIFICATION_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.notification.AppNotificationSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/notification_settings" />
</activity>
<!-- Show regulatory info (from settings item or dialing "*#07#") -->
<activity android:name="RegulatoryInfoDisplayActivity"
......
......@@ -12,8 +12,8 @@
-keep class com.android.settings.accounts.*
-keep class com.android.settings.fuelgauge.*
-keep class com.android.settings.users.*
-keep class com.android.settings.NotificationStation
-keep class com.android.settings.nfc.*
-keep class com.android.settings.notification.*
# Keep click responders
-keepclassmembers class com.android.settings.inputmethod.UserDictionaryAddWordActivity {
......
......@@ -33,26 +33,6 @@
android:contentDescription="@null"
android:scaleType="center" />
<ImageView
android:id="@android:id/icon1"
android:layout_width="@dimen/notification_app_icon_badge_size"
android:layout_height="@dimen/notification_app_icon_badge_size"
android:layout_marginLeft="@dimen/notification_app_icon_badge_margin"
android:layout_marginTop="@dimen/notification_app_icon_badge_margin"
android:background="#bb8b0000"
android:contentDescription="@null" />
<ImageView
android:id="@android:id/icon2"
android:layout_width="@dimen/notification_app_icon_badge_size"
android:layout_height="@dimen/notification_app_icon_badge_size"
android:layout_alignBottom="@android:id/icon"
android:layout_alignEnd="@android:id/icon"
android:layout_marginBottom="@dimen/notification_app_icon_badge_margin"
android:layout_marginEnd="@dimen/notification_app_icon_badge_margin"
android:background="#bb006400"
android:contentDescription="@null" />
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
......@@ -63,6 +43,18 @@
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_app_icon_size"
android:layout_toEndOf="@android:id/icon"
android:gravity="bottom"
android:ellipsize="end"
android:singleLine="true"
android:textAlignment="viewStart"
android:textColor="#888"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
<View
......
......@@ -44,4 +44,22 @@
android:text="@string/app_notifications_dialog_show"
android:textAppearance="?android:attr/textAppearanceListItem" />
<CheckBox
android:id="@android:id/button2"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_app_icon_size"
android:layout_below="@android:id/button1"
android:layout_marginStart="@dimen/content_margin_left"
android:text="@string/app_notifications_dialog_priority"
android:textAppearance="?android:attr/textAppearanceListItem" />
<CheckBox
android:id="@android:id/button3"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_app_icon_size"
android:layout_below="@android:id/button2"
android:layout_marginStart="@dimen/content_margin_left"
android:text="@string/app_notifications_dialog_visibility"
android:textAppearance="?android:attr/textAppearanceListItem" />
</RelativeLayout>
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/notification_display_settings"
android:key="notification_display_settings"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
<!-- Pulse notification light -->
<SwitchPreference
android:key="notification_pulse"
android:title="@string/notification_pulse_title"
android:switchTextOff=""
android:switchTextOn=""
android:persistent="false" />
<!-- When device is locked -->
<com.android.settings.notification.DropDownPreference
android:key="lock_screen_notifications"
android:title="@string/lock_screen_notifications_title"
android:persistent="false" />
<!-- When do not disturb is on -->
<com.android.settings.notification.DropDownPreference
android:key="zen_mode_notifications"
android:title="@string/zen_mode_notifications_title"
android:persistent="false" />
<!-- App notifications -->
<PreferenceScreen
android:key="app_notifications"
android:title="@string/app_notifications_title"
android:fragment="com.android.settings.notification.AppNotificationSettings" />
</PreferenceScreen>
......@@ -19,41 +19,78 @@
android:key="notification_settings"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
<com.android.settings.DefaultRingtonePreference
android:key="notification_sound"
android:title="@string/default_sound"
android:dialogTitle="@string/notification_sound_dialog_title"
android:persistent="false"
android:ringtoneType="notification" />
<!-- Media volume -->
<com.android.settings.notification.VolumeSeekBarPreference
android:key="media_volume"
android:icon="@*android:drawable/ic_audio_vol"
android:title="@string/media_volume_option_title" />
<CheckBoxPreference
android:key="notification_pulse"
android:title="@string/notification_pulse_title"
android:persistent="false" />
<!-- Alarm volume -->
<com.android.settings.notification.VolumeSeekBarPreference
android:key="alarm_volume"
android:icon="@*android:drawable/ic_audio_alarm"
android:title="@string/alarm_volume_option_title" />
<CheckBoxPreference
android:key="heads_up"
android:title="@string/heads_up_enabled_title"
android:persistent="false" />
<!-- Ring volume -->
<com.android.settings.notification.VolumeSeekBarPreference
android:key="ring_volume"
android:icon="@*android:drawable/ic_audio_ring_notif"
android:title="@string/ring_volume_option_title" />
<!-- Do not disturb -->
<PreferenceScreen
android:key="zen_mode"
android:title="@string/zen_mode_settings_title"
android:fragment="com.android.settings.notification.ZenModeSettings" />
<!-- When calls and notifications arrive -->
<com.android.settings.notification.DropDownPreference
android:key="toggle_lock_screen_notifications"
android:title="@string/lock_screen_notifications"
android:key="ringer_mode"
android:title="@string/ringer_mode_title"
android:persistent="false" />
<PreferenceScreen
android:key="configure"
android:title="@string/notification_settings_apps_title"
android:fragment="com.android.settings.notification.AppNotificationSettings" />
<!-- Phone ringtone -->
<com.android.settings.DefaultRingtonePreference
android:key="ringtone"
android:title="@string/ringtone_title"
android:dialogTitle="@string/ringtone_title"
android:persistent="false"
android:ringtoneType="ringtone" />
<PreferenceScreen
android:key="zen_mode"
android:title="@string/title_zen_mode"
android:fragment="com.android.settings.notification.ZenModeSettings" />
<!-- Default notification ringtone -->
<com.android.settings.DefaultRingtonePreference
android:key="notification_ringtone"
android:title="@string/notification_ringtone_title"
android:dialogTitle="@string/notification_ringtone_title"
android:persistent="false"
android:ringtoneType="notification" />
<!-- Vibrate when ringing -->
<SwitchPreference
android:key="vibrate_when_ringing"
android:title="@string/vibrate_when_ringing_title"
android:switchTextOff=""
android:switchTextOn=""
android:persistent="false" />
<!-- Showing notifications -->
<Preference
android:key="showing_notifications"
android:title="@string/notification_display_settings"
android:persistent="false"
android:fragment="com.android.settings.notification.NotificationDisplaySettings" />
<!-- Touch sounds -->
<Preference
android:key="touch_sounds"
android:title="@string/touch_sound_settings"
android:persistent="false"
android:fragment="com.android.settings.notification.TouchSoundSettings" />
<!-- Notification access -->
<Preference
android:key="manage_notification_access"
android:title="@string/manage_notification_access"
android:title="@string/manage_notification_access_title"
android:persistent="false"
android:fragment="com.android.settings.notification.NotificationAccessSettings" />
......
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/touch_sound_settings"
android:key="touch_sound_settings"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
<!-- Dial pad tones -->
<SwitchPreference
android:key="dial_pad_tones"
android:title="@string/dial_pad_tones_title"
android:switchTextOff=""
android:switchTextOn=""
android:persistent="false" />
<!-- Screen locking / unlocking -->
<SwitchPreference
android:key="screen_locking_sounds"
android:title="@string/screen_locking_sounds_title"
android:switchTextOff=""
android:switchTextOn=""
android:persistent="false" />
<!-- Other touch sounds -->
<SwitchPreference
android:key="other_touch_sounds"
android:title="@string/other_touch_sounds_title"
android:switchTextOff=""
android:switchTextOn=""
android:persistent="false" />
<!-- Vibrate on touch -->
<SwitchPreference
android:key="vibrate_on_touch"
android:title="@string/vibrate_on_touch_title"
android:switchTextOff=""
android:switchTextOn=""
android:persistent="false" />
</PreferenceScreen>
......@@ -34,6 +34,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.SeekBarVolumizer;
import android.preference.VolumePreference;
import android.provider.Settings;
import android.provider.Settings.System;
......@@ -173,10 +174,10 @@ public class RingerVolumePreference extends VolumePreference {
mSeekBars[i] = seekBar;
if (SEEKBAR_TYPE[i] == AudioManager.STREAM_MUSIC) {
mSeekBarVolumizer[i] = new SeekBarVolumizer(getContext(), seekBar,
SEEKBAR_TYPE[i], getMediaVolumeUri(getContext()));
SEEKBAR_TYPE[i], getMediaVolumeUri(getContext()), this);
} else {
mSeekBarVolumizer[i] = new SeekBarVolumizer(getContext(), seekBar,
SEEKBAR_TYPE[i]);
SEEKBAR_TYPE[i], null, this);
}
}
......@@ -275,7 +276,7 @@ public class RingerVolumePreference extends VolumePreference {
}
@Override
protected void onSampleStarting(SeekBarVolumizer volumizer) {
public void onSampleStarting(SeekBarVolumizer volumizer) {
super.onSampleStarting(volumizer);
for (SeekBarVolumizer vol : mSeekBarVolumizer) {
if (vol != null && vol != volumizer) vol.stopSample();
......
......@@ -88,6 +88,9 @@ public class Settings extends SettingsActivity {
public static class PrintJobSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeSettingsActivity extends SettingsActivity { /* empty */ }
public static class NotificationSettingsActivity extends SettingsActivity { /* empty */ }
public static class NotificationDisplaySettingsActivity extends SettingsActivity { /* empty */ }
public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ }
public static class TouchSoundSettingsActivity extends SettingsActivity { /* empty */ }
public static class TopLevelSettings extends SettingsActivity { /* empty */ }
}
......
/*
* 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.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen;
import android.preference.TwoStatePreference;
import android.provider.Settings.System;
import android.util.Log;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
import java.util.ArrayList;
import java.util.List;
public class TouchSoundSettings extends SettingsPreferenceFragment implements Indexable {
private static final String TAG = "TouchSoundSettings";
private static final String KEY_DIAL_PAD_TONES = "dial_pad_tones";
private static final String KEY_SCREEN_LOCKING_SOUNDS = "screen_locking_sounds";
private static final String KEY_OTHER_TOUCH_SOUNDS = "other_touch_sounds";
private static final String KEY_VIBRATE_ON_TOUCH = "vibrate_on_touch";
private final Handler mHandler = new Handler();
private final SettingsObserver mSettingsObserver = new SettingsObserver();
private AudioManager mAudioManager;
private SystemSettingPref mDialPadTones;
private SystemSettingPref mScreenLockingSounds;
private SystemSettingPref mOtherTouchSounds;
private SystemSettingPref mVibrateOnTouch;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.touch_sound_settings);
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
final boolean hasVoice = Utils.isVoiceCapable(getActivity());
final Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
final boolean hasHaptic = vibrator != null && vibrator.hasVibrator();
mDialPadTones = new SystemSettingPref(hasVoice,
KEY_DIAL_PAD_TONES, System.DTMF_TONE_WHEN_DIALING);
mScreenLockingSounds = new SystemSettingPref(true,
KEY_SCREEN_LOCKING_SOUNDS, System.LOCKSCREEN_SOUNDS_ENABLED);
mOtherTouchSounds = new SystemSettingPref(true,
KEY_OTHER_TOUCH_SOUNDS,System.SOUND_EFFECTS_ENABLED) {
@Override
protected void setSetting(boolean value) {
if (value) {
mAudioManager.loadSoundEffects();
} else {
mAudioManager.unloadSoundEffects();
}
super.setSetting(value);
}
};
mVibrateOnTouch = new SystemSettingPref(hasHaptic,
KEY_VIBRATE_ON_TOUCH, System.HAPTIC_FEEDBACK_ENABLED);
}
@Override
public void onResume() {
super.onResume();
mSettingsObserver.register(true);
}
@Override
public void onPause() {
super.onPause();
mSettingsObserver.register(false);
}
// === Common system setting preference helper ===
private class SystemSettingPref {
private final String mSetting;
private final Uri mUri;
private TwoStatePreference mPref;
private SystemSettingPref(boolean applicable, String key, String setting) {
mSetting = setting;
mUri = System.getUriFor(mSetting);
if (!applicable) removePreference(key);
mPref = (TwoStatePreference) getPreferenceScreen().findPreference(key);
if (mPref == null) return;
update();
mPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
setSetting((Boolean)newValue);
return true;
}
});
}
protected void setSetting(boolean value) {
System.putInt(getContentResolver(), mSetting, value ? 1 : 0);
}
private Uri getUri() {
return mUri;
}
private void update() {
if (mPref == null) return;
mPref.setChecked(System.getInt(getContentResolver(), mSetting, 1) != 0);
}
}
// === Indexing ===
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
add(result, context, R.string.touch_sound_settings);
add(result, context, R.string.dial_pad_tones_title);
add(result, context, R.string.screen_locking_sounds_title);
add(result, context, R.string.other_touch_sounds_title);
add(result, context, R.string.vibrate_on_touch_title);
return result;
}
private void add(List<SearchIndexableRaw> result, Context context, int title) {
final Resources res = context.getResources();
final SearchIndexableRaw data = new SearchIndexableRaw(context);
data.title = res.getString(title);
data.screenTitle = res.getString(R.string.touch_sound_settings);
result.add(data);
}
};
// === Callbacks ===
private final class SettingsObserver extends ContentObserver {
public SettingsObserver() {
super(mHandler);
}
public void register(boolean register) {
final ContentResolver cr = getContentResolver();
if (register) {
cr.registerContentObserver(mDialPadTones.getUri(), false, this);
cr.registerContentObserver(mScreenLockingSounds.getUri(), false, this);
cr.registerContentObserver(mOtherTouchSounds.getUri(), false, this);
cr.registerContentObserver(mVibrateOnTouch.getUri(), false, this);
} else {
cr.unregisterContentObserver(this);
}
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
if (mDialPadTones.getUri().equals(uri)) {
mDialPadTones.update();
}
if (mScreenLockingSounds.getUri().equals(uri)) {
mScreenLockingSounds.update();
}
if (mOtherTouchSounds.getUri().equals(uri)) {
mOtherTouchSounds.update();
}
if (mVibrateOnTouch.getUri().equals(uri)) {
mVibrateOnTouch.update();
}
}
}
}
/*
* 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.ContentResolver;
import android.content.Context;
import android.media.AudioManager;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.preference.SeekBarPreference;
import android.preference.SeekBarVolumizer;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;
import com.android.settings.R;
/** A slider preference that directly controls an audio stream volume (no dialog) **/
public class VolumeSeekBarPreference extends SeekBarPreference
implements PreferenceManager.OnActivityStopListener {
private static final String TAG = "VolumeSeekBarPreference";
private final Context mContext;
private int mStream;
private SeekBar mSeekBar;
private SeekBarVolumizer mVolumizer;
private Callback mCallback;
public VolumeSeekBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
public void setStream(int stream) {
mStream = stream;
}
public void setCallback(Callback callback) {
mCallback = callback;
}
@Override
public void onActivityStop() {
if (mVolumizer != null) {
mVolumizer.stop();
}
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
if (mStream == 0) {
Log.w(TAG, "No stream found, not binding volumizer");
return;
}
getPreferenceManager().registerOnActivityStopListener(this);
final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
if (seekBar == mSeekBar) return;
mSeekBar = seekBar;
final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() {
@Override
public void onSampleStarting(SeekBarVolumizer sbv) {
if (mCallback != null) {
mCallback.onSampleStarting(sbv);
}
}
};
final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null;
mVolumizer = new SeekBarVolumizer(mContext, seekBar, mStream, sampleUri, sbvc);
}
private Uri getMediaVolumeUri() {
return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
+ mContext.getPackageName()
+ "/" + R.raw.media_volume);
}
public interface Callback {
void onSampleStarting(SeekBarVolumizer sbv);
}
}
......@@ -329,7 +329,7 @@ public class ZenModeSettings extends SettingsPreferenceFragment implements Index
if (automatic == null || automa