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

Commit 3c930613 authored by Pinyao Ting's avatar Pinyao Ting
Browse files

Persists bubbles to disk (part 4)

1. Decouple Bubble from NotificationEntry
2. Convert ShortcutInfo into Bubbles
3. Load overflow bubbles into memory

Test: follow the following steps
1. add a few bubbles from test app
2. restart the device
3. add a bubble from test app
4. click the plus sign to expand overview bubbles
5. verify overflow bubbles is displayed properly

This reverts commit b28e0568.
Reason for revert: Rolling-forward with fixed unit test

Bug: 156697897
Bug: 149713060
Change-Id: I21e4b17ee53ee7b6698115e1b497253bb54b355f
parent 0c5fe51a
Loading
Loading
Loading
Loading
+106 −9
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
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;

@@ -27,6 +28,7 @@ import android.app.Notification;
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;
@@ -55,6 +57,11 @@ 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;

@@ -96,11 +103,38 @@ class Bubble implements BubbleViewProvider {
    private Bitmap mBadgedImage;
    private int mDotColor;
    private Path mDotPath;
    private int mFlags;

    /**
     * Generate a unique identifier for this bubble based on given {@link NotificationEntry}. If
     * {@link ShortcutInfo} was found in the notification entry, the identifier would be generated
     * from {@link ShortcutInfo} instead. See also {@link #key(ShortcutInfo)}.
     */
    @NonNull
    public static String key(@NonNull final NotificationEntry entry) {
        final ShortcutInfo shortcutInfo = entry.getRanking().getShortcutInfo();
        if (shortcutInfo != null) return key(shortcutInfo);
        return entry.getKey();
    }

    /**
     * Generate a unique identifier for this bubble based on given {@link ShortcutInfo}.
     * See also {@link #key(NotificationEntry)}.
     */
    @NonNull
    public static String key(@NonNull final ShortcutInfo shortcutInfo) {
        return shortcutInfo.getUserId() + "|" + shortcutInfo.getPackage() + "|"
                + shortcutInfo.getId();
    }

    // TODO: Decouple Bubble from NotificationEntry and transform ShortcutInfo into Bubble
    /**
     * 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(ShortcutInfo shortcutInfo) {
        mShortcutInfo = shortcutInfo;
        mKey = shortcutInfo.getId();
        mKey = key(shortcutInfo);
        mFlags = 0;
    }

    /** Used in tests when no UI is required. */
@@ -108,9 +142,10 @@ class Bubble implements BubbleViewProvider {
    Bubble(NotificationEntry e,
            BubbleController.NotificationSuppressionChangedListener listener) {
        mEntry = e;
        mKey = e.getKey();
        mKey = key(e);
        mLastUpdated = e.getSbn().getPostTime();
        mSuppressionListener = listener;
        mFlags = e.getSbn().getNotification().flags;
    }

    @Override
@@ -118,12 +153,22 @@ class Bubble implements BubbleViewProvider {
        return mKey;
    }

    @Nullable
    public NotificationEntry getEntry() {
        return mEntry;
    }

    @Nullable
    public UserHandle getUser() {
        if (mEntry != null) return mEntry.getSbn().getUser();
        if (mShortcutInfo != null) return mShortcutInfo.getUserHandle();
        return null;
    }

    public String getPackageName() {
        return mEntry.getSbn().getPackageName();
        return mEntry == null
                ? mShortcutInfo == null ? null : mShortcutInfo.getPackage()
                : mEntry.getSbn().getPackageName();
    }

    @Override
@@ -167,6 +212,18 @@ class Bubble implements BubbleViewProvider {
        return mExpandedView;
    }

    @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;
    }

    /**
     * Call when the views should be removed, ensure this is called to clean up ActivityView
     * content.
@@ -207,7 +264,8 @@ class Bubble implements BubbleViewProvider {
    void inflate(BubbleViewInfoTask.Callback callback,
            Context context,
            BubbleStackView stackView,
            BubbleIconFactory iconFactory) {
            BubbleIconFactory iconFactory,
            boolean skipInflation) {
        if (isBubbleLoading()) {
            mInflationTask.cancel(true /* mayInterruptIfRunning */);
        }
@@ -215,6 +273,7 @@ class Bubble implements BubbleViewProvider {
                context,
                stackView,
                iconFactory,
                skipInflation,
                callback);
        if (mInflateSynchronously) {
            mInflationTask.onPostExecute(mInflationTask.doInBackground());
@@ -327,6 +386,7 @@ class Bubble implements BubbleViewProvider {
     * Whether this notification should be shown in the shade.
     */
    boolean showInShade() {
        if (mEntry == null) return false;
        return !shouldSuppressNotification() || !mEntry.isClearable();
    }

@@ -334,8 +394,8 @@ class Bubble implements BubbleViewProvider {
     * 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) {
@@ -366,6 +426,7 @@ class Bubble implements BubbleViewProvider {
     */
    @Override
    public boolean showDot() {
        if (mEntry == null) return false;
        return mShowBubbleUpdateDot
                && !mEntry.shouldSuppressNotificationDot()
                && !shouldSuppressNotification();
@@ -375,6 +436,7 @@ class Bubble implements BubbleViewProvider {
     * Whether the flyout for the bubble should be shown.
     */
    boolean showFlyout() {
        if (mEntry == null) return false;
        return !mSuppressFlyout && !mEntry.shouldSuppressPeek()
                && !shouldSuppressNotification()
                && !mEntry.shouldSuppressNotificationList();
@@ -394,6 +456,7 @@ class Bubble implements BubbleViewProvider {
    }

    float getDesiredHeight(Context context) {
        if (mEntry == null) return 0;
        Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
        boolean useRes = data.getDesiredHeightResId() != 0;
        if (useRes) {
@@ -407,6 +470,7 @@ class Bubble implements BubbleViewProvider {
    }

    String getDesiredHeightString() {
        if (mEntry == null) return String.valueOf(0);
        Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
        boolean useRes = data.getDesiredHeightResId() != 0;
        if (useRes) {
@@ -423,11 +487,13 @@ class Bubble implements BubbleViewProvider {
     * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
     */
    boolean usingShortcutInfo() {
        return mEntry.getBubbleMetadata().getShortcutId() != null;
        return mEntry != null && mEntry.getBubbleMetadata().getShortcutId() != null
                || mShortcutInfo != null;
    }

    @Nullable
    PendingIntent getBubbleIntent() {
        if (mEntry == null) return null;
        Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
        if (data != null) {
            return data.getIntent();
@@ -435,16 +501,32 @@ class Bubble implements BubbleViewProvider {
        return null;
    }

    Intent getSettingsIntent() {
    Intent getSettingsIntent(final Context context) {
        final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
        intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
        intent.putExtra(Settings.EXTRA_APP_UID, mEntry.getSbn().getUid());
        final int uid = getUid(context);
        if (uid != -1) {
            intent.putExtra(Settings.EXTRA_APP_UID, uid);
        }
        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        return intent;
    }

    private int getUid(final Context context) {
        if (mEntry != null) return mEntry.getSbn().getUid();
        final PackageManager pm = context.getPackageManager();
        if (pm == null) return -1;
        try {
            final ApplicationInfo info = pm.getApplicationInfo(mShortcutInfo.getPackage(), 0);
            return info.uid;
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "cannot find uid", e);
        }
        return -1;
    }

    private int getDimenForPackageUser(Context context, int resId, String pkg, int userId) {
        PackageManager pm = context.getPackageManager();
        Resources r;
@@ -466,11 +548,13 @@ class Bubble implements BubbleViewProvider {
    }

    private boolean shouldSuppressNotification() {
        if (mEntry == null) return false;
        return mEntry.getBubbleMetadata() != null
                && mEntry.getBubbleMetadata().isNotificationSuppressed();
    }

    boolean shouldAutoExpand() {
        if (mEntry == null) return false;
        Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
        return (metadata != null && metadata.getAutoExpandBubble()) ||  mShouldAutoExpand;
    }
@@ -479,6 +563,19 @@ class Bubble implements BubbleViewProvider {
        mShouldAutoExpand = shouldAutoExpand;
    }

    public boolean isBubble() {
        if (mEntry == null) return (mFlags & FLAG_BUBBLE) != 0;
        return (mEntry.getSbn().getNotification().flags & FLAG_BUBBLE) != 0;
    }

    public void enable(int option) {
        mFlags |= option;
    }

    public void disable(int option) {
        mFlags &= ~option;
    }

    @Override
    public String toString() {
        return "Bubble{" + mKey + '}';
+82 −29
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.INotificationManager;
@@ -113,6 +114,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Bubbles are a special type of content that can "float" on top of other apps or System UI.
@@ -243,13 +245,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
         * This can happen when an app cancels a bubbled notification or when the user dismisses a
         * bubble.
         */
        void removeNotification(NotificationEntry entry, int reason);
        void removeNotification(@NonNull NotificationEntry entry, int reason);

        /**
         * Called when a bubbled notification has changed whether it should be
         * filtered from the shade.
         */
        void invalidateNotifications(String reason);
        void invalidateNotifications(@NonNull String reason);

        /**
         * Called on a bubbled entry that has been removed when there are no longer
@@ -259,7 +261,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
         * removes all remnants of the group's summary from the notification pipeline.
         * TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
         */
        void maybeCancelSummary(NotificationEntry entry);
        void maybeCancelSummary(@NonNull NotificationEntry entry);
    }

    /**
@@ -604,6 +606,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi

            mStackView.setUnbubbleConversationCallback(notificationEntry ->
                    onUserChangedBubble(notificationEntry, false /* shouldBubble */));
            // Lazy load overflow bubbles from disk
            loadOverflowBubblesFromDisk();
        }

        addToWindowManagerMaybe();
@@ -755,10 +759,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        mBubbleIconFactory = new BubbleIconFactory(mContext);
        // Reload each bubble
        for (Bubble b: mBubbleData.getBubbles()) {
            b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory);
            b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory,
                    false /* skipInflation */);
        }
        for (Bubble b: mBubbleData.getOverflowBubbles()) {
            b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory);
            b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory,
                    false /* skipInflation */);
        }
    }

@@ -845,7 +851,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi

    void promoteBubbleFromOverflow(Bubble bubble) {
        bubble.setInflateSynchronously(mInflateSynchronously);
        setIsBubble(bubble.getEntry(), /* isBubble */ true);
        setIsBubble(bubble, /* isBubble */ true);
        mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
    }

@@ -895,10 +901,30 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        updateBubble(notif, false /* suppressFlyout */, true /* showInShade */);
    }

    /**
     * Fills the overflow bubbles by loading them from disk.
     */
    void loadOverflowBubblesFromDisk() {
        if (!mBubbleData.getOverflowBubbles().isEmpty()) {
            // we don't need to load overflow bubbles from disk if it is already in memory
            return;
        }
        mDataRepository.loadBubbles((bubbles) -> {
            bubbles.forEach(bubble -> {
                if (mBubbleData.getBubbles().contains(bubble)) {
                    // if the bubble is already active, there's no need to push it to overflow
                    return;
                }
                bubble.inflate((b) -> mBubbleData.overflowBubble(DISMISS_AGED, bubble),
                        mContext, mStackView, mBubbleIconFactory, true /* skipInflation */);
            });
            return null;
        });
    }

    void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
        // Lazy init stack view when a bubble is created
        ensureStackViewCreated();

        // If this is an interruptive notif, mark that it's interrupted
        if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
            notif.setInterruption();
@@ -918,11 +944,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                            return;
                        }
                        mHandler.post(
                                () -> removeBubble(bubble.getEntry(),
                                () -> removeBubble(bubble.getKey(),
                                        BubbleController.DISMISS_INVALID_INTENT));
                    });
                },
                mContext, mStackView, mBubbleIconFactory);
                mContext, mStackView, mBubbleIconFactory, false /* skipInflation */);
    }

    /**
@@ -934,7 +960,10 @@ 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(NotificationEntry entry, boolean shouldBubble) {
    public void onUserChangedBubble(@Nullable final NotificationEntry entry, boolean shouldBubble) {
        if (entry == null) {
            return;
        }
        NotificationChannel channel = entry.getChannel();
        final String appPkg = entry.getSbn().getPackageName();
        final int appUid = entry.getSbn().getUid();
@@ -973,14 +1002,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    }

    /**
     * Removes the bubble with the given NotificationEntry.
     * Removes the bubble with the given key.
     * <p>
     * Must be called from the main thread.
     */
    @MainThread
    void removeBubble(NotificationEntry entry, int reason) {
        if (mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
            mBubbleData.notificationEntryRemoved(entry, reason);
    void removeBubble(String key, int reason) {
        if (mBubbleData.hasAnyBubbleWithKey(key)) {
            mBubbleData.notificationEntryRemoved(key, reason);
        }
    }

@@ -998,7 +1027,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                && canLaunchInActivityView(mContext, entry);
        if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
            // It was previously a bubble but no longer a bubble -- lets remove it
            removeBubble(entry, DISMISS_NO_LONGER_BUBBLE);
            removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE);
        } else if (shouldBubble && entry.isBubble()) {
            updateBubble(entry);
        }
@@ -1012,10 +1041,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
            // Remove any associated bubble children with the summary
            final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
            for (int i = 0; i < bubbleChildren.size(); i++) {
                removeBubble(bubbleChildren.get(i).getEntry(), DISMISS_GROUP_CANCELLED);
                removeBubble(bubbleChildren.get(i).getKey(), DISMISS_GROUP_CANCELLED);
            }
        } else {
            removeBubble(entry, DISMISS_NOTIF_CANCEL);
            removeBubble(entry.getKey(), DISMISS_NOTIF_CANCEL);
        }
    }

@@ -1037,7 +1066,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
            rankingMap.getRanking(key, mTmpRanking);
            boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
            if (isActiveBubble && !mTmpRanking.canBubble()) {
                mBubbleData.notificationEntryRemoved(entry, BubbleController.DISMISS_BLOCKED);
                mBubbleData.notificationEntryRemoved(entry.getKey(),
                        BubbleController.DISMISS_BLOCKED);
            } else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
                entry.setFlagBubble(true);
                onEntryUpdated(entry);
@@ -1045,7 +1075,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        }
    }

    private void setIsBubble(NotificationEntry entry, boolean isBubble) {
    private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble) {
        Objects.requireNonNull(entry);
        if (isBubble) {
            entry.getSbn().getNotification().flags |= FLAG_BUBBLE;
        } else {
@@ -1058,6 +1089,24 @@ 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) {
            setIsBubble(b.getEntry(), isBubble);
        } else {
            try {
                mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0);
            } catch (RemoteException e) {
                // Bad things have happened
            }
        }
    }

    @SuppressWarnings("FieldCanBeLocal")
    private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() {

@@ -1097,18 +1146,21 @@ 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);
                            }
                        }
                    } else {
                        if (bubble.getEntry().isBubble() && bubble.showInShade()) {
                            setIsBubble(bubble.getEntry(), false /* isBubble */);
                        if (bubble.isBubble() && bubble.showInShade()) {
                            setIsBubble(bubble, false /* isBubble */);
                        }
                        if (bubble.getEntry().getRow() != null) {
                        if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) {
                            bubble.getEntry().getRow().updateBubbleButton();
                        }
                    }

                }
                if (bubble.getEntry() != null) {
                    final String groupKey = bubble.getEntry().getSbn().getGroupKey();
                    if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) {
                        // Time to potentially remove the summary
@@ -1117,6 +1169,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                        }
                    }
                }
            }
            mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);

            if (update.addedBubble != null) {
@@ -1138,7 +1191,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi

            if (update.selectionChanged) {
                mStackView.setSelectedBubble(update.selectedBubble);
                if (update.selectedBubble != null) {
                if (update.selectedBubble != null && update.selectedBubble.getEntry() != null) {
                    mNotificationGroupManager.updateSuppression(
                            update.selectedBubble.getEntry());
                }
+16 −8
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
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;
@@ -214,7 +215,7 @@ public class BubbleData {
                    notificationEntryUpdated(bubble, false /* suppressFlyout */,
                            true /* showInShade */);
                },
                mContext, stack, factory);
                mContext, stack, factory, false /* skipInflation */);
    }

    void setShowingOverflow(boolean showingOverflow) {
@@ -268,7 +269,8 @@ public class BubbleData {
        }
        mPendingBubbles.remove(bubble); // No longer pending once we're here
        Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
        suppressFlyout |= !bubble.getEntry().getRanking().visuallyInterruptive();
        suppressFlyout |= bubble.getEntry() == null
                || !bubble.getEntry().getRanking().visuallyInterruptive();

        if (prevBubble == null) {
            // Create a new bubble
@@ -297,11 +299,14 @@ public class BubbleData {
        dispatchPendingChanges();
    }

    public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) {
    /**
     * Called when a notification associated with a bubble is removed.
     */
    public void notificationEntryRemoved(String key, @DismissReason int reason) {
        if (DEBUG_BUBBLE_DATA) {
            Log.d(TAG, "notificationEntryRemoved: entry=" + entry + " reason=" + reason);
            Log.d(TAG, "notificationEntryRemoved: key=" + key + " reason=" + reason);
        }
        doRemove(entry.getKey(), reason);
        doRemove(key, reason);
        dispatchPendingChanges();
    }

@@ -349,7 +354,7 @@ public class BubbleData {
            return bubbleChildren;
        }
        for (Bubble b : mBubbles) {
            if (groupKey.equals(b.getEntry().getSbn().getGroupKey())) {
            if (b.getEntry() != null && groupKey.equals(b.getEntry().getSbn().getGroupKey())) {
                bubbleChildren.add(b);
            }
        }
@@ -447,8 +452,10 @@ public class BubbleData {
            Bubble newSelected = mBubbles.get(newIndex);
            setSelectedBubbleInternal(newSelected);
        }
        if (bubbleToRemove.getEntry() != null) {
            maybeSendDeleteIntent(reason, bubbleToRemove.getEntry());
        }
    }

    void overflowBubble(@DismissReason int reason, Bubble bubble) {
        if (bubble.getPendingIntentCanceled()
@@ -615,7 +622,8 @@ public class BubbleData {
        return true;
    }

    private void maybeSendDeleteIntent(@DismissReason int reason, NotificationEntry entry) {
    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
+3 −2
Original line number Diff line number Diff line
@@ -74,7 +74,9 @@ internal class BubbleDataRepository @Inject constructor(

    private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> {
        return bubbles.mapNotNull { b ->
            val shortcutId = b.shortcutInfo?.id ?: return@mapNotNull null
            var shortcutId = b.shortcutInfo?.id
            if (shortcutId == null) shortcutId = b.entry?.bubbleMetadata?.shortcutId
            if (shortcutId == null) return@mapNotNull null
            BubbleEntity(userId, b.packageName, shortcutId)
        }
    }
@@ -108,7 +110,6 @@ internal class BubbleDataRepository @Inject constructor(
    /**
     * Load bubbles from disk.
     */
    // TODO: call this method from BubbleController and update UI
    @SuppressLint("WrongConstant")
    fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch {
        /**
+2 −7
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.recents.TriangleShape;
import com.android.systemui.statusbar.AlphaOptimizedButton;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;

/**
 * Container for the expanded bubble view, handles rendering the caret and settings icon.
@@ -161,7 +160,7 @@ public class BubbleExpandedView extends LinearLayout {
                            // the bubble again so we'll just remove it.
                            Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
                                    + ", " + e.getMessage() + "; removing bubble");
                            mBubbleController.removeBubble(getBubbleEntry(),
                            mBubbleController.removeBubble(getBubbleKey(),
                                    BubbleController.DISMISS_INVALID_INTENT);
                        }
                    });
@@ -205,7 +204,7 @@ public class BubbleExpandedView extends LinearLayout {
            }
            if (mBubble != null) {
                // Must post because this is called from a binder thread.
                post(() -> mBubbleController.removeBubble(mBubble.getEntry(),
                post(() -> mBubbleController.removeBubble(mBubble.getKey(),
                        BubbleController.DISMISS_TASK_FINISHED));
            }
        }
@@ -297,10 +296,6 @@ public class BubbleExpandedView extends LinearLayout {
        return mBubble != null ? mBubble.getKey() : "null";
    }

    private NotificationEntry getBubbleEntry() {
        return mBubble != null ? mBubble.getEntry() : null;
    }

    void setManageClickListener(OnClickListener manageClickListener) {
        findViewById(R.id.settings_button).setOnClickListener(manageClickListener);
    }
Loading