Merge "Don't auto-dismiss children with certain flags"
This commit is contained in:
@@ -44,6 +44,7 @@ import static java.util.Objects.requireNonNull;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Notification;
|
||||
import android.os.RemoteException;
|
||||
import android.service.notification.NotificationListenerService.Ranking;
|
||||
import android.service.notification.NotificationListenerService.RankingMap;
|
||||
@@ -239,8 +240,7 @@ public class NotifCollection implements Dumpable {
|
||||
// Also mark any children as dismissed as system server will auto-dismiss them as well
|
||||
if (entry.getSbn().getNotification().isGroupSummary()) {
|
||||
for (NotificationEntry otherEntry : mNotificationSet.values()) {
|
||||
if (otherEntry.getSbn().getGroupKey().equals(entry.getSbn().getGroupKey())
|
||||
&& otherEntry.getDismissState() != DISMISSED) {
|
||||
if (shouldAutoDismiss(otherEntry, entry.getSbn().getGroupKey())) {
|
||||
otherEntry.setDismissState(PARENT_DISMISSED);
|
||||
if (isCanceled(otherEntry)) {
|
||||
canceledEntries.add(otherEntry);
|
||||
@@ -544,6 +544,28 @@ public class NotifCollection implements Dumpable {
|
||||
return entry.getDismissState() != NOT_DISMISSED;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a group summary is dismissed, NotificationManager will also try to dismiss its children.
|
||||
* Returns true if we think dismissing the group summary with group key
|
||||
* <code>dismissedGroupKey</code> will cause NotificationManager to also dismiss
|
||||
* <code>entry</code>.
|
||||
*
|
||||
* See NotificationManager.cancelGroupChildrenByListLocked() for corresponding code.
|
||||
*/
|
||||
private static boolean shouldAutoDismiss(
|
||||
NotificationEntry entry,
|
||||
String dismissedGroupKey) {
|
||||
return entry.getSbn().getGroupKey().equals(dismissedGroupKey)
|
||||
&& !entry.getSbn().getNotification().isGroupSummary()
|
||||
&& !hasFlag(entry, Notification.FLAG_FOREGROUND_SERVICE)
|
||||
&& !hasFlag(entry, Notification.FLAG_BUBBLE)
|
||||
&& entry.getDismissState() != DISMISSED;
|
||||
}
|
||||
|
||||
private static boolean hasFlag(NotificationEntry entry, int flag) {
|
||||
return (entry.getSbn().getNotification().flags & flag) != 0;
|
||||
}
|
||||
|
||||
private void dispatchOnEntryInit(NotificationEntry entry) {
|
||||
mAmDispatchingToOtherCode = true;
|
||||
for (NotifCollectionListener listener : mNotifCollectionListeners) {
|
||||
|
||||
@@ -140,6 +140,11 @@ public class SbnBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SbnBuilder setFlag(Context context, int mask, boolean value) {
|
||||
modifyNotification(context).setFlag(mask, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Notification.Builder modifyNotification(Context context) {
|
||||
if (mNotification != null) {
|
||||
mNotificationBuilder = new Notification.Builder(context, mNotification);
|
||||
|
||||
@@ -46,9 +46,12 @@ import static org.mockito.Mockito.when;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Notification;
|
||||
import android.os.RemoteException;
|
||||
import android.service.notification.NotificationListenerService.Ranking;
|
||||
import android.service.notification.NotificationListenerService.RankingMap;
|
||||
import android.service.notification.NotificationStats;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.util.ArrayMap;
|
||||
@@ -733,6 +736,78 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
assertEquals(NOT_DISMISSED, entry1.getDismissState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissingSummaryDoesNotDismissForegroundServiceChildren() {
|
||||
// GIVEN a collection with three grouped notifs in it
|
||||
CollectionEvent notif0 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 0)
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
CollectionEvent notif1 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 1)
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setFlag(mContext, Notification.FLAG_FOREGROUND_SERVICE, true));
|
||||
CollectionEvent notif2 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 2)
|
||||
.setGroup(mContext, GROUP_1));
|
||||
|
||||
// WHEN the summary is dismissed
|
||||
mCollection.dismissNotification(notif0.entry, defaultStats(notif0.entry));
|
||||
|
||||
// THEN the foreground service child is not dismissed
|
||||
assertEquals(DISMISSED, notif0.entry.getDismissState());
|
||||
assertEquals(NOT_DISMISSED, notif1.entry.getDismissState());
|
||||
assertEquals(PARENT_DISMISSED, notif2.entry.getDismissState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissingSummaryDoesNotDismissBubbledChildren() {
|
||||
// GIVEN a collection with three grouped notifs in it
|
||||
CollectionEvent notif0 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 0)
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
CollectionEvent notif1 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 1)
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setFlag(mContext, Notification.FLAG_BUBBLE, true));
|
||||
CollectionEvent notif2 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 2)
|
||||
.setGroup(mContext, GROUP_1));
|
||||
|
||||
// WHEN the summary is dismissed
|
||||
mCollection.dismissNotification(notif0.entry, defaultStats(notif0.entry));
|
||||
|
||||
// THEN the bubbled child is not dismissed
|
||||
assertEquals(DISMISSED, notif0.entry.getDismissState());
|
||||
assertEquals(NOT_DISMISSED, notif1.entry.getDismissState());
|
||||
assertEquals(PARENT_DISMISSED, notif2.entry.getDismissState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissingSummaryDoesNotDismissDuplicateSummaries() {
|
||||
// GIVEN a group with a two summaries
|
||||
CollectionEvent notif0 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 0)
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
CollectionEvent notif1 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 1)
|
||||
.setGroup(mContext, GROUP_1)
|
||||
.setGroupSummary(mContext, true));
|
||||
CollectionEvent notif2 = postNotif(
|
||||
buildNotif(TEST_PACKAGE, 2)
|
||||
.setGroup(mContext, GROUP_1));
|
||||
|
||||
// WHEN the first summary is dismissed
|
||||
mCollection.dismissNotification(notif0.entry, defaultStats(notif0.entry));
|
||||
|
||||
// THEN the second summary is not auto-dismissed (but the child is)
|
||||
assertEquals(DISMISSED, notif0.entry.getDismissState());
|
||||
assertEquals(NOT_DISMISSED, notif1.entry.getDismissState());
|
||||
assertEquals(PARENT_DISMISSED, notif2.entry.getDismissState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifetimeExtendersAreQueriedWhenNotifRemoved() {
|
||||
// GIVEN a couple notifications and a few lifetime extenders
|
||||
@@ -1000,6 +1075,13 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
|
||||
}
|
||||
|
||||
public CollectionEvent postNotif(NotificationEntryBuilder builder) {
|
||||
clearInvocations(mCollectionListener);
|
||||
NotifEvent rawEvent = mNoMan.postNotif(builder);
|
||||
verify(mCollectionListener).onEntryAdded(mEntryCaptor.capture());
|
||||
return new CollectionEvent(rawEvent, requireNonNull(mEntryCaptor.getValue()));
|
||||
}
|
||||
|
||||
private static class RecordingCollectionListener implements NotifCollectionListener {
|
||||
private final Map<String, NotificationEntry> mLastSeenEntries = new ArrayMap<>();
|
||||
|
||||
@@ -1014,6 +1096,7 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
|
||||
@Override
|
||||
public void onEntryUpdated(NotificationEntry entry) {
|
||||
mLastSeenEntries.put(entry.getKey(), entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1098,6 +1181,26 @@ public class NotifCollectionTest extends SysuiTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around {@link NotifEvent} that adds the NotificationEntry that the collection under
|
||||
* test creates.
|
||||
*/
|
||||
private static class CollectionEvent {
|
||||
public final String key;
|
||||
public final StatusBarNotification sbn;
|
||||
public final Ranking ranking;
|
||||
public final RankingMap rankingMap;
|
||||
public final NotificationEntry entry;
|
||||
|
||||
private CollectionEvent(NotifEvent rawEvent, NotificationEntry entry) {
|
||||
this.key = rawEvent.key;
|
||||
this.sbn = rawEvent.sbn;
|
||||
this.ranking = rawEvent.ranking;
|
||||
this.rankingMap = rawEvent.rankingMap;
|
||||
this.entry = entry;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String TEST_PACKAGE = "com.android.test.collection";
|
||||
private static final String TEST_PACKAGE2 = "com.android.test.collection2";
|
||||
|
||||
|
||||
@@ -162,6 +162,11 @@ public class NotificationEntryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public NotificationEntryBuilder setFlag(Context context, int mask, boolean value) {
|
||||
mSbnBuilder.setFlag(context, mask, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/* Delegated to RankingBuilder */
|
||||
|
||||
public NotificationEntryBuilder setRank(int rank) {
|
||||
|
||||
Reference in New Issue
Block a user