summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/notification/BubbleExtractor.java3
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java14
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java30
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java71
5 files changed, 120 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java
index f2eb176aa676..2fa80cd8e4e4 100644
--- a/services/core/java/com/android/server/notification/BubbleExtractor.java
+++ b/services/core/java/com/android/server/notification/BubbleExtractor.java
@@ -76,7 +76,8 @@ public class BubbleExtractor implements NotificationSignalExtractor {
record.setAllowBubble(appCanShowBubble);
}
}
- final boolean applyFlag = mBubbleChecker.isNotificationAppropriateToBubble(record);
+ final boolean applyFlag = mBubbleChecker.isNotificationAppropriateToBubble(record)
+ && !record.isFlagBubbleRemoved();
if (applyFlag) {
record.getNotification().flags |= FLAG_BUBBLE;
} else {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 87061e1d488c..ebc1bc4938d6 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1214,10 +1214,12 @@ public class NotificationManagerService extends SystemService {
// apps querying noMan will know that their notification is not showing
// as a bubble.
r.getNotification().flags &= ~FLAG_BUBBLE;
+ r.setFlagBubbleRemoved(true);
} else {
// Enqueue will trigger resort & if the flag is allowed to be true it'll
// be applied there.
r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
+ r.setFlagBubbleRemoved(false);
mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(),
r, isAppForeground));
}
@@ -5637,6 +5639,7 @@ public class NotificationManagerService extends SystemService {
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
r.setPostSilently(postSilently);
+ r.setFlagBubbleRemoved(false);
if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
final boolean fgServiceShown = channel.isFgServiceShown();
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 3f24b38161c3..54a0f9f46892 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -187,6 +187,7 @@ public final class NotificationRecord {
private boolean mSuggestionsGeneratedByAssistant;
private boolean mEditChoicesBeforeSending;
private boolean mHasSeenSmartReplies;
+ private boolean mFlagBubbleRemoved;
private boolean mPostSilently;
/**
* Whether this notification (and its channels) should be considered user locked. Used in
@@ -1201,6 +1202,19 @@ public final class NotificationRecord {
return stats.hasBeenVisiblyExpanded();
}
+ /**
+ * When the bubble state on a notif changes due to user action (e.g. dismiss a bubble) then
+ * this value is set until an update or bubble change event due to user action (e.g. create
+ * bubble from sysui)
+ **/
+ public boolean isFlagBubbleRemoved() {
+ return mFlagBubbleRemoved;
+ }
+
+ public void setFlagBubbleRemoved(boolean flagBubbleRemoved) {
+ mFlagBubbleRemoved = flagBubbleRemoved;
+ }
+
public void setSystemGeneratedSmartActions(
ArrayList<Notification.Action> systemGeneratedSmartActions) {
mSystemGeneratedSmartActions = systemGeneratedSmartActions;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
index c7cef05ce442..0dbbbaa9cdd6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
@@ -47,6 +47,7 @@ import org.mockito.MockitoAnnotations;
public class BubbleExtractorTest extends UiServiceTestCase {
@Mock RankingConfig mConfig;
+ @Mock BubbleExtractor.BubbleChecker mBubbleChecker;
BubbleExtractor mBubbleExtractor;
private String mPkg = "com.android.server.notification";
@@ -141,4 +142,33 @@ public class BubbleExtractorTest extends UiServiceTestCase {
assertFalse(r.canBubble());
}
+
+ @Test
+ public void testFlagBubble_true() {
+ when(mConfig.bubblesEnabled()).thenReturn(true);
+ when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+
+ mBubbleExtractor.setBubbleChecker(mBubbleChecker);
+ when(mBubbleChecker.isNotificationAppropriateToBubble(r)).thenReturn(true);
+ mBubbleExtractor.process(r);
+
+ assertTrue(r.canBubble());
+ assertTrue(r.getNotification().isBubbleNotification());
+ }
+
+ @Test
+ public void testFlagBubble_noFlag_previouslyRemoved() {
+ when(mConfig.bubblesEnabled()).thenReturn(true);
+ when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+ r.setFlagBubbleRemoved(true);
+
+ mBubbleExtractor.setBubbleChecker(mBubbleChecker);
+ when(mBubbleChecker.isNotificationAppropriateToBubble(r)).thenReturn(true);
+ mBubbleExtractor.process(r);
+
+ assertTrue(r.canBubble());
+ assertFalse(r.getNotification().isBubbleNotification());
+ }
}
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 d2417f9d10c5..702642045eeb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -78,6 +78,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
import android.app.IActivityManager;
@@ -154,6 +155,7 @@ import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer;
+import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiServiceTestCase;
@@ -380,12 +382,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
MockitoAnnotations.initMocks(this);
+ DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
+ when(deviceIdleInternal.getNotificationWhitelistDuration()).thenReturn(3000L);
+ ActivityManagerInternal activityManagerInternal = mock(ActivityManagerInternal.class);
+
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
LocalServices.addService(StatusBarManagerInternal.class, mStatusBar);
+ LocalServices.removeServiceForTest(DeviceIdleInternal.class);
+ LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.addService(ActivityManagerInternal.class, activityManagerInternal);
doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
@@ -5592,6 +5602,67 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testNotificationBubbleIsFlagRemoved_resetOnUpdate() throws Exception {
+ // Bubbles are allowed!
+ setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */);
+ // Notif with bubble metadata
+ NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
+ "testNotificationBubbleIsFlagRemoved_resetOnUpdate");
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ // Flag shouldn't be modified
+ NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
+ assertFalse(recordToCheck.isFlagBubbleRemoved());
+
+ // Notify we're not a bubble
+ mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false);
+ waitForIdle();
+ // Flag should be modified
+ recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
+ assertTrue(recordToCheck.isFlagBubbleRemoved());
+
+
+ // Update the notif
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ // And the flag is reset
+ recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
+ assertFalse(recordToCheck.isFlagBubbleRemoved());
+ }
+
+ @Test
+ public void testNotificationBubbleIsFlagRemoved_resetOnBubbleChangedTrue() throws Exception {
+ // Bubbles are allowed!
+ setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */);
+ // Notif with bubble metadata
+ NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
+ "testNotificationBubbleIsFlagRemoved_trueOnBubbleChangedTrue");
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ // Flag shouldn't be modified
+ NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
+ assertFalse(recordToCheck.isFlagBubbleRemoved());
+
+ // Notify we're not a bubble
+ mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false);
+ waitForIdle();
+ // Flag should be modified
+ recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey());
+ assertTrue(recordToCheck.isFlagBubbleRemoved());
+
+ // Notify we are a bubble
+ mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true);
+ waitForIdle();
+ // And the flag is reset
+ assertFalse(recordToCheck.isFlagBubbleRemoved());
+ }
+
+ @Test
public void testOnBubbleNotificationSuppressionChanged() throws Exception {
// Bubbles are allowed!
setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */);