If something is suppressed from the notification list don't bubble it
Also set it to not auto-expand since it's unexpected to have bubbles expand when DND turns off. Test: BubblesTest NewNotifPipelineBubblesTest Bug: 226316876 Change-Id: Ieb77b211f2b11fea83a2ff6e34e6f31b0f96919e
This commit is contained in:
@@ -1037,7 +1037,15 @@ public class BubbleController {
|
||||
}
|
||||
} else {
|
||||
Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */);
|
||||
inflateAndAdd(bubble, suppressFlyout, showInShade);
|
||||
if (notif.shouldSuppressNotificationList()) {
|
||||
// If we're suppressing notifs for DND, we don't want the bubbles to randomly
|
||||
// expand when DND turns off so flip the flag.
|
||||
if (bubble.shouldAutoExpand()) {
|
||||
bubble.setShouldAutoExpand(false);
|
||||
}
|
||||
} else {
|
||||
inflateAndAdd(bubble, suppressFlyout, showInShade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1069,7 +1077,8 @@ public class BubbleController {
|
||||
}
|
||||
}
|
||||
|
||||
private void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp) {
|
||||
@VisibleForTesting
|
||||
public void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp) {
|
||||
// shouldBubbleUp checks canBubble & for bubble metadata
|
||||
boolean shouldBubble = shouldBubbleUp && canLaunchInTaskView(mContext, entry);
|
||||
if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
|
||||
@@ -1095,7 +1104,8 @@ public class BubbleController {
|
||||
}
|
||||
}
|
||||
|
||||
private void onRankingUpdated(RankingMap rankingMap,
|
||||
@VisibleForTesting
|
||||
public void onRankingUpdated(RankingMap rankingMap,
|
||||
HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey) {
|
||||
if (mTmpRanking == null) {
|
||||
mTmpRanking = new NotificationListenerService.Ranking();
|
||||
@@ -1106,19 +1116,22 @@ public class BubbleController {
|
||||
Pair<BubbleEntry, Boolean> entryData = entryDataByKey.get(key);
|
||||
BubbleEntry entry = entryData.first;
|
||||
boolean shouldBubbleUp = entryData.second;
|
||||
|
||||
if (entry != null && !isCurrentProfile(
|
||||
entry.getStatusBarNotification().getUser().getIdentifier())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry != null && (entry.shouldSuppressNotificationList()
|
||||
|| entry.getRanking().isSuspended())) {
|
||||
shouldBubbleUp = false;
|
||||
}
|
||||
rankingMap.getRanking(key, mTmpRanking);
|
||||
boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
|
||||
if (isActiveBubble && !mTmpRanking.canBubble()) {
|
||||
boolean isActiveOrInOverflow = mBubbleData.hasAnyBubbleWithKey(key);
|
||||
boolean isActive = mBubbleData.hasBubbleInStackWithKey(key);
|
||||
if (isActiveOrInOverflow && !mTmpRanking.canBubble()) {
|
||||
// If this entry is no longer allowed to bubble, dismiss with the BLOCKED reason.
|
||||
// This means that the app or channel's ability to bubble has been revoked.
|
||||
mBubbleData.dismissBubbleWithKey(key, DISMISS_BLOCKED);
|
||||
} else if (isActiveBubble && (!shouldBubbleUp || entry.getRanking().isSuspended())) {
|
||||
} else if (isActiveOrInOverflow && !shouldBubbleUp) {
|
||||
// If this entry is allowed to bubble, but cannot currently bubble up or is
|
||||
// suspended, dismiss it. This happens when DND is enabled and configured to hide
|
||||
// bubbles, or focus mode is enabled and the app is designated as distracting.
|
||||
@@ -1126,9 +1139,9 @@ public class BubbleController {
|
||||
// notification, so that the bubble will be re-created if shouldBubbleUp returns
|
||||
// true.
|
||||
mBubbleData.dismissBubbleWithKey(key, DISMISS_NO_BUBBLE_UP);
|
||||
} else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
|
||||
} else if (entry != null && mTmpRanking.isBubble() && !isActive) {
|
||||
entry.setFlagBubble(true);
|
||||
onEntryUpdated(entry, shouldBubbleUp && !entry.getRanking().isSuspended());
|
||||
onEntryUpdated(entry, shouldBubbleUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,6 +1057,22 @@ public class BubbleData {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pending bubble with given notification <code>key</code>
|
||||
*
|
||||
* @param key notification key
|
||||
* @return bubble that matches or null
|
||||
*/
|
||||
@VisibleForTesting(visibility = PRIVATE)
|
||||
public Bubble getPendingBubbleWithKey(String key) {
|
||||
for (Bubble b : mPendingBubbles.values()) {
|
||||
if (b.getKey().equals(key)) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = PRIVATE)
|
||||
void setTimeSource(TimeSource timeSource) {
|
||||
mTimeSource = timeSource;
|
||||
|
||||
@@ -57,6 +57,7 @@ import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
@@ -70,6 +71,8 @@ import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
@@ -147,6 +150,7 @@ import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -1466,6 +1470,50 @@ public class BubblesTest extends SysuiTestCase {
|
||||
verify(mBubbleController).onBubbleMetadataFlagChanged(b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateBubble_skipsDndSuppressListNotifs() {
|
||||
mBubbleEntry = new BubbleEntry(mRow.getSbn(), mRow.getRanking(), mRow.isDismissable(),
|
||||
mRow.shouldSuppressNotificationDot(), true /* DndSuppressNotifFromList */,
|
||||
mRow.shouldSuppressPeek());
|
||||
mBubbleEntry.getBubbleMetadata().setFlags(
|
||||
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
|
||||
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
Bubble b = mBubbleData.getPendingBubbleWithKey(mBubbleEntry.getKey());
|
||||
assertThat(b.shouldAutoExpand()).isFalse();
|
||||
assertThat(mBubbleData.getBubbleInStackWithKey(mBubbleEntry.getKey())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRankingUpdate_DndSuppressListNotif() {
|
||||
// It's in the stack
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mBubbleEntry.getKey())).isTrue();
|
||||
|
||||
// Set current user profile
|
||||
SparseArray<UserInfo> userInfos = new SparseArray<>();
|
||||
userInfos.put(mBubbleEntry.getStatusBarNotification().getUser().getIdentifier(),
|
||||
mock(UserInfo.class));
|
||||
mBubbleController.onCurrentProfilesChanged(userInfos);
|
||||
|
||||
// Send ranking update that the notif is suppressed from the list.
|
||||
HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey = new HashMap<>();
|
||||
mBubbleEntry = new BubbleEntry(mRow.getSbn(), mRow.getRanking(), mRow.isDismissable(),
|
||||
mRow.shouldSuppressNotificationDot(), true /* DndSuppressNotifFromList */,
|
||||
mRow.shouldSuppressPeek());
|
||||
Pair<BubbleEntry, Boolean> pair = new Pair(mBubbleEntry, true);
|
||||
entryDataByKey.put(mBubbleEntry.getKey(), pair);
|
||||
|
||||
NotificationListenerService.RankingMap rankingMap =
|
||||
mock(NotificationListenerService.RankingMap.class);
|
||||
when(rankingMap.getOrderedKeys()).thenReturn(new String[] { mBubbleEntry.getKey() });
|
||||
mBubbleController.onRankingUpdated(rankingMap, entryDataByKey);
|
||||
|
||||
// Should no longer be in the stack
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mBubbleEntry.getKey())).isFalse();
|
||||
}
|
||||
|
||||
/** Creates a bubble using the userId and package. */
|
||||
private Bubble createBubble(int userId, String pkg) {
|
||||
final UserHandle userHandle = new UserHandle(userId);
|
||||
|
||||
@@ -50,6 +50,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
@@ -59,6 +60,8 @@ import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
@@ -128,6 +131,7 @@ import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -1286,6 +1290,50 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
verify(mBubbleController).onBubbleMetadataFlagChanged(b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateBubble_skipsDndSuppressListNotifs() {
|
||||
mBubbleEntry = new BubbleEntry(mRow.getSbn(), mRow.getRanking(), mRow.isDismissable(),
|
||||
mRow.shouldSuppressNotificationDot(), true /* DndSuppressNotifFromList */,
|
||||
mRow.shouldSuppressPeek());
|
||||
mBubbleEntry.getBubbleMetadata().setFlags(
|
||||
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
|
||||
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
Bubble b = mBubbleData.getPendingBubbleWithKey(mBubbleEntry.getKey());
|
||||
assertThat(b.shouldAutoExpand()).isFalse();
|
||||
assertThat(mBubbleData.getBubbleInStackWithKey(mBubbleEntry.getKey())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRankingUpdate_DndSuppressListNotif() {
|
||||
// It's in the stack
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mBubbleEntry.getKey())).isTrue();
|
||||
|
||||
// Set current user profile
|
||||
SparseArray<UserInfo> userInfos = new SparseArray<>();
|
||||
userInfos.put(mBubbleEntry.getStatusBarNotification().getUser().getIdentifier(),
|
||||
mock(UserInfo.class));
|
||||
mBubbleController.onCurrentProfilesChanged(userInfos);
|
||||
|
||||
// Send ranking update that the notif is suppressed from the list.
|
||||
HashMap<String, Pair<BubbleEntry, Boolean>> entryDataByKey = new HashMap<>();
|
||||
mBubbleEntry = new BubbleEntry(mRow.getSbn(), mRow.getRanking(), mRow.isDismissable(),
|
||||
mRow.shouldSuppressNotificationDot(), true /* DndSuppressNotifFromList */,
|
||||
mRow.shouldSuppressPeek());
|
||||
Pair<BubbleEntry, Boolean> pair = new Pair(mBubbleEntry, true);
|
||||
entryDataByKey.put(mBubbleEntry.getKey(), pair);
|
||||
|
||||
NotificationListenerService.RankingMap rankingMap =
|
||||
mock(NotificationListenerService.RankingMap.class);
|
||||
when(rankingMap.getOrderedKeys()).thenReturn(new String[] { mBubbleEntry.getKey() });
|
||||
mBubbleController.onRankingUpdated(rankingMap, entryDataByKey);
|
||||
|
||||
// Should no longer be in the stack
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mBubbleEntry.getKey())).isFalse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bubble metadata flags for this entry. These flags are normally set by
|
||||
* NotificationManagerService when the notification is sent, however, these tests do not
|
||||
|
||||
Reference in New Issue
Block a user