Limit unconfigurability to specified channels. am: 80fa6b5833
am: 0320d4e69f
Change-Id: Icc6ba97501c229ae8d5bf5a7169feae2af85f3a2
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index c5b8379..db060b6 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -211,7 +211,8 @@
MasterSwitchPreference channelPref = new MasterSwitchPreference(
getPrefContext());
channelPref.setSwitchEnabled(mSuspendedAppsAdmin == null
- && isChannelBlockable(mAppRow.systemApp, channel));
+ && isChannelBlockable(mAppRow.systemApp, channel)
+ && isChannelConfigurable(channel));
channelPref.setKey(channel.getId());
channelPref.setTitle(channel.getName());
channelPref.setChecked(channel.getImportance() != IMPORTANCE_NONE);
diff --git a/src/com/android/settings/notification/ChannelNotificationSettings.java b/src/com/android/settings/notification/ChannelNotificationSettings.java
index 63434b4..c873c07 100644
--- a/src/com/android/settings/notification/ChannelNotificationSettings.java
+++ b/src/com/android/settings/notification/ChannelNotificationSettings.java
@@ -213,7 +213,7 @@
private void setupVibrate() {
mVibrate = (RestrictedSwitchPreference) findPreference(KEY_VIBRATE);
mVibrate.setDisabledByAdmin(mSuspendedAppsAdmin);
- mVibrate.setEnabled(!(mAppRow.lockedImportance || mVibrate.isDisabledByAdmin()));
+ mVibrate.setEnabled(!mVibrate.isDisabledByAdmin() && isChannelConfigurable(mChannel));
mVibrate.setChecked(mChannel.shouldVibrate());
mVibrate.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
@@ -230,7 +230,7 @@
private void setupRingtone() {
mRingtone = (NotificationSoundPreference) findPreference(KEY_RINGTONE);
mRingtone.setRingtone(mChannel.getSound());
- mRingtone.setEnabled(!(mAppRow.lockedImportance));
+ mRingtone.setEnabled(isChannelConfigurable(mChannel));
mRingtone.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
@@ -286,7 +286,7 @@
channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
channelArgs.putString(Settings.EXTRA_CHANNEL_ID, mChannel.getId());
- mImportance.setEnabled(mSuspendedAppsAdmin == null && !mAppRow.lockedImportance);
+ mImportance.setEnabled(mSuspendedAppsAdmin == null && isChannelConfigurable(mChannel));
// Set up intent to show importance selection only if this setting is enabled.
if (mImportance.isEnabled()) {
Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index 96737db..82e3a9e 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -30,6 +30,7 @@
import android.util.IconDrawableFactory;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.Utils;
public class NotificationBackend {
@@ -60,15 +61,28 @@
row.systemApp = Utils.isSystemPackage(context.getResources(), pm, app);
final String[] nonBlockablePkgs = context.getResources().getStringArray(
com.android.internal.R.array.config_nonBlockableNotificationPackages);
+ markAppRowWithBlockables(nonBlockablePkgs, row, app.packageName);
+ return row;
+ }
+
+ @VisibleForTesting static void markAppRowWithBlockables(String[] nonBlockablePkgs, AppRow row,
+ String packageName) {
if (nonBlockablePkgs != null) {
int N = nonBlockablePkgs.length;
for (int i = 0; i < N; i++) {
- if (app.packageName.equals(nonBlockablePkgs[i])) {
+ String pkg = nonBlockablePkgs[i];
+ if (pkg == null) {
+ continue;
+ } else if (pkg.contains(":")) {
+ // Interpret as channel; lock only this channel for this app.
+ if (packageName.equals(pkg.split(":", 2)[0])) {
+ row.lockedChannelId = pkg.split(":", 2 )[1];
+ }
+ } else if (packageName.equals(nonBlockablePkgs[i])) {
row.systemApp = row.lockedImportance = true;
}
}
}
- return row;
}
public boolean getNotificationsBanned(String pkg, int uid) {
@@ -184,6 +198,7 @@
public boolean first; // first app in section
public boolean systemApp;
public boolean lockedImportance;
+ public String lockedChannelId;
public boolean showBadge;
public int userId;
}
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 911c827..48ca207 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -293,8 +293,8 @@
private void setupImportanceToggle() {
mImportanceToggle = (RestrictedSwitchPreference) findPreference(KEY_ALLOW_SOUND);
mImportanceToggle.setDisabledByAdmin(mSuspendedAppsAdmin);
- mImportanceToggle.setEnabled(!(mAppRow.lockedImportance
- || mImportanceToggle.isDisabledByAdmin()));
+ mImportanceToggle.setEnabled(isChannelConfigurable(mChannel)
+ && !mImportanceToggle.isDisabledByAdmin());
mImportanceToggle.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT
|| mChannel.getImportance() == IMPORTANCE_UNSPECIFIED);
mImportanceToggle.setOnPreferenceChangeListener(
@@ -315,7 +315,7 @@
protected void setupPriorityPref(boolean priority) {
mPriority = (RestrictedSwitchPreference) findPreference(KEY_BYPASS_DND);
mPriority.setDisabledByAdmin(mSuspendedAppsAdmin);
- mPriority.setEnabled(!(mAppRow.lockedImportance || mPriority.isDisabledByAdmin()));
+ mPriority.setEnabled(isChannelConfigurable(mChannel) && !mPriority.isDisabledByAdmin());
mPriority.setChecked(priority);
mPriority.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
@@ -447,10 +447,15 @@
return lockscreenSecure;
}
+ protected boolean isChannelConfigurable(NotificationChannel channel) {
+ return !channel.getId().equals(mAppRow.lockedChannelId);
+ }
+
protected boolean isChannelBlockable(boolean systemApp, NotificationChannel channel) {
if (!mAppRow.systemApp) {
return true;
}
+
return channel.isBlockableSystem()
|| channel.getImportance() == NotificationManager.IMPORTANCE_NONE;
}
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationBackendTest.java b/tests/robotests/src/com/android/settings/notification/NotificationBackendTest.java
new file mode 100644
index 0000000..d380900
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/NotificationBackendTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.NotificationManager;
+import android.app.NotificationManager.Policy;
+import android.content.Context;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.notification.NotificationBackend.AppRow;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import org.robolectric.annotation.Config;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class NotificationBackendTest {
+
+ @Test
+ public void testMarkAppRow_unblockablePackage() {
+ AppRow appRow = new AppRow();
+ String packageName = "foo.bar.unblockable";
+ appRow.pkg = packageName;
+ String[] nonBlockablePkgs = new String[2];
+ nonBlockablePkgs[0] = packageName;
+ nonBlockablePkgs[1] = "some.other.package";
+ NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, appRow, packageName);
+
+ // This package has a package lock but no locked channels
+ assertTrue(appRow.lockedImportance);
+ assertNull(appRow.lockedChannelId);
+ }
+
+ @Test
+ public void testMarkAppRow_unblockableChannelOrPkg() {
+ String channelBlockName = "foo.bar.pkgWithChannel";
+ String pkgBlockName = "foo.bar.pkgBlock";
+ String[] nonBlockablePkgs = new String[2];
+ nonBlockablePkgs[0] = pkgBlockName;
+ nonBlockablePkgs[1] = channelBlockName + ":SpecificChannel";
+
+ // This package has a channel level lock but no full package lock
+ AppRow channelBlockApp = new AppRow();
+ channelBlockApp.pkg = channelBlockName;
+ NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, channelBlockApp,
+ channelBlockName);
+ assertFalse(channelBlockApp.lockedImportance);
+ assertEquals("SpecificChannel", channelBlockApp.lockedChannelId);
+
+ // This other package has the reverse
+ AppRow pkgBlock = new AppRow();
+ pkgBlock.pkg = pkgBlockName;
+ NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, pkgBlock, pkgBlockName);
+ assertTrue(pkgBlock.lockedImportance);
+ assertNull(pkgBlock.lockedChannelId);
+
+ // This third package has no locks at all
+ AppRow otherAppRow = new AppRow();
+ otherAppRow.pkg ="foo.bar.nothingBlocked";
+ NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, otherAppRow,
+ "foo.bar.nothingBlocked");
+ assertFalse(otherAppRow.lockedImportance);
+ assertNull(otherAppRow.lockedChannelId);
+ }
+
+ @Test
+ public void testMarkAppRow_unblockableChannelAndPkg() {
+ AppRow appRow = new AppRow();
+ String packageName = "foo.bar.unblockable";
+ appRow.pkg = packageName;
+ String[] nonBlockablePkgs = new String[2];
+ nonBlockablePkgs[0] = "foo.bar.unblockable";
+ nonBlockablePkgs[1] = "foo.bar.unblockable:SpecificChannel";
+ NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, appRow, packageName);
+
+ // This package has both a channel lock and a package lock
+ assertTrue(appRow.lockedImportance);
+ assertEquals("SpecificChannel", appRow.lockedChannelId);
+ }
+
+ @Test
+ public void testMarkAppRow_channelNameWithColons() {
+ AppRow appRow = new AppRow();
+ String packageName = "foo.bar.unblockable";
+ String channelName = "SpecificChannel:1234:abc:defg";
+ appRow.pkg = packageName;
+ String[] nonBlockablePkgs = new String[1];
+ nonBlockablePkgs[0] = packageName + ":" + channelName;
+ NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, appRow, packageName);
+
+ assertEquals(channelName, appRow.lockedChannelId);
+ }
+
+
+ @Test
+ public void testMarkAppRow_blocklistWithNullEntries() {
+ AppRow appRow = new AppRow();
+ String packageName = "foo.bar.unblockable";
+ appRow.pkg = packageName;
+ String[] nonBlockablePkgs = new String[6]; // extra long list with some entries left null
+ nonBlockablePkgs[2] = "foo.bar.unblockable";
+ nonBlockablePkgs[4] = "foo.bar.unblockable:SpecificChannel";
+ NotificationBackend.markAppRowWithBlockables(nonBlockablePkgs, appRow, packageName);
+
+ assertTrue(appRow.lockedImportance);
+ assertEquals("SpecificChannel", appRow.lockedChannelId);
+ }
+}