Merge "Updates to Adjustment.KEY_IMPORTANCE handling"

This commit is contained in:
TreeHugger Robot
2018-12-11 23:25:32 +00:00
committed by Android (Google) Code Review
5 changed files with 117 additions and 42 deletions

View File

@@ -80,11 +80,18 @@ public final class Adjustment implements Parcelable {
* 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.
* <p> If used from
* {@link NotificationAssistantService#onNotificationEnqueued(StatusBarNotification)}, and
* received before the notification is posted, it can block a notification from appearing or
* silence it. Importance adjustments received too late from
* {@link NotificationAssistantService#onNotificationEnqueued(StatusBarNotification)} will be
* ignored.
* </p>
* <p>If used from
* {@link NotificationAssistantService#adjustNotification(Adjustment)}, it can
* visually demote or cancel a notification, but use this with care if they notification was
* recently posted because the notification may already have made noise.
* </p>
*/
public static final String KEY_IMPORTANCE = "key_importance";

View File

@@ -3621,12 +3621,19 @@ public class NotificationManagerService extends SystemService {
&& mAssistants.isSameUser(token, r.getUserId())) {
applyAdjustment(r, adjustment);
r.applyAdjustments();
// importance is checked at the beginning of the
// PostNotificationRunnable, before the signal extractors are run, so
// calculate the final importance here
r.calculateImportance();
foundEnqueued = true;
break;
}
}
if (!foundEnqueued) {
// adjustment arrived too late to apply to enqueued; apply to posted
// However, since the notification is now posted and may have alerted,
// ignore any importance related adjustments
adjustment.getSignals().remove(Adjustment.KEY_IMPORTANCE);
applyAdjustmentFromAssistant(token, adjustment);
}
}
@@ -3656,8 +3663,12 @@ public class NotificationManagerService extends SystemService {
NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
applyAdjustment(r, adjustment);
r.applyImportanceFromAdjustments();
if (r.getImportance() == IMPORTANCE_NONE) {
// If the assistant has blocked the notification, cancel it
// This will trigger a sort, so we don't have to explicitly ask for
// one here.
if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE)
&& adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE)
== IMPORTANCE_NONE) {
cancelNotificationsFromListener(token, new String[]{r.getKey()});
} else {
needsSort = true;
@@ -4758,7 +4769,6 @@ public class NotificationManagerService extends SystemService {
enqueueStatus);
}
mRankingHelper.extractSignals(r);
// tell the assistant service about the notification
if (mAssistants.isEnabled()) {
mAssistants.onNotificationEnqueuedLocked(r);
@@ -4842,7 +4852,7 @@ public class NotificationManagerService extends SystemService {
| Notification.FLAG_NO_CLEAR;
}
applyZenModeLocked(r);
mRankingHelper.extractSignals(r);
mRankingHelper.sort(mNotificationList);
if (!r.isHidden()) {
@@ -5627,6 +5637,7 @@ public class NotificationManagerService extends SystemService {
ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
ArrayList<ArrayList<Notification.Action>> systemSmartActionsBefore = new ArrayList<>(N);
ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N);
int[] importancesBefore = new int[N];
for (int i = 0; i < N; i++) {
final NotificationRecord r = mNotificationList.get(i);
orderBefore.add(r.getKey());
@@ -5640,6 +5651,7 @@ public class NotificationManagerService extends SystemService {
suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
systemSmartActionsBefore.add(r.getSystemGeneratedSmartActions());
smartRepliesBefore.add(r.getSmartReplies());
importancesBefore[i] = r.getImportance();
mRankingHelper.extractSignals(r);
}
mRankingHelper.sort(mNotificationList);
@@ -5657,7 +5669,8 @@ public class NotificationManagerService extends SystemService {
r.getSuppressedVisualEffects())
|| !Objects.equals(systemSmartActionsBefore.get(i),
r.getSystemGeneratedSmartActions())
|| !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())) {
|| !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())
|| importancesBefore[i] != r.getImportance()) {
mHandler.scheduleSendRankingUpdate();
return;
}

View File

@@ -21,10 +21,8 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.service.notification.NotificationListenerService.Ranking
.USER_SENTIMENT_NEUTRAL;
import static android.service.notification.NotificationListenerService.Ranking
.USER_SENTIMENT_POSITIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -609,6 +607,17 @@ public final class NotificationRecord {
mIsAppImportanceLocked, this.sbn.getNotification());
}
public boolean hasAdjustment(String key) {
synchronized (mAdjustments) {
for (Adjustment adjustment : mAdjustments) {
if (adjustment.getSignals().containsKey(key)) {
return true;
}
}
}
return false;
}
public void addAdjustment(Adjustment adjustment) {
synchronized (mAdjustments) {
mAdjustments.add(adjustment);
@@ -669,18 +678,6 @@ public final class NotificationRecord {
.addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_REPLIES,
getSmartReplies().size()));
}
}
applyImportanceFromAdjustments();
}
}
/**
* Update importance from the adjustment.
*/
public void applyImportanceFromAdjustments() {
synchronized (mAdjustments) {
for (Adjustment adjustment : mAdjustments) {
Bundle signals = adjustment.getSignals();
if (signals.containsKey(Adjustment.KEY_IMPORTANCE)) {
int importance = signals.getInt(Adjustment.KEY_IMPORTANCE);
importance = Math.max(IMPORTANCE_UNSPECIFIED, importance);
@@ -752,6 +749,8 @@ public final class NotificationRecord {
*/
public void setSystemImportance(int importance) {
mSystemImportance = importance;
// System importance is only changed in enqueue, so it's ok for us to calculate the
// importance directly instead of waiting for signal extractor.
calculateImportance();
}
@@ -762,7 +761,16 @@ public final class NotificationRecord {
*/
public void setAssistantImportance(int importance) {
mAssistantImportance = importance;
calculateImportance();
// Unlike the system importance, the assistant importance can change on posted
// notifications, so don't calculateImportance() here, but wait for the signal extractors.
}
/**
* Returns the importance set by the assistant, or IMPORTANCE_UNSPECIFIED if the assistant
* hasn't set it.
*/
public int getAssistantImportance() {
return mAssistantImportance;
}
/**
@@ -774,7 +782,8 @@ public final class NotificationRecord {
if (getChannel().hasUserSetImportance()) {
mImportanceExplanation = "user";
}
if (!getChannel().hasUserSetImportance() && mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
if (!getChannel().hasUserSetImportance()
&& mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
mImportance = mAssistantImportance;
mImportanceExplanation = "asst";
}

View File

@@ -20,6 +20,7 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREG
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MAX;
@@ -183,7 +184,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Resources mResources;
private NotificationChannel mTestNotificationChannel = new NotificationChannel(
TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
@Mock
private NotificationListeners mListeners;
@Mock private NotificationAssistants mAssistants;
@@ -430,7 +431,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCreateNotificationChannels_SingleChannel() throws Exception {
final NotificationChannel channel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel)));
final NotificationChannel createdChannel =
@@ -452,9 +453,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCreateNotificationChannels_TwoChannels() throws Exception {
final NotificationChannel channel1 =
new NotificationChannel("id1", "name", NotificationManager.IMPORTANCE_DEFAULT);
new NotificationChannel("id1", "name", IMPORTANCE_DEFAULT);
final NotificationChannel channel2 =
new NotificationChannel("id2", "name", NotificationManager.IMPORTANCE_DEFAULT);
new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel1, channel2)));
assertTrue(mBinderService.getNotificationChannel(PKG, "id1") != null);
@@ -465,7 +466,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()
throws Exception {
final NotificationChannel channel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel)));
@@ -476,14 +477,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
new ParceledListSlice(Arrays.asList(dupeChannel)));
final NotificationChannel createdChannel =
mBinderService.getNotificationChannel(PKG, "id");
assertEquals(NotificationManager.IMPORTANCE_DEFAULT, createdChannel.getImportance());
assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
}
@Test
public void testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()
throws Exception {
final NotificationChannel channel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel)));
@@ -501,7 +502,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()
throws Exception {
final NotificationChannel channel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel)));
@@ -524,14 +525,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()
throws Exception {
final NotificationChannel channel1 =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
final NotificationChannel channel2 =
new NotificationChannel("id", "name", IMPORTANCE_HIGH);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel1, channel2)));
final NotificationChannel createdChannel =
mBinderService.getNotificationChannel(PKG, "id");
assertEquals(NotificationManager.IMPORTANCE_DEFAULT, createdChannel.getImportance());
assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
}
@Test
@@ -756,13 +757,18 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testBlockedNotifications_blockedByAssistant() throws Exception {
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
NotificationChannel channel = new NotificationChannel("id", "name",
NotificationManager.IMPORTANCE_HIGH);
NotificationRecord r = generateNotificationRecord(channel);
mService.addEnqueuedNotification(r);
r.setAssistantImportance(IMPORTANCE_NONE);
Bundle bundle = new Bundle();
bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE);
Adjustment adjustment = new Adjustment(
r.sbn.getPackageName(), r.getKey(), bundle, "", r.getUser().getIdentifier());
mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(r.getKey());
@@ -1814,7 +1820,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mListener = mock(ManagedServices.ManagedServiceInfo.class);
when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
try {
try {
mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
null, PKG, Process.myUserHandle());
fail("listeners that don't have a companion device shouldn't be able to call this");
@@ -2617,7 +2623,7 @@ try {
}
@Test
public void testAssistantIBlockingTriggersCancel() throws Exception {
public void testAssistantBlockingTriggersCancel() throws Exception {
final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
mService.addNotification(r);
NotificationManagerService.WorkerHandler handler = mock(
@@ -2656,6 +2662,43 @@ try {
assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment());
}
@Test
public void testApplyEnqueuedAdjustmentFromAssistant_importance_onTime() throws Exception {
final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
mService.addEnqueuedNotification(r);
NotificationManagerService.WorkerHandler handler = mock(
NotificationManagerService.WorkerHandler.class);
mService.setHandler(handler);
when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
Bundle signals = new Bundle();
signals.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
Adjustment adjustment = new Adjustment(
r.sbn.getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
assertEquals(IMPORTANCE_LOW, r.getImportance());
}
@Test
public void testApplyEnqueuedAdjustmentFromAssistant_importance_tooLate() throws Exception {
final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
mService.addNotification(r);
NotificationManagerService.WorkerHandler handler = mock(
NotificationManagerService.WorkerHandler.class);
mService.setHandler(handler);
when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
Bundle signals = new Bundle();
signals.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
Adjustment adjustment = new Adjustment(
r.sbn.getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
assertEquals(IMPORTANCE_DEFAULT, r.getImportance());
assertFalse(r.hasAdjustment(Adjustment.KEY_IMPORTANCE));
}
@Test
public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception {
final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
@@ -2856,7 +2899,7 @@ try {
@Test
public void updateUriPermissions_update() throws Exception {
NotificationChannel c = new NotificationChannel(
TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
Message message1 = new Message("", 0, "");
message1.setData("",

View File

@@ -760,6 +760,7 @@ public class NotificationRecordTest extends UiServiceTestCase {
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.setAssistantImportance(IMPORTANCE_LOW);
record.calculateImportance();
assertEquals(IMPORTANCE_LOW, record.getImportance());
// assistant ignored if user expressed preference
@@ -767,6 +768,7 @@ public class NotificationRecordTest extends UiServiceTestCase {
channel.lockFields(USER_LOCKED_IMPORTANCE);
record.setAssistantImportance(IMPORTANCE_LOW);
record.calculateImportance();
assertEquals(channel.getImportance(), record.getImportance());
}
@@ -779,6 +781,7 @@ public class NotificationRecordTest extends UiServiceTestCase {
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.setAssistantImportance(IMPORTANCE_LOW);
record.calculateImportance();
assertEquals(IMPORTANCE_LOW, record.getImportance());
record.updateNotificationChannel(