Bubble API: Allow developers to create BubbleMetadata from a shortcut id
Adds an option to specify a bubble via a shortcutId. If the builder had
icon / intent previously specified, the shortcutId will clobber those
and vice versa.
Unfortunately, this means that BubbleMetadata#getIcon and #getIntent may
return null when previously they were non-null. I've deprecated these
getters and introduced new ones along with new setters so that the naming
remains consistent.
NoMan will check if that shortcut exists before applying FLAG_BUBBLE.
Update SystemUI to use BubbleMetadata builder with shortcut id for the
shortcut experiment.
Adds test to ensure the launcher apps callback is added / removed
appropriately & that notifs with shortcut bubbles are properly flagged
or unflagged.
Test: atest NotificationManagerServiceTest
Test: atest NotificationTest NotificationManagerTest (see CTS CL)
Bug: 138116133
Bug: 144352570
Change-Id: I2e8155edc7fd70d6978fc80310f071bf6510e0d2
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 77c8e0b..b89305e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -346,14 +346,14 @@
* To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
*/
boolean usingShortcutInfo() {
- return BubbleExperimentConfig.isShortcutIntent(getBubbleIntent());
+ return mEntry.getBubbleMetadata().getShortcutId() != null;
}
@Nullable
PendingIntent getBubbleIntent() {
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
if (data != null) {
- return data.getIntent();
+ return data.getBubbleIntent();
}
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 644d8c4..e642d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -1075,8 +1075,12 @@
*/
static boolean canLaunchInActivityView(Context context, NotificationEntry entry) {
PendingIntent intent = entry.getBubbleMetadata() != null
- ? entry.getBubbleMetadata().getIntent()
+ ? entry.getBubbleMetadata().getBubbleIntent()
: null;
+ if (entry.getBubbleMetadata() != null
+ && entry.getBubbleMetadata().getShortcutId() != null) {
+ return true;
+ }
if (intent == null) {
Log.w(TAG, "Unable to create bubble -- no intent: " + entry.getKey());
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index c1705db..5c46496 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -357,7 +357,7 @@
if (isNew) {
mBubbleIntent = mBubble.getBubbleIntent();
- if (mBubbleIntent != null) {
+ if (mBubbleIntent != null || mBubble.getShortcutInfo() != null) {
setContentVisibility(false);
mActivityView.setVisibility(VISIBLE);
}
@@ -543,7 +543,8 @@
}
private boolean usingActivityView() {
- return mBubbleIntent != null && mActivityView != null;
+ return (mBubbleIntent != null || mBubble.getShortcutInfo() != null)
+ && mActivityView != null;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 4c1cf49..4252f72 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -29,7 +29,6 @@
import android.app.PendingIntent;
import android.app.Person;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Color;
@@ -182,7 +181,7 @@
ShortcutInfo info = getShortcutInfo(context, entry.getSbn().getPackageName(),
entry.getSbn().getUser(), shortcutId);
if (info != null) {
- metadata = createForShortcut(context, entry);
+ metadata = createForShortcut(shortcutId);
}
// Replace existing metadata with shortcut, or we're bubbling for experiment
@@ -259,30 +258,17 @@
}
if (intent != null) {
return new Notification.BubbleMetadata.Builder()
+ .createIntentBubble(intent, icon)
.setDesiredHeight(BUBBLE_HEIGHT)
- .setIcon(icon)
- .setIntent(intent)
.build();
}
return null;
}
- static Notification.BubbleMetadata createForShortcut(Context context, NotificationEntry entry) {
- // ShortcutInfo does not return an icon, instead a Drawable, lets just use
- // notification icon for BubbleMetadata.
- Icon icon = entry.getSbn().getNotification().getSmallIcon();
-
- // ShortcutInfo does not return the intent, lets make a fake but identifiable
- // intent so we can still add bubbleMetadata
- if (sDummyShortcutIntent == null) {
- Intent i = new Intent(SHORTCUT_DUMMY_INTENT);
- sDummyShortcutIntent = PendingIntent.getActivity(context, 0, i,
- PendingIntent.FLAG_UPDATE_CURRENT);
- }
+ static Notification.BubbleMetadata createForShortcut(String shortcutId) {
return new Notification.BubbleMetadata.Builder()
.setDesiredHeight(BUBBLE_HEIGHT)
- .setIcon(icon)
- .setIntent(sDummyShortcutIntent)
+ .createShortcutBubble(shortcutId)
.build();
}
@@ -304,10 +290,6 @@
: null;
}
- static boolean isShortcutIntent(PendingIntent intent) {
- return intent != null && intent.equals(sDummyShortcutIntent);
- }
-
static List<Person> getPeopleFromNotification(NotificationEntry entry) {
Bundle extras = entry.getSbn().getNotification().extras;
ArrayList<Person> personList = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
index b32dbb7..3b818db 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
@@ -18,6 +18,7 @@
import android.app.Notification;
import android.content.Context;
import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
@@ -48,16 +49,19 @@
/**
* Returns the drawable that the developer has provided to display in the bubble.
*/
- Drawable getBubbleDrawable(Bubble b, Context context) {
- if (b.getShortcutInfo() != null && b.usingShortcutInfo()) {
+ Drawable getBubbleDrawable(Context context, ShortcutInfo shortcutInfo,
+ Notification.BubbleMetadata metadata) {
+ if (shortcutInfo != null) {
LauncherApps launcherApps =
(LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
int density = context.getResources().getConfiguration().densityDpi;
- return launcherApps.getShortcutIconDrawable(b.getShortcutInfo(), density);
+ return launcherApps.getShortcutIconDrawable(shortcutInfo, density);
} else {
- Notification.BubbleMetadata metadata = b.getEntry().getBubbleMetadata();
- Icon ic = metadata.getIcon();
- return ic.loadDrawable(context);
+ Icon ic = metadata.getBubbleIcon();
+ if (ic != null) {
+ return ic.loadDrawable(context);
+ }
+ return null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
index 41f5028..8924cd6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
@@ -126,15 +126,22 @@
StatusBarNotification sbn = b.getEntry().getSbn();
String packageName = sbn.getPackageName();
- // Shortcut info for this bubble
- String shortcutId = sbn.getNotification().getShortcutId();
- if (BubbleExperimentConfig.useShortcutInfoToBubble(c)
- && shortcutId != null) {
- info.shortcutInfo = BubbleExperimentConfig.getShortcutInfo(c,
- packageName,
- sbn.getUser(), shortcutId);
+ // Real shortcut info for this bubble
+ String bubbleShortcutId = b.getEntry().getBubbleMetadata().getShortcutId();
+ if (bubbleShortcutId != null) {
+ info.shortcutInfo = BubbleExperimentConfig.getShortcutInfo(c, packageName,
+ sbn.getUser(), bubbleShortcutId);
+ } else {
+ // Check for experimental shortcut
+ String shortcutId = sbn.getNotification().getShortcutId();
+ if (BubbleExperimentConfig.useShortcutInfoToBubble(c) && shortcutId != null) {
+ info.shortcutInfo = BubbleExperimentConfig.getShortcutInfo(c,
+ packageName,
+ sbn.getUser(), shortcutId);
+ }
}
+
// App name & app icon
PackageManager pm = c.getPackageManager();
ApplicationInfo appInfo;
@@ -158,7 +165,8 @@
}
// Badged bubble image
- Drawable bubbleDrawable = iconFactory.getBubbleDrawable(b, c);
+ Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
+ b.getEntry().getBubbleMetadata());
BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon);
info.badgedBubbleImage = iconFactory.getBubbleBitmap(bubbleDrawable,
badgeBitmapInfo).icon;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 66ed864..bbf2dde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -188,7 +188,9 @@
return false;
}
- if (entry.getBubbleMetadata() == null || entry.getBubbleMetadata().getIntent() == null) {
+ if (entry.getBubbleMetadata() == null
+ || (entry.getBubbleMetadata().getShortcutId() == null
+ && entry.getBubbleMetadata().getBubbleIntent() == null)) {
if (DEBUG) {
Log.d(TAG, "No bubble up: notification: " + sbn.getKey()
+ " doesn't have valid metadata");