diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index 7f78ddf2cf1c5..6da7bc8a2ade0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java @@ -15,7 +15,6 @@ */ package com.android.systemui.bubbles; -import static android.app.Notification.FLAG_BUBBLE; import static android.os.AsyncTask.Status.FINISHED; import static android.view.Display.INVALID_DISPLAY; @@ -29,21 +28,19 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; -import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Path; -import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.os.Bundle; +import android.graphics.drawable.Icon; import android.os.UserHandle; import android.provider.Settings; -import android.service.notification.StatusBarNotification; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.InstanceId; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -57,17 +54,12 @@ import java.util.Objects; class Bubble implements BubbleViewProvider { private static final String TAG = "Bubble"; - /** - * NotificationEntry associated with the bubble. A null value implies this bubble is loaded - * from disk. - */ - @Nullable - private NotificationEntry mEntry; private final String mKey; private long mLastUpdated; private long mLastAccessed; + @Nullable private BubbleController.NotificationSuppressionChangedListener mSuppressionListener; /** Whether the bubble should show a dot for the notification indicating updated content. */ @@ -75,8 +67,6 @@ class Bubble implements BubbleViewProvider { /** Whether flyout text should be suppressed, regardless of any other flags or state. */ private boolean mSuppressFlyout; - /** Whether this bubble should auto expand regardless of the normal flag, used for overflow. */ - private boolean mShouldAutoExpand; // Items that are typically loaded later private String mAppName; @@ -92,6 +82,7 @@ class Bubble implements BubbleViewProvider { * Presentational info about the flyout. */ public static class FlyoutMessage { + @Nullable public Icon senderIcon; @Nullable public Drawable senderAvatar; @Nullable public CharSequence senderName; @Nullable public CharSequence message; @@ -109,16 +100,39 @@ class Bubble implements BubbleViewProvider { private UserHandle mUser; @NonNull private String mPackageName; + @Nullable + private String mTitle; + @Nullable + private Icon mIcon; + private boolean mIsBubble; + private boolean mIsVisuallyInterruptive; + private boolean mIsClearable; + private boolean mShouldSuppressNotificationDot; + private boolean mShouldSuppressNotificationList; + private boolean mShouldSuppressPeek; private int mDesiredHeight; @DimenRes private int mDesiredHeightResId; + /** for logging **/ + @Nullable + private InstanceId mInstanceId; + @Nullable + private String mChannelId; + private int mNotificationId; + private int mAppUid = -1; + + @Nullable + private PendingIntent mIntent; + @Nullable + private PendingIntent mDeleteIntent; + /** * Create a bubble with limited information based on given {@link ShortcutInfo}. * Note: Currently this is only being used when the bubble is persisted to disk. */ Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo, - final int desiredHeight, final int desiredHeightResId) { + final int desiredHeight, final int desiredHeightResId, @Nullable final String title) { Objects.requireNonNull(key); Objects.requireNonNull(shortcutInfo); mShortcutInfo = shortcutInfo; @@ -126,8 +140,10 @@ class Bubble implements BubbleViewProvider { mFlags = 0; mUser = shortcutInfo.getUserHandle(); mPackageName = shortcutInfo.getPackage(); + mIcon = shortcutInfo.getIcon(); mDesiredHeight = desiredHeight; mDesiredHeightResId = desiredHeightResId; + mTitle = title; } /** Used in tests when no UI is required. */ @@ -145,12 +161,6 @@ class Bubble implements BubbleViewProvider { return mKey; } - @Nullable - public NotificationEntry getEntry() { - return mEntry; - } - - @NonNull public UserHandle getUser() { return mUser; } @@ -203,14 +213,7 @@ class Bubble implements BubbleViewProvider { @Nullable public String getTitle() { - final CharSequence titleCharSeq; - if (mEntry == null) { - titleCharSeq = null; - } else { - titleCharSeq = mEntry.getSbn().getNotification().extras.getCharSequence( - Notification.EXTRA_TITLE); - } - return titleCharSeq != null ? titleCharSeq.toString() : null; + return mTitle; } /** @@ -331,17 +334,44 @@ class Bubble implements BubbleViewProvider { void setEntry(@NonNull final NotificationEntry entry) { Objects.requireNonNull(entry); Objects.requireNonNull(entry.getSbn()); - mEntry = entry; mLastUpdated = entry.getSbn().getPostTime(); - mFlags = entry.getSbn().getNotification().flags; + mIsBubble = entry.getSbn().getNotification().isBubbleNotification(); mPackageName = entry.getSbn().getPackageName(); mUser = entry.getSbn().getUser(); + mTitle = getTitle(entry); + mIsClearable = entry.isClearable(); + mShouldSuppressNotificationDot = entry.shouldSuppressNotificationDot(); + mShouldSuppressNotificationList = entry.shouldSuppressNotificationList(); + mShouldSuppressPeek = entry.shouldSuppressPeek(); + mChannelId = entry.getSbn().getNotification().getChannelId(); + mNotificationId = entry.getSbn().getId(); + mAppUid = entry.getSbn().getUid(); + mInstanceId = entry.getSbn().getInstanceId(); + mFlyoutMessage = BubbleViewInfoTask.extractFlyoutMessage(entry); + if (entry.getRanking() != null) { + mShortcutInfo = entry.getRanking().getShortcutInfo() != null + ? entry.getRanking().getShortcutInfo() : mShortcutInfo; + mIsVisuallyInterruptive = entry.getRanking().visuallyInterruptive(); + } if (entry.getBubbleMetadata() != null) { + mFlags = entry.getBubbleMetadata().getFlags(); mDesiredHeight = entry.getBubbleMetadata().getDesiredHeight(); mDesiredHeightResId = entry.getBubbleMetadata().getDesiredHeightResId(); + mIcon = entry.getBubbleMetadata().getIcon(); + mIntent = entry.getBubbleMetadata().getIntent(); + mDeleteIntent = entry.getBubbleMetadata().getDeleteIntent(); } } + @Nullable + Icon getIcon() { + return mIcon; + } + + boolean isVisuallyInterruptive() { + return mIsVisuallyInterruptive; + } + /** * @return the last time this bubble was updated or accessed, whichever is most recent. */ @@ -364,6 +394,19 @@ class Bubble implements BubbleViewProvider { return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY; } + public InstanceId getInstanceId() { + return mInstanceId; + } + + @Nullable + public String getChannelId() { + return mChannelId; + } + + public int getNotificationId() { + return mNotificationId; + } + /** * Should be invoked whenever a Bubble is accessed (selected while expanded). */ @@ -384,24 +427,19 @@ class Bubble implements BubbleViewProvider { * Whether this notification should be shown in the shade. */ boolean showInShade() { - if (mEntry == null) return false; - return !shouldSuppressNotification() || !mEntry.isClearable(); + return !shouldSuppressNotification() || !mIsClearable; } /** * Sets whether this notification should be suppressed in the shade. */ void setSuppressNotification(boolean suppressNotification) { - if (mEntry == null) return; boolean prevShowInShade = showInShade(); - Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); - int flags = data.getFlags(); if (suppressNotification) { - flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; + mFlags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; } else { - flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; + mFlags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; } - data.setFlags(flags); if (showInShade() != prevShowInShade && mSuppressionListener != null) { mSuppressionListener.onBubbleNotificationSuppressionChange(this); @@ -424,9 +462,8 @@ class Bubble implements BubbleViewProvider { */ @Override public boolean showDot() { - if (mEntry == null) return false; return mShowBubbleUpdateDot - && !mEntry.shouldSuppressNotificationDot() + && !mShouldSuppressNotificationDot && !shouldSuppressNotification(); } @@ -434,10 +471,9 @@ class Bubble implements BubbleViewProvider { * Whether the flyout for the bubble should be shown. */ boolean showFlyout() { - if (mEntry == null) return false; - return !mSuppressFlyout && !mEntry.shouldSuppressPeek() + return !mSuppressFlyout && !mShouldSuppressPeek && !shouldSuppressNotification() - && !mEntry.shouldSuppressNotificationList(); + && !mShouldSuppressNotificationList; } /** @@ -480,25 +516,14 @@ class Bubble implements BubbleViewProvider { } } - /** - * Whether shortcut information should be used to populate the bubble. - *
- * To populate the activity use {@link LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)}.
- * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
- */
- boolean usingShortcutInfo() {
- return mEntry != null && mEntry.getBubbleMetadata().getShortcutId() != null
- || mShortcutInfo != null;
+ @Nullable
+ PendingIntent getBubbleIntent() {
+ return mIntent;
}
@Nullable
- PendingIntent getBubbleIntent() {
- if (mEntry == null) return null;
- Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
- if (data != null) {
- return data.getIntent();
- }
- return null;
+ PendingIntent getDeleteIntent() {
+ return mDeleteIntent;
}
Intent getSettingsIntent(final Context context) {
@@ -514,8 +539,12 @@ class Bubble implements BubbleViewProvider {
return intent;
}
+ public int getAppUid() {
+ return mAppUid;
+ }
+
private int getUid(final Context context) {
- if (mEntry != null) return mEntry.getSbn().getUid();
+ if (mAppUid != -1) return mAppUid;
final PackageManager pm = context.getPackageManager();
if (pm == null) return -1;
try {
@@ -548,24 +577,27 @@ class Bubble implements BubbleViewProvider {
}
private boolean shouldSuppressNotification() {
- if (mEntry == null) return true;
- return mEntry.getBubbleMetadata() != null
- && mEntry.getBubbleMetadata().isNotificationSuppressed();
+ return isEnabled(Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
}
- boolean shouldAutoExpand() {
- if (mEntry == null) return mShouldAutoExpand;
- Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
- return (metadata != null && metadata.getAutoExpandBubble()) || mShouldAutoExpand;
+ public boolean shouldAutoExpand() {
+ return isEnabled(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
}
void setShouldAutoExpand(boolean shouldAutoExpand) {
- mShouldAutoExpand = shouldAutoExpand;
+ if (shouldAutoExpand) {
+ enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
+ } else {
+ disable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
+ }
+ }
+
+ public void setIsBubble(final boolean isBubble) {
+ mIsBubble = isBubble;
}
public boolean isBubble() {
- if (mEntry == null) return (mFlags & FLAG_BUBBLE) != 0;
- return (mEntry.getSbn().getNotification().flags & FLAG_BUBBLE) != 0;
+ return mIsBubble;
}
public void enable(int option) {
@@ -576,6 +608,10 @@ class Bubble implements BubbleViewProvider {
mFlags &= ~option;
}
+ public boolean isEnabled(int option) {
+ return (mFlags & option) != 0;
+ }
+
@Override
public String toString() {
return "Bubble{" + mKey + '}';
@@ -610,34 +646,24 @@ class Bubble implements BubbleViewProvider {
@Override
public void logUIEvent(int bubbleCount, int action, float normalX, float normalY, int index) {
- if (this.getEntry() == null
- || this.getEntry().getSbn() == null) {
- SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
- null /* package name */,
- null /* notification channel */,
- 0 /* notification ID */,
- 0 /* bubble position */,
- bubbleCount,
- action,
- normalX,
- normalY,
- false /* unread bubble */,
- false /* on-going bubble */,
- false /* isAppForeground (unused) */);
- } else {
- StatusBarNotification notification = this.getEntry().getSbn();
- SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
- notification.getPackageName(),
- notification.getNotification().getChannelId(),
- notification.getId(),
- index,
- bubbleCount,
- action,
- normalX,
- normalY,
- this.showInShade(),
- false /* isOngoing (unused) */,
- false /* isAppForeground (unused) */);
- }
+ SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
+ mPackageName,
+ mChannelId,
+ mNotificationId,
+ index,
+ bubbleCount,
+ action,
+ normalX,
+ normalY,
+ showInShade(),
+ false /* isOngoing (unused) */,
+ false /* isAppForeground (unused) */);
+ }
+
+ @Nullable
+ private static String getTitle(@NonNull final NotificationEntry e) {
+ final CharSequence titleCharSeq = e.getSbn().getNotification().extras.getCharSequence(
+ Notification.EXTRA_TITLE);
+ return titleCharSeq == null ? null : titleCharSeq.toString();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index c4c5da42ec06d..b2c5402c7cd35 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -505,8 +505,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
addNotifCallback(new NotifCallback() {
@Override
public void removeNotification(NotificationEntry entry, int reason) {
- mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
- reason);
+ mNotificationEntryManager.performRemoveNotification(entry.getSbn(), reason);
}
@Override
@@ -637,8 +636,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mStackView.setExpandListener(mExpandListener);
}
- mStackView.setUnbubbleConversationCallback(notificationEntry ->
- onUserChangedBubble(notificationEntry, false /* shouldBubble */));
+ mStackView.setUnbubbleConversationCallback(key -> {
+ final NotificationEntry entry =
+ mNotificationEntryManager.getPendingOrActiveNotif(key);
+ if (entry != null) {
+ onUserChangedBubble(entry, false /* shouldBubble */);
+ }
+ });
}
addToWindowManagerMaybe();
@@ -1024,10 +1028,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* @param entry the notification to change bubble state for.
* @param shouldBubble whether the notification should show as a bubble or not.
*/
- public void onUserChangedBubble(@Nullable final NotificationEntry entry, boolean shouldBubble) {
- if (entry == null) {
- return;
- }
+ public void onUserChangedBubble(@NonNull final NotificationEntry entry, boolean shouldBubble) {
NotificationChannel channel = entry.getChannel();
final String appPkg = entry.getSbn().getPackageName();
final int appUid = entry.getSbn().getUid();
@@ -1103,7 +1104,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mBubbleData.removeSuppressedSummary(groupKey);
// Remove any associated bubble children with the summary
- final List