Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0532b99 authored by Mady Mellor's avatar Mady Mellor
Browse files

Bubble API: suppress bubble

Apps want to hide their bubble when/if the user is viewing
the same content outside of the bubble (e.g. bubble for
alice, user opens up conversation in main app for alice).

Devs can set a flag on BubbleMetadata to request this
behavior.

The match of bubble to activity is done via a locusId. So
apps must set a locusId on the notification & activity to
make this match (done in other CL).

Bug: 170267239
Test: atest NotificationManagerTest NotificationTest (see CTS CL)
Change-Id: I9f2efd3fd1ba4abdd8e579b51245d39a6be9186f
parent 9bcd1aef
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -5808,6 +5808,8 @@ package android.app {
    method @Nullable public android.graphics.drawable.Icon getIcon();
    method @Nullable public android.app.PendingIntent getIntent();
    method @Nullable public String getShortcutId();
    method public boolean isBubbleSuppressable();
    method public boolean isBubbleSuppressed();
    method public boolean isNotificationSuppressed();
    method public void writeToParcel(android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
@@ -5824,6 +5826,7 @@ package android.app {
    method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
    method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
    method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
    method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressBubble(boolean);
    method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressNotification(boolean);
  }
+59 −0
Original line number Diff line number Diff line
@@ -9789,6 +9789,22 @@ public class Notification implements Parcelable
         */
        public static final int FLAG_SUPPRESS_NOTIFICATION = 0x00000002;

        /**
         * Indicates whether the bubble should be visually suppressed from the bubble stack if the
         * user is viewing the same content outside of the bubble. For example, the user has a
         * bubble with Alice and then opens up the main app and navigates to Alice's page.
         *
         * @hide
         */
        public static final int FLAG_SHOULD_SUPPRESS_BUBBLE = 0x00000004;

        /**
         * Indicates whether the bubble is visually suppressed from the bubble stack.
         *
         * @hide
         */
        public static final int FLAG_SUPPRESS_BUBBLE = 0x00000008;

        private BubbleMetadata(PendingIntent expandIntent, PendingIntent deleteIntent,
                Icon icon, int height, @DimenRes int heightResId, String shortcutId) {
            mPendingIntent = expandIntent;
@@ -9931,6 +9947,32 @@ public class Notification implements Parcelable
            return (mFlags & FLAG_SUPPRESS_NOTIFICATION) != 0;
        }

        /**
         * Indicates whether the bubble should be visually suppressed from the bubble stack if the
         * user is viewing the same content outside of the bubble. For example, the user has a
         * bubble with Alice and then opens up the main app and navigates to Alice's page.
         *
         * To match the activity and the bubble notification, the bubble notification should
         * have a locus id set that matches a locus id set on the activity.
         *
         * @return whether this bubble should be suppressed when the same content is visible
         * outside of the bubble.
         *
         * @see BubbleMetadata.Builder#setSuppressBubble(boolean)
         */
        public boolean isBubbleSuppressable() {
            return (mFlags & FLAG_SHOULD_SUPPRESS_BUBBLE) != 0;
        }

        /**
         * Indicates whether the bubble is currently visually suppressed from the bubble stack.
         *
         * @see BubbleMetadata.Builder#setSuppressBubble(boolean)
         */
        public boolean isBubbleSuppressed() {
            return (mFlags & FLAG_SUPPRESS_BUBBLE) != 0;
        }

        public static final @android.annotation.NonNull Parcelable.Creator<BubbleMetadata> CREATOR =
                new Parcelable.Creator<BubbleMetadata>() {

@@ -10272,6 +10314,23 @@ public class Notification implements Parcelable
                return this;
            }

            /**
             * Indicates whether the bubble should be visually suppressed from the bubble stack if
             * the user is viewing the same content outside of the bubble. For example, the user has
             * a bubble with Alice and then opens up the main app and navigates to Alice's page.
             *
             * To match the activity and the bubble notification, the bubble notification should
             * have a locus id set that matches a locus id set on the activity.
             *
             * {@link Notification.Builder#setLocusId(LocusId)}
             * {@link Activity#setLocusContext(LocusId, Bundle)}
             */
            @NonNull
            public BubbleMetadata.Builder setSuppressBubble(boolean suppressBubble) {
                setFlag(FLAG_SHOULD_SUPPRESS_BUBBLE, suppressBubble);
                return this;
            }

            /**
             * Sets an intent to send when this bubble is explicitly removed by the user.
             *
+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ interface IStatusBarService
            in int notificationLocation, boolean modifiedBeforeSending);
    void onNotificationSettingsViewed(String key);
    void onNotificationBubbleChanged(String key, boolean isBubble, int flags);
    void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed);
    void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed, boolean isBubbleSuppressed);
    void hideCurrentInputMethodForBubbles();
    void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName);
    void clearInlineReplyUriPermissions(String key);
+9 −2
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ public class Bubble implements BubbleViewProvider {
    private long mLastAccessed;

    @Nullable
    private Bubbles.NotificationSuppressionChangedListener mSuppressionListener;
    private Bubbles.SuppressionChangedListener mSuppressionListener;

    /** Whether the bubble should show a dot for the notification indicating updated content. */
    private boolean mShowBubbleUpdateDot = true;
@@ -184,7 +184,7 @@ public class Bubble implements BubbleViewProvider {

    @VisibleForTesting(visibility = PRIVATE)
    Bubble(@NonNull final BubbleEntry entry,
            @Nullable final Bubbles.NotificationSuppressionChangedListener listener,
            @Nullable final Bubbles.SuppressionChangedListener listener,
            final Bubbles.PendingIntentCanceledListener intentCancelListener,
            Executor mainExecutor) {
        mKey = entry.getKey();
@@ -549,6 +549,13 @@ public class Bubble implements BubbleViewProvider {
        return !shouldSuppressNotification() || !mIsClearable;
    }

    /**
     * Whether this bubble is currently being hidden from the stack.
     */
    boolean isSuppressed() {
        return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE) != 0;
    }

    /**
     * Whether this notification conversation is important.
     */
+3 −6
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.wm.shell.bubbles;

import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
@@ -28,7 +27,6 @@ import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_BOT
import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_LEFT;
import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_NONE;
import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_RIGHT;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_AGED;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_BLOCKED;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_GROUP_CANCELLED;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_INVALID_INTENT;
@@ -42,7 +40,6 @@ import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_CHANGED;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
@@ -243,15 +240,15 @@ public class BubbleController {
        mBubbleData = data;
        mBubbleData.setListener(mBubbleDataListener);
        mBubbleData.setSuppressionChangedListener(bubble -> {
            // Make sure NoMan knows it's not showing in the shade anymore so anyone querying it
            // can tell.
            // Make sure NoMan knows suppression state so that anyone querying it can tell.
            try {
                mBarService.onBubbleNotificationSuppressionChanged(bubble.getKey(),
                        !bubble.showInShade());
                        !bubble.showInShade(), bubble.isSuppressed());
            } catch (RemoteException e) {
                // Bad things have happened
            }
        });

        mBubbleData.setPendingIntentCancelledListener(bubble -> {
            if (bubble.getBubbleIntent() == null) {
                return;
Loading