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

Commit 72d9b176 authored by Ned Burns's avatar Ned Burns Committed by Android (Google) Code Review
Browse files

Merge changes Iecbd8999,Ic2d5860e,If1b69c19 into rvc-dev

* changes:
  Move icon logic out of NotificationEntry
  Add getAllNotifs() to CommonNotifCollection
  Change NotifCollection to use an event queue
parents b80e9d23 d8b5154b
Loading
Loading
Loading
Loading
+17 −6
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener;

import java.util.List;

@@ -159,20 +160,30 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
    }

    public void setEntry(NotificationEntry entry) {
        if (entry != null) {
        if (mShowingEntry != null) {
            mShowingEntry.removeOnSensitivityChangedListener(mOnSensitivityChangedListener);
        }
        mShowingEntry = entry;

        if (mShowingEntry != null) {
            CharSequence text = entry.headsUpStatusBarText;
            if (entry.isSensitive()) {
                text = entry.headsUpStatusBarTextPublic;
            }
            mTextView.setText(text);
            mShowingEntry.setOnSensitiveChangedListener(() -> setEntry(entry));
        } else if (mShowingEntry != null){
            mShowingEntry.setOnSensitiveChangedListener(null);
            mShowingEntry = null;
            mShowingEntry.addOnSensitivityChangedListener(mOnSensitivityChangedListener);
        }
    }

    private final OnSensitivityChangedListener mOnSensitivityChangedListener = entry -> {
        if (entry != mShowingEntry) {
            throw new IllegalStateException("Got a sensitivity change for " + entry
                    + " but mShowingEntry is " + mShowingEntry);
        }
        // Update the text
        setEntry(entry);
    };

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
+4 −4
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -262,11 +263,11 @@ public class NotificationMediaManager implements Dumpable {
        synchronized (mEntryManager) {
            NotificationEntry entry = mEntryManager
                    .getActiveNotificationUnfiltered(mMediaNotificationKey);
            if (entry == null || entry.expandedIcon == null) {
            if (entry == null || entry.getIcons().getShelfIcon() == null) {
                return null;
            }

            return entry.expandedIcon.getSourceIcon();
            return entry.getIcons().getShelfIcon().getSourceIcon();
        }
    }

@@ -284,8 +285,7 @@ public class NotificationMediaManager implements Dumpable {
        boolean metaDataChanged = false;

        synchronized (mEntryManager) {
            Set<NotificationEntry> allNotifications =
                    mEntryManager.getPendingAndActiveNotifications();
            Collection<NotificationEntry> allNotifications = mEntryManager.getAllNotifs();

            // Promote the media notification with a controller in 'playing' state, if any.
            NotificationEntry mediaNotification = null;
+3 −3
Original line number Diff line number Diff line
@@ -329,7 +329,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
                    expandableRow.setAboveShelf(false);
                }
                if (notGoneIndex == 0) {
                    StatusBarIconView icon = expandableRow.getEntry().expandedIcon;
                    StatusBarIconView icon = expandableRow.getEntry().getIcons().getShelfIcon();
                    NotificationIconContainer.IconState iconState = getIconState(icon);
                    // The icon state might be null in rare cases where the notification is actually
                    // added to the layout, but not to the shelf. An example are replied messages,
@@ -432,7 +432,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
            // if the shelf is clipped, lets make sure we also clip the icon
            maxTop = Math.max(maxTop, getTranslationY() + getClipTopAmount());
        }
        StatusBarIconView icon = row.getEntry().expandedIcon;
        StatusBarIconView icon = row.getEntry().getIcons().getShelfIcon();
        float shelfIconPosition = getTranslationY() + icon.getTop() + icon.getTranslationY();
        if (shelfIconPosition < maxTop && !mAmbientState.isFullyHidden()) {
            int top = (int) (maxTop - shelfIconPosition);
@@ -444,7 +444,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
    }

    private void updateContinuousClipping(final ExpandableNotificationRow row) {
        StatusBarIconView icon = row.getEntry().expandedIcon;
        StatusBarIconView icon = row.getEntry().getIcons().getShelfIcon();
        boolean needsContinuousClipping = ViewState.isAnimatingY(icon) && !mAmbientState.isDozing();
        boolean isContinuousClipping = icon.getTag(TAG_CONTINUOUS_CLIPPING) != null;
        if (needsContinuousClipping && !isContinuousClipping) {
+19 −11
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
@@ -56,9 +57,9 @@ import com.android.systemui.util.leak.LeakDetector;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -105,6 +106,10 @@ public class NotificationEntryManager implements
     */
    public static final int UNDEFINED_DISMISS_REASON = 0;

    private final Set<NotificationEntry> mAllNotifications = new ArraySet<>();
    private final Set<NotificationEntry> mReadOnlyAllNotifications =
            Collections.unmodifiableSet(mAllNotifications);

    /** Pending notifications are ones awaiting inflation */
    @VisibleForTesting
    protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
@@ -468,6 +473,8 @@ public class NotificationEntryManager implements
                    entry.removeRow();
                }

                mAllNotifications.remove(entry);

                // Let's remove the children if this was a summary
                handleGroupSummaryRemoved(key);
                removeVisibleNotification(key);
@@ -548,6 +555,7 @@ public class NotificationEntryManager implements
                notification,
                ranking,
                mFgsFeatureController.isForegroundServiceDismissalEnabled());
        mAllNotifications.add(entry);

        mLeakDetector.trackInstance(entry);

@@ -708,15 +716,6 @@ public class NotificationEntryManager implements
        return mPendingNotifications.values();
    }

    /**
     * @return all notifications we're currently aware of (both pending and active notifications)
     */
    public Set<NotificationEntry> getPendingAndActiveNotifications() {
        Set<NotificationEntry> allNotifs = new HashSet<>(mPendingNotifications.values());
        allNotifs.addAll(mSortedAndFiltered);
        return allNotifs;
    }

    /**
     * Use this method to retrieve a notification entry that has been prepared for presentation.
     * Note that the notification may be filtered out and never shown to the user.
@@ -842,7 +841,7 @@ public class NotificationEntryManager implements

    private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
        pw.print(indent);
        pw.println("  [" + i + "] key=" + e.getKey() + " icon=" + e.icon);
        pw.println("  [" + i + "] key=" + e.getKey() + " icon=" + e.getIcons().getStatusBarIcon());
        StatusBarNotification n = e.getSbn();
        pw.print(indent);
        pw.println("      pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
@@ -861,6 +860,15 @@ public class NotificationEntryManager implements
        return mReadOnlyNotifications;
    }

    /**
     * Returns a collections containing ALL notifications we know about, including ones that are
     * hidden or for other users. See {@link CommonNotifCollection#getAllNotifs()}.
     */
    @Override
    public Collection<NotificationEntry> getAllNotifs() {
        return mReadOnlyAllNotifications;
    }

    /** @return A count of the active notifications */
    public int getActiveNotificationsCount() {
        return mReadOnlyNotifications.size();
+49 −83
Original line number Diff line number Diff line
@@ -64,24 +64,34 @@ import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent;
import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler;
import com.android.systemui.statusbar.notification.collection.notifcollection.CleanUpEntryEvent;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.EntryAddedEvent;
import com.android.systemui.statusbar.notification.collection.notifcollection.EntryRemovedEvent;
import com.android.systemui.statusbar.notification.collection.notifcollection.EntryUpdatedEvent;
import com.android.systemui.statusbar.notification.collection.notifcollection.InitEntryEvent;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifEvent;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.collection.notifcollection.RankingAppliedEvent;
import com.android.systemui.statusbar.notification.collection.notifcollection.RankingUpdatedEvent;
import com.android.systemui.util.Assert;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;

import javax.inject.Inject;
import javax.inject.Singleton;
@@ -124,6 +134,8 @@ public class NotifCollection implements Dumpable {
    private final List<NotifLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
    private final List<NotifDismissInterceptor> mDismissInterceptors = new ArrayList<>();

    private Queue<NotifEvent> mEventQueue = new ArrayDeque<>();

    private boolean mAttached = false;
    private boolean mAmDispatchingToOtherCode;

@@ -160,8 +172,8 @@ public class NotifCollection implements Dumpable {
        mBuildListener = buildListener;
    }

    /** @see NotifPipeline#getActiveNotifs() */
    Collection<NotificationEntry> getActiveNotifs() {
    /** @see NotifPipeline#getAllNotifs() */
    Collection<NotificationEntry> getAllNotifs() {
        Assert.isMainThread();
        return mReadOnlyNotificationSet;
    }
@@ -242,7 +254,7 @@ public class NotifCollection implements Dumpable {
        }

        locallyDismissNotifications(entriesToLocallyDismiss);
        rebuildList();
        dispatchEventsAndRebuildList();
    }

    /**
@@ -251,8 +263,7 @@ public class NotifCollection implements Dumpable {
    public void dismissNotification(
            NotificationEntry entry,
            @NonNull DismissedByUserStats stats) {
        dismissNotifications(List.of(
                new Pair<NotificationEntry, DismissedByUserStats>(entry, stats)));
        dismissNotifications(List.of(new Pair<>(entry, stats)));
    }

    /**
@@ -268,7 +279,7 @@ public class NotifCollection implements Dumpable {
            // system process is dead if we're here.
        }

        final List<NotificationEntry> entries = new ArrayList(getActiveNotifs());
        final List<NotificationEntry> entries = new ArrayList<>(getAllNotifs());
        for (int i = entries.size() - 1; i >= 0; i--) {
            NotificationEntry entry = entries.get(i);
            if (!shouldDismissOnClearAll(entry, userId)) {
@@ -283,7 +294,7 @@ public class NotifCollection implements Dumpable {
        }

        locallyDismissNotifications(entries);
        rebuildList();
        dispatchEventsAndRebuildList();
    }

    /**
@@ -326,8 +337,9 @@ public class NotifCollection implements Dumpable {
    private void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
        Assert.isMainThread();

        postNotification(sbn, requireRanking(rankingMap, sbn.getKey()), rankingMap);
        rebuildList();
        postNotification(sbn, requireRanking(rankingMap, sbn.getKey()));
        applyRanking(rankingMap);
        dispatchEventsAndRebuildList();
    }

    private void onNotificationGroupPosted(List<CoalescedEvent> batch) {
@@ -336,9 +348,9 @@ public class NotifCollection implements Dumpable {
        mLogger.logNotifGroupPosted(batch.get(0).getSbn().getGroupKey(), batch.size());

        for (CoalescedEvent event : batch) {
            postNotification(event.getSbn(), event.getRanking(), null);
            postNotification(event.getSbn(), event.getRanking());
        }
        rebuildList();
        dispatchEventsAndRebuildList();
    }

    private void onNotificationRemoved(
@@ -354,55 +366,49 @@ public class NotifCollection implements Dumpable {
            throw new IllegalStateException("No notification to remove with key " + sbn.getKey());
        }
        entry.mCancellationReason = reason;
        applyRanking(rankingMap);
        tryRemoveNotification(entry);
        rebuildList();
        applyRanking(rankingMap);
        dispatchEventsAndRebuildList();
    }

    private void onNotificationRankingUpdate(RankingMap rankingMap) {
        Assert.isMainThread();
        mEventQueue.add(new RankingUpdatedEvent(rankingMap));
        applyRanking(rankingMap);
        dispatchNotificationRankingUpdate(rankingMap);
        rebuildList();
        dispatchEventsAndRebuildList();
    }

    private void postNotification(
            StatusBarNotification sbn,
            Ranking ranking,
            @Nullable RankingMap rankingMap) {
            Ranking ranking) {
        NotificationEntry entry = mNotificationSet.get(sbn.getKey());

        if (entry == null) {
            // A new notification!
            mLogger.logNotifPosted(sbn.getKey());

            entry = new NotificationEntry(sbn, ranking);
            mNotificationSet.put(sbn.getKey(), entry);
            dispatchOnEntryInit(entry);

            if (rankingMap != null) {
                applyRanking(rankingMap);
            }

            dispatchOnEntryAdded(entry);
            mLogger.logNotifPosted(sbn.getKey());
            mEventQueue.add(new InitEntryEvent(entry));
            mEventQueue.add(new EntryAddedEvent(entry));

        } else {
            // Update to an existing entry
            mLogger.logNotifUpdated(sbn.getKey());

            // Notification is updated so it is essentially re-added and thus alive again, so we
            // can reset its state.
            // TODO: If a coalesced event ever gets here, it's possible to lose track of children,
            //  since their rankings might have been updated earlier (and thus we may no longer
            //  think a child is associated with this locally-dismissed entry).
            cancelLocalDismissal(entry);
            cancelLifetimeExtension(entry);
            cancelDismissInterception(entry);
            entry.mCancellationReason = REASON_NOT_CANCELED;

            entry.setSbn(sbn);
            if (rankingMap != null) {
                applyRanking(rankingMap);
            }

            dispatchOnEntryUpdated(entry);
            mLogger.logNotifUpdated(sbn.getKey());
            mEventQueue.add(new EntryUpdatedEvent(entry));
        }
    }

@@ -432,8 +438,8 @@ public class NotifCollection implements Dumpable {
        if (!isLifetimeExtended(entry)) {
            mNotificationSet.remove(entry.getKey());
            cancelDismissInterception(entry);
            dispatchOnEntryRemoved(entry, entry.mCancellationReason);
            dispatchOnEntryCleanUp(entry);
            mEventQueue.add(new EntryRemovedEvent(entry, entry.mCancellationReason));
            mEventQueue.add(new CleanUpEntryEvent(entry));
            return true;
        } else {
            return false;
@@ -466,9 +472,16 @@ public class NotifCollection implements Dumpable {
                }
            }
        }
        mEventQueue.add(new RankingAppliedEvent());
    }

    private void dispatchEventsAndRebuildList() {
        mAmDispatchingToOtherCode = true;
        while (!mEventQueue.isEmpty()) {
            mEventQueue.remove().dispatchTo(mNotifCollectionListeners);
        }
        mAmDispatchingToOtherCode = false;

    private void rebuildList() {
        if (mBuildListener != null) {
            mBuildListener.onBuildList(mReadOnlyNotificationSet);
        }
@@ -491,7 +504,7 @@ public class NotifCollection implements Dumpable {

        if (!isLifetimeExtended(entry)) {
            if (tryRemoveNotification(entry)) {
                rebuildList();
                dispatchEventsAndRebuildList();
            }
        }
    }
@@ -660,57 +673,9 @@ public class NotifCollection implements Dumpable {
                || entry.getSbn().getUser().getIdentifier() == userId;
    }

    private void dispatchOnEntryInit(NotificationEntry entry) {
        mAmDispatchingToOtherCode = true;
        for (NotifCollectionListener listener : mNotifCollectionListeners) {
            listener.onEntryInit(entry);
        }
        mAmDispatchingToOtherCode = false;
    }

    private void dispatchOnEntryAdded(NotificationEntry entry) {
        mAmDispatchingToOtherCode = true;
        for (NotifCollectionListener listener : mNotifCollectionListeners) {
            listener.onEntryAdded(entry);
        }
        mAmDispatchingToOtherCode = false;
    }

    private void dispatchOnEntryUpdated(NotificationEntry entry) {
        mAmDispatchingToOtherCode = true;
        for (NotifCollectionListener listener : mNotifCollectionListeners) {
            listener.onEntryUpdated(entry);
        }
        mAmDispatchingToOtherCode = false;
    }

    private void dispatchNotificationRankingUpdate(RankingMap map) {
        mAmDispatchingToOtherCode = true;
        for (NotifCollectionListener listener : mNotifCollectionListeners) {
            listener.onRankingUpdate(map);
        }
        mAmDispatchingToOtherCode = false;
    }

    private void dispatchOnEntryRemoved(NotificationEntry entry, @CancellationReason int reason) {
        mAmDispatchingToOtherCode = true;
        for (NotifCollectionListener listener : mNotifCollectionListeners) {
            listener.onEntryRemoved(entry, reason);
        }
        mAmDispatchingToOtherCode = false;
    }

    private void dispatchOnEntryCleanUp(NotificationEntry entry) {
        mAmDispatchingToOtherCode = true;
        for (NotifCollectionListener listener : mNotifCollectionListeners) {
            listener.onEntryCleanUp(entry);
        }
        mAmDispatchingToOtherCode = false;
    }

    @Override
    public void dump(@NonNull FileDescriptor fd, PrintWriter pw, @NonNull String[] args) {
        final List<NotificationEntry> entries = new ArrayList<>(getActiveNotifs());
        final List<NotificationEntry> entries = new ArrayList<>(getAllNotifs());

        pw.println("\t" + TAG + " unsorted/unfiltered notifications:");
        if (entries.size() == 0) {
@@ -754,6 +719,7 @@ public class NotifCollection implements Dumpable {
    private static final String TAG = "NotifCollection";

    @IntDef(prefix = { "REASON_" }, value = {
            REASON_NOT_CANCELED,
            REASON_UNKNOWN,
            REASON_CLICK,
            REASON_CANCEL_ALL,
Loading