summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/notification/BubbleExtractor.java27
-rw-r--r--services/core/java/com/android/server/notification/ShortcutHelper.java40
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java51
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java10
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java50
5 files changed, 143 insertions, 35 deletions
diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java
index d7d413c2ffb0..0fa339f65cdb 100644
--- a/services/core/java/com/android/server/notification/BubbleExtractor.java
+++ b/services/core/java/com/android/server/notification/BubbleExtractor.java
@@ -75,9 +75,19 @@ public class BubbleExtractor implements NotificationSignalExtractor {
mConfig.getBubblePreference(
record.getSbn().getPackageName(), record.getSbn().getUid());
NotificationChannel recordChannel = record.getChannel();
+ boolean canPresentAsBubble = canPresentAsBubble(record)
+ && !mActivityManager.isLowRamDevice()
+ && record.isConversation()
+ && (record.getNotification().flags & FLAG_FOREGROUND_SERVICE) == 0;
- if (!mConfig.bubblesEnabled() || bubblePreference == BUBBLE_PREFERENCE_NONE) {
+ if (!mConfig.bubblesEnabled()
+ || bubblePreference == BUBBLE_PREFERENCE_NONE
+ || !canPresentAsBubble) {
record.setAllowBubble(false);
+ if (!canPresentAsBubble) {
+ // clear out bubble metadata since it can't be used
+ record.getNotification().setBubbleMetadata(null);
+ }
} else if (recordChannel == null) {
// the app is allowed but there's no channel to check
record.setAllowBubble(true);
@@ -86,14 +96,15 @@ public class BubbleExtractor implements NotificationSignalExtractor {
} else if (bubblePreference == BUBBLE_PREFERENCE_SELECTED) {
record.setAllowBubble(recordChannel.canBubble());
}
+ if (DBG) {
+ Slog.d(TAG, "record: " + record.getKey()
+ + " appPref: " + bubblePreference
+ + " canBubble: " + record.canBubble()
+ + " canPresentAsBubble: " + canPresentAsBubble
+ + " flagRemoved: " + record.isFlagBubbleRemoved());
+ }
- final boolean fulfillsPolicy = record.canBubble()
- && record.isConversation()
- && !mActivityManager.isLowRamDevice()
- && (record.getNotification().flags & FLAG_FOREGROUND_SERVICE) == 0;
- final boolean applyFlag = fulfillsPolicy
- && canPresentAsBubble(record)
- && !record.isFlagBubbleRemoved();
+ final boolean applyFlag = record.canBubble() && !record.isFlagBubbleRemoved();
if (applyFlag) {
record.getNotification().flags |= FLAG_BUBBLE;
} else {
diff --git a/services/core/java/com/android/server/notification/ShortcutHelper.java b/services/core/java/com/android/server/notification/ShortcutHelper.java
index e79d33fa5f7a..0fa522cf51de 100644
--- a/services/core/java/com/android/server/notification/ShortcutHelper.java
+++ b/services/core/java/com/android/server/notification/ShortcutHelper.java
@@ -28,6 +28,7 @@ import android.content.pm.ShortcutServiceInternal;
import android.os.Binder;
import android.os.Handler;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -111,6 +112,15 @@ public class ShortcutHelper {
}
if (!foundShortcut) {
bubbleKeysToRemove.add(shortcutBubbles.get(shortcutId));
+ shortcutBubbles.remove(shortcutId);
+ if (shortcutBubbles.isEmpty()) {
+ mActiveShortcutBubbles.remove(packageName);
+ if (mLauncherAppsCallbackRegistered
+ && mActiveShortcutBubbles.isEmpty()) {
+ mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
+ mLauncherAppsCallbackRegistered = false;
+ }
+ }
}
}
}
@@ -209,15 +219,16 @@ public class ShortcutHelper {
* @param removedNotification true if this notification is being removed
* @param handler handler to register the callback with
*/
- void maybeListenForShortcutChangesForBubbles(NotificationRecord r, boolean removedNotification,
+ void maybeListenForShortcutChangesForBubbles(NotificationRecord r,
+ boolean removedNotification,
Handler handler) {
final String shortcutId = r.getNotification().getBubbleMetadata() != null
? r.getNotification().getBubbleMetadata().getShortcutId()
: null;
- if (shortcutId == null) {
- return;
- }
- if (r.getNotification().isBubbleNotification() && !removedNotification) {
+ if (!removedNotification
+ && !TextUtils.isEmpty(shortcutId)
+ && r.getShortcutInfo() != null
+ && r.getShortcutInfo().getId().equals(shortcutId)) {
// Must track shortcut based bubbles in case the shortcut is removed
HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
r.getSbn().getPackageName());
@@ -235,10 +246,21 @@ public class ShortcutHelper {
HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
r.getSbn().getPackageName());
if (packageBubbles != null) {
- packageBubbles.remove(shortcutId);
- }
- if (packageBubbles != null && packageBubbles.isEmpty()) {
- mActiveShortcutBubbles.remove(r.getSbn().getPackageName());
+ if (!TextUtils.isEmpty(shortcutId)) {
+ packageBubbles.remove(shortcutId);
+ } else {
+ // Check if there was a matching entry
+ for (String pkgShortcutId : packageBubbles.keySet()) {
+ String entryKey = packageBubbles.get(pkgShortcutId);
+ if (r.getKey().equals(entryKey)) {
+ // No longer has shortcut id so remove it
+ packageBubbles.remove(pkgShortcutId);
+ }
+ }
+ }
+ if (packageBubbles.isEmpty()) {
+ mActiveShortcutBubbles.remove(r.getSbn().getPackageName());
+ }
}
if (mLauncherAppsCallbackRegistered && mActiveShortcutBubbles.isEmpty()) {
mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
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 38b71b707196..13457f0a284c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
@@ -26,6 +26,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -166,6 +168,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_ALL /* app */,
ALLOW_BUBBLE_OFF /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -178,6 +182,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_ALL /* app */,
DEFAULT_ALLOW_BUBBLE /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -190,6 +196,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_ALL /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -202,6 +210,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(false /* feature */,
BUBBLE_PREFERENCE_ALL /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -215,6 +225,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_NONE /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -228,6 +240,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_NONE /* app */,
DEFAULT_ALLOW_BUBBLE /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -241,6 +255,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_SELECTED /* app */,
DEFAULT_ALLOW_BUBBLE /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -254,6 +270,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_SELECTED /* app */,
ALLOW_BUBBLE_OFF /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -267,6 +285,9 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(true /* feature */,
BUBBLE_PREFERENCE_SELECTED /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
+
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -279,6 +300,9 @@ public class BubbleExtractorTest extends UiServiceTestCase {
setUpBubblesEnabled(false /* feature */,
BUBBLE_PREFERENCE_SELECTED /* app */,
ALLOW_BUBBLE_ON /* channel */);
+ when(mActivityManager.isLowRamDevice()).thenReturn(false);
+ setUpShortcutBubble(true /* isValid */);
+
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
@@ -305,6 +329,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
mBubbleExtractor.process(r);
assertTrue(r.canBubble());
+ assertNotNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -320,6 +345,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
mBubbleExtractor.process(r);
assertTrue(r.canBubble());
+ assertNotNull(r.getNotification().getBubbleMetadata());
assertTrue(r.getNotification().isBubbleNotification());
}
@@ -335,6 +361,7 @@ public class BubbleExtractorTest extends UiServiceTestCase {
mBubbleExtractor.process(r);
assertTrue(r.canBubble());
+ assertNotNull(r.getNotification().getBubbleMetadata());
assertTrue(r.getNotification().isBubbleNotification());
}
@@ -350,7 +377,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
r.setShortcutInfo(null);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -366,7 +394,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
r.setShortcutInfo(null);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -381,7 +410,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -395,7 +425,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(false /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -414,7 +445,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -429,7 +461,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -445,7 +478,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
assertFalse(r.getNotification().isBubbleNotification());
}
@@ -462,7 +496,8 @@ public class BubbleExtractorTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord(true /* bubble */);
mBubbleExtractor.process(r);
- assertTrue(r.canBubble());
+ assertFalse(r.canBubble());
+ assertNull(r.getNotification().getBubbleMetadata());
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 ced780475fb7..2bea491949de 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6135,8 +6135,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
"tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
-
// Test: Send the bubble notification
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
@@ -6168,12 +6166,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
// We're no longer a bubble
- Notification notif2 = mService.getNotificationRecord(
- nr.getSbn().getKey()).getNotification();
- assertFalse(notif2.isBubbleNotification());
+ NotificationRecord notif2 = mService.getNotificationRecord(
+ nr.getSbn().getKey());
+ assertNull(notif2.getShortcutInfo());
+ assertFalse(notif2.getNotification().isBubbleNotification());
}
-
@Test
public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved()
throws RemoteException {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
index eb2d9fed197f..c700a090fa2e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
@@ -48,6 +48,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
@SmallTest
@@ -73,6 +74,8 @@ public class ShortcutHelperTest extends UiServiceTestCase {
StatusBarNotification mSbn;
@Mock
Notification.BubbleMetadata mBubbleMetadata;
+ @Mock
+ ShortcutInfo mShortcutInfo;
ShortcutHelper mShortcutHelper;
@@ -86,13 +89,13 @@ public class ShortcutHelperTest extends UiServiceTestCase {
when(mNr.getSbn()).thenReturn(mSbn);
when(mSbn.getPackageName()).thenReturn(PKG);
when(mNr.getNotification()).thenReturn(mNotif);
+ when(mNr.getShortcutInfo()).thenReturn(mShortcutInfo);
+ when(mShortcutInfo.getId()).thenReturn(SHORTCUT_ID);
when(mNotif.getBubbleMetadata()).thenReturn(mBubbleMetadata);
when(mBubbleMetadata.getShortcutId()).thenReturn(SHORTCUT_ID);
}
private LauncherApps.Callback addShortcutBubbleAndVerifyListener() {
- when(mNotif.isBubbleNotification()).thenReturn(true);
-
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
false /* removed */,
null /* handler */);
@@ -124,12 +127,40 @@ public class ShortcutHelperTest extends UiServiceTestCase {
}
@Test
- public void testBubbleNoLongerBubble_listenerRemoved() {
+ public void testBubbleNoLongerHasBubbleMetadata_listenerRemoved() {
// First set it up to listen
addShortcutBubbleAndVerifyListener();
// Then make it not a bubble
- when(mNotif.isBubbleNotification()).thenReturn(false);
+ when(mNotif.getBubbleMetadata()).thenReturn(null);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
+ false /* removed */,
+ null /* handler */);
+
+ verify(mLauncherApps, times(1)).unregisterCallback(any());
+ }
+
+ @Test
+ public void testBubbleNoLongerHasShortcutId_listenerRemoved() {
+ // First set it up to listen
+ addShortcutBubbleAndVerifyListener();
+
+ // Clear out shortcutId
+ when(mBubbleMetadata.getShortcutId()).thenReturn(null);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
+ false /* removed */,
+ null /* handler */);
+
+ verify(mLauncherApps, times(1)).unregisterCallback(any());
+ }
+
+ @Test
+ public void testNotifNoLongerHasShortcut_listenerRemoved() {
+ // First set it up to listen
+ addShortcutBubbleAndVerifyListener();
+
+ // Clear out shortcutId
+ when(mNr.getShortcutInfo()).thenReturn(null);
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
false /* removed */,
null /* handler */);
@@ -138,6 +169,17 @@ public class ShortcutHelperTest extends UiServiceTestCase {
}
@Test
+ public void testOnShortcutsChanged_listenerRemoved() {
+ // First set it up to listen
+ LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener();
+
+ // App shortcuts are removed:
+ callback.onShortcutsChanged(PKG, Collections.emptyList(), mock(UserHandle.class));
+
+ verify(mLauncherApps, times(1)).unregisterCallback(any());
+ }
+
+ @Test
public void testListenerNotifiedOnShortcutRemoved() {
LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener();