Merge "Make bubble flag removals from notification delegate (sysui) sticky" into rvc-dev am: b68f9f985f am: 74b17548d9 am: aabf86c243

Change-Id: I50d31c581e7877185aa2bcb5c54597f27d416998
This commit is contained in:
Mady Mellor
2020-03-27 23:10:19 +00:00
committed by Automerger Merge Worker
5 changed files with 120 additions and 1 deletions

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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());
@@ -5591,6 +5601,67 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
}
@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!