summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Julia Reynolds <juliacr@google.com> 2019-01-11 10:38:08 -0500
committer Julia Reynolds <juliacr@google.com> 2019-01-14 14:03:55 +0000
commit413ba846b377a1dd094ce94fa6ded78104de8b51 (patch)
tree7355c732139116c21ddf91bb91dae26accd81809
parent5ca575ae71493aedfbd93da032692ad5a1d50f27 (diff)
Don't allow importance updates for oem locked channels
Test: atest, make sure missed call notifications are no longer demoted by aosp notification assistant Change-Id: I80728bae67501d64359e0dac02dca928c34a7e95 Fixes: 122657004
-rw-r--r--api/test-current.txt5
-rw-r--r--core/java/android/app/NotificationChannel.java64
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java3
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java54
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java48
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java117
7 files changed, 273 insertions, 21 deletions
diff --git a/api/test-current.txt b/api/test-current.txt
index 957f957d21a3..89ab8028686a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -219,6 +219,11 @@ package android.app {
method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean);
}
+ public final class NotificationChannel implements android.os.Parcelable {
+ method public boolean isImportanceLockedByOEM();
+ method public void setImportanceLockedByOEM(boolean);
+ }
+
public final class NotificationChannelGroup implements android.os.Parcelable {
method public int getUserLockedFields();
method public void lockFields(int);
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 41ceaafa56a9..950e9aa939f8 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -19,6 +19,7 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.NotificationManager.Importance;
import android.content.ContentResolver;
@@ -168,6 +169,7 @@ public final class NotificationChannel implements Parcelable {
// If this is a blockable system notification channel.
private boolean mBlockableSystem = false;
private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+ private boolean mImportanceLockedByOEM;
/**
* Creates a notification channel.
@@ -230,6 +232,7 @@ public final class NotificationChannel implements Parcelable {
mLightColor = in.readInt();
mBlockableSystem = in.readBoolean();
mAllowAppOverlay = in.readBoolean();
+ mImportanceLockedByOEM = in.readBoolean();
}
@Override
@@ -283,6 +286,7 @@ public final class NotificationChannel implements Parcelable {
dest.writeInt(mLightColor);
dest.writeBoolean(mBlockableSystem);
dest.writeBoolean(mAllowAppOverlay);
+ dest.writeBoolean(mImportanceLockedByOEM);
}
/**
@@ -649,6 +653,22 @@ public final class NotificationChannel implements Parcelable {
}
/**
+ * @hide
+ */
+ @TestApi
+ public void setImportanceLockedByOEM(boolean locked) {
+ mImportanceLockedByOEM = locked;
+ }
+
+ /**
+ * @hide
+ */
+ @TestApi
+ public boolean isImportanceLockedByOEM() {
+ return mImportanceLockedByOEM;
+ }
+
+ /**
* Returns whether the user has chosen the importance of this channel, either to affirm the
* initial selection from the app, or changed it to be higher or lower.
* @see #getImportance()
@@ -952,25 +972,26 @@ public final class NotificationChannel implements Parcelable {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NotificationChannel that = (NotificationChannel) o;
- return getImportance() == that.getImportance() &&
- mBypassDnd == that.mBypassDnd &&
- getLockscreenVisibility() == that.getLockscreenVisibility() &&
- mLights == that.mLights &&
- getLightColor() == that.getLightColor() &&
- getUserLockedFields() == that.getUserLockedFields() &&
- isFgServiceShown() == that.isFgServiceShown() &&
- mVibrationEnabled == that.mVibrationEnabled &&
- mShowBadge == that.mShowBadge &&
- isDeleted() == that.isDeleted() &&
- isBlockableSystem() == that.isBlockableSystem() &&
- mAllowAppOverlay == that.mAllowAppOverlay &&
- Objects.equals(getId(), that.getId()) &&
- Objects.equals(getName(), that.getName()) &&
- Objects.equals(mDesc, that.mDesc) &&
- Objects.equals(getSound(), that.getSound()) &&
- Arrays.equals(mVibration, that.mVibration) &&
- Objects.equals(getGroup(), that.getGroup()) &&
- Objects.equals(getAudioAttributes(), that.getAudioAttributes());
+ return getImportance() == that.getImportance()
+ && mBypassDnd == that.mBypassDnd
+ && getLockscreenVisibility() == that.getLockscreenVisibility()
+ && mLights == that.mLights
+ && getLightColor() == that.getLightColor()
+ && getUserLockedFields() == that.getUserLockedFields()
+ && isFgServiceShown() == that.isFgServiceShown()
+ && mVibrationEnabled == that.mVibrationEnabled
+ && mShowBadge == that.mShowBadge
+ && isDeleted() == that.isDeleted()
+ && isBlockableSystem() == that.isBlockableSystem()
+ && mAllowAppOverlay == that.mAllowAppOverlay
+ && Objects.equals(getId(), that.getId())
+ && Objects.equals(getName(), that.getName())
+ && Objects.equals(mDesc, that.mDesc)
+ && Objects.equals(getSound(), that.getSound())
+ && Arrays.equals(mVibration, that.mVibration)
+ && Objects.equals(getGroup(), that.getGroup())
+ && Objects.equals(getAudioAttributes(), that.getAudioAttributes())
+ && mImportanceLockedByOEM == that.mImportanceLockedByOEM;
}
@Override
@@ -979,7 +1000,8 @@ public final class NotificationChannel implements Parcelable {
getLockscreenVisibility(), getSound(), mLights, getLightColor(),
getUserLockedFields(),
isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
- getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay);
+ getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay,
+ mImportanceLockedByOEM);
result = 31 * result + Arrays.hashCode(mVibration);
return result;
}
@@ -1007,6 +1029,7 @@ public final class NotificationChannel implements Parcelable {
+ ", mAudioAttributes=" + mAudioAttributes
+ ", mBlockableSystem=" + mBlockableSystem
+ ", mAllowAppOverlay=" + mAllowAppOverlay
+ + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ '}';
pw.println(prefix + output);
}
@@ -1033,6 +1056,7 @@ public final class NotificationChannel implements Parcelable {
+ ", mAudioAttributes=" + mAudioAttributes
+ ", mBlockableSystem=" + mBlockableSystem
+ ", mAllowAppOverlay=" + mAllowAppOverlay
+ + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ '}';
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7ecdad27c505..7b7a3ec9809d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1581,6 +1581,9 @@ public class NotificationManagerService extends SystemService {
mIsAutomotive =
mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
+
+ mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
+ com.android.internal.R.array.config_nonBlockableNotificationPackages));
}
@Override
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 2ec7773dfdb1..559874167429 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -785,7 +785,8 @@ public final class NotificationRecord {
mImportanceExplanation = "user";
}
if (!getChannel().hasUserSetImportance()
- && mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
+ && mAssistantImportance != IMPORTANCE_UNSPECIFIED
+ && !getChannel().isImportanceLockedByOEM()) {
mImportance = mAssistantImportance;
mImportanceExplanation = "asst";
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 7c0e0b0983fb..28f6972636be 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -68,6 +68,7 @@ public class PreferencesHelper implements RankingConfig {
private static final String TAG = "NotificationPrefHelper";
private static final int XML_VERSION = 1;
private static final int UNKNOWN_UID = UserHandle.USER_NULL;
+ private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
@VisibleForTesting
static final String TAG_RANKING = "ranking";
@@ -94,6 +95,7 @@ public class PreferencesHelper implements RankingConfig {
private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED;
private static final boolean DEFAULT_SHOW_BADGE = true;
private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+ private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE = false;
/**
* Default value for what fields are user locked. See {@link LockableAppFields} for all lockable
* fields.
@@ -621,6 +623,12 @@ public class PreferencesHelper implements RankingConfig {
channel.setLockscreenVisibility(r.visibility);
}
clearLockedFields(channel);
+ channel.setImportanceLockedByOEM(r.oemLockedImportance);
+ if (!channel.isImportanceLockedByOEM()) {
+ if (r.futureOemLockedChannels.remove(channel.getId())) {
+ channel.setImportanceLockedByOEM(true);
+ }
+ }
if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
channel.setLockscreenVisibility(
NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
@@ -664,6 +672,12 @@ public class PreferencesHelper implements RankingConfig {
} else {
updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
}
+ // no importance updates are allowed if OEM blocked it
+ updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM());
+ if (updatedChannel.isImportanceLockedByOEM()) {
+ updatedChannel.setImportance(channel.getImportance());
+ }
+
r.channels.put(updatedChannel.getId(), updatedChannel);
if (onlyHasDefaultChannel(pkg, uid)) {
@@ -753,6 +767,44 @@ public class PreferencesHelper implements RankingConfig {
}
}
+ public void lockChannelsForOEM(String[] appOrChannelList) {
+ if (appOrChannelList == null) {
+ return;
+ }
+ for (String appOrChannel : appOrChannelList) {
+ if (!TextUtils.isEmpty(appOrChannel)) {
+ String[] appSplit = appOrChannel.split(NON_BLOCKABLE_CHANNEL_DELIM);
+ if (appSplit != null && appSplit.length > 0) {
+ String appName = appSplit[0];
+ String channelId = appSplit.length == 2 ? appSplit[1] : null;
+
+ synchronized (mPackagePreferences) {
+ for (PackagePreferences r : mPackagePreferences.values()) {
+ if (r.pkg.equals(appName)) {
+ if (channelId == null) {
+ // lock all channels for the app
+ r.oemLockedImportance = true;
+ for (NotificationChannel channel : r.channels.values()) {
+ channel.setImportanceLockedByOEM(true);
+ }
+ } else {
+ NotificationChannel channel = r.channels.get(channelId);
+ if (channel != null) {
+ channel.setImportanceLockedByOEM(true);
+ } else {
+ // if this channel shows up in the future, make sure it'll
+ // be locked immediately
+ r.futureOemLockedChannels.add(channelId);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg,
int uid, String groupId, boolean includeDeleted) {
Preconditions.checkNotNull(pkg);
@@ -1604,6 +1656,8 @@ public class PreferencesHelper implements RankingConfig {
boolean showBadge = DEFAULT_SHOW_BADGE;
boolean appOverlay = DEFAULT_ALLOW_APP_OVERLAY;
int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
+ boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
+ List<String> futureOemLockedChannels = new ArrayList<>();
Delegate delegate = null;
ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 9bcbcd5777d2..b9ae7d5e3f93 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -792,4 +792,52 @@ public class NotificationRecordTest extends UiServiceTestCase {
assertFalse(record.isNewEnoughForAlerting(record.mUpdateTimeMs + (1000 * 60 * 60)));
}
+
+ @Test
+ public void testIgnoreImportanceAdjustmentsForOemLockedChannels() {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+ channel.setImportanceLockedByOEM(true);
+
+ StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /* defaultLights */, groupId /* group */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+ assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+
+ Bundle bundle = new Bundle();
+ bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
+ Adjustment adjustment = new Adjustment(
+ PKG_O, record.getKey(), bundle, "", record.getUserId());
+
+ record.addAdjustment(adjustment);
+ record.applyAdjustments();
+ record.calculateImportance();
+
+ assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+ }
+
+ @Test
+ public void testApplyImportanceAdjustmentsForNonOemLockedChannels() {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+ channel.setImportanceLockedByOEM(false);
+
+ StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /* defaultLights */, groupId /* group */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+ assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+
+ Bundle bundle = new Bundle();
+ bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
+ Adjustment adjustment = new Adjustment(
+ PKG_O, record.getKey(), bundle, "", record.getUserId());
+
+ record.addAdjustment(adjustment);
+ record.applyAdjustments();
+ record.calculateImportance();
+
+ assertEquals(IMPORTANCE_LOW, record.getImportance());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 0b7348194b26..0fcfea716e8f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2187,4 +2187,121 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
mHelper.getAppLockedFields(PKG_O, UID_O));
}
+
+ @Test
+ public void testLockChannelsForOEM_emptyList() {
+ mHelper.lockChannelsForOEM(null);
+ mHelper.lockChannelsForOEM(new String[0]);
+ // no exception
+ }
+
+ @Test
+ public void testLockChannelsForOEM_appWide() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+ // different uids, same package
+ mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+ mHelper.createNotificationChannel(PKG_O, 3, b, false, false);
+ mHelper.createNotificationChannel(PKG_O, 30, c, true, true);
+
+ mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+ .isImportanceLockedByOEM());
+ assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
+ .isImportanceLockedByOEM());
+ assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false)
+ .isImportanceLockedByOEM());
+ }
+
+ @Test
+ public void testLockChannelsForOEM_onlyGivenPkg() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+ mHelper.createNotificationChannel(PKG_N_MR1, 30, b, false, false);
+
+ mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+ .isImportanceLockedByOEM());
+ assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 30, b.getId(), false)
+ .isImportanceLockedByOEM());
+ }
+
+ @Test
+ public void testLockChannelsForOEM_channelSpecific() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+ // different uids, same package
+ mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+ mHelper.createNotificationChannel(PKG_O, 3, b, false, false);
+ mHelper.createNotificationChannel(PKG_O, 30, c, true, true);
+
+ mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"});
+
+ assertFalse(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+ .isImportanceLockedByOEM());
+ assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
+ .isImportanceLockedByOEM());
+ assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false)
+ .isImportanceLockedByOEM());
+ }
+
+ @Test
+ public void testLockChannelsForOEM_channelDoesNotExistYet_appWide() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+
+ mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+ .isImportanceLockedByOEM());
+
+ mHelper.createNotificationChannel(PKG_O, 3, b, true, false);
+ assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
+ .isImportanceLockedByOEM());
+ }
+
+ @Test
+ public void testLockChannelsForOEM_channelDoesNotExistYet_channelSpecific() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+ mHelper.lockChannelsForOEM(new String[] {PKG_O + ":a", PKG_O + ":b"});
+
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+ .isImportanceLockedByOEM());
+
+ mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false);
+ assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+ .isImportanceLockedByOEM());
+ }
+
+ @Test
+ public void testUpdateNotificationChannel_oemLockedImportance() {
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+ mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+ NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
+ update.setAllowAppOverlay(false);
+
+ mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
+
+ assertEquals(IMPORTANCE_HIGH,
+ mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+ assertEquals(false,
+ mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canOverlayApps());
+
+ mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
+
+ assertEquals(IMPORTANCE_HIGH,
+ mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+ }
}