The quietening round 2 part 1
Allow the notification assistant to block or silence
incoming notifications, or demote notifications after they
are posted
Also temporarily silence everything by default
Plus: bonus refactoring of the cancel notification runnable so I could
write just one of those tests :)
Bug: 111475013
Test: manual, runtest systemui-notification
Change-Id: Ifa04a21919f60d06080cd63e7d7747180b641308
diff --git a/api/system-current.txt b/api/system-current.txt
index cb7f7bb..5766a4c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4668,6 +4668,7 @@
method public int getUser();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+ field public static final java.lang.String KEY_IMPORTANCE = "key_importance";
field public static final java.lang.String KEY_PEOPLE = "key_people";
field public static final java.lang.String KEY_SMART_ACTIONS = "key_smart_actions";
field public static final java.lang.String KEY_SMART_REPLIES = "key_smart_replies";
diff --git a/api/test-current.txt b/api/test-current.txt
index 63ece40..9d6c0eb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1047,6 +1047,7 @@
method public int getUser();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+ field public static final java.lang.String KEY_IMPORTANCE = "key_importance";
field public static final java.lang.String KEY_PEOPLE = "key_people";
field public static final java.lang.String KEY_SMART_ACTIONS = "key_smart_actions";
field public static final java.lang.String KEY_SMART_REPLIES = "key_smart_replies";
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 03fd139..09d0c53 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -602,6 +602,13 @@
/**
* @hide
*/
+ public boolean isImportanceLocked() {
+ return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0;
+ }
+
+ /**
+ * @hide
+ */
public void populateFromXmlForRestore(XmlPullParser parser, Context context) {
populateFromXml(parser, true, context);
}
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index e0c354a..518f8ed 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -77,6 +77,18 @@
public static final String KEY_SMART_REPLIES = "key_smart_replies";
/**
+ * Data type: int, one of importance values e.g.
+ * {@link android.app.NotificationManager#IMPORTANCE_MIN}.
+ *
+ * If used from
+ * {@link NotificationAssistantService#onNotificationEnqueued(StatusBarNotification)}, it can
+ * block a notification from appearing or silence it. If used from
+ * {@link NotificationAssistantService#adjustNotification(Adjustment)}, it can visually
+ * demote a notification.
+ */
+ public static final String KEY_IMPORTANCE = "key_importance";
+
+ /**
* Create a notification adjustment.
*
* @param pkg The package of the notification.
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 9d19898..4b4350f 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -16,6 +16,7 @@
package android.ext.services.notification;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.service.notification.NotificationListenerService.Ranking
.USER_SENTIMENT_NEGATIVE;
@@ -204,17 +205,22 @@
@NonNull StatusBarNotification statusBarNotification,
@NonNull ArrayList<Notification.Action> smartActions,
@NonNull ArrayList<CharSequence> smartReplies) {
- if (smartActions.isEmpty() && smartReplies.isEmpty()) {
- return null;
- }
Bundle signals = new Bundle();
- signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
- signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
+ if (!smartActions.isEmpty()) {
+ signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
+ }
+ if (!smartReplies.isEmpty()) {
+ signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
+ }
+
+ // TODO: Apply rules to what gets silenced
+ signals.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
+
return new Adjustment(
statusBarNotification.getPackageName(),
statusBarNotification.getKey(),
signals,
- "smart action, reply" /* explanation */,
+ "",
statusBarNotification.getUserId());
}
diff --git a/services/core/java/com/android/server/notification/ImportanceExtractor.java b/services/core/java/com/android/server/notification/ImportanceExtractor.java
index dfdd55b..ca41b74 100644
--- a/services/core/java/com/android/server/notification/ImportanceExtractor.java
+++ b/services/core/java/com/android/server/notification/ImportanceExtractor.java
@@ -41,7 +41,7 @@
if (DBG) Slog.d(TAG, "missing config");
return null;
}
- record.setUserImportance(record.getChannel().getImportance());
+ record.calculateImportance();
return null;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f487200..7a16925 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3484,20 +3484,25 @@
public void applyAdjustmentsFromAssistant(INotificationListener token,
List<Adjustment> adjustments) {
+ boolean needsSort = false;
final long identity = Binder.clearCallingIdentity();
try {
- boolean appliedAdjustment = false;
synchronized (mNotificationLock) {
mAssistants.checkServiceTokenLocked(token);
for (Adjustment adjustment : adjustments) {
NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
applyAdjustment(r, adjustment);
- appliedAdjustment = true;
+ r.applyAdjustments();
+ if (r.getImportance() == IMPORTANCE_NONE) {
+ cancelNotificationsFromListener(token, new String[]{r.getKey()});
+ } else {
+ needsSort = true;
+ }
}
}
}
- if (appliedAdjustment) {
+ if (needsSort) {
mRankingHandler.requestSort();
}
} finally {
@@ -4118,14 +4123,16 @@
// an opinion otherwise (and the channel hasn't yet shown a fg service).
if (TextUtils.isEmpty(channelId)
|| NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
- r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
+ r.setSystemImportance(IMPORTANCE_LOW);
} else {
channel.setImportance(IMPORTANCE_LOW);
+ r.setSystemImportance(IMPORTANCE_LOW);
if (!fgServiceShown) {
channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
channel.setFgServiceShown(true);
}
- mPreferencesHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
+ mPreferencesHelper.updateNotificationChannel(
+ pkg, notificationUid, channel, false);
r.updateNotificationChannel(channel);
}
} else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
@@ -4299,11 +4306,7 @@
usageStats.registerSuspendedByAdmin(r);
return isPackageSuspended;
}
- final boolean isBlocked =
- mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
- || mPreferencesHelper.getImportance(pkg, callingUid)
- == NotificationManager.IMPORTANCE_NONE
- || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
+ final boolean isBlocked = isBlocked(r);
if (isBlocked) {
Slog.e(TAG, "Suppressing notification from package by user request.");
usageStats.registerBlocked(r);
@@ -4311,6 +4314,15 @@
return isBlocked;
}
+ private boolean isBlocked(NotificationRecord r) {
+ final String pkg = r.sbn.getPackageName();
+ final int callingUid = r.sbn.getUid();
+ return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
+ || mPreferencesHelper.getImportance(pkg, callingUid)
+ == NotificationManager.IMPORTANCE_NONE
+ || r.getImportance() == NotificationManager.IMPORTANCE_NONE;
+ }
+
protected class SnoozeNotificationRunnable implements Runnable {
private final String mKey;
private final long mDuration;
@@ -4387,6 +4399,88 @@
}
}
+ protected class CancelNotificationRunnable implements Runnable {
+ private final int mCallingUid;
+ private final int mCallingPid;
+ private final String mPkg;
+ private final String mTag;
+ private final int mId;
+ private final int mMustHaveFlags;
+ private final int mMustNotHaveFlags;
+ private final boolean mSendDelete;
+ private final int mUserId;
+ private final int mReason;
+ private final int mRank;
+ private final int mCount;
+ private final ManagedServiceInfo mListener;
+
+ CancelNotificationRunnable(final int callingUid, final int callingPid,
+ final String pkg, final String tag, final int id,
+ final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
+ final int userId, final int reason, int rank, int count,
+ final ManagedServiceInfo listener) {
+ this.mCallingUid = callingUid;
+ this.mCallingPid = callingPid;
+ this.mPkg = pkg;
+ this.mTag = tag;
+ this.mId = id;
+ this.mMustHaveFlags = mustHaveFlags;
+ this.mMustNotHaveFlags = mustNotHaveFlags;
+ this.mSendDelete = sendDelete;
+ this.mUserId = userId;
+ this.mReason = reason;
+ this.mRank = rank;
+ this.mCount = count;
+ this.mListener = listener;
+ }
+
+ @Override
+ public void run() {
+ String listenerName = mListener == null ? null : mListener.component.toShortString();
+ if (DBG) {
+ EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag,
+ mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName);
+ }
+
+ synchronized (mNotificationLock) {
+ // Look for the notification, searching both the posted and enqueued lists.
+ NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
+ if (r != null) {
+ // The notification was found, check if it should be removed.
+
+ // Ideally we'd do this in the caller of this method. However, that would
+ // require the caller to also find the notification.
+ if (mReason == REASON_CLICK) {
+ mUsageStats.registerClickedByUser(r);
+ }
+
+ if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
+ return;
+ }
+ if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
+ return;
+ }
+
+ // Cancel the notification.
+ boolean wasPosted = removeFromNotificationListsLocked(r);
+ cancelNotificationLocked(
+ r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
+ cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
+ mSendDelete, null);
+ updateLightsLocked();
+ } else {
+ // No notification was found, assume that it is snoozed and cancel it.
+ if (mReason != REASON_SNOOZED) {
+ final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
+ if (wasSnoozed) {
+ savePolicyFile();
+ }
+ }
+ }
+ }
+ }
+ }
+
protected class EnqueueNotificationRunnable implements Runnable {
private final NotificationRecord r;
private final int userId;
@@ -4486,6 +4580,11 @@
return;
}
+ if (isBlocked(r)) {
+ Slog.i(TAG, "notification blocked by assistant request");
+ return;
+ }
+
r.setHidden(isPackageSuspendedLocked(r));
NotificationRecord old = mNotificationsByKey.get(key);
final StatusBarNotification n = r.sbn;
@@ -5409,6 +5508,11 @@
}
}
+ protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) {
+ if (!hasCallbacks(cancelRunnable)) {
+ sendMessage(Message.obtain(this, cancelRunnable));
+ }
+ }
}
private final class RankingHandlerWorker extends Handler implements RankingHandler
@@ -5734,56 +5838,15 @@
void cancelNotification(final int callingUid, final int callingPid,
final String pkg, final String tag, final int id,
final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
- final int userId, final int reason, int rank, int count, final ManagedServiceInfo listener) {
-
+ final int userId, final int reason, int rank, int count,
+ final ManagedServiceInfo listener) {
// In enqueueNotificationInternal notifications are added by scheduling the
// work on the worker handler. Hence, we also schedule the cancel on this
// handler to avoid a scenario where an add notification call followed by a
// remove notification call ends up in not removing the notification.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- String listenerName = listener == null ? null : listener.component.toShortString();
- if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
- userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
-
- synchronized (mNotificationLock) {
- // Look for the notification, searching both the posted and enqueued lists.
- NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
- if (r != null) {
- // The notification was found, check if it should be removed.
-
- // Ideally we'd do this in the caller of this method. However, that would
- // require the caller to also find the notification.
- if (reason == REASON_CLICK) {
- mUsageStats.registerClickedByUser(r);
- }
-
- if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
- return;
- }
- if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
- return;
- }
-
- // Cancel the notification.
- boolean wasPosted = removeFromNotificationListsLocked(r);
- cancelNotificationLocked(r, sendDelete, reason, rank, count, wasPosted, listenerName);
- cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
- sendDelete, null);
- updateLightsLocked();
- } else {
- // No notification was found, assume that it is snoozed and cancel it.
- if (reason != REASON_SNOOZED) {
- final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
- if (wasSnoozed) {
- savePolicyFile();
- }
- }
- }
- }
- }
- });
+ mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid,
+ pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank,
+ count, listener));
}
/**
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 469828b..a86927e 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -49,7 +49,6 @@
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.Adjustment;
@@ -142,7 +141,8 @@
private int mAuthoritativeRank;
private String mGlobalSortKey;
private int mPackageVisibility;
- private int mUserImportance = IMPORTANCE_UNSPECIFIED;
+ private int mSystemImportance = IMPORTANCE_UNSPECIFIED;
+ private int mAssistantImportance = IMPORTANCE_UNSPECIFIED;
private int mImportance = IMPORTANCE_UNSPECIFIED;
private CharSequence mImportanceExplanation = null;
@@ -198,7 +198,7 @@
mSound = calculateSound();
mVibration = calculateVibration();
mAttributes = calculateAttributes();
- mImportance = calculateImportance();
+ mImportance = calculateInitialImportance();
mLight = calculateLights();
mAdjustments = new ArrayList<>();
mStats = new NotificationStats();
@@ -321,7 +321,7 @@
return attributes;
}
- private int calculateImportance() {
+ private int calculateInitialImportance() {
final Notification n = sbn.getNotification();
int importance = getChannel().getImportance();
int requestedImportance = IMPORTANCE_DEFAULT;
@@ -525,8 +525,10 @@
pw.println(prefix + "mRecentlyIntrusive=" + mRecentlyIntrusive);
pw.println(prefix + "mPackagePriority=" + mPackagePriority);
pw.println(prefix + "mPackageVisibility=" + mPackageVisibility);
- pw.println(prefix + "mUserImportance="
- + NotificationListenerService.Ranking.importanceToString(mUserImportance));
+ pw.println(prefix + "mSystemImportance="
+ + NotificationListenerService.Ranking.importanceToString(mSystemImportance));
+ pw.println(prefix + "mAsstImportance="
+ + NotificationListenerService.Ranking.importanceToString(mAssistantImportance));
pw.println(prefix + "mImportance="
+ NotificationListenerService.Ranking.importanceToString(mImportance));
pw.println(prefix + "mImportanceExplanation=" + mImportanceExplanation);
@@ -641,6 +643,12 @@
if (signals.containsKey(Adjustment.KEY_SMART_REPLIES)) {
setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES));
}
+ if (signals.containsKey(Adjustment.KEY_IMPORTANCE)) {
+ int importance = signals.getInt(Adjustment.KEY_IMPORTANCE);
+ importance = Math.max(IMPORTANCE_UNSPECIFIED, importance);
+ importance = Math.min(IMPORTANCE_HIGH, importance);
+ setAssistantImportance(importance);
+ }
}
}
}
@@ -654,7 +662,7 @@
mContactAffinity = contactAffinity;
if (mImportance < IMPORTANCE_DEFAULT &&
mContactAffinity > ValidateNotificationPeople.VALID_CONTACT) {
- setImportance(IMPORTANCE_DEFAULT, getPeopleExplanation());
+ setSystemImportance(IMPORTANCE_DEFAULT);
}
}
@@ -693,11 +701,6 @@
return mPackageVisibility;
}
- public void setUserImportance(int importance) {
- mUserImportance = importance;
- applyUserImportance();
- }
-
private String getUserExplanation() {
if (mUserExplanation == null) {
mUserExplanation = mContext.getResources().getString(
@@ -706,31 +709,42 @@
return mUserExplanation;
}
- private String getPeopleExplanation() {
- if (mPeopleExplanation == null) {
- mPeopleExplanation = mContext.getResources().getString(
- com.android.internal.R.string.importance_from_person);
- }
- return mPeopleExplanation;
+ /**
+ * Sets the importance value the system thinks the record should have.
+ * e.g. bumping up foreground service notifications or people to people notifications.
+ */
+ public void setSystemImportance(int importance) {
+ mSystemImportance = importance;
+ calculateImportance();
}
- private void applyUserImportance() {
- if (mUserImportance != IMPORTANCE_UNSPECIFIED) {
- mImportance = mUserImportance;
- mImportanceExplanation = getUserExplanation();
- }
+ /**
+ * Sets the importance value the
+ * {@link android.service.notification.NotificationAssistantService} thinks the record should
+ * have.
+ */
+ public void setAssistantImportance(int importance) {
+ mAssistantImportance = importance;
+ calculateImportance();
}
- public int getUserImportance() {
- return mUserImportance;
- }
-
- public void setImportance(int importance, CharSequence explanation) {
- if (importance != IMPORTANCE_UNSPECIFIED) {
- mImportance = importance;
- mImportanceExplanation = explanation;
+ /**
+ * Recalculates the importance of the record after fields affecting importance have changed
+ */
+ protected void calculateImportance() {
+ mImportance = calculateInitialImportance();
+ mImportanceExplanation = "app";
+ if (getChannel().isImportanceLocked()) {
+ mImportanceExplanation = "user";
}
- applyUserImportance();
+ if (!getChannel().isImportanceLocked() && mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
+ mImportance = mAssistantImportance;
+ mImportanceExplanation = "asst";
+ }
+ if (mSystemImportance != IMPORTANCE_UNSPECIFIED) {
+ mImportance = mSystemImportance;
+ mImportanceExplanation = "system";
+ }
}
public int getImportance() {
@@ -920,7 +934,7 @@
}
/**
- * @see RankingHelper#getIsAppImportanceLocked(String, int)
+ * @see PreferencesHelper#getIsAppImportanceLocked(String, int)
*/
public boolean getIsAppImportanceLocked() {
return mIsAppImportanceLocked;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 7abf49e..59eab3f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -411,7 +411,7 @@
@Test
public void testLights() throws Exception {
NotificationRecord r = getLightsNotification();
- r.setImportance(NotificationManager.IMPORTANCE_DEFAULT, "for testing");
+ r.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
mService.buzzBeepBlinkLocked(r);
@@ -454,7 +454,7 @@
@Test
public void testNoInterruptionForMin() throws Exception {
NotificationRecord r = getBeepyNotification();
- r.setImportance(NotificationManager.IMPORTANCE_MIN, "foo");
+ r.setSystemImportance(NotificationManager.IMPORTANCE_MIN);
mService.buzzBeepBlinkLocked(r);
@@ -1015,7 +1015,7 @@
@Test
public void testA11yMinInitialPost() throws Exception {
NotificationRecord r = getQuietNotification();
- r.setImportance(IMPORTANCE_MIN, "");
+ r.setSystemImportance(IMPORTANCE_MIN);
mService.buzzBeepBlinkLocked(r);
verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt());
}
@@ -1072,7 +1072,7 @@
@Test
public void testLightsUnimportant() {
NotificationRecord r = getLightsNotification();
- r.setImportance(IMPORTANCE_LOW, "testing");
+ r.setSystemImportance(IMPORTANCE_LOW);
mService.buzzBeepBlinkLocked(r);
verifyNeverLights();
assertFalse(r.isInterruptive());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
index 73d5961..abc6e3c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -79,7 +79,7 @@
//
@Test
- public void testAppPreferenceChannelNone() throws Exception {
+ public void testAppPreferenceChannelNone() {
ImportanceExtractor extractor = new ImportanceExtractor();
extractor.setConfig(mConfig);
@@ -93,12 +93,12 @@
extractor.process(r);
- assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, r.getUserImportance());
+ assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, r.getImportance());
assertEquals(notificationImportance, r.getImportance());
}
@Test
- public void testAppPreferenceChannelPreference() throws Exception {
+ public void testAppPreferenceChannelPreference() {
ImportanceExtractor extractor = new ImportanceExtractor();
extractor.setConfig(mConfig);
@@ -111,6 +111,6 @@
extractor.process(r);
- assertEquals(r.getUserImportance(), NotificationManager.IMPORTANCE_HIGH);
+ assertEquals(r.getImportance(), NotificationManager.IMPORTANCE_HIGH);
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
index 7ee0501..b30bb4b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
@@ -110,7 +110,7 @@
mRecordMinCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
callPkg, 1, "minCall", callUid, callUid, n1,
new UserHandle(userId), "", 2000), getDefaultChannel());
- mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
+ mRecordMinCall.setSystemImportance(NotificationManager.IMPORTANCE_MIN);
Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
@@ -119,7 +119,7 @@
mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
callPkg, 1, "highcall", callUid, callUid, n2,
new UserHandle(userId), "", 1999), getDefaultChannel());
- mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+ mRecordHighCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MediaStyle()
@@ -128,14 +128,14 @@
mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "media", uid2, uid2, n3, new UserHandle(userId),
"", 1499), getDefaultChannel());
- mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+ mRecordDefaultMedia.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MessagingStyle("sender!")).build();
mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
"", 1599), getDefaultChannel());
- mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+ mRecordInlineReply.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
if (smsPkg != null) {
@@ -144,7 +144,7 @@
mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
"", 1299), getDefaultChannel());
- mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+ mRecordSms.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
}
Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
@@ -152,20 +152,20 @@
pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId),
"", 1259), getDefaultChannel());
mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
- mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+ mRecordStarredContact.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId),
"", 1259), getDefaultChannel());
mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
- mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+ mRecordContact.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
"", 1258), getDefaultChannel());
- mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+ mRecordUrgent.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE)
@@ -175,7 +175,7 @@
mRecordCheater = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "cheater", uid2, uid2, n9, new UserHandle(userId),
"", 9258), getDefaultChannel());
- mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
+ mRecordCheater.setSystemImportance(NotificationManager.IMPORTANCE_LOW);
mRecordCheater.setPackagePriority(Notification.PRIORITY_MAX);
Notification n10 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -183,7 +183,7 @@
mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId),
"", 1599), getDefaultChannel());
- mRecordEmail.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+ mRecordEmail.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n11 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE)
@@ -192,7 +192,7 @@
mRecordCheaterColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "cheater", uid2, uid2, n11, new UserHandle(userId),
"", 9258), getDefaultChannel());
- mRecordCheaterColorized.setUserImportance(NotificationManager.IMPORTANCE_LOW);
+ mRecordCheaterColorized.setSystemImportance(NotificationManager.IMPORTANCE_LOW);
Notification n12 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE)
@@ -202,7 +202,7 @@
mNoMediaSessionMedia = new NotificationRecord(mContext, new StatusBarNotification(
pkg2, pkg2, 1, "cheater", uid2, uid2, n12, new UserHandle(userId),
"", 9258), getDefaultChannel());
- mNoMediaSessionMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+ mNoMediaSessionMedia.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
Notification n13 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
@@ -211,7 +211,7 @@
mRecordColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "colorized", uid2, uid2, n13,
new UserHandle(userId), "", 1999), getDefaultChannel());
- mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+ mRecordHighCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n14 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
@@ -221,7 +221,7 @@
mRecordColorizedCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
callPkg, 1, "colorizedCall", callUid, callUid, n14,
new UserHandle(userId), "", 1999), getDefaultChannel());
- mRecordColorizedCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+ mRecordColorizedCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 0cbb1aa..4dcb8cf 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -73,7 +73,6 @@
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.IUriGrantsManager;
-import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
@@ -727,6 +726,25 @@
}
@Test
+ public void testBlockedNotifications_blockedByAssistant() throws Exception {
+ when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+
+ NotificationChannel channel = new NotificationChannel("id", "name",
+ NotificationManager.IMPORTANCE_HIGH);
+ NotificationRecord r = generateNotificationRecord(channel);
+ mService.addEnqueuedNotification(r);
+
+ r.setAssistantImportance(IMPORTANCE_NONE);
+
+ NotificationManagerService.PostNotificationRunnable runnable =
+ mService.new PostNotificationRunnable(r.getKey());
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats, never()).registerPostedByApp(any());
+ }
+
+ @Test
public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
@@ -2494,6 +2512,27 @@
}
@Test
+ public void testAssistantIBlockingTriggersCancel() throws Exception {
+ final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ mService.addNotification(r);
+ NotificationManagerService.WorkerHandler handler = mock(
+ NotificationManagerService.WorkerHandler.class);
+ mService.setHandler(handler);
+
+ Bundle signals = new Bundle();
+ signals.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE);
+ Adjustment adjustment = new Adjustment(
+ r.sbn.getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+ mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+
+ waitForIdle();
+
+ verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate();
+ verify(handler, times(1)).scheduleCancelNotification(any());
+ }
+
+ @Test
public void testApplyEnqueuedAdjustmentFromAssistant_singleUser() throws Exception {
final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
mService.addEnqueuedNotification(r);
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 6be633e..11b086c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -16,6 +16,9 @@
package com.android.server.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.service.notification.NotificationListenerService.Ranking
.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking
@@ -306,14 +309,14 @@
@Test
public void testImportance_locked_preUpgrade() throws Exception {
- defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
+ defaultChannel.setImportance(IMPORTANCE_LOW);
defaultChannel.lockFields(USER_LOCKED_IMPORTANCE);
StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /* defaultLights */, null /* group */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
- assertEquals(NotificationManager.IMPORTANCE_LOW, record.getImportance());
+ assertEquals(IMPORTANCE_LOW, record.getImportance());
}
@Test
@@ -718,4 +721,73 @@
record.setSmartActions(smartActions);
assertEquals(smartActions, record.getSmartActions());
}
+
+ @Test
+ public void testUpdateNotificationChannel() {
+ 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(channel.getImportance(), record.getImportance());
+
+ record.updateNotificationChannel(
+ new NotificationChannel(channelId, "", channel.getImportance() - 1));
+
+ assertEquals(channel.getImportance() - 1, record.getImportance());
+ }
+
+ @Test
+ public void testCalculateImportance_systemImportance() {
+ channel.setImportance(IMPORTANCE_HIGH);
+ 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);
+
+ record.setSystemImportance(IMPORTANCE_LOW);
+ assertEquals(IMPORTANCE_LOW, record.getImportance());
+
+ record = new NotificationRecord(mMockContext, sbn, channel);
+ channel.lockFields(USER_LOCKED_IMPORTANCE);
+
+ record.setSystemImportance(IMPORTANCE_LOW);
+ assertEquals(IMPORTANCE_LOW, record.getImportance());
+ }
+
+ @Test
+ public void testCalculateImportance_asstImportance() {
+ channel.setImportance(IMPORTANCE_HIGH);
+ 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);
+
+ record.setAssistantImportance(IMPORTANCE_LOW);
+ assertEquals(IMPORTANCE_LOW, record.getImportance());
+
+ // assistant ignored if user expressed preference
+ record = new NotificationRecord(mMockContext, sbn, channel);
+ channel.lockFields(USER_LOCKED_IMPORTANCE);
+
+ record.setAssistantImportance(IMPORTANCE_LOW);
+ assertEquals(channel.getImportance(), record.getImportance());
+ }
+
+ @Test
+ public void testCalculateImportance_asstImportanceChannelUpdate() {
+ channel.setImportance(IMPORTANCE_HIGH);
+ 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);
+
+ record.setAssistantImportance(IMPORTANCE_LOW);
+ assertEquals(IMPORTANCE_LOW, record.getImportance());
+
+ record.updateNotificationChannel(
+ new NotificationChannel(channelId, "", IMPORTANCE_DEFAULT));
+
+ assertEquals(IMPORTANCE_LOW, record.getImportance());
+ }
}