From d07c2deaf035e8aae86fa5f0b11ef36d237d653a Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Fri, 29 May 2020 17:50:34 -0700 Subject: decouple Bubble from NotificationEntry 1. decouple Bubble from NotificationEntry 2. save title from Bubble into BubbleEntity 3. copied boolean values from NotificationEntry into Bubble for UI variants (e.g. isVisuallyInterruptive, isClearable, shouldSuppressNotificationDot... e.t.c) Bug: 151474524 Change-Id: I606c6ff93b3dc3867b4d0a6129d7117d9999c170 Test: manual --- .../src/com/android/systemui/bubbles/Bubble.java | 224 ++++++++++++--------- .../android/systemui/bubbles/BubbleController.java | 80 ++++---- .../com/android/systemui/bubbles/BubbleData.java | 38 ++-- .../systemui/bubbles/BubbleDataRepository.kt | 23 ++- .../systemui/bubbles/BubbleExpandedView.java | 2 +- .../android/systemui/bubbles/BubbleFlyoutView.java | 6 +- .../systemui/bubbles/BubbleIconFactory.java | 8 +- .../android/systemui/bubbles/BubbleLoggerImpl.java | 7 +- .../systemui/bubbles/BubbleOverflowActivity.java | 4 +- .../android/systemui/bubbles/BubbleStackView.java | 10 +- .../systemui/bubbles/BubbleViewInfoTask.java | 80 +++----- .../systemui/bubbles/storage/BubbleEntity.kt | 3 +- .../systemui/bubbles/storage/BubbleXmlHelper.kt | 5 +- .../systemui/bubbles/BubbleControllerTest.java | 45 +++-- .../com/android/systemui/bubbles/BubbleTest.java | 18 +- .../NewNotifPipelineBubbleControllerTest.java | 26 ++- .../storage/BubblePersistentRepositoryTest.kt | 2 +- .../storage/BubbleVolatileRepositoryTest.kt | 7 +- .../bubbles/storage/BubbleXmlHelperTest.kt | 24 +-- 19 files changed, 324 insertions(+), 288 deletions(-) (limited to 'packages/SystemUI') diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index 7f78ddf2cf1c..6da7bc8a2ade 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 c4c5da42ec06..b2c5402c7cd3 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 bubbleChildren = mBubbleData.getBubblesInGroup(groupKey); + final List bubbleChildren = mBubbleData.getBubblesInGroup( + groupKey, mNotificationEntryManager); for (int i = 0; i < bubbleChildren.size(); i++) { removeBubble(bubbleChildren.get(i).getKey(), DISMISS_GROUP_CANCELLED); } @@ -1161,21 +1163,18 @@ public class BubbleController implements ConfigurationController.ConfigurationLi private void setIsBubble(@NonNull final Bubble b, final boolean isBubble) { Objects.requireNonNull(b); - if (isBubble) { - b.enable(FLAG_BUBBLE); - } else { - b.disable(FLAG_BUBBLE); - } - if (b.getEntry() != null) { + b.setIsBubble(isBubble); + final NotificationEntry entry = mNotificationEntryManager + .getPendingOrActiveNotif(b.getKey()); + if (entry != null) { // Updating the entry to be a bubble will trigger our normal update flow - setIsBubble(b.getEntry(), isBubble, b.shouldAutoExpand()); + setIsBubble(entry, isBubble, b.shouldAutoExpand()); } else if (isBubble) { - // If we have no entry to update, it's a persisted bubble so - // we need to add it to the stack ourselves + // If bubble doesn't exist, it's a persisted bubble so we need to add it to the + // stack ourselves Bubble bubble = mBubbleData.getOrCreateBubble(null, b /* persistedBubble */); inflateAndAdd(bubble, bubble.shouldAutoExpand() /* suppressFlyout */, !bubble.shouldAutoExpand() /* showInShade */); - } } @@ -1214,6 +1213,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (reason == DISMISS_NOTIF_CANCEL) { bubblesToBeRemovedFromRepository.add(bubble); } + final NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif( + bubble.getKey()); if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) { if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey()) && (!bubble.showInShade() @@ -1222,26 +1223,27 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // The bubble is now gone & the notification is hidden from the shade, so // time to actually remove it for (NotifCallback cb : mCallbacks) { - if (bubble.getEntry() != null) { - cb.removeNotification(bubble.getEntry(), REASON_CANCEL); + if (entry != null) { + cb.removeNotification(entry, REASON_CANCEL); } } } else { if (bubble.isBubble()) { setIsBubble(bubble, false /* isBubble */); } - if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) { - bubble.getEntry().getRow().updateBubbleButton(); + if (entry != null && entry.getRow() != null) { + entry.getRow().updateBubbleButton(); } } } - if (bubble.getEntry() != null) { - final String groupKey = bubble.getEntry().getSbn().getGroupKey(); - if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) { + if (entry != null) { + final String groupKey = entry.getSbn().getGroupKey(); + if (mBubbleData.getBubblesInGroup( + groupKey, mNotificationEntryManager).isEmpty()) { // Time to potentially remove the summary for (NotifCallback cb : mCallbacks) { - cb.maybeCancelSummary(bubble.getEntry()); + cb.maybeCancelSummary(entry); } } } @@ -1266,9 +1268,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (update.selectionChanged && mStackView != null) { mStackView.setSelectedBubble(update.selectedBubble); - if (update.selectedBubble != null && update.selectedBubble.getEntry() != null) { - mNotificationGroupManager.updateSuppression( - update.selectedBubble.getEntry()); + if (update.selectedBubble != null) { + final NotificationEntry entry = mNotificationEntryManager + .getPendingOrActiveNotif(update.selectedBubble.getKey()); + if (entry != null) { + mNotificationGroupManager.updateSuppression(entry); + } } } @@ -1341,7 +1346,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } String groupKey = entry.getSbn().getGroupKey(); - ArrayList bubbleChildren = mBubbleData.getBubblesInGroup(groupKey); + ArrayList bubbleChildren = mBubbleData.getBubblesInGroup( + groupKey, mNotificationEntryManager); boolean isSuppressedSummary = (mBubbleData.isSummarySuppressed(groupKey) && mBubbleData.getSummaryKey(groupKey).equals(entry.getKey())); boolean isSummary = entry.getSbn().getNotification().isGroupSummary(); @@ -1361,9 +1367,15 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // As far as group manager is concerned, once a child is no longer shown // in the shade, it is essentially removed. Bubble bubbleChild = mBubbleData.getAnyBubbleWithkey(child.getKey()); - mNotificationGroupManager.onEntryRemoved(bubbleChild.getEntry()); - bubbleChild.setSuppressNotification(true); - bubbleChild.setShowDot(false /* show */); + if (bubbleChild != null) { + final NotificationEntry entry = mNotificationEntryManager + .getPendingOrActiveNotif(bubbleChild.getKey()); + if (entry != null) { + mNotificationGroupManager.onEntryRemoved(entry); + } + bubbleChild.setSuppressNotification(true); + bubbleChild.setShowDot(false /* show */); + } } else { // non-bubbled children can be removed for (NotifCallback cb : mCallbacks) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java index 20a9a8cf324c..c8706126c1ad 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java @@ -22,7 +22,6 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.NonNull; -import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.util.Log; @@ -34,6 +33,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.bubbles.BubbleController.DismissReason; +import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.io.FileDescriptor; @@ -256,8 +256,7 @@ public class BubbleData { } mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey()); - suppressFlyout |= bubble.getEntry() == null - || !bubble.getEntry().getRanking().visuallyInterruptive(); + suppressFlyout |= !bubble.isVisuallyInterruptive(); if (prevBubble == null) { // Create a new bubble @@ -335,13 +334,15 @@ public class BubbleData { * Retrieves any bubbles that are part of the notification group represented by the provided * group key. */ - ArrayList getBubblesInGroup(@Nullable String groupKey) { + ArrayList getBubblesInGroup(@Nullable String groupKey, @NonNull + NotificationEntryManager nem) { ArrayList bubbleChildren = new ArrayList<>(); if (groupKey == null) { return bubbleChildren; } for (Bubble b : mBubbles) { - if (b.getEntry() != null && groupKey.equals(b.getEntry().getSbn().getGroupKey())) { + final NotificationEntry entry = nem.getPendingOrActiveNotif(b.getKey()); + if (entry != null && groupKey.equals(entry.getSbn().getGroupKey())) { bubbleChildren.add(b); } } @@ -439,9 +440,7 @@ public class BubbleData { Bubble newSelected = mBubbles.get(newIndex); setSelectedBubbleInternal(newSelected); } - if (bubbleToRemove.getEntry() != null) { - maybeSendDeleteIntent(reason, bubbleToRemove.getEntry()); - } + maybeSendDeleteIntent(reason, bubbleToRemove); } void overflowBubble(@DismissReason int reason, Bubble bubble) { @@ -611,21 +610,14 @@ public class BubbleData { return true; } - private void maybeSendDeleteIntent(@DismissReason int reason, - @NonNull final NotificationEntry entry) { - if (reason == BubbleController.DISMISS_USER_GESTURE) { - Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata(); - PendingIntent deleteIntent = bubbleMetadata != null - ? bubbleMetadata.getDeleteIntent() - : null; - if (deleteIntent != null) { - try { - deleteIntent.send(); - } catch (PendingIntent.CanceledException e) { - Log.w(TAG, "Failed to send delete intent for bubble with key: " - + entry.getKey()); - } - } + private void maybeSendDeleteIntent(@DismissReason int reason, @NonNull final Bubble bubble) { + if (reason != BubbleController.DISMISS_USER_GESTURE) return; + PendingIntent deleteIntent = bubble.getDeleteIntent(); + if (deleteIntent == null) return; + try { + deleteIntent.send(); + } catch (PendingIntent.CanceledException e) { + Log.w(TAG, "Failed to send delete intent for bubble with key: " + bubble.getKey()); } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt index d20f40559b5d..0c25d144938c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt @@ -74,11 +74,15 @@ internal class BubbleDataRepository @Inject constructor( private fun transform(userId: Int, bubbles: List): List { return bubbles.mapNotNull { b -> - var shortcutId = b.shortcutInfo?.id - if (shortcutId == null) shortcutId = b.entry?.bubbleMetadata?.shortcutId - if (shortcutId == null) return@mapNotNull null - BubbleEntity(userId, b.packageName, shortcutId, b.key, b.rawDesiredHeight, - b.rawDesiredHeightResId) + BubbleEntity( + userId, + b.packageName, + b.shortcutInfo?.id ?: return@mapNotNull null, + b.key, + b.rawDesiredHeight, + b.rawDesiredHeightResId, + b.title + ) } } @@ -159,8 +163,13 @@ internal class BubbleDataRepository @Inject constructor( val bubbles = entities.mapNotNull { entity -> shortcutMap[ShortcutKey(entity.userId, entity.packageName)] ?.first { shortcutInfo -> entity.shortcutId == shortcutInfo.id } - ?.let { shortcutInfo -> Bubble(entity.key, shortcutInfo, entity.desiredHeight, - entity.desiredHeightResId) } + ?.let { shortcutInfo -> Bubble( + entity.key, + shortcutInfo, + entity.desiredHeight, + entity.desiredHeightResId, + entity.title + ) } } uiScope.launch { cb(bubbles) } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 6dcc9dcdc63c..471a769c8204 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -169,7 +169,7 @@ public class BubbleExpandedView extends LinearLayout { return; } try { - if (!mIsOverflow && mBubble.usingShortcutInfo()) { + if (!mIsOverflow && mBubble.getShortcutInfo() != null) { options.setApplyActivityFlagsForBubbles(true); mActivityView.startShortcutActivity(mBubble.getShortcutInfo(), options, null /* sourceBounds */); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java index 8c76cda3290f..1fa3aaae5e61 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java @@ -31,6 +31,7 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.PointF; import android.graphics.RectF; +import android.graphics.drawable.Drawable; import android.graphics.drawable.ShapeDrawable; import android.text.TextUtils; import android.view.LayoutInflater; @@ -223,9 +224,10 @@ public class BubbleFlyoutView extends FrameLayout { float[] dotCenter, boolean hideDot) { - if (flyoutMessage.senderAvatar != null && flyoutMessage.isGroupChat) { + final Drawable senderAvatar = flyoutMessage.senderAvatar; + if (senderAvatar != null && flyoutMessage.isGroupChat) { mSenderAvatar.setVisibility(VISIBLE); - mSenderAvatar.setImageDrawable(flyoutMessage.senderAvatar); + mSenderAvatar.setImageDrawable(senderAvatar); } else { mSenderAvatar.setVisibility(GONE); mSenderAvatar.setTranslationX(0); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java index 74231c648f00..a799f2d739e5 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java @@ -15,7 +15,8 @@ */ package com.android.systemui.bubbles; -import android.app.Notification; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; @@ -50,15 +51,14 @@ public class BubbleIconFactory extends BaseIconFactory { /** * Returns the drawable that the developer has provided to display in the bubble. */ - Drawable getBubbleDrawable(Context context, ShortcutInfo shortcutInfo, - Notification.BubbleMetadata metadata) { + Drawable getBubbleDrawable(@NonNull final Context context, + @Nullable final ShortcutInfo shortcutInfo, @Nullable final Icon ic) { if (shortcutInfo != null) { LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); int density = context.getResources().getConfiguration().densityDpi; return launcherApps.getShortcutIconDrawable(shortcutInfo, density); } else { - Icon ic = metadata.getIcon(); if (ic != null) { if (ic.getType() == Icon.TYPE_URI || ic.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java index c5faae0d703e..c1dd8c36ff6f 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java @@ -16,8 +16,6 @@ package com.android.systemui.bubbles; -import android.service.notification.StatusBarNotification; - import com.android.internal.logging.UiEventLoggerImpl; /** @@ -32,12 +30,11 @@ public class BubbleLoggerImpl extends UiEventLoggerImpl implements BubbleLogger * @param e UI event */ public void log(Bubble b, UiEventEnum e) { - if (b.getEntry() == null) { + if (b.getInstanceId() == null) { // Added from persistence -- TODO log this with specific event? return; } - StatusBarNotification sbn = b.getEntry().getSbn(); - logWithInstanceId(e, sbn.getUid(), sbn.getPackageName(), sbn.getInstanceId()); + logWithInstanceId(e, b.getAppUid(), b.getPackageName(), b.getInstanceId()); } /** diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java index b4672c14b49a..ea324af3bd1a 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java @@ -300,9 +300,7 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter mUnbubbleConversationCallback; + private Consumer mUnbubbleConversationCallback; private SysUiState mSysUiState; @@ -997,10 +996,7 @@ public class BubbleStackView extends FrameLayout mManageMenu.findViewById(R.id.bubble_manage_menu_dont_bubble_container).setOnClickListener( view -> { showManageMenu(false /* show */); - final Bubble bubble = mBubbleData.getSelectedBubble(); - if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) { - mUnbubbleConversationCallback.accept(bubble.getEntry()); - } + mUnbubbleConversationCallback.accept(mBubbleData.getSelectedBubble().getKey()); }); mManageMenu.findViewById(R.id.bubble_manage_menu_settings_container).setOnClickListener( @@ -1348,7 +1344,7 @@ public class BubbleStackView extends FrameLayout /** Sets the function to call to un-bubble the given conversation. */ public void setUnbubbleConversationCallback( - Consumer unbubbleConversationCallback) { + Consumer unbubbleConversationCallback) { mUnbubbleConversationCallback = unbubbleConversationCallback; } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java index 525d5b56cc8e..3e4ff5262bbd 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java @@ -37,8 +37,6 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.AsyncTask; import android.os.Parcelable; -import android.os.UserHandle; -import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.Log; import android.util.PathParser; @@ -53,6 +51,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.lang.ref.WeakReference; import java.util.List; +import java.util.Objects; /** * Simple task to inflate views & load necessary info to display a bubble. @@ -129,35 +128,10 @@ public class BubbleViewInfoTask extends AsyncTask style = underlyingNotif.getNotificationStyle(); @@ -264,20 +240,9 @@ public class BubbleViewInfoTask extends AsyncTask - - + + + """.trimIndent() ByteArrayOutputStream().use { writeXml(it, bubbles) @@ -54,12 +54,12 @@ class BubbleXmlHelperTest : SysuiTestCase() { @Test fun testReadXml() { val src = """ - - - - - - + + + + + + """.trimIndent() val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8))) assertEquals("failed parsing bubbles from xml\n$src", bubbles, actual) -- cgit v1.2.3-59-g8ed1b