Loading core/java/android/app/Notification.java +33 −9 Original line number Diff line number Diff line Loading @@ -8644,17 +8644,23 @@ public class Notification implements Parcelable public static final int FLAG_AUTO_EXPAND_BUBBLE = 0x00000001; /** * If set and the app posting the bubble is in the foreground, the bubble will * be posted <b>without</b> the associated notification in the notification shade. * Indicates whether the notification associated with the bubble is being visually * suppressed from the notification shade. When <code>true</code> the notification is * hidden, when <code>false</code> the notification shows as normal. * * <p>This flag has no effect if the app posting the bubble is not in the foreground. * The app is considered foreground if it is visible and on the screen, note that * a foreground service does not qualify. * </p> * <p>Apps sending bubbles may set this flag so that the bubble is posted <b>without</b> * the associated notification in the notification shade.</p> * * <p>Generally this flag should only be set if the user has performed an action to request * or create a bubble, or if the user has seen the content in the notification and the * notification is no longer relevant.</p> * <p>Apps sending bubbles can only apply this flag when the app is in the foreground, * otherwise the flag is not respected. The app is considered foreground if it is visible * and on the screen, note that a foreground service does not qualify.</p> * * <p>Generally this flag should only be set by the app if the user has performed an * action to request or create a bubble, or if the user has seen the content in the * notification and the notification is no longer relevant. </p> * * <p>The system will also update this flag with <code>true</code> to hide the notification * from the user once the bubble has been expanded. </p> * * @hide */ Loading Loading @@ -8772,6 +8778,24 @@ public class Notification implements Parcelable } /** * Indicates whether the notification associated with the bubble is being visually * suppressed from the notification shade. When <code>true</code> the notification is * hidden, when <code>false</code> the notification shows as normal. * * <p>Apps sending bubbles may set this flag so that the bubble is posted <b>without</b> * the associated notification in the notification shade.</p> * * <p>Apps sending bubbles can only apply this flag when the app is in the foreground, * otherwise the flag is not respected. The app is considered foreground if it is visible * and on the screen, note that a foreground service does not qualify.</p> * * <p>Generally the app should only set this flag if the user has performed an * action to request or create a bubble, or if the user has seen the content in the * notification and the notification is no longer relevant. </p> * * <p>The system will update this flag with <code>true</code> to hide the notification * from the user once the bubble has been expanded.</p> * * @return whether this bubble should suppress the notification when it is posted. * * @see BubbleMetadata.Builder#setSuppressNotification(boolean) Loading core/java/com/android/internal/statusbar/IStatusBarService.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ interface IStatusBarService in int notificationLocation, boolean modifiedBeforeSending); void onNotificationSettingsViewed(String key); void onNotificationBubbleChanged(String key, boolean isBubble); void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed); void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName); void clearInlineReplyUriPermissions(String key); Loading packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +30 −24 Original line number Diff line number Diff line Loading @@ -60,6 +60,14 @@ class Bubble { private long mLastUpdated; private long mLastAccessed; private BubbleController.NotificationSuppressionChangedListener mSuppressionListener; /** Whether the bubble should show a dot for the notification indicating updated content. */ private boolean mShowBubbleUpdateDot = true; /** Whether flyout text should be suppressed, regardless of any other flags or state. */ private boolean mSuppressFlyout; // Items that are typically loaded later private String mAppName; private ShortcutInfo mShortcutInfo; Loading @@ -70,20 +78,6 @@ class Bubble { private BubbleViewInfoTask mInflationTask; private boolean mInflateSynchronously; /** * Whether this notification should be shown in the shade when it is also displayed as a bubble. * * <p>When a notification is a bubble we don't show it in the shade once the bubble has been * expanded</p> */ private boolean mShowInShadeWhenBubble = true; /** Whether the bubble should show a dot for the notification indicating updated content. */ private boolean mShowBubbleUpdateDot = true; /** Whether flyout text should be suppressed, regardless of any other flags or state. */ private boolean mSuppressFlyout; /** * Presentational info about the flyout. */ Loading @@ -106,11 +100,13 @@ class Bubble { /** Used in tests when no UI is required. */ @VisibleForTesting(visibility = PRIVATE) Bubble(NotificationEntry e) { Bubble(NotificationEntry e, BubbleController.NotificationSuppressionChangedListener listener) { mEntry = e; mKey = e.getKey(); mLastUpdated = e.getSbn().getPostTime(); mGroupId = groupId(e); mSuppressionListener = listener; } public String getKey() { Loading Loading @@ -278,7 +274,7 @@ class Bubble { */ void markAsAccessedAt(long lastAccessedMillis) { mLastAccessed = lastAccessedMillis; setShowInShade(false); setSuppressNotification(true); setShowDot(false /* show */, true /* animate */); } Loading @@ -290,20 +286,30 @@ class Bubble { } /** * Whether this notification should be shown in the shade when it is also displayed as a * bubble. * Whether this notification should be shown in the shade. */ boolean showInShade() { return !mEntry.isRowDismissed() && !shouldSuppressNotification() && (!mEntry.isClearable() || mShowInShadeWhenBubble); return !shouldSuppressNotification() || !mEntry.isClearable(); } /** * Sets whether this notification should be shown in the shade when it is also displayed as a * bubble. * Sets whether this notification should be suppressed in the shade. */ void setShowInShade(boolean showInShade) { mShowInShadeWhenBubble = showInShade; void setSuppressNotification(boolean suppressNotification) { boolean prevShowInShade = showInShade(); Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); int flags = data.getFlags(); if (suppressNotification) { flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; } else { flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; } data.setFlags(flags); if (showInShade() != prevShowInShade && mSuppressionListener != null) { mSuppressionListener.onBubbleNotificationSuppressionChange(this); } } /** Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +27 −3 Original line number Diff line number Diff line Loading @@ -223,6 +223,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi void onBubbleScreenshot(Bubble bubble); } /** * Listener to be notified when a bubbles' notification suppression state changes. */ public interface NotificationSuppressionChangedListener { /** * Called when the notification suppression state of a bubble changes. */ void onBubbleNotificationSuppressionChange(Bubble bubble); } /** * Listens for the current state of the status bar and updates the visibility state * of bubbles as needed. Loading Loading @@ -303,9 +314,22 @@ public class BubbleController implements ConfigurationController.ConfigurationLi configurationController.addCallback(this /* configurationListener */); mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered); mBubbleData = data; mBubbleData.setListener(mBubbleDataListener); mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered); mBubbleData.setSuppressionChangedListener(new NotificationSuppressionChangedListener() { @Override public void onBubbleNotificationSuppressionChange(Bubble bubble) { // Make sure NoMan knows it's not showing in the shade anymore so anyone querying it // can tell. try { mBarService.onBubbleNotificationSuppressionChanged(bubble.getKey(), !bubble.showInShade()); } catch (RemoteException e) { // Bad things have happened } } }); mNotificationEntryManager = entryManager; mNotificationEntryManager.addNotificationEntryListener(mEntryListener); Loading Loading @@ -720,7 +744,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi Bubble bubble = mBubbleData.getBubbleWithKey(key); boolean bubbleExtended = entry != null && entry.isBubble() && userRemovedNotif; if (bubbleExtended) { bubble.setShowInShade(false); bubble.setSuppressNotification(true); bubble.setShowDot(false /* show */, true /* animate */); mNotificationEntryManager.updateNotifications( "BubbleController.onNotificationRemoveRequested"); Loading @@ -747,7 +771,7 @@ 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. mNotificationGroupManager.onEntryRemoved(bubbleChild.getEntry()); bubbleChild.setShowInShade(false); bubbleChild.setSuppressNotification(true); bubbleChild.setShowDot(false /* show */, true /* animate */); } // And since all children are removed, remove the summary. Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +13 −3 Original line number Diff line number Diff line Loading @@ -134,6 +134,9 @@ public class BubbleData { @Nullable private Listener mListener; @Nullable private BubbleController.NotificationSuppressionChangedListener mSuppressionListener; /** * We track groups with summaries that aren't visibly displayed but still kept around because * the bubble(s) associated with the summary still exist. Loading @@ -158,6 +161,11 @@ public class BubbleData { mMaxOverflowBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_overflow); } public void setSuppressionChangedListener( BubbleController.NotificationSuppressionChangedListener listener) { mSuppressionListener = listener; } public boolean hasBubbles() { return !mBubbles.isEmpty(); } Loading Loading @@ -219,7 +227,7 @@ public class BubbleData { return b; } } bubble = new Bubble(entry); bubble = new Bubble(entry, mSuppressionListener); mPendingBubbles.add(bubble); } else { bubble.setEntry(entry); Loading Loading @@ -258,11 +266,13 @@ public class BubbleData { } else if (mSelectedBubble == null) { setSelectedBubbleInternal(bubble); } boolean isBubbleExpandedAndSelected = mExpanded && mSelectedBubble == bubble; bubble.setShowInShade(!isBubbleExpandedAndSelected && showInShade); boolean suppress = isBubbleExpandedAndSelected || !showInShade || !bubble.showInShade(); bubble.setSuppressNotification(suppress); bubble.setShowDot(!isBubbleExpandedAndSelected /* show */, true /* animate */); dispatchPendingChanges(); dispatchPendingChanges(); } public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) { Loading Loading
core/java/android/app/Notification.java +33 −9 Original line number Diff line number Diff line Loading @@ -8644,17 +8644,23 @@ public class Notification implements Parcelable public static final int FLAG_AUTO_EXPAND_BUBBLE = 0x00000001; /** * If set and the app posting the bubble is in the foreground, the bubble will * be posted <b>without</b> the associated notification in the notification shade. * Indicates whether the notification associated with the bubble is being visually * suppressed from the notification shade. When <code>true</code> the notification is * hidden, when <code>false</code> the notification shows as normal. * * <p>This flag has no effect if the app posting the bubble is not in the foreground. * The app is considered foreground if it is visible and on the screen, note that * a foreground service does not qualify. * </p> * <p>Apps sending bubbles may set this flag so that the bubble is posted <b>without</b> * the associated notification in the notification shade.</p> * * <p>Generally this flag should only be set if the user has performed an action to request * or create a bubble, or if the user has seen the content in the notification and the * notification is no longer relevant.</p> * <p>Apps sending bubbles can only apply this flag when the app is in the foreground, * otherwise the flag is not respected. The app is considered foreground if it is visible * and on the screen, note that a foreground service does not qualify.</p> * * <p>Generally this flag should only be set by the app if the user has performed an * action to request or create a bubble, or if the user has seen the content in the * notification and the notification is no longer relevant. </p> * * <p>The system will also update this flag with <code>true</code> to hide the notification * from the user once the bubble has been expanded. </p> * * @hide */ Loading Loading @@ -8772,6 +8778,24 @@ public class Notification implements Parcelable } /** * Indicates whether the notification associated with the bubble is being visually * suppressed from the notification shade. When <code>true</code> the notification is * hidden, when <code>false</code> the notification shows as normal. * * <p>Apps sending bubbles may set this flag so that the bubble is posted <b>without</b> * the associated notification in the notification shade.</p> * * <p>Apps sending bubbles can only apply this flag when the app is in the foreground, * otherwise the flag is not respected. The app is considered foreground if it is visible * and on the screen, note that a foreground service does not qualify.</p> * * <p>Generally the app should only set this flag if the user has performed an * action to request or create a bubble, or if the user has seen the content in the * notification and the notification is no longer relevant. </p> * * <p>The system will update this flag with <code>true</code> to hide the notification * from the user once the bubble has been expanded.</p> * * @return whether this bubble should suppress the notification when it is posted. * * @see BubbleMetadata.Builder#setSuppressNotification(boolean) Loading
core/java/com/android/internal/statusbar/IStatusBarService.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ interface IStatusBarService in int notificationLocation, boolean modifiedBeforeSending); void onNotificationSettingsViewed(String key); void onNotificationBubbleChanged(String key, boolean isBubble); void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed); void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName); void clearInlineReplyUriPermissions(String key); Loading
packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +30 −24 Original line number Diff line number Diff line Loading @@ -60,6 +60,14 @@ class Bubble { private long mLastUpdated; private long mLastAccessed; private BubbleController.NotificationSuppressionChangedListener mSuppressionListener; /** Whether the bubble should show a dot for the notification indicating updated content. */ private boolean mShowBubbleUpdateDot = true; /** Whether flyout text should be suppressed, regardless of any other flags or state. */ private boolean mSuppressFlyout; // Items that are typically loaded later private String mAppName; private ShortcutInfo mShortcutInfo; Loading @@ -70,20 +78,6 @@ class Bubble { private BubbleViewInfoTask mInflationTask; private boolean mInflateSynchronously; /** * Whether this notification should be shown in the shade when it is also displayed as a bubble. * * <p>When a notification is a bubble we don't show it in the shade once the bubble has been * expanded</p> */ private boolean mShowInShadeWhenBubble = true; /** Whether the bubble should show a dot for the notification indicating updated content. */ private boolean mShowBubbleUpdateDot = true; /** Whether flyout text should be suppressed, regardless of any other flags or state. */ private boolean mSuppressFlyout; /** * Presentational info about the flyout. */ Loading @@ -106,11 +100,13 @@ class Bubble { /** Used in tests when no UI is required. */ @VisibleForTesting(visibility = PRIVATE) Bubble(NotificationEntry e) { Bubble(NotificationEntry e, BubbleController.NotificationSuppressionChangedListener listener) { mEntry = e; mKey = e.getKey(); mLastUpdated = e.getSbn().getPostTime(); mGroupId = groupId(e); mSuppressionListener = listener; } public String getKey() { Loading Loading @@ -278,7 +274,7 @@ class Bubble { */ void markAsAccessedAt(long lastAccessedMillis) { mLastAccessed = lastAccessedMillis; setShowInShade(false); setSuppressNotification(true); setShowDot(false /* show */, true /* animate */); } Loading @@ -290,20 +286,30 @@ class Bubble { } /** * Whether this notification should be shown in the shade when it is also displayed as a * bubble. * Whether this notification should be shown in the shade. */ boolean showInShade() { return !mEntry.isRowDismissed() && !shouldSuppressNotification() && (!mEntry.isClearable() || mShowInShadeWhenBubble); return !shouldSuppressNotification() || !mEntry.isClearable(); } /** * Sets whether this notification should be shown in the shade when it is also displayed as a * bubble. * Sets whether this notification should be suppressed in the shade. */ void setShowInShade(boolean showInShade) { mShowInShadeWhenBubble = showInShade; void setSuppressNotification(boolean suppressNotification) { boolean prevShowInShade = showInShade(); Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); int flags = data.getFlags(); if (suppressNotification) { flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; } else { flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; } data.setFlags(flags); if (showInShade() != prevShowInShade && mSuppressionListener != null) { mSuppressionListener.onBubbleNotificationSuppressionChange(this); } } /** Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +27 −3 Original line number Diff line number Diff line Loading @@ -223,6 +223,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi void onBubbleScreenshot(Bubble bubble); } /** * Listener to be notified when a bubbles' notification suppression state changes. */ public interface NotificationSuppressionChangedListener { /** * Called when the notification suppression state of a bubble changes. */ void onBubbleNotificationSuppressionChange(Bubble bubble); } /** * Listens for the current state of the status bar and updates the visibility state * of bubbles as needed. Loading Loading @@ -303,9 +314,22 @@ public class BubbleController implements ConfigurationController.ConfigurationLi configurationController.addCallback(this /* configurationListener */); mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered); mBubbleData = data; mBubbleData.setListener(mBubbleDataListener); mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered); mBubbleData.setSuppressionChangedListener(new NotificationSuppressionChangedListener() { @Override public void onBubbleNotificationSuppressionChange(Bubble bubble) { // Make sure NoMan knows it's not showing in the shade anymore so anyone querying it // can tell. try { mBarService.onBubbleNotificationSuppressionChanged(bubble.getKey(), !bubble.showInShade()); } catch (RemoteException e) { // Bad things have happened } } }); mNotificationEntryManager = entryManager; mNotificationEntryManager.addNotificationEntryListener(mEntryListener); Loading Loading @@ -720,7 +744,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi Bubble bubble = mBubbleData.getBubbleWithKey(key); boolean bubbleExtended = entry != null && entry.isBubble() && userRemovedNotif; if (bubbleExtended) { bubble.setShowInShade(false); bubble.setSuppressNotification(true); bubble.setShowDot(false /* show */, true /* animate */); mNotificationEntryManager.updateNotifications( "BubbleController.onNotificationRemoveRequested"); Loading @@ -747,7 +771,7 @@ 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. mNotificationGroupManager.onEntryRemoved(bubbleChild.getEntry()); bubbleChild.setShowInShade(false); bubbleChild.setSuppressNotification(true); bubbleChild.setShowDot(false /* show */, true /* animate */); } // And since all children are removed, remove the summary. Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +13 −3 Original line number Diff line number Diff line Loading @@ -134,6 +134,9 @@ public class BubbleData { @Nullable private Listener mListener; @Nullable private BubbleController.NotificationSuppressionChangedListener mSuppressionListener; /** * We track groups with summaries that aren't visibly displayed but still kept around because * the bubble(s) associated with the summary still exist. Loading @@ -158,6 +161,11 @@ public class BubbleData { mMaxOverflowBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_overflow); } public void setSuppressionChangedListener( BubbleController.NotificationSuppressionChangedListener listener) { mSuppressionListener = listener; } public boolean hasBubbles() { return !mBubbles.isEmpty(); } Loading Loading @@ -219,7 +227,7 @@ public class BubbleData { return b; } } bubble = new Bubble(entry); bubble = new Bubble(entry, mSuppressionListener); mPendingBubbles.add(bubble); } else { bubble.setEntry(entry); Loading Loading @@ -258,11 +266,13 @@ public class BubbleData { } else if (mSelectedBubble == null) { setSelectedBubbleInternal(bubble); } boolean isBubbleExpandedAndSelected = mExpanded && mSelectedBubble == bubble; bubble.setShowInShade(!isBubbleExpandedAndSelected && showInShade); boolean suppress = isBubbleExpandedAndSelected || !showInShade || !bubble.showInShade(); bubble.setSuppressNotification(suppress); bubble.setShowDot(!isBubbleExpandedAndSelected /* show */, true /* animate */); dispatchPendingChanges(); dispatchPendingChanges(); } public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) { Loading