Add settings page for notification channel groups
Bug: 63927402
Test: tests/unit/src/com/android/settings/notification/.*
Change-Id: Iebf7d8ba54f0cf5801a42f3161354d3cc5e5c848
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e3decb0..7702257 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2700,6 +2700,22 @@
android:value="com.android.settings.notification.AppNotificationSettings" />
</activity>
+ <!-- Show channel group-level notification settings (group passed in as extras) -->
+ <activity android:name="Settings$ChannelGroupNotificationSettingsActivity"
+ android:exported="true">
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.CHANNEL_GROUP_NOTIFICATION_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.notification.ChannelGroupNotificationSettings" />
+ </activity>
+
+
<!-- Show channel-level notification settings (channel passed in as extras) -->
<activity android:name="Settings$ChannelNotificationSettingsActivity"
android:exported="true">
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ec83053..0edb017 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6835,6 +6835,9 @@
<!-- [CHAR LIMIT=100] Notification channel title -->
<string name="notification_channel_title">Notification category</string>
+ <!-- [CHAR LIMIT=200] Notification channel group title -->
+ <string name="notification_group_title">Notification category group</string>
+
<!-- [CHAR LIMIT=100] Notification importance screen title -->
<string name="notification_importance_title">Importance</string>
@@ -7002,12 +7005,21 @@
<!-- [CHAR LIMIT=NONE] Text appearing when channel notifications are off -->
<string name="channel_notifications_off_desc">Android is blocking this category of notifications from appearing on this device</string>
+ <!-- [CHAR LIMIT=NONE] Text appearing when channel group notifications are off -->
+ <string name="channel_group_notifications_off_desc">Android is blocking this group of notifications from appearing on this device</string>
+
<!-- [CHAR LIMIT=NONE] App notification settings: channels title -->
<string name="notification_channels">Categories</string>
<!-- [CHAR LIMIT=NONE] App notification settings: non-grouped-channels title -->
<string name="notification_channels_other">Other</string>
+ <!-- [CHAR LIMIT=45] App notification settings, group summary-->
+ <plurals name="notification_group_summary">
+ <item quantity="one"><xliff:g id="count" example="1">%d</xliff:g> category</item>
+ <item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> categories</item>
+ </plurals>
+
<!-- [CHAR LIMIT=NONE] App notification settings: no channels -->
<string name="no_channels">This app has not posted any notifications</string>
diff --git a/res/xml/upgraded_channel_notification_settings.xml b/res/xml/upgraded_channel_notification_settings.xml
index 2cece9e..ee23435 100644
--- a/res/xml/upgraded_channel_notification_settings.xml
+++ b/res/xml/upgraded_channel_notification_settings.xml
@@ -38,6 +38,7 @@
settings:useAdditionalSummary="true" />
<PreferenceCategory
+ android:key="advanced"
android:title="@string/advanced_apps">
<!-- Visibility Override -->
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index a696172..ecdf4ba 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -124,6 +124,7 @@
public static class NotificationAppListActivity extends SettingsActivity { /* empty */ }
public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ChannelNotificationSettingsActivity extends SettingsActivity { /* empty */ }
+ public static class ChannelGroupNotificationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ManageDomainUrlsActivity extends SettingsActivity { /* empty */ }
public static class AutomaticStorageManagerSettingsActivity extends SettingsActivity { /* empty */ }
public static class GamesStorageActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 380c070..a03314c 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -100,6 +100,7 @@
import com.android.settings.nfc.PaymentSettings;
import com.android.settings.notification.AppNotificationSettings;
import com.android.settings.notification.ChannelNotificationSettings;
+import com.android.settings.notification.ChannelGroupNotificationSettings;
import com.android.settings.notification.ConfigureNotificationSettings;
import com.android.settings.notification.NotificationAccessSettings;
import com.android.settings.notification.NotificationStation;
@@ -209,6 +210,7 @@
BatterySaverSettings.class.getName(),
AppNotificationSettings.class.getName(),
ChannelNotificationSettings.class.getName(),
+ ChannelGroupNotificationSettings.class.getName(),
ApnSettings.class.getName(),
ApnEditor.class.getName(),
WifiCallingSettings.class.getName(),
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index 78a0a74..29eb4a3 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -26,6 +26,7 @@
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceGroup;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -50,7 +51,6 @@
import java.util.Comparator;
import java.util.List;
-import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
@@ -105,7 +105,7 @@
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... unused) {
- mChannelGroupList = mBackend.getChannelGroups(mPkg, mUid).getList();
+ mChannelGroupList = mBackend.getGroups(mPkg, mUid).getList();
Collections.sort(mChannelGroupList, mChannelGroupComparator);
return null;
}
@@ -115,7 +115,7 @@
if (getHost() == null) {
return;
}
- populateChannelList();
+ populateList();
addAppLinkPref();
}
}.execute();
@@ -144,7 +144,7 @@
getPreferenceScreen().addPreference(pref);
}
- private void populateChannelList() {
+ private void populateList() {
if (!mChannelGroups.isEmpty()) {
// If there's anything in mChannelGroups, we've called populateChannelList twice.
// Clear out existing channels and log.
@@ -166,30 +166,7 @@
empty.setEnabled(false);
groupCategory.addPreference(empty);
} else {
- for (NotificationChannelGroup group : mChannelGroupList) {
- PreferenceCategory groupCategory = new PreferenceCategory(getPrefContext());
- if (group.getId() == null) {
- groupCategory.setTitle(mChannelGroupList.size() > 1
- ? R.string.notification_channels_other
- : R.string.notification_channels);
- groupCategory.setKey(KEY_GENERAL_CATEGORY);
- } else {
- groupCategory.setTitle(group.getName());
- groupCategory.setKey(group.getId());
- }
- groupCategory.setOrderingAsAdded(true);
- getPreferenceScreen().addPreference(groupCategory);
- mChannelGroups.add(groupCategory);
-
- final List<NotificationChannel> channels = group.getChannels();
- Collections.sort(channels, mChannelComparator);
- int N = channels.size();
- for (int i = 0; i < N; i++) {
- final NotificationChannel channel = channels.get(i);
- populateSingleChannelPrefs(groupCategory, channel);
- }
- }
-
+ populateGroupList();
int deletedChannelCount = mBackend.getDeletedChannelCount(mAppRow.pkg, mAppRow.uid);
if (deletedChannelCount > 0) {
mDeletedChannels = new FooterPreference(getPrefContext());
@@ -202,48 +179,63 @@
getPreferenceScreen().addPreference(mDeletedChannels);
}
}
-
updateDependents(mAppRow.banned);
}
- private void populateSingleChannelPrefs(PreferenceCategory groupCategory,
- final NotificationChannel channel) {
- MasterSwitchPreference channelPref = new MasterSwitchPreference(
+ private void populateGroupList() {
+ PreferenceCategory groupCategory = new PreferenceCategory(getPrefContext());
+ groupCategory.setTitle(R.string.notification_channels);
+ groupCategory.setKey(KEY_GENERAL_CATEGORY);
+ groupCategory.setOrderingAsAdded(true);
+ getPreferenceScreen().addPreference(groupCategory);
+ mChannelGroups.add(groupCategory);
+ for (NotificationChannelGroup group : mChannelGroupList) {
+ final List<NotificationChannel> channels = group.getChannels();
+ int N = channels.size();
+ // app defined groups with one channel and channels with no group display the channel
+ // name and no summary and link directly to the channel page unless the group is blocked
+ if ((group.getId() == null || N < 2) && !group.isBlocked()) {
+ Collections.sort(channels, mChannelComparator);
+ for (int i = 0; i < N; i++) {
+ final NotificationChannel channel = channels.get(i);
+ populateSingleChannelPrefs(groupCategory, channel, "");
+ }
+ } else {
+ populateGroupPreference(groupCategory, group, N);
+ }
+ }
+ }
+
+ void populateGroupPreference(PreferenceGroup parent,
+ final NotificationChannelGroup group, int channelCount) {
+ MasterSwitchPreference groupPref = new MasterSwitchPreference(
getPrefContext());
- channelPref.setSwitchEnabled(mSuspendedAppsAdmin == null
- && isChannelBlockable(mAppRow.systemApp, channel)
- && isChannelConfigurable(channel));
- channelPref.setKey(channel.getId());
- channelPref.setTitle(channel.getName());
- channelPref.setChecked(channel.getImportance() != IMPORTANCE_NONE);
- channelPref.setSummary(getImportanceSummary(channel));
- Bundle channelArgs = new Bundle();
- channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
- channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
- channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
- Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
- ChannelNotificationSettings.class.getName(),
- channelArgs, null, R.string.notification_channel_title, null, false,
+ groupPref.setSwitchEnabled(mSuspendedAppsAdmin == null
+ && isChannelGroupBlockable(group));
+ groupPref.setKey(group.getId());
+ groupPref.setTitle(group.getName());
+ groupPref.setChecked(!group.isBlocked());
+ groupPref.setSummary(getResources().getQuantityString(
+ R.plurals.notification_group_summary, channelCount, channelCount));
+ Bundle groupArgs = new Bundle();
+ groupArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
+ groupArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
+ groupArgs.putString(Settings.EXTRA_CHANNEL_GROUP_ID, group.getId());
+ Intent groupIntent = Utils.onBuildStartFragmentIntent(getActivity(),
+ ChannelGroupNotificationSettings.class.getName(),
+ groupArgs, null, R.string.notification_group_title, null, false,
getMetricsCategory());
- channelPref.setIntent(channelIntent);
+ groupPref.setIntent(groupIntent);
- channelPref.setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference,
- Object o) {
- boolean value = (Boolean) o;
- int importance = value ? IMPORTANCE_LOW : IMPORTANCE_NONE;
- channel.setImportance(importance);
- channel.lockFields(
- NotificationChannel.USER_LOCKED_IMPORTANCE);
- channelPref.setSummary(getImportanceSummary(channel));
- mBackend.updateChannel(mPkg, mUid, channel);
+ groupPref.setOnPreferenceChangeListener(
+ (preference, o) -> {
+ boolean value = (Boolean) o;
+ group.setBlocked(!value);
+ mBackend.updateChannelGroup(mPkg, mUid, group);
- return true;
- }
+ return true;
});
- groupCategory.addPreference(channelPref);
+ parent.addPreference(groupPref);
}
void setupBadge() {
@@ -330,38 +322,6 @@
}
}
- private String getImportanceSummary(NotificationChannel channel) {
- switch (channel.getImportance()) {
- case NotificationManager.IMPORTANCE_UNSPECIFIED:
- return getContext().getString(R.string.notification_importance_unspecified);
- case NotificationManager.IMPORTANCE_NONE:
- return getContext().getString(R.string.notification_toggle_off);
- case NotificationManager.IMPORTANCE_MIN:
- return getContext().getString(R.string.notification_importance_min);
- case NotificationManager.IMPORTANCE_LOW:
- return getContext().getString(R.string.notification_importance_low);
- case NotificationManager.IMPORTANCE_DEFAULT:
- return getContext().getString(R.string.notification_importance_default);
- case NotificationManager.IMPORTANCE_HIGH:
- case NotificationManager.IMPORTANCE_MAX:
- default:
- return getContext().getString(R.string.notification_importance_high);
- }
-
- }
-
- private Comparator<NotificationChannel> mChannelComparator =
- new Comparator<NotificationChannel>() {
-
- @Override
- public int compare(NotificationChannel left, NotificationChannel right) {
- if (left.isDeleted() != right.isDeleted()) {
- return Boolean.compare(left.isDeleted(), right.isDeleted());
- }
- return left.getId().compareTo(right.getId());
- }
- };
-
private Comparator<NotificationChannelGroup> mChannelGroupComparator =
new Comparator<NotificationChannelGroup>() {
diff --git a/src/com/android/settings/notification/ChannelGroupNotificationSettings.java b/src/com/android/settings/notification/ChannelGroupNotificationSettings.java
new file mode 100644
index 0000000..7837ec8
--- /dev/null
+++ b/src/com/android/settings/notification/ChannelGroupNotificationSettings.java
@@ -0,0 +1,188 @@
+/*
+ * 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.app.Activity;
+import android.app.NotificationChannel;
+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 com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.widget.FooterPreference;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ChannelGroupNotificationSettings extends NotificationSettingsBase {
+ private static final String TAG = "ChannelGroupSettings";
+
+ private static String KEY_DELETED = "deleted";
+
+ private EntityHeaderController mHeaderPref;
+ private List<Preference> mChannels = new ArrayList();
+ private FooterPreference mDeletedChannels;
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.NOTIFICATION_CHANNEL_GROUP;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null || mChannelGroup == null) {
+ Log.w(TAG, "Missing package or uid or packageinfo or group");
+ finish();
+ return;
+ }
+
+ if (getPreferenceScreen() != null) {
+ getPreferenceScreen().removeAll();
+ }
+ addPreferencesFromResource(R.xml.notification_settings);
+ setupBlock();
+ addHeaderPref();
+ addAppLinkPref();
+ addFooterPref();
+ populateChannelList();
+
+ updateDependents(mChannelGroup.isBlocked());
+ }
+
+ @Override
+ void setupBadge() {
+
+ }
+
+ private void populateChannelList() {
+ if (!mChannels.isEmpty()) {
+ // If there's anything in mChannels, we've called populateChannelList twice.
+ // Clear out existing channels and log.
+ Log.w(TAG, "Notification channel group posted twice to settings - old size " +
+ mChannels.size() + ", new size " + mChannels.size());
+ for (Preference p : mChannels) {
+ getPreferenceScreen().removePreference(p);
+ }
+ }
+ if (mChannelGroup.getChannels().isEmpty()) {
+ Preference empty = new Preference(getPrefContext());
+ empty.setTitle(R.string.no_channels);
+ empty.setEnabled(false);
+ getPreferenceScreen().addPreference(empty);
+ mChannels.add(empty);
+
+ } else {
+ final List<NotificationChannel> channels = mChannelGroup.getChannels();
+ Collections.sort(channels, mChannelComparator);
+ for (NotificationChannel channel : channels) {
+ mChannels.add(populateSingleChannelPrefs(
+ getPreferenceScreen(), channel, getImportanceSummary(channel)));
+ }
+
+ int deletedChannelCount = mBackend.getDeletedChannelCount(mAppRow.pkg, mAppRow.uid);
+ if (deletedChannelCount > 0) {
+ mDeletedChannels = new FooterPreference(getPrefContext());
+ mDeletedChannels.setSelectable(false);
+ mDeletedChannels.setTitle(getResources().getQuantityString(
+ R.plurals.deleted_channels, deletedChannelCount, deletedChannelCount));
+ mDeletedChannels.setEnabled(false);
+ mDeletedChannels.setKey(KEY_DELETED);
+ mDeletedChannels.setOrder(ORDER_LAST);
+ getPreferenceScreen().addPreference(mDeletedChannels);
+ mChannels.add(mDeletedChannels);
+ }
+ }
+
+ updateDependents(mAppRow.banned);
+ }
+
+ private void addHeaderPref() {
+ ArrayMap<String, NotificationBackend.AppRow> rows = new ArrayMap<>();
+ rows.put(mAppRow.pkg, mAppRow);
+ collectConfigActivities(rows);
+ final Activity activity = getActivity();
+ mHeaderPref = EntityHeaderController
+ .newInstance(activity, this /* fragment */, null /* header */)
+ .setRecyclerView(getListView(), getLifecycle());
+ final Preference pref = mHeaderPref
+ .setIcon(mAppRow.icon)
+ .setLabel(mChannelGroup.getName())
+ .setSummary(mAppRow.label)
+ .setPackageName(mAppRow.pkg)
+ .setUid(mAppRow.uid)
+ .setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
+ EntityHeaderController.ActionType.ACTION_NONE)
+ .setHasAppInfoLink(true)
+ .done(activity, getPrefContext());
+ getPreferenceScreen().addPreference(pref);
+ }
+
+ private void addFooterPref() {
+ if (!TextUtils.isEmpty(mChannelGroup.getDescription())) {
+ FooterPreference descPref = new FooterPreference(getPrefContext());
+ descPref.setOrder(ORDER_LAST);
+ descPref.setSelectable(false);
+ descPref.setTitle(mChannelGroup.getDescription());
+ getPreferenceScreen().addPreference(descPref);
+ mChannels.add(descPref);
+ }
+ }
+
+ private 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(!mChannelGroup.isBlocked());
+ mSwitchBar.addOnSwitchChangeListener((switchView, isChecked) -> {
+ mChannelGroup.setBlocked(!isChecked);
+ mBackend.updateChannelGroup(mPkg, mUid, mChannelGroup);
+ updateDependents(!isChecked);
+ });
+
+ mBlockBar = new LayoutPreference(getPrefContext(), switchBarContainer);
+ mBlockBar.setOrder(ORDER_FIRST);
+ mBlockBar.setKey(KEY_BLOCK);
+ getPreferenceScreen().addPreference(mBlockBar);
+
+ if (!isChannelGroupBlockable(mChannelGroup)) {
+ setVisible(mBlockBar, false);
+ }
+
+ setupBlockDesc(R.string.channel_group_notifications_off_desc);
+ }
+
+ protected void updateDependents(boolean banned) {
+ for (Preference channel : mChannels) {
+ setVisible(channel, !banned);
+ }
+ if (mAppLink != null) {
+ setVisible(mAppLink, !banned);
+ }
+ setVisible(mBlockBar, isChannelGroupBlockable(mChannelGroup));
+ setVisible(mBlockedDesc, mAppRow.banned || mChannelGroup.isBlocked());
+ }
+}
diff --git a/src/com/android/settings/notification/ChannelNotificationSettings.java b/src/com/android/settings/notification/ChannelNotificationSettings.java
index 2f95dd2..41f9801 100644
--- a/src/com/android/settings/notification/ChannelNotificationSettings.java
+++ b/src/com/android/settings/notification/ChannelNotificationSettings.java
@@ -26,6 +26,7 @@
import android.os.AsyncTask;
import android.provider.Settings;
import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceGroup;
import android.text.TextUtils;
import android.text.BidiFormatter;
import android.text.SpannableStringBuilder;
@@ -57,6 +58,7 @@
private static final String KEY_VIBRATE = "vibrate";
private static final String KEY_RINGTONE = "ringtone";
private static final String KEY_IMPORTANCE = "importance";
+ private static final String KEY_ADVANCED = "advanced";
private Preference mImportance;
private RestrictedSwitchPreference mLights;
@@ -65,6 +67,7 @@
private FooterPreference mFooter;
private NotificationChannelGroup mChannelGroup;
private EntityHeaderController mHeaderPref;
+ private PreferenceGroup mAdvanced;
@Override
public int getMetricsCategory() {
@@ -96,24 +99,10 @@
populateUpgradedChannelPrefs();
if (mChannel.getGroup() != null) {
- // Go look up group name
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... unused) {
- if (mChannel.getGroup() != null) {
- mChannelGroup = mBackend.getGroup(mChannel.getGroup(), mPkg, mUid);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Void unused) {
- if (getHost() == null || mChannelGroup == null) {
- return;
- }
- setChannelGroupLabel(mChannelGroup.getName());
- }
- }.execute();
+ mChannelGroup = mBackend.getGroup(mPkg, mUid, mChannel.getGroup());
+ if (mChannelGroup != null) {
+ setChannelGroupLabel(mChannelGroup.getName());
+ }
}
}
@@ -129,6 +118,7 @@
setupVibrate();
setupRingtone();
setupImportance();
+ mAdvanced = (PreferenceGroup) findPreference(KEY_ADVANCED);
}
private void addHeaderPref() {
@@ -272,7 +262,7 @@
mBlockBar.setKey(KEY_BLOCK);
getPreferenceScreen().addPreference(mBlockBar);
- if (!isChannelBlockable(mAppRow.systemApp, mChannel)) {
+ if (!isChannelBlockable(mChannel)) {
setVisible(mBlockBar, false);
}
@@ -373,6 +363,7 @@
if (mShowLegacyChannelConfig) {
setVisible(mImportanceToggle, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
} else {
+ setVisible(mAdvanced, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
setVisible(mImportance, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
setVisible(mLights, checkCanBeVisible(
NotificationManager.IMPORTANCE_DEFAULT) && canPulseLight());
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index 82e3a9e..4de528e 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -136,8 +136,7 @@
}
}
-
- public NotificationChannelGroup getGroup(String groupId, String pkg, int uid) {
+ public NotificationChannelGroup getGroup(String pkg, int uid, String groupId) {
if (groupId == null) {
return null;
}
@@ -149,7 +148,19 @@
}
}
- public ParceledListSlice<NotificationChannelGroup> getChannelGroups(String pkg, int uid) {
+ public NotificationChannelGroup getGroupWithChannels(String pkg, int uid, String groupId) {
+ if (groupId == null) {
+ return null;
+ }
+ try {
+ return sINM.getPopulatedNotificationChannelGroupForPackage(pkg, uid, groupId, true);
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return null;
+ }
+ }
+
+ public ParceledListSlice<NotificationChannelGroup> getGroups(String pkg, int uid) {
try {
return sINM.getNotificationChannelGroupsForPackage(pkg, uid, false);
} catch (Exception e) {
@@ -166,6 +177,15 @@
}
}
+ public void updateChannelGroup(String pkg, int uid, NotificationChannelGroup group) {
+ try {
+ sINM.updateNotificationChannelGroupForPackage(pkg, uid, group);
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ }
+ }
+
+
public int getDeletedChannelCount(String pkg, int uid) {
try {
return sINM.getDeletedChannelCount(pkg, uid);
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 3849882..8c70a20 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -24,8 +24,10 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.LayoutPreference;
+import com.android.settings.widget.MasterSwitchPreference;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedSwitchPreference;
@@ -33,6 +35,7 @@
import android.app.Notification;
import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -51,8 +54,8 @@
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.support.v7.preference.PreferenceGroup;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -61,6 +64,7 @@
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
abstract public class NotificationSettingsBase extends SettingsPreferenceFragment {
@@ -106,6 +110,7 @@
protected EnforcedAdmin mSuspendedAppsAdmin;
protected boolean mDndVisualEffectsSuppressed;
+ protected NotificationChannelGroup mChannelGroup;
protected NotificationChannel mChannel;
protected NotificationBackend.AppRow mAppRow;
protected boolean mShowLegacyChannelConfig = false;
@@ -185,6 +190,11 @@
mChannel = (args != null && args.containsKey(Settings.EXTRA_CHANNEL_ID)) ?
mBackend.getChannel(mPkg, mUid, args.getString(Settings.EXTRA_CHANNEL_ID)) : null;
+ mChannelGroup = (args != null && args.containsKey(Settings.EXTRA_CHANNEL_GROUP_ID)) ?
+ mBackend.getGroupWithChannels(mPkg, mUid,
+ args.getString(Settings.EXTRA_CHANNEL_GROUP_ID))
+ : null;
+
mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
mContext, mPkg, mUserId);
NotificationManager.Policy policy = mNm.getNotificationPolicy();
@@ -249,6 +259,10 @@
if (mChannel != null) {
row.settingsIntent.putExtra(Notification.EXTRA_CHANNEL_ID, mChannel.getId());
}
+ if (mChannelGroup != null) {
+ row.settingsIntent.putExtra(
+ Notification.EXTRA_CHANNEL_GROUP_ID, mChannelGroup.getId());
+ }
}
}
@@ -276,7 +290,7 @@
protected void addAppLinkPref() {
if (mAppRow.settingsIntent != null && mAppLink == null) {
addPreferencesFromResource(R.xml.inapp_notification_settings);
- mAppLink = (Preference) findPreference(KEY_APP_LINK);
+ mAppLink = findPreference(KEY_APP_LINK);
mAppLink.setIntent(mAppRow.settingsIntent);
}
}
@@ -392,16 +406,56 @@
}
protected void setupBlockDesc(int summaryResId) {
- mBlockedDesc = (FooterPreference) getPreferenceScreen().findPreference(
- KEY_BLOCKED_DESC);
mBlockedDesc = new FooterPreference(getPrefContext());
mBlockedDesc.setSelectable(false);
mBlockedDesc.setTitle(summaryResId);
mBlockedDesc.setEnabled(false);
mBlockedDesc.setOrder(50);
+ mBlockedDesc.setKey(KEY_BLOCKED_DESC);
getPreferenceScreen().addPreference(mBlockedDesc);
}
+ protected Preference populateSingleChannelPrefs(PreferenceGroup parent,
+ final NotificationChannel channel, String summary) {
+ MasterSwitchPreference channelPref = new MasterSwitchPreference(
+ getPrefContext());
+ channelPref.setSwitchEnabled(mSuspendedAppsAdmin == null
+ && isChannelBlockable(channel)
+ && isChannelConfigurable(channel));
+ channelPref.setKey(channel.getId());
+ channelPref.setTitle(channel.getName());
+ channelPref.setChecked(channel.getImportance() != IMPORTANCE_NONE);
+ channelPref.setSummary(summary);
+ Bundle channelArgs = new Bundle();
+ channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
+ channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
+ channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
+ Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
+ ChannelNotificationSettings.class.getName(),
+ channelArgs, null, R.string.notification_channel_title, null, false,
+ getMetricsCategory());
+ channelPref.setIntent(channelIntent);
+
+ channelPref.setOnPreferenceChangeListener(
+ new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference,
+ Object o) {
+ boolean value = (Boolean) o;
+ int importance = value ? IMPORTANCE_LOW : IMPORTANCE_NONE;
+ channel.setImportance(importance);
+ channel.lockFields(
+ NotificationChannel.USER_LOCKED_IMPORTANCE);
+ channelPref.setSummary(summary);
+ mBackend.updateChannel(mPkg, mUid, channel);
+
+ return true;
+ }
+ });
+ parent.addPreference(channelPref);
+ return channelPref;
+ }
+
protected boolean checkCanBeVisible(int minImportanceVisible) {
int importance = mChannel.getImportance();
if (importance == NotificationManager.IMPORTANCE_UNSPECIFIED) {
@@ -410,6 +464,26 @@
return importance >= minImportanceVisible;
}
+ protected String getImportanceSummary(NotificationChannel channel) {
+ switch (channel.getImportance()) {
+ case NotificationManager.IMPORTANCE_UNSPECIFIED:
+ return getContext().getString(R.string.notification_importance_unspecified);
+ case NotificationManager.IMPORTANCE_NONE:
+ return getContext().getString(R.string.notification_toggle_off);
+ case NotificationManager.IMPORTANCE_MIN:
+ return getContext().getString(R.string.notification_importance_min);
+ case NotificationManager.IMPORTANCE_LOW:
+ return getContext().getString(R.string.notification_importance_low);
+ case NotificationManager.IMPORTANCE_DEFAULT:
+ return getContext().getString(R.string.notification_importance_default);
+ case NotificationManager.IMPORTANCE_HIGH:
+ case NotificationManager.IMPORTANCE_MAX:
+ default:
+ return getContext().getString(R.string.notification_importance_high);
+ }
+
+ }
+
private void setRestrictedIfNotificationFeaturesDisabled(CharSequence entry,
CharSequence entryValue, int keyguardNotificationFeatures) {
RestrictedLockUtils.EnforcedAdmin admin =
@@ -459,7 +533,7 @@
return !channel.getId().equals(mAppRow.lockedChannelId);
}
- protected boolean isChannelBlockable(boolean systemApp, NotificationChannel channel) {
+ protected boolean isChannelBlockable(NotificationChannel channel) {
if (!mAppRow.systemApp) {
return true;
}
@@ -468,6 +542,14 @@
|| channel.getImportance() == NotificationManager.IMPORTANCE_NONE;
}
+ protected boolean isChannelGroupBlockable(NotificationChannelGroup group) {
+ if (!mAppRow.systemApp) {
+ return true;
+ }
+
+ return group.isBlocked();
+ }
+
protected void startListeningToPackageRemove() {
if (mListeningToPackageRemove) {
return;
@@ -501,4 +583,12 @@
}
}
};
+
+ protected Comparator<NotificationChannel> mChannelComparator =
+ (left, right) -> {
+ if (left.isDeleted() != right.isDeleted()) {
+ return Boolean.compare(left.isDeleted(), right.isDeleted());
+ }
+ return left.getId().compareTo(right.getId());
+ };
}
diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable
index 695342e..a08536a 100644
--- a/tests/robotests/assets/grandfather_not_implementing_indexable
+++ b/tests/robotests/assets/grandfather_not_implementing_indexable
@@ -23,6 +23,7 @@
com.android.settings.deviceinfo.Status
com.android.settings.datausage.DataSaverSummary
com.android.settings.notification.ChannelNotificationSettings
+com.android.settings.notification.ChannelGroupNotificationSettings
com.android.settings.datausage.AppDataUsage
com.android.settings.accessibility.FontSizePreferenceFragmentForSetupWizard
com.android.settings.applications.ManageDomainUrls
diff --git a/tests/unit/src/com/android/settings/notification/AppNotificationSettingsTest.java b/tests/unit/src/com/android/settings/notification/AppNotificationSettingsTest.java
index 22e98c7..16a0b43 100644
--- a/tests/unit/src/com/android/settings/notification/AppNotificationSettingsTest.java
+++ b/tests/unit/src/com/android/settings/notification/AppNotificationSettingsTest.java
@@ -16,7 +16,29 @@
package com.android.settings.notification;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import android.support.test.espresso.intent.Intents;
+
+import static android.support.test.espresso.intent.Intents.intended;
+import static android.support.test.espresso.intent.matcher.IntentMatchers.hasExtra;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.junit.Assert.fail;
+
import android.app.Instrumentation;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
@@ -29,12 +51,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
-import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static org.hamcrest.Matchers.allOf;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class AppNotificationSettingsTest {
@@ -42,10 +58,29 @@
private Context mTargetContext;
private Instrumentation mInstrumentation;
+ NotificationManager mNm;
+ private NotificationChannelGroup mGroup1;
+ private NotificationChannel mGroup1Channel1;
+ private NotificationChannel mGroup1Channel2;
+ private NotificationChannelGroup mGroup2;
+ private NotificationChannel mGroup2Channel1;
+ private NotificationChannel mUngroupedChannel;
+
@Before
public void setUp() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mTargetContext = mInstrumentation.getTargetContext();
+ mNm = (NotificationManager) mTargetContext.getSystemService(Context.NOTIFICATION_SERVICE);
+
+ mGroup1 = new NotificationChannelGroup(this.getClass().getName() + "1", "group1");
+ mGroup2 = new NotificationChannelGroup(this.getClass().getName() + "2", "group2");
+ mNm.createNotificationChannelGroup(mGroup1);
+ mNm.createNotificationChannelGroup(mGroup2);
+
+ mGroup1Channel1 = createChannel(mGroup1, this.getClass().getName()+ "c1-1");
+ mGroup1Channel2 = createChannel(mGroup1, this.getClass().getName()+ "c1-2");
+ mGroup2Channel1 = createChannel(mGroup2, this.getClass().getName()+ "c2-1");
+ mUngroupedChannel = createChannel(null, this.getClass().getName()+ "c");
}
@Test
@@ -60,4 +95,72 @@
.check(doesNotExist());
}
+ @Test
+ public void launchNotificationSetting_showGroupsWithMultipleChannels() {
+ final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName());
+ mInstrumentation.startActivitySync(intent);
+ onView(allOf(withText(mGroup1.getName().toString()))).check(
+ matches(isDisplayed()));
+ try {
+ onView(allOf(withText(mGroup1Channel1.getName().toString())))
+ .check(matches(isDisplayed()));
+ fail("Channel erroneously appearing");
+ } catch (Exception e) {
+ // expected
+ }
+ // links to group page
+ Intents.init();
+ onView(allOf(withText(mGroup1.getName().toString()))).perform(click());
+ intended(allOf(hasExtra(EXTRA_SHOW_FRAGMENT,
+ ChannelGroupNotificationSettings.class.getName())));
+ Intents.release();
+ }
+
+ @Test
+ public void launchNotificationSetting_showUngroupedChannels() {
+ final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName());
+ mInstrumentation.startActivitySync(intent);
+ onView(allOf(withText(mUngroupedChannel.getName().toString())))
+ .check(matches(isDisplayed()));
+ // links directly to channel page
+ Intents.init();
+ onView(allOf(withText(mUngroupedChannel.getName().toString()))).perform(click());
+ intended(allOf(hasExtra(EXTRA_SHOW_FRAGMENT, ChannelNotificationSettings.class.getName())));
+ Intents.release();
+ }
+
+ @Test
+ public void launchNotificationSetting_showGroupsWithOneChannel() {
+ final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName());
+ mInstrumentation.startActivitySync(intent);
+
+ onView(allOf(withText(mGroup2Channel1.getName().toString())))
+ .check(matches(isDisplayed()));
+ try {
+ onView(allOf(withText(mGroup2.getName().toString()))).check(
+ matches(isDisplayed()));
+ fail("Group erroneously appearing");
+ } catch (Exception e) {
+ // expected
+ }
+
+ // links directly to channel page
+ Intents.init();
+ onView(allOf(withText(mGroup2Channel1.getName().toString()))).perform(click());
+ intended(allOf(hasExtra(EXTRA_SHOW_FRAGMENT, ChannelNotificationSettings.class.getName())));
+ Intents.release();
+ }
+
+ private NotificationChannel createChannel(NotificationChannelGroup group,
+ String id) {
+ NotificationChannel channel = new NotificationChannel(id, id, IMPORTANCE_DEFAULT);
+ if (group != null) {
+ channel.setGroup(group.getId());
+ }
+ mNm.createNotificationChannel(channel);
+ return channel;
+ }
}
diff --git a/tests/unit/src/com/android/settings/notification/ChannelGroupNotificationSettingsTest.java b/tests/unit/src/com/android/settings/notification/ChannelGroupNotificationSettingsTest.java
new file mode 100644
index 0000000..ce2c408
--- /dev/null
+++ b/tests/unit/src/com/android/settings/notification/ChannelGroupNotificationSettingsTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.junit.Assert.fail;
+
+import android.app.INotificationManager;
+import android.app.Instrumentation;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ChannelGroupNotificationSettingsTest {
+
+ private Context mTargetContext;
+ private Instrumentation mInstrumentation;
+ private NotificationManager mNm;
+
+ @Before
+ public void setUp() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mTargetContext = mInstrumentation.getTargetContext();
+ mNm = (NotificationManager) mTargetContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ @Test
+ public void launchNotificationSetting_displaysChannels() {
+ NotificationChannelGroup group =
+ new NotificationChannelGroup(this.getClass().getName(), this.getClass().getName());
+ group.setDescription("description");
+ NotificationChannel channel = new NotificationChannel(this.getClass().getName(),
+ "channel" + this.getClass().getName(), IMPORTANCE_MIN);
+ channel.setGroup(this.getClass().getName());
+ NotificationChannel channel2 = new NotificationChannel("2"+this.getClass().getName(),
+ "2channel" + this.getClass().getName(), IMPORTANCE_MIN);
+ channel2.setGroup(this.getClass().getName());
+
+ mNm.createNotificationChannelGroup(group);
+ mNm.createNotificationChannel(channel);
+ mNm.createNotificationChannel(channel2);
+
+ final Intent intent = new Intent(Settings.ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName())
+ .putExtra(Settings.EXTRA_CHANNEL_GROUP_ID, group.getId());
+
+ mInstrumentation.startActivitySync(intent);
+
+ onView(allOf(withText(group.getName().toString()))).check(matches(isDisplayed()));
+ onView(allOf(withText(channel.getName().toString()))).check(
+ matches(isDisplayed()));
+ onView(allOf(withText(group.getDescription().toString()))).check(
+ matches(isDisplayed()));
+ onView(allOf(withText(channel2.getName().toString()))).check(
+ matches(isDisplayed()));
+ try {
+ onView(allOf(withText("Android is blocking this group of notifications from"
+ + " appearing on this device"))).check(matches(isDisplayed()));
+ fail("Blocking footer erroneously appearing");
+ } catch (Exception e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void launchNotificationSettings_blockedGroup() throws Exception {
+ NotificationChannelGroup blocked =
+ new NotificationChannelGroup("blocked", "blocked");
+ NotificationChannel channel =
+ new NotificationChannel("channel", "channel", IMPORTANCE_HIGH);
+ channel.setGroup(blocked.getId());
+ mNm.createNotificationChannelGroup(blocked);
+ mNm.createNotificationChannel(channel);
+
+ INotificationManager sINM = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ blocked.setBlocked(true);
+ sINM.updateNotificationChannelGroupForPackage(
+ mTargetContext.getPackageName(), Process.myUid(), blocked);
+
+ final Intent intent = new Intent(Settings.ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName())
+ .putExtra(Settings.EXTRA_CHANNEL_GROUP_ID, blocked.getId());
+ mInstrumentation.startActivitySync(intent);
+
+ onView(allOf(withText("Off"), isDisplayed())).check(matches(isDisplayed()));
+ onView(allOf(withText("Android is blocking this group of notifications from"
+ + " appearing on this device"))).check(matches(isDisplayed()));
+
+ try {
+ onView(allOf(withText(channel.getName().toString()))).check(matches(isDisplayed()));
+ fail("settings appearing for blocked group");
+ } catch (Exception e) {
+ // expected
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/settings/notification/ChannelNotificationSettingsTest.java b/tests/unit/src/com/android/settings/notification/ChannelNotificationSettingsTest.java
new file mode 100644
index 0000000..1244dcd
--- /dev/null
+++ b/tests/unit/src/com/android/settings/notification/ChannelNotificationSettingsTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.NotificationManager.IMPORTANCE_MIN;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.junit.Assert.fail;
+
+import android.app.INotificationManager;
+import android.app.Instrumentation;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ChannelNotificationSettingsTest {
+
+ private Context mTargetContext;
+ private Instrumentation mInstrumentation;
+ private NotificationChannel mNotificationChannel;
+ private NotificationManager mNm;
+
+ @Before
+ public void setUp() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mTargetContext = mInstrumentation.getTargetContext();
+
+ mNm = (NotificationManager) mTargetContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mNotificationChannel = new NotificationChannel(this.getClass().getName(),
+ this.getClass().getName(), IMPORTANCE_MIN);
+ mNm.createNotificationChannel(mNotificationChannel);
+ }
+
+ @Test
+ public void launchNotificationSetting_shouldNotCrash() {
+ final Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName())
+ .putExtra(Settings.EXTRA_CHANNEL_ID, mNotificationChannel.getId());
+ mInstrumentation.startActivitySync(intent);
+
+ onView(allOf(withText(mNotificationChannel.getName().toString()))).check(
+ matches(isDisplayed()));
+ }
+
+ @Test
+ public void launchNotificationSettings_blockedChannel() throws Exception {
+ NotificationChannel blocked =
+ new NotificationChannel("blocked", "blocked", IMPORTANCE_NONE);
+ mNm.createNotificationChannel(blocked);
+
+ INotificationManager sINM = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ blocked.setImportance(IMPORTANCE_NONE);
+ sINM.updateNotificationChannelForPackage(
+ mTargetContext.getPackageName(), Process.myUid(), blocked);
+
+ final Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName())
+ .putExtra(Settings.EXTRA_CHANNEL_ID, blocked.getId());
+ mInstrumentation.startActivitySync(intent);
+
+ onView(allOf(withText("Off"), isDisplayed())).check(matches(isDisplayed()));
+ onView(allOf(withText("Android is blocking this category of notifications from"
+ + " appearing on this device"))).check(matches(isDisplayed()));
+
+ try {
+ onView(allOf(withText("On the lock screen"))).check(matches(isDisplayed()));
+ fail("settings appearing for blocked channel");
+ } catch (Exception e) {
+ // expected
+ }
+ }
+}