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

Commit d3ec630b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "rely-on-bubble-not-entry" into qt-r1-bubbles-dev

* changes:
  Base stuff on Bubble rather than NotifEntry; move stuff into Bubble
  Getters for private methods on Bubble & move dismissed from NotifEntry to Bubble
parents 93736f4d 99a30260
Loading
Loading
Loading
Loading
+197 −35
Original line number Diff line number Diff line
@@ -20,33 +20,46 @@ import static android.view.Display.INVALID_DISPLAY;

import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;

import android.annotation.Nullable;
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.PackageManager;
import android.content.res.Resources;
import android.os.Parcelable;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;

import java.util.List;
import java.util.Objects;

/**
 * Encapsulates the data and UI elements of a bubble.
 */
class Bubble {
    private static final String TAG = "Bubble";

    private NotificationEntry mEntry;
    private final String mKey;
    private final String mGroupId;
    private String mAppName;

    private boolean mInflated;
    public NotificationEntry entry;
    BubbleView iconView;
    BubbleExpandedView expandedView;
    private BubbleView mIconView;
    private BubbleExpandedView mExpandedView;

    private long mLastUpdated;
    private long mLastAccessed;
    private PackageManager mPm;
    private boolean mIsRemoved;

    public static String groupId(NotificationEntry entry) {
        UserHandle user = entry.notification.getUser();
@@ -56,25 +69,25 @@ class Bubble {
    /** Used in tests when no UI is required. */
    @VisibleForTesting(visibility = PRIVATE)
    Bubble(Context context, NotificationEntry e) {
        entry = e;
        mEntry = e;
        mKey = e.key;
        mLastUpdated = e.notification.getPostTime();
        mGroupId = groupId(e);

        mPm = context.getPackageManager();
        PackageManager pm = context.getPackageManager();
        ApplicationInfo info;
        try {
            info = mPm.getApplicationInfo(
                entry.notification.getPackageName(),
            info = pm.getApplicationInfo(
                mEntry.notification.getPackageName(),
                PackageManager.MATCH_UNINSTALLED_PACKAGES
                    | PackageManager.MATCH_DISABLED_COMPONENTS
                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                    | PackageManager.MATCH_DIRECT_BOOT_AWARE);
            if (info != null) {
                mAppName = String.valueOf(mPm.getApplicationLabel(info));
                mAppName = String.valueOf(pm.getApplicationLabel(info));
            }
        } catch (PackageManager.NameNotFoundException unused) {
            mAppName = entry.notification.getPackageName();
            mAppName = mEntry.notification.getPackageName();
        }
    }

@@ -82,12 +95,24 @@ class Bubble {
        return mKey;
    }

    public NotificationEntry getEntry() {
        return mEntry;
    }

    public boolean showInShadeWhenBubble() {
        return mEntry.showInShadeWhenBubble();
    }

    public void setShowInShadeWhenBubble(boolean showInShade) {
        mEntry.setShowInShadeWhenBubble(showInShade);
    }

    public String getGroupId() {
        return mGroupId;
    }

    public String getPackageName() {
        return entry.notification.getPackageName();
        return mEntry.notification.getPackageName();
    }

    public String getAppName() {
@@ -98,23 +123,31 @@ class Bubble {
        return mInflated;
    }

    public void updateDotVisibility() {
        if (iconView != null) {
            iconView.updateDotVisibility(true /* animate */);
    void updateDotVisibility() {
        if (mIconView != null) {
            mIconView.updateDotVisibility(true /* animate */);
        }
    }

    public BubbleView getIconView() {
        return mIconView;
    }

    public BubbleExpandedView getExpandedView() {
        return mExpandedView;
    }

    void inflate(LayoutInflater inflater, BubbleStackView stackView) {
        if (mInflated) {
            return;
        }
        iconView = (BubbleView) inflater.inflate(
        mIconView = (BubbleView) inflater.inflate(
                R.layout.bubble_view, stackView, false /* attachToRoot */);
        iconView.setNotif(entry);
        mIconView.setBubble(this);

        expandedView = (BubbleExpandedView) inflater.inflate(
        mExpandedView = (BubbleExpandedView) inflater.inflate(
                R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
        expandedView.setEntry(entry, stackView, mAppName);
        mExpandedView.setBubble(this, stackView, mAppName);

        mInflated = true;
    }
@@ -128,46 +161,54 @@ class Bubble {
     * and setting {@code false} actually means rendering the expanded view in transparent.
     */
    void setContentVisibility(boolean visibility) {
        if (expandedView != null) {
            expandedView.setContentVisibility(visibility);
        if (mExpandedView != null) {
            mExpandedView.setContentVisibility(visibility);
        }
    }

    void setDismissed() {
        entry.setBubbleDismissed(true);
    void setRemoved() {
        mIsRemoved = true;
        // TODO: move this somewhere where it can be guaranteed not to run until safe from flicker
        if (expandedView != null) {
            expandedView.cleanUpExpandedState();
        if (mExpandedView != null) {
            mExpandedView.cleanUpExpandedState();
        }
    }

    void setRemoved(boolean removed) {
        mIsRemoved = removed;
    }

    boolean isRemoved() {
        return mIsRemoved;
    }

    void setEntry(NotificationEntry entry) {
        this.entry = entry;
        mEntry = entry;
        mLastUpdated = entry.notification.getPostTime();
        if (mInflated) {
            iconView.update(entry);
            expandedView.update(entry);
            mIconView.update(this);
            mExpandedView.update(this);
        }
    }

    /**
     * @return the newer of {@link #getLastUpdateTime()} and {@link #getLastAccessTime()}
     */
    public long getLastActivity() {
    long getLastActivity() {
        return Math.max(mLastUpdated, mLastAccessed);
    }

    /**
     * @return the timestamp in milliseconds of the most recent notification entry for this bubble
     */
    public long getLastUpdateTime() {
    long getLastUpdateTime() {
        return mLastUpdated;
    }

    /**
     * @return the timestamp in milliseconds when this bubble was last displayed in expanded state
     */
    public long getLastAccessTime() {
    long getLastAccessTime() {
        return mLastAccessed;
    }

@@ -175,7 +216,7 @@ class Bubble {
     * @return the display id of the virtual display on which bubble contents is drawn.
     */
    int getDisplayId() {
        return expandedView != null ? expandedView.getVirtualDisplayId() : INVALID_DISPLAY;
        return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY;
    }

    /**
@@ -183,14 +224,135 @@ class Bubble {
     */
    void markAsAccessedAt(long lastAccessedMillis) {
        mLastAccessed = lastAccessedMillis;
        entry.setShowInShadeWhenBubble(false);
        setShowInShadeWhenBubble(false);
    }

    /**
     * @return whether bubble is from a notification associated with a foreground service.
     * Returns whether the notification for this bubble is a foreground service. It shows that this
     * is an ongoing bubble.
     */
    public boolean isOngoing() {
        return entry.isForegroundService();
    boolean isOngoing() {
        int flags = mEntry.notification.getNotification().flags;
        return (flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
    }

    float getDesiredHeight(Context context) {
        Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
        boolean useRes = data.getDesiredHeightResId() != 0;
        if (useRes) {
            return getDimenForPackageUser(context, data.getDesiredHeightResId(),
                    mEntry.notification.getPackageName(),
                    mEntry.notification.getUser().getIdentifier());
        } else {
            return data.getDesiredHeight()
                    * context.getResources().getDisplayMetrics().density;
        }
    }

    @Nullable
    PendingIntent getBubbleIntent(Context context) {
        Notification notif = mEntry.notification.getNotification();
        Notification.BubbleMetadata data = notif.getBubbleMetadata();
        if (BubbleController.canLaunchInActivityView(context, mEntry) && data != null) {
            return data.getIntent();
        }
        return null;
    }

    Intent getSettingsIntent() {
        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.notification.getUid());
        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        return intent;
    }

    /**
     * Returns our best guess for the most relevant text summary of the latest update to this
     * notification, based on its type. Returns null if there should not be an update message.
     */
    CharSequence getUpdateMessage(Context context) {
        final Notification underlyingNotif = mEntry.notification.getNotification();
        final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle();

        try {
            if (Notification.BigTextStyle.class.equals(style)) {
                // Return the big text, it is big so probably important. If it's not there use the
                // normal text.
                CharSequence bigText =
                        underlyingNotif.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
                return !TextUtils.isEmpty(bigText)
                        ? bigText
                        : underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
            } else if (Notification.MessagingStyle.class.equals(style)) {
                final List<Notification.MessagingStyle.Message> messages =
                        Notification.MessagingStyle.Message.getMessagesFromBundleArray(
                                (Parcelable[]) underlyingNotif.extras.get(
                                        Notification.EXTRA_MESSAGES));

                final Notification.MessagingStyle.Message latestMessage =
                        Notification.MessagingStyle.findLatestIncomingMessage(messages);

                if (latestMessage != null) {
                    final CharSequence personName = latestMessage.getSenderPerson() != null
                            ? latestMessage.getSenderPerson().getName()
                            : null;

                    // Prepend the sender name if available since group chats also use messaging
                    // style.
                    if (!TextUtils.isEmpty(personName)) {
                        return context.getResources().getString(
                                R.string.notification_summary_message_format,
                                personName,
                                latestMessage.getText());
                    } else {
                        return latestMessage.getText();
                    }
                }
            } else if (Notification.InboxStyle.class.equals(style)) {
                CharSequence[] lines =
                        underlyingNotif.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);

                // Return the last line since it should be the most recent.
                if (lines != null && lines.length > 0) {
                    return lines[lines.length - 1];
                }
            } else if (Notification.MediaStyle.class.equals(style)) {
                // Return nothing, media updates aren't typically useful as a text update.
                return null;
            } else {
                // Default to text extra.
                return underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
            }
        } catch (ClassCastException | NullPointerException | ArrayIndexOutOfBoundsException e) {
            // No use crashing, we'll just return null and the caller will assume there's no update
            // message.
            e.printStackTrace();
        }

        return null;
    }

    private int getDimenForPackageUser(Context context, int resId, String pkg, int userId) {
        PackageManager pm = context.getPackageManager();
        Resources r;
        if (pkg != null) {
            try {
                if (userId == UserHandle.USER_ALL) {
                    userId = UserHandle.USER_SYSTEM;
                }
                r = pm.getResourcesForApplicationAsUser(pkg, userId);
                return r.getDimensionPixelSize(resId);
            } catch (PackageManager.NameNotFoundException ex) {
                // Uninstalled, don't care
            } catch (Resources.NotFoundException e) {
                // Invalid res id, return 0 and user our default
                Log.e(TAG, "Couldn't find desired height res id", e);
            }
        }
        return 0;
    }

    @Override
+13 −11
Original line number Diff line number Diff line
@@ -408,7 +408,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        // TEMP: refactor to change this to pass entry
        Bubble bubble = mBubbleData.getBubbleWithKey(key);
        if (bubble != null) {
            mBubbleData.notificationEntryRemoved(bubble.entry, reason);
            mBubbleData.notificationEntryRemoved(bubble.getEntry(), reason);
        }
    }

@@ -420,7 +420,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                if (!mBubbleData.hasBubbleWithKey(key)) {
                    return false;
                }
                NotificationEntry entry = mBubbleData.getBubbleWithKey(key).entry;
                Bubble bubble = mBubbleData.getBubbleWithKey(key);
                NotificationEntry entry = bubble.getEntry();

                final boolean isClearAll = reason == REASON_CANCEL_ALL;
                final boolean isUserDimiss = reason == REASON_CANCEL;
@@ -434,7 +435,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi

                // The bubble notification sticks around in the data as long as the bubble is
                // not dismissed and the app hasn't cancelled the notification.
                boolean bubbleExtended = entry.isBubble() && !entry.isBubbleDismissed()
                boolean bubbleExtended = entry.isBubble() && !bubble.isRemoved()
                        && userRemovedNotif;
                if (bubbleExtended) {
                    entry.setShowInShadeWhenBubble(false);
@@ -443,7 +444,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                    }
                    mNotificationEntryManager.updateNotifications();
                    return true;
                } else if (!userRemovedNotif && !entry.isBubbleDismissed()) {
                } else if (!userRemovedNotif && !bubble.isRemoved()) {
                    // This wasn't a user removal so we should remove the bubble as well
                    mBubbleData.notificationEntryRemoved(entry, DISMISS_NOTIF_CANCEL);
                    return false;
@@ -488,7 +489,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                removeBubble(entry.key, DISMISS_NO_LONGER_BUBBLE);
            } else if (shouldBubble) {
                updateShowInShadeForSuppressNotification(entry);
                entry.setBubbleDismissed(false); // updates come back as bubbles even if dismissed
                Bubble b = mBubbleData.getBubbleWithKey(entry.key);
                b.setRemoved(false); // updates come back as bubbles even if dismissed
                updateBubble(entry);
            }
        }
@@ -531,13 +533,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                mStackView.removeBubble(bubble);

                if (!mBubbleData.hasBubbleWithKey(bubble.getKey())
                        && !bubble.entry.showInShadeWhenBubble()) {
                        && !bubble.showInShadeWhenBubble()) {
                    // The bubble is gone & the notification is gone, time to actually remove it
                    mNotificationEntryManager.performRemoveNotification(bubble.entry.notification,
                            UNDEFINED_DISMISS_REASON);
                    mNotificationEntryManager.performRemoveNotification(
                            bubble.getEntry().notification, UNDEFINED_DISMISS_REASON);
                } else {
                    // Update the flag for SysUI
                    bubble.entry.notification.getNotification().flags &= ~FLAG_BUBBLE;
                    bubble.getEntry().notification.getNotification().flags &= ~FLAG_BUBBLE;

                    // Make sure NoMan knows it's not a bubble anymore so anyone querying it will
                    // get right result back
@@ -758,8 +760,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
            if (expandedBubble.getDisplayId() == displayId) {
                mBubbleData.setExpanded(false);
            }
            if (expandedBubble.expandedView != null) {
                expandedBubble.expandedView.notifyDisplayEmpty();
            if (expandedBubble.getExpandedView() != null) {
                expandedBubble.getExpandedView().notifyDisplayEmpty();
            }
        }
    }
+4 −4
Original line number Diff line number Diff line
@@ -302,8 +302,8 @@ public class BubbleData {
            Bubble newSelected = mBubbles.get(newIndex);
            setSelectedBubbleInternal(newSelected);
        }
        bubbleToRemove.setDismissed();
        maybeSendDeleteIntent(reason, bubbleToRemove.entry);
        bubbleToRemove.setRemoved();
        maybeSendDeleteIntent(reason, bubbleToRemove.getEntry());
    }

    public void dismissAll(@DismissReason int reason) {
@@ -317,8 +317,8 @@ public class BubbleData {
        setSelectedBubbleInternal(null);
        while (!mBubbles.isEmpty()) {
            Bubble bubble = mBubbles.remove(0);
            bubble.setDismissed();
            maybeSendDeleteIntent(reason, bubble.entry);
            bubble.setRemoved();
            maybeSendDeleteIntent(reason, bubble.getEntry());
            mStateChange.bubbleRemoved(bubble, reason);
        }
        dispatchPendingChanges();
+27 −89

File changed.

Preview size limit exceeded, changes collapsed.

+42 −55

File changed.

Preview size limit exceeded, changes collapsed.

Loading