Merge "Updates to Adjustment.KEY_IMPORTANCE handling"
This commit is contained in:
committed by
Android (Google) Code Review
commit
61b6eb9127
@@ -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";
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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("",
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user