From 38c16a9417cfcdc162fdd3faae0131a45990478e Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Fri, 21 Apr 2017 08:27:06 -0400 Subject: [PATCH] App & channel notification settings updates - change 'block all' to an on/off switch bar - update channel list summary text when notifications are toggled on/off on app settings page - Add 'off state' text - change style of foot items - change 'importance' from a dropdown to its own page Bug: 37538972 Bug: 37479730 Fixes: 37541624 Fixes: 37549732 Test: manual Change-Id: I0e5cc66ba539ce2b76b4ad6541bf6bfb5b58c373 --- res/layout/styled_switch_bar.xml | 31 ++++ res/values/strings.xml | 27 ++-- res/xml/app_notification_settings.xml | 7 - res/xml/channel_notification_settings.xml | 11 +- res/xml/notification_importance.xml | 38 +++++ .../notification/AppNotificationSettings.java | 101 +++++++----- .../ChannelImportanceSettings.java | 151 ++++++++++++++++++ .../ChannelNotificationSettings.java | 148 ++++++++--------- .../NotificationSettingsBase.java | 15 +- .../NotificationSoundPreference.java | 16 ++ .../NotificationSwitchBarPreference.java | 81 ++++++++++ .../search/SearchIndexableResources.java | 3 + 12 files changed, 489 insertions(+), 140 deletions(-) create mode 100644 res/layout/styled_switch_bar.xml create mode 100644 res/xml/notification_importance.xml create mode 100644 src/com/android/settings/notification/ChannelImportanceSettings.java create mode 100644 src/com/android/settings/notification/NotificationSwitchBarPreference.java diff --git a/res/layout/styled_switch_bar.xml b/res/layout/styled_switch_bar.xml new file mode 100644 index 00000000000..dd61907efac --- /dev/null +++ b/res/layout/styled_switch_bar.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index b255123dab8..848d2eb9676 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6558,7 +6558,10 @@ Notifications - + + Notification category + + Importance @@ -6579,17 +6582,17 @@ Make sound and pop on screen - - Low: No sound or visual interruption + + Low - - Medium: No sound + + Medium - - High: Make sound + + High - - Urgent: Make sound and pop on screen + + Urgent Allow Sound @@ -6694,6 +6697,12 @@ Loading apps... + + Android is blocking this app\'s notifications from appearing on this device + + + Android is blocking this category of notifications from appearing on this device + Categories diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml index ef8a45cb273..bfb91ef8fa7 100644 --- a/res/xml/app_notification_settings.xml +++ b/res/xml/app_notification_settings.xml @@ -18,13 +18,6 @@ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" android:title="@string/app_notifications_title" android:key="app_notification_settings"> - - - - - - - diff --git a/res/xml/notification_importance.xml b/res/xml/notification_importance.xml new file mode 100644 index 00000000000..f801f3c1583 --- /dev/null +++ b/res/xml/notification_importance.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java index db5cf2fb07c..e91a8497706 100644 --- a/src/com/android/settings/notification/AppNotificationSettings.java +++ b/src/com/android/settings/notification/AppNotificationSettings.java @@ -24,6 +24,7 @@ import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import android.app.Activity; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; +import android.app.NotificationManager; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; @@ -33,17 +34,22 @@ import android.support.v7.preference.PreferenceCategory; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Switch; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.AppHeader; -import com.android.settings.DimmableIconPreference; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.applications.AppHeaderController; import com.android.settings.applications.AppInfoBase; +import com.android.settings.applications.LayoutPreference; import com.android.settings.notification.NotificationBackend.AppRow; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.widget.FooterPreference; import com.android.settings.widget.MasterSwitchPreference; +import com.android.settings.widget.SwitchBar; import com.android.settingslib.RestrictedSwitchPreference; import java.text.Collator; @@ -57,12 +63,14 @@ public class AppNotificationSettings extends NotificationSettingsBase { private static final String TAG = "AppNotificationSettings"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final String KEY_BLOCK = "block"; private static final String KEY_IMPORTANCE = "allow_sound"; private List mChannelGroupList; private List mChannelGroups = new ArrayList(); private RestrictedSwitchPreference mImportanceToggle; + private LayoutPreference mBlockBar; + private FooterPreference mDeletedChannels; + private SwitchBar mSwitchBar; private boolean mShowLegacyChannelConfig = false; @@ -88,8 +96,8 @@ public class AppNotificationSettings extends NotificationSettingsBase { addPreferencesFromResource(R.xml.app_notification_settings); getPreferenceScreen().setOrderingAsAdded(true); - mBlock = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BLOCK); mBadge = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BADGE); + mBlockedDesc = (FooterPreference) getPreferenceScreen().findPreference(KEY_BLOCKED_DESC); setupBlock(); setupBadge(); @@ -127,11 +135,7 @@ public class AppNotificationSettings extends NotificationSettingsBase { .done(activity, getPrefContext()); getPreferenceScreen().addPreference(pref); - if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) { - Log.w(TAG, "Missing package or uid or packageinfo"); - finish(); - return; - } + updateDependents(mAppRow.banned); } private void populateChannelList() { @@ -187,12 +191,12 @@ public class AppNotificationSettings extends NotificationSettingsBase { int deletedChannelCount = mBackend.getDeletedChannelCount(mAppRow.pkg, mAppRow.uid); if (deletedChannelCount > 0) { - DimmableIconPreference deletedPref = new DimmableIconPreference(getPrefContext()); - deletedPref.setSelectable(false); - deletedPref.setTitle(getResources().getQuantityString( + mDeletedChannels = new FooterPreference(getPrefContext()); + mDeletedChannels.setSelectable(false); + mDeletedChannels.setTitle(getResources().getQuantityString( R.plurals.deleted_channels, deletedChannelCount, deletedChannelCount)); - deletedPref.setIcon(R.drawable.ic_info); - getPreferenceScreen().addPreference(deletedPref); + mDeletedChannels.setEnabled(false); + getPreferenceScreen().addPreference(mDeletedChannels); } } updateDependents(mAppRow.banned); @@ -214,7 +218,8 @@ public class AppNotificationSettings extends NotificationSettingsBase { channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId()); Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(), ChannelNotificationSettings.class.getName(), - channelArgs, null, 0, null, false, getMetricsCategory()); + channelArgs, null, R.string.notification_channel_title, null, false, + getMetricsCategory()); channelPref.setIntent(channelIntent); channelPref.setOnPreferenceChangeListener( @@ -227,6 +232,7 @@ public class AppNotificationSettings extends NotificationSettingsBase { channel.setImportance(importance); channel.lockFields( NotificationChannel.USER_LOCKED_IMPORTANCE); + channelPref.setSummary(getImportanceSummary(channel.getImportance())); mBackend.updateChannel(mPkg, mUid, channel); return true; @@ -237,8 +243,7 @@ public class AppNotificationSettings extends NotificationSettingsBase { private void populateDefaultChannelPrefs() { addPreferencesFromResource(R.xml.legacy_channel_notification_settings); - mPriority = - (RestrictedSwitchPreference) findPreference(KEY_BYPASS_DND); + mPriority = (RestrictedSwitchPreference) findPreference(KEY_BYPASS_DND); mVisibilityOverride = (RestrictedDropDownPreference) findPreference(KEY_VISIBILITY_OVERRIDE); mImportanceToggle = (RestrictedSwitchPreference) findPreference(KEY_IMPORTANCE); @@ -248,8 +253,11 @@ public class AppNotificationSettings extends NotificationSettingsBase { setupVisOverridePref(mChannel.getLockscreenVisibility()); setupImportanceToggle(); } + mSwitchBar.setChecked(!mAppRow.banned + && mChannel.getImportance() != NotificationManager.IMPORTANCE_NONE); } + // 'allow sound' private void setupImportanceToggle() { mImportanceToggle.setDisabledByAdmin(mSuspendedAppsAdmin); mImportanceToggle.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT @@ -268,6 +276,40 @@ public class AppNotificationSettings extends NotificationSettingsBase { }); } + protected void setupBlock() { + View switchBarContainer = LayoutInflater.from( + getPrefContext()).inflate(R.layout.styled_switch_bar, null); + mSwitchBar = switchBarContainer.findViewById(R.id.switch_bar); + mSwitchBar.show(); + mSwitchBar.setDisabledByAdmin(mSuspendedAppsAdmin); + mSwitchBar.setChecked(!mAppRow.banned); + mSwitchBar.addOnSwitchChangeListener(new SwitchBar.OnSwitchChangeListener() { + @Override + public void onSwitchChanged(Switch switchView, boolean isChecked) { + if (mShowLegacyChannelConfig && mChannel != null) { + final int importance = isChecked ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_NONE; + mImportanceToggle.setChecked(importance == IMPORTANCE_UNSPECIFIED); + mChannel.setImportance(importance); + mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); + mBackend.updateChannel(mPkg, mUid, mChannel); + } + mBackend.setNotificationsEnabledForPackage(mPkgInfo.packageName, mUid, isChecked); + updateDependents(!isChecked); + } + }); + + mBlockBar = new LayoutPreference(getPrefContext(), switchBarContainer); + mBlockBar.setOrder(-500); + mBlockBar.setKey(KEY_BLOCK); + getPreferenceScreen().addPreference(mBlockBar); + + if (mAppRow.systemApp && !mAppRow.banned) { + setVisible(mBlockBar, false); + } + + setupBlockDesc(R.string.app_notifications_off_desc); + } + private void setupBadge() { mBadge.setDisabledByAdmin(mSuspendedAppsAdmin); mBadge.setChecked(mAppRow.showBadge); @@ -281,31 +323,14 @@ public class AppNotificationSettings extends NotificationSettingsBase { }); } - private void setupBlock() { - if (mAppRow.systemApp && !mAppRow.banned) { - setVisible(mBlock, false); - } else { - mBlock.setDisabledByAdmin(mSuspendedAppsAdmin); - mBlock.setChecked(mAppRow.banned); - mBlock.setOnPreferenceChangeListener( - new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, - Object newValue) { - final boolean blocked = (Boolean) newValue; - mBackend.setNotificationsEnabledForPackage(mPkgInfo.packageName, mUid, - !blocked); - updateDependents(blocked); - return true; - } - }); - } - } - private void updateDependents(boolean banned) { for (PreferenceCategory category : mChannelGroups) { setVisible(category, !banned); } + if (mDeletedChannels != null) { + setVisible(mDeletedChannels, !banned); + } + setVisible(mBlockedDesc, banned); setVisible(mBadge, !banned); if (mShowLegacyChannelConfig) { setVisible(mImportanceToggle, !banned); @@ -313,7 +338,7 @@ public class AppNotificationSettings extends NotificationSettingsBase { setVisible(mVisibilityOverride, !banned); } if (mAppRow.systemApp && !mAppRow.banned) { - setVisible(mBlock, false); + setVisible(mBlockBar, false); } } diff --git a/src/com/android/settings/notification/ChannelImportanceSettings.java b/src/com/android/settings/notification/ChannelImportanceSettings.java new file mode 100644 index 00000000000..b396b205127 --- /dev/null +++ b/src/com/android/settings/notification/ChannelImportanceSettings.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2017 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 static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE; +import static android.app.NotificationManager.IMPORTANCE_DEFAULT; +import static android.app.NotificationManager.IMPORTANCE_HIGH; +import static android.app.NotificationManager.IMPORTANCE_LOW; +import static android.app.NotificationManager.IMPORTANCE_MAX; +import static android.app.NotificationManager.IMPORTANCE_MIN; + +import android.content.Context; +import android.provider.SearchIndexableResource; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settings.widget.RadioButtonPreference; + +import java.util.ArrayList; +import java.util.List; + +public class ChannelImportanceSettings extends NotificationSettingsBase + implements RadioButtonPreference.OnClickListener, Indexable { + private static final String TAG = "NotiImportance"; + + private static final String KEY_IMPORTANCE_HIGH = "importance_high"; + private static final String KEY_IMPORTANCE_DEFAULT = "importance_default"; + private static final String KEY_IMPORTANCE_LOW = "importance_low"; + private static final String KEY_IMPORTANCE_MIN = "importance_min"; + + List mImportances = new ArrayList<>(); + + @Override + public int getMetricsCategory() { + return MetricsEvent.NOTIFICATION_CHANNEL_IMPORTANCE; + } + + @Override + public void onResume() { + super.onResume(); + if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null || mChannel == null) { + Log.w(TAG, "Missing package or uid or packageinfo or channel"); + finish(); + return; + } + createPreferenceHierarchy(); + } + + @Override + public void onPause() { + super.onPause(); + } + + private PreferenceScreen createPreferenceHierarchy() { + PreferenceScreen root = getPreferenceScreen(); + if (root != null) { + root.removeAll(); + } + addPreferencesFromResource(R.xml.notification_importance); + root = getPreferenceScreen(); + + for (int i = 0; i < root.getPreferenceCount(); i++) { + Preference pref = root.getPreference(i); + if (pref instanceof RadioButtonPreference) { + RadioButtonPreference radioPref = (RadioButtonPreference) pref; + radioPref.setOnClickListener(this); + mImportances.add(radioPref); + } + } + + switch (mChannel.getImportance()) { + case IMPORTANCE_MIN: + updateRadioButtons(KEY_IMPORTANCE_MIN); + break; + case IMPORTANCE_LOW: + updateRadioButtons(KEY_IMPORTANCE_LOW); + break; + case IMPORTANCE_DEFAULT: + updateRadioButtons(KEY_IMPORTANCE_DEFAULT); + break; + case IMPORTANCE_HIGH: + case IMPORTANCE_MAX: + updateRadioButtons(KEY_IMPORTANCE_HIGH); + break; + } + + return root; + } + + private void updateRadioButtons(String selectionKey) { + for (RadioButtonPreference pref : mImportances) { + if (selectionKey.equals(pref.getKey())) { + pref.setChecked(true); + } else { + pref.setChecked(false); + } + } + } + + @Override + public void onRadioButtonClicked(RadioButtonPreference clicked) { + switch (clicked.getKey()) { + case KEY_IMPORTANCE_HIGH: + mChannel.setImportance(IMPORTANCE_HIGH); + break; + case KEY_IMPORTANCE_DEFAULT: + mChannel.setImportance(IMPORTANCE_DEFAULT); + break; + case KEY_IMPORTANCE_LOW: + mChannel.setImportance(IMPORTANCE_LOW); + break; + case KEY_IMPORTANCE_MIN: + mChannel.setImportance(IMPORTANCE_MIN); + break; + } + updateRadioButtons(clicked.getKey()); + mChannel.lockFields(USER_LOCKED_IMPORTANCE); + mBackend.updateChannel(mAppRow.pkg, mAppRow.uid, mChannel); + } + + // This page exists per notification channel; should not be included + // in search + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + return null; + } + }; +} diff --git a/src/com/android/settings/notification/ChannelNotificationSettings.java b/src/com/android/settings/notification/ChannelNotificationSettings.java index f6a7b425a95..0fb42d27355 100644 --- a/src/com/android/settings/notification/ChannelNotificationSettings.java +++ b/src/com/android/settings/notification/ChannelNotificationSettings.java @@ -16,9 +16,7 @@ package com.android.settings.notification; -import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; -import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.IMPORTANCE_NONE; import android.app.Activity; @@ -27,25 +25,31 @@ import android.app.NotificationManager; import android.content.Intent; import android.content.pm.UserInfo; import android.net.Uri; +import android.os.Bundle; import android.os.UserHandle; import android.provider.Settings; import android.support.v7.preference.Preference; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Switch; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; -import com.android.settings.DimmableIconPreference; +import com.android.settings.AppHeader; import com.android.settings.R; import com.android.settings.RingtonePreference; +import com.android.settings.Utils; import com.android.settings.applications.AppHeaderController; +import com.android.settings.applications.AppInfoBase; +import com.android.settings.applications.LayoutPreference; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.widget.FooterPreference; +import com.android.settings.widget.SwitchBar; import com.android.settingslib.RestrictedSwitchPreference; -import java.util.ArrayList; -import java.util.List; - public class ChannelNotificationSettings extends NotificationSettingsBase { private static final String TAG = "ChannelSettings"; @@ -53,10 +57,13 @@ public class ChannelNotificationSettings extends NotificationSettingsBase { protected static final String KEY_VIBRATE = "vibrate"; protected static final String KEY_RINGTONE = "ringtone"; + protected Preference mImportance; protected RestrictedSwitchPreference mLights; protected RestrictedSwitchPreference mVibrate; protected NotificationSoundPreference mRingtone; + protected LayoutPreference mBlockBar; + @Override public int getMetricsCategory() { return MetricsEvent.NOTIFICATION_TOPIC_NOTIFICATION; @@ -75,33 +82,33 @@ public class ChannelNotificationSettings extends NotificationSettingsBase { getPreferenceScreen().removeAll(); } addPreferencesFromResource(R.xml.channel_notification_settings); - getPreferenceScreen().setOrderingAsAdded(true); // load settings intent ArrayMap rows = new ArrayMap(); rows.put(mAppRow.pkg, mAppRow); collectConfigActivities(rows); - mBlock = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BLOCK); + mBlockedDesc = (FooterPreference) getPreferenceScreen().findPreference(KEY_BLOCKED_DESC); mBadge = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BADGE); - mImportance = (RestrictedDropDownPreference) findPreference(KEY_IMPORTANCE); - mPriority = - (RestrictedSwitchPreference) findPreference(KEY_BYPASS_DND); + mImportance = findPreference(KEY_IMPORTANCE); + mPriority = (RestrictedSwitchPreference) findPreference(KEY_BYPASS_DND); mVisibilityOverride = (RestrictedDropDownPreference) findPreference(KEY_VISIBILITY_OVERRIDE); mLights = (RestrictedSwitchPreference) findPreference(KEY_LIGHTS); mVibrate = (RestrictedSwitchPreference) findPreference(KEY_VIBRATE); mRingtone = (NotificationSoundPreference) findPreference(KEY_RINGTONE); - if (mPkgInfo != null && mChannel != null) { - setupPriorityPref(mChannel.canBypassDnd()); - setupVisOverridePref(mChannel.getLockscreenVisibility()); - setupLights(); - setupVibrate(); - setupRingtone(); - setupBlockAndImportance(); - updateDependents(); - } + + setupPriorityPref(mChannel.canBypassDnd()); + setupVisOverridePref(mChannel.getLockscreenVisibility()); + setupLights(); + setupVibrate(); + setupRingtone(); + setupBadge(); + setupBlock(); + setupImportance(); + updateDependents(); + final Activity activity = getActivity(); final Preference pref = FeatureFactory.getFactory(activity) .getApplicationFeatureProvider(activity) @@ -124,12 +131,13 @@ public class ChannelNotificationSettings extends NotificationSettingsBase { } if (!TextUtils.isEmpty(mChannel.getDescription())) { - DimmableIconPreference descPref = new DimmableIconPreference(getPrefContext()); + FooterPreference descPref = new FooterPreference(getPrefContext()); descPref.setSelectable(false); descPref.setSummary(mChannel.getDescription()); - descPref.setIcon(R.drawable.ic_info); + descPref.setEnabled(false); getPreferenceScreen().addPreference(descPref); } + } private void setupLights() { @@ -175,27 +183,38 @@ public class ChannelNotificationSettings extends NotificationSettingsBase { }); } - protected void setupBlockAndImportance() { + protected void setupBlock() { + View switchBarContainer = LayoutInflater.from( + getPrefContext()).inflate(R.layout.styled_switch_bar, null); + SwitchBar switchBar = switchBarContainer.findViewById(R.id.switch_bar); + switchBar.show(); + switchBar.setDisabledByAdmin(mSuspendedAppsAdmin); + switchBar.setChecked(mChannel.getImportance() != NotificationManager.IMPORTANCE_NONE); + switchBar.addOnSwitchChangeListener(new SwitchBar.OnSwitchChangeListener() { + @Override + public void onSwitchChanged(Switch switchView, boolean isChecked) { + int importance = isChecked ? IMPORTANCE_LOW : IMPORTANCE_NONE; + mImportance.setSummary(getImportanceSummary(importance)); + mChannel.setImportance(importance); + mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); + mBackend.updateChannel(mPkg, mUid, mChannel); + updateDependents(); + } + }); + + mBlockBar = new LayoutPreference(getPrefContext(), switchBarContainer); + mBlockBar.setOrder(-500); + mBlockBar.setKey(KEY_BLOCK); + getPreferenceScreen().addPreference(mBlockBar); + if (mAppRow.systemApp && mChannel.getImportance() != NotificationManager.IMPORTANCE_NONE) { - setVisible(mBlock, false); - } else { - mBlock.setEnabled(mAppRow.systemApp); - mBlock.setDisabledByAdmin(mSuspendedAppsAdmin); - mBlock.setChecked(mChannel.getImportance() == NotificationManager.IMPORTANCE_NONE); - mBlock.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - final boolean value = (Boolean) newValue; - int importance = value ? IMPORTANCE_NONE : IMPORTANCE_LOW; - mImportance.setValue(String.valueOf(importance)); - mChannel.setImportance(importance); - mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); - mBackend.updateChannel(mPkg, mUid, mChannel); - updateDependents(); - return true; - } - }); + setVisible(mBlockBar, false); } + + setupBlockDesc(R.string.channel_notifications_off_desc); + } + + protected void setupBadge() { mBadge.setDisabledByAdmin(mSuspendedAppsAdmin); mBadge.setEnabled(mAppRow.showBadge); mBadge.setChecked(mChannel.canShowBadge()); @@ -209,41 +228,21 @@ public class ChannelNotificationSettings extends NotificationSettingsBase { return true; } }); + } - mImportance.setDisabledByAdmin(mSuspendedAppsAdmin); - final int numImportances = IMPORTANCE_HIGH - IMPORTANCE_MIN + 1; - List summaries = new ArrayList<>(); - List values = new ArrayList<>(); - - for (int i = 0; i < numImportances; i++) { - int importance = i + 1; - summaries.add(getImportanceSummary(importance)); - values.add(String.valueOf(importance)); - } - if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId())) { - // Add option to reset to letting the app decide - summaries.add(getImportanceSummary(NotificationManager.IMPORTANCE_UNSPECIFIED)); - values.add(String.valueOf(NotificationManager.IMPORTANCE_UNSPECIFIED)); - } - mImportance.setEntryValues(values.toArray(new String[0])); - mImportance.setEntries(summaries.toArray(new String[0])); - mImportance.setValue(String.valueOf(mChannel.getImportance())); + protected void setupImportance() { + Bundle channelArgs = new Bundle(); + channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid); + channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true); + channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg); + channelArgs.putString(Settings.EXTRA_CHANNEL_ID, mChannel.getId()); + Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(), + ChannelImportanceSettings.class.getName(), + channelArgs, null, R.string.notification_importance_title, null, + false, getMetricsCategory()); + mImportance.setIntent(channelIntent); + mImportance.setEnabled(mSuspendedAppsAdmin == null); mImportance.setSummary(getImportanceSummary(mChannel.getImportance())); - if (mAppRow.lockedImportance) { - mImportance.setEnabled(false); - } else { - mImportance.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - int importance = Integer.parseInt((String) newValue); - mChannel.setImportance(importance); - mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); - mBackend.updateChannel(mPkg, mUid, mChannel); - updateDependents(); - return true; - } - }); - } } private boolean isLockScreenSecure() { @@ -292,6 +291,7 @@ public class ChannelNotificationSettings extends NotificationSettingsBase { } private void updateDependents() { + setVisible(mBlockedDesc, mChannel.getImportance() == IMPORTANCE_NONE); setVisible(mBadge, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN)); setVisible(mImportance, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN)); setVisible(mLights, checkCanBeVisible( diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java index ff0a5127c85..c08f161d3b8 100644 --- a/src/com/android/settings/notification/NotificationSettingsBase.java +++ b/src/com/android/settings/notification/NotificationSettingsBase.java @@ -19,6 +19,7 @@ package com.android.settings.notification; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.applications.AppInfoBase; +import com.android.settings.widget.FooterPreference; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedSwitchPreference; @@ -39,6 +40,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.service.notification.NotificationListenerService; +import android.support.v7.preference.DropDownPreference; import android.support.v7.preference.Preference; import android.text.TextUtils; import android.util.ArrayMap; @@ -63,6 +65,7 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen protected static final String KEY_BYPASS_DND = "bypass_dnd"; protected static final String KEY_VISIBILITY_OVERRIDE = "visibility_override"; protected static final String KEY_IMPORTANCE = "importance"; + protected static final String KEY_BLOCKED_DESC = "block_desc"; protected PackageManager mPm; protected UserManager mUm; @@ -73,11 +76,10 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen protected int mUserId; protected String mPkg; protected PackageInfo mPkgInfo; - protected RestrictedSwitchPreference mBlock; protected RestrictedSwitchPreference mBadge; - protected RestrictedDropDownPreference mImportance; protected RestrictedSwitchPreference mPriority; protected RestrictedDropDownPreference mVisibilityOverride; + protected FooterPreference mBlockedDesc; protected EnforcedAdmin mSuspendedAppsAdmin; protected boolean mDndVisualEffectsSuppressed; @@ -325,6 +327,15 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen mVisibilityOverride.setDisabledByAdmin(mSuspendedAppsAdmin); } + protected void setupBlockDesc(int summaryResId) { + mBlockedDesc = new FooterPreference(getPrefContext()); + mBlockedDesc.setSelectable(false); + mBlockedDesc.setTitle(summaryResId); + mBlockedDesc.setEnabled(false); + mBlockedDesc.setOrder(50); + getPreferenceScreen().addPreference(mBlockedDesc); + } + private void setRestrictedIfNotificationFeaturesDisabled(CharSequence entry, CharSequence entryValue, int keyguardNotificationFeatures) { diff --git a/src/com/android/settings/notification/NotificationSoundPreference.java b/src/com/android/settings/notification/NotificationSoundPreference.java index c0074857e80..71684d5cf75 100644 --- a/src/com/android/settings/notification/NotificationSoundPreference.java +++ b/src/com/android/settings/notification/NotificationSoundPreference.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2017 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; diff --git a/src/com/android/settings/notification/NotificationSwitchBarPreference.java b/src/com/android/settings/notification/NotificationSwitchBarPreference.java new file mode 100644 index 00000000000..7729543a245 --- /dev/null +++ b/src/com/android/settings/notification/NotificationSwitchBarPreference.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2017 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.Context; +import android.support.v7.preference.PreferenceViewHolder; +import android.util.AttributeSet; +import android.view.View; + +import com.android.settings.applications.LayoutPreference; +import com.android.settings.widget.ToggleSwitch; +import com.android.settingslib.RestrictedLockUtils; + +public class NotificationSwitchBarPreference extends LayoutPreference { + private ToggleSwitch mSwitch; + private boolean mChecked; + private boolean mEnableSwitch = true; + + public NotificationSwitchBarPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + mSwitch = (ToggleSwitch) holder.findViewById(android.R.id.switch_widget); + if (mSwitch != null) { + mSwitch.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!mSwitch.isEnabled()) { + return; + } + mChecked = !mChecked; + setChecked(mChecked); + if (!callChangeListener(mChecked)) { + setChecked(!mChecked); + } + } + }); + mSwitch.setChecked(mChecked); + mSwitch.setEnabled(mEnableSwitch); + } + } + + public boolean isChecked() { + return mSwitch != null && mSwitch.isEnabled() && mChecked; + } + + public void setChecked(boolean checked) { + mChecked = checked; + if (mSwitch != null) { + mSwitch.setChecked(checked); + } + } + + public void setSwitchEnabled(boolean enabled) { + mEnableSwitch = enabled; + if (mSwitch != null) { + mSwitch.setEnabled(enabled); + } + } + + public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) { + setSwitchEnabled(admin == null); + } +} diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index f7882ae5572..d1d6945e097 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -65,6 +65,7 @@ import com.android.settings.location.LocationSettings; import com.android.settings.location.ScanningSettings; import com.android.settings.network.NetworkDashboardFragment; import com.android.settings.nfc.PaymentSettings; +import com.android.settings.notification.ChannelImportanceSettings; import com.android.settings.notification.ConfigureNotificationSettings; import com.android.settings.notification.SoundSettings; import com.android.settings.notification.ZenModePrioritySettings; @@ -179,6 +180,8 @@ public final class SearchIndexableResources { R.drawable.ic_settings_accessibility); addIndex(AccessibilityShortcutPreferenceFragment.class, NO_DATA_RES_ID, R.drawable.ic_settings_accessibility); + addIndex(ChannelImportanceSettings.class, NO_DATA_RES_ID, + R.drawable.ic_settings_notifications); } private SearchIndexableResources() {