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

Commit b5361461 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: 17b5e3d4 am: 6a3f9562

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

Change-Id: Ia99574169c4d1da1b2d540d40b5c1ce0485e2f6d
parents 2cc10f4d 6a3f9562
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