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

Commit 6f9511d8 authored by Mady Mellor's avatar Mady Mellor Committed by Automerger Merge Worker
Browse files

Merge "Make sure PendingIntent cancel listener is unregistered" into rvc-dev...

Merge "Make sure PendingIntent cancel listener is unregistered" into rvc-dev am: 0e3d9d31 am: 8c7fa9de

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12037679

Change-Id: I6312408e601e56425c3a115af39dfc417b7640c1
parents c969dcbb 8c7fa9de
Loading
Loading
Loading
Loading
+53 −7
Original line number Diff line number Diff line
@@ -124,8 +124,26 @@ class Bubble implements BubbleViewProvider {
    private int mNotificationId;
    private int mAppUid = -1;

    /**
     * A bubble is created and can be updated. This intent is updated until the user first
     * expands the bubble. Once the user has expanded the contents, we ignore the intent updates
     * to prevent restarting the intent & possibly altering UI state in the activity in front of
     * the user.
     *
     * Once the bubble is overflowed, the activity is finished and updates to the
     * notification are respected. Typically an update to an overflowed bubble would result in
     * that bubble being added back to the stack anyways.
     */
    @Nullable
    private PendingIntent mIntent;
    private boolean mIntentActive;
    @Nullable
    private PendingIntent.CancelListener mIntentCancelListener;

    /**
     * Sent when the bubble & notification are no longer visible to the user (i.e. no
     * notification in the shade, no bubble in the stack or overflow).
     */
    @Nullable
    private PendingIntent mDeleteIntent;

@@ -150,13 +168,19 @@ class Bubble implements BubbleViewProvider {
        mShowBubbleUpdateDot = false;
    }

    /** Used in tests when no UI is required. */
    @VisibleForTesting(visibility = PRIVATE)
    Bubble(@NonNull final NotificationEntry e,
            @Nullable final BubbleController.NotificationSuppressionChangedListener listener) {
            @Nullable final BubbleController.NotificationSuppressionChangedListener listener,
            final BubbleController.PendingIntentCanceledListener intentCancelListener) {
        Objects.requireNonNull(e);
        mKey = e.getKey();
        mSuppressionListener = listener;
        mIntentCancelListener = intent -> {
            if (mIntent != null) {
                mIntent.unregisterCancelListener(mIntentCancelListener);
            }
            intentCancelListener.onPendingIntentCanceled(this);
        };
        setEntry(e);
    }

@@ -238,6 +262,10 @@ class Bubble implements BubbleViewProvider {
            mExpandedView = null;
        }
        mIconView = null;
        if (mIntent != null) {
            mIntent.unregisterCancelListener(mIntentCancelListener);
        }
        mIntentActive = false;
    }

    void setPendingIntentCanceled() {
@@ -371,11 +399,24 @@ class Bubble implements BubbleViewProvider {
            mDesiredHeight = entry.getBubbleMetadata().getDesiredHeight();
            mDesiredHeightResId = entry.getBubbleMetadata().getDesiredHeightResId();
            mIcon = entry.getBubbleMetadata().getIcon();

            if (!mIntentActive || mIntent == null) {
                if (mIntent != null) {
                    mIntent.unregisterCancelListener(mIntentCancelListener);
                }
                mIntent = entry.getBubbleMetadata().getIntent();
                if (mIntent != null) {
                    mIntent.registerCancelListener(mIntentCancelListener);
                }
            } else if (mIntent != null && entry.getBubbleMetadata().getIntent() == null) {
                // Was an intent bubble now it's a shortcut bubble... still unregister the listener
                mIntent.unregisterCancelListener(mIntentCancelListener);
                mIntent = null;
            }
            mDeleteIntent = entry.getBubbleMetadata().getDeleteIntent();
        }
        mIsImportantConversation =
                entry.getChannel() == null ? false : entry.getChannel().isImportantConversation();
                entry.getChannel() != null && entry.getChannel().isImportantConversation();
    }

    @Nullable
@@ -395,10 +436,15 @@ class Bubble implements BubbleViewProvider {
    }

    /**
     * @return if the bubble was ever expanded
     * Sets if the intent used for this bubble is currently active (i.e. populating an
     * expanded view, expanded or not).
     */
    boolean getWasAccessed() {
        return mLastAccessed != 0L;
    void setIntentActive() {
        mIntentActive = true;
    }

    boolean isIntentActive() {
        return mIntentActive;
    }

    /**
+23 −17
Original line number Diff line number Diff line
@@ -262,6 +262,16 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        void onBubbleNotificationSuppressionChange(Bubble bubble);
    }

    /**
     * Listener to be notified when a pending intent has been canceled for a bubble.
     */
    public interface PendingIntentCanceledListener {
        /**
         * Called when the pending intent for a bubble has been canceled.
         */
        void onPendingIntentCanceled(Bubble bubble);
    }

    /**
     * Callback for when the BubbleController wants to interact with the notification pipeline to:
     * - Remove a previously bubbled notification
@@ -390,6 +400,18 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                }
            }
        });
        mBubbleData.setPendingIntentCancelledListener(bubble -> {
            if (bubble.getBubbleIntent() == null) {
                return;
            }
            if (bubble.isIntentActive()) {
                bubble.setPendingIntentCanceled();
                return;
            }
            mHandler.post(
                    () -> removeBubble(bubble.getKey(),
                            BubbleController.DISMISS_INVALID_INTENT));
        });

        mNotificationEntryManager = entryManager;
        mNotificationGroupManager = groupManager;
@@ -1101,23 +1123,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        // Lazy init stack view when a bubble is created
        ensureStackViewCreated();
        bubble.setInflateSynchronously(mInflateSynchronously);
        bubble.inflate(
                b -> {
                    mBubbleData.notificationEntryUpdated(b, suppressFlyout,
                            showInShade);
                    if (bubble.getBubbleIntent() == null) {
                        return;
                    }
                    bubble.getBubbleIntent().registerCancelListener(pendingIntent -> {
                        if (bubble.getWasAccessed()) {
                            bubble.setPendingIntentCanceled();
                            return;
                        }
                        mHandler.post(
                                () -> removeBubble(bubble.getKey(),
                                        BubbleController.DISMISS_INVALID_INTENT));
                    });
                },
        bubble.inflate(b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade),
                mContext, mStackView, mBubbleIconFactory, false /* skipInflation */);
    }

+8 −2
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ import javax.inject.Singleton;
@Singleton
public class BubbleData {

    BubbleLogger mLogger = new BubbleLoggerImpl();
    private BubbleLogger mLogger = new BubbleLoggerImpl();

    private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleData" : TAG_BUBBLES;

@@ -137,6 +137,7 @@ public class BubbleData {

    @Nullable
    private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;
    private BubbleController.PendingIntentCanceledListener mCancelledListener;

    /**
     * We track groups with summaries that aren't visibly displayed but still kept around because
@@ -167,6 +168,11 @@ public class BubbleData {
        mSuppressionListener = listener;
    }

    public void setPendingIntentCancelledListener(
            BubbleController.PendingIntentCanceledListener listener) {
        mCancelledListener = listener;
    }

    public boolean hasBubbles() {
        return !mBubbles.isEmpty();
    }
@@ -236,7 +242,7 @@ public class BubbleData {
                bubbleToReturn = mPendingBubbles.get(key);
            } else if (entry != null) {
                // New bubble
                bubbleToReturn = new Bubble(entry, mSuppressionListener);
                bubbleToReturn = new Bubble(entry, mSuppressionListener, mCancelledListener);
            } else {
                // Persisted bubble being promoted
                bubbleToReturn = persistedBubble;
+3 −0
Original line number Diff line number Diff line
@@ -183,6 +183,9 @@ public class BubbleExpandedView extends LinearLayout {
                                // Apply flags to make behaviour match documentLaunchMode=always.
                                fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
                                fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
                                if (mBubble != null) {
                                    mBubble.setIntentActive();
                                }
                                mActivityView.startActivity(mPendingIntent, fillInIntent, options);
                            }
                        } catch (RuntimeException e) {
+12 −17
Original line number Diff line number Diff line
@@ -107,6 +107,9 @@ public class BubbleDataTest extends SysuiTestCase {
    @Mock
    private BubbleController.NotificationSuppressionChangedListener mSuppressionListener;

    @Mock
    private BubbleController.PendingIntentCanceledListener mPendingIntentCanceledListener;

    @Before
    public void setUp() throws Exception {
        mNotificationTestHelper = new NotificationTestHelper(
@@ -127,20 +130,20 @@ public class BubbleDataTest extends SysuiTestCase {
        modifyRanking(mEntryInterruptive)
                .setVisuallyInterruptive(true)
                .build();
        mBubbleInterruptive = new Bubble(mEntryInterruptive, mSuppressionListener);
        mBubbleInterruptive = new Bubble(mEntryInterruptive, mSuppressionListener, null);

        ExpandableNotificationRow row = mNotificationTestHelper.createBubble();
        mEntryDismissed = createBubbleEntry(1, "dismissed", "package.d");
        mEntryDismissed.setRow(row);
        mBubbleDismissed = new Bubble(mEntryDismissed, mSuppressionListener);
        mBubbleDismissed = new Bubble(mEntryDismissed, mSuppressionListener, null);

        mBubbleA1 = new Bubble(mEntryA1, mSuppressionListener);
        mBubbleA2 = new Bubble(mEntryA2, mSuppressionListener);
        mBubbleA3 = new Bubble(mEntryA3, mSuppressionListener);
        mBubbleB1 = new Bubble(mEntryB1, mSuppressionListener);
        mBubbleB2 = new Bubble(mEntryB2, mSuppressionListener);
        mBubbleB3 = new Bubble(mEntryB3, mSuppressionListener);
        mBubbleC1 = new Bubble(mEntryC1, mSuppressionListener);
        mBubbleA1 = new Bubble(mEntryA1, mSuppressionListener, mPendingIntentCanceledListener);
        mBubbleA2 = new Bubble(mEntryA2, mSuppressionListener, mPendingIntentCanceledListener);
        mBubbleA3 = new Bubble(mEntryA3, mSuppressionListener, mPendingIntentCanceledListener);
        mBubbleB1 = new Bubble(mEntryB1, mSuppressionListener, mPendingIntentCanceledListener);
        mBubbleB2 = new Bubble(mEntryB2, mSuppressionListener, mPendingIntentCanceledListener);
        mBubbleB3 = new Bubble(mEntryB3, mSuppressionListener, mPendingIntentCanceledListener);
        mBubbleC1 = new Bubble(mEntryC1, mSuppressionListener, mPendingIntentCanceledListener);

        mBubbleData = new BubbleData(getContext());

@@ -847,14 +850,6 @@ public class BubbleDataTest extends SysuiTestCase {
        when(entry.getSbn().getPostTime()).thenReturn(postTime);
    }

    private void setOngoing(NotificationEntry entry, boolean ongoing) {
        if (ongoing) {
            entry.getSbn().getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
        } else {
            entry.getSbn().getNotification().flags &= ~Notification.FLAG_FOREGROUND_SERVICE;
        }
    }

    /**
     * No ExpandableNotificationRow is required to test BubbleData. This setup is all that is
     * required for BubbleData functionality and verification. NotificationTestHelper is used only
Loading