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

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

Merge "Rework Notification Sectioning"

parents b116d877 4822097e
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -99,6 +99,13 @@ public class ListDumper {
                    .append(")");
        }

        if (entry.mNotifSection != null) {
            sb.append(" sectionIndex=")
                    .append(entry.getSection())
                    .append(" sectionName=")
                    .append(entry.mNotifSection.getName());
        }

        if (includeRecordKeeping) {
            NotificationEntry notifEntry = entry.getRepresentativeEntry();
            StringBuilder rksb = new StringBuilder();
+5 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.collection;

import android.annotation.Nullable;

import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;

/**
 * Abstract superclass for top-level entries, i.e. things that can appear in the final notification
 * list shown to users. In practice, this means either GroupEntries or NotificationEntries.
@@ -27,7 +29,9 @@ public abstract class ListEntry {

    @Nullable private GroupEntry mParent;
    @Nullable private GroupEntry mPreviousParent;
    private int mSection;
    @Nullable NotifSection mNotifSection;

    private int mSection = -1;
    int mFirstAddedIteration = -1;

    ListEntry(String key) {
+9 −10
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.OnBefo
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;

@@ -48,7 +48,7 @@ import javax.inject.Singleton;
 *   GroupEntry. These groups are then transformed in order to remove children or completely split
 *   them apart. To participate, see {@link #addPromoter}.
 * - Sorted: All top-level notifications are sorted. To participate, see
 *   {@link #setSectionsProvider} and {@link #setComparators}
 *   {@link #setSections} and {@link #setComparators}
 *
 * The exact order of all hooks is as follows:
 *  0. Collection listeners are fired ({@link #addCollectionListener}).
@@ -58,7 +58,7 @@ import javax.inject.Singleton;
 *  3. OnBeforeTransformGroupListeners are fired ({@link #addOnBeforeTransformGroupsListener})
 *  4. NotifPromoters are called on each notification with a parent ({@link #addPromoter})
 *  5. OnBeforeSortListeners are fired ({@link #addOnBeforeSortListener})
 *  6. SectionsProvider is called on each top-level entry in the list ({@link #setSectionsProvider})
 *  6. Top-level entries are assigned sections by NotifSections ({@link #setSections})
 *  7. Top-level entries within the same section are sorted by NotifComparators
 *     ({@link #setComparators})
 *  8. Pre-render filters are fired on each notification ({@link #addPreRenderFilter})
@@ -142,14 +142,13 @@ public class NotifPipeline {
    }

    /**
     * Assigns sections to each top-level entry, where a section is simply an integer. Sections are
     * the primary metric by which top-level entries are sorted; NotifComparators are only consulted
     * when two entries are in the same section. The pipeline doesn't assign any particular meaning
     * to section IDs -- from it's perspective they're just numbers and it sorts them by a simple
     * numerical comparison.
     * Sections that are used to sort top-level entries.  If two entries have the same section,
     * NotifComparators are consulted. Sections from this list are called in order for each
     * notification passed through the pipeline. The first NotifSection to return true for
     * {@link NotifSection#isInSection(ListEntry)} sets the entry as part of its Section.
     */
    public void setSectionsProvider(SectionsProvider provider) {
        mShadeListBuilder.setSectionsProvider(provider);
    public void setSections(List<NotifSection> sections) {
        mShadeListBuilder.setSections(sections);
    }

    /**
+65 −22
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static com.android.systemui.statusbar.notification.collection.listbuilder
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.util.ArrayMap;
import android.util.Pair;

import com.android.systemui.DumpController;
import com.android.systemui.Dumpable;
@@ -40,7 +41,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.Pipeli
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.statusbar.notification.logging.NotifEvent;
import com.android.systemui.statusbar.notification.logging.NotifLog;
@@ -82,7 +83,7 @@ public class ShadeListBuilder implements Dumpable {
    private final List<NotifPromoter> mNotifPromoters = new ArrayList<>();
    private final List<NotifFilter> mNotifPreRenderFilters = new ArrayList<>();
    private final List<NotifComparator> mNotifComparators = new ArrayList<>();
    private SectionsProvider mSectionsProvider = new DefaultSectionsProvider();
    private final List<NotifSection> mNotifSections = new ArrayList<>();

    private final List<OnBeforeTransformGroupsListener> mOnBeforeTransformGroupsListeners =
            new ArrayList<>();
@@ -170,12 +171,15 @@ public class ShadeListBuilder implements Dumpable {
        promoter.setInvalidationListener(this::onPromoterInvalidated);
    }

    void setSectionsProvider(SectionsProvider provider) {
    void setSections(List<NotifSection> sections) {
        Assert.isMainThread();
        mPipelineState.requireState(STATE_IDLE);

        mSectionsProvider = provider;
        provider.setInvalidationListener(this::onSectionsProviderInvalidated);
        mNotifSections.clear();
        for (NotifSection section : sections) {
            mNotifSections.add(section);
            section.setInvalidationListener(this::onNotifSectionInvalidated);
        }
    }

    void setComparators(List<NotifComparator> comparators) {
@@ -230,12 +234,12 @@ public class ShadeListBuilder implements Dumpable {
        rebuildListIfBefore(STATE_TRANSFORMING);
    }

    private void onSectionsProviderInvalidated(SectionsProvider provider) {
    private void onNotifSectionInvalidated(NotifSection section) {
        Assert.isMainThread();

        mNotifLog.log(NotifEvent.SECTIONS_PROVIDER_INVALIDATED, String.format(
                "Sections provider \"%s\" invalidated; pipeline state is %d",
                provider.getName(),
        mNotifLog.log(NotifEvent.SECTION_INVALIDATED, String.format(
                "Section \"%s\" invalidated; pipeline state is %d",
                section.getName(),
                mPipelineState.getState()));

        rebuildListIfBefore(STATE_SORTING);
@@ -318,7 +322,7 @@ public class ShadeListBuilder implements Dumpable {
        sortList();

        // Step 6: Filter out entries after pre-group filtering, grouping, promoting and sorting
        // Now filters can see grouping information to determine whether to filter or not
        // Now filters can see grouping information to determine whether to filter or not.
        mPipelineState.incrementTo(STATE_PRE_RENDER_FILTERING);
        filterNotifs(mNotifList, mNewNotifList, mNotifPreRenderFilters);
        applyNewNotifList();
@@ -580,6 +584,8 @@ public class ShadeListBuilder implements Dumpable {
     * filtered out during any of the filtering steps.
     */
    private void annulAddition(ListEntry entry) {
        entry.setSection(-1);
        entry.mNotifSection = null;
        entry.setParent(null);
        if (entry.mFirstAddedIteration == mIterationCount) {
            entry.mFirstAddedIteration = -1;
@@ -589,11 +595,12 @@ public class ShadeListBuilder implements Dumpable {
    private void sortList() {
        // Assign sections to top-level elements and sort their children
        for (ListEntry entry : mNotifList) {
            entry.setSection(mSectionsProvider.getSection(entry));
            Pair<NotifSection, Integer> sectionWithIndex = applySections(entry);
            if (entry instanceof GroupEntry) {
                GroupEntry parent = (GroupEntry) entry;
                for (NotificationEntry child : parent.getChildren()) {
                    child.setSection(0);
                    child.mNotifSection = sectionWithIndex.first;
                    child.setSection(sectionWithIndex.second);
                }
                parent.sortChildren(sChildComparator);
            }
@@ -754,6 +761,45 @@ public class ShadeListBuilder implements Dumpable {
        return null;
    }

    private Pair<NotifSection, Integer> applySections(ListEntry entry) {
        final Pair<NotifSection, Integer> sectionWithIndex = findSection(entry);
        final NotifSection section = sectionWithIndex.first;
        final Integer sectionIndex = sectionWithIndex.second;

        if (section != entry.mNotifSection) {
            if (entry.mNotifSection == null) {
                mNotifLog.log(NotifEvent.SECTION_CHANGED, String.format(
                        "%s: sectioned by '%s' [index=%d].",
                        entry.getKey(),
                        section.getName(),
                        sectionIndex));
            } else {
                mNotifLog.log(NotifEvent.SECTION_CHANGED, String.format(
                        "%s: section changed: '%s' [index=%d] -> '%s [index=%d]'.",
                        entry.getKey(),
                        entry.mNotifSection,
                        entry.getSection(),
                        section,
                        sectionIndex));
            }

            entry.mNotifSection = section;
            entry.setSection(sectionIndex);
        }

        return sectionWithIndex;
    }

    private Pair<NotifSection, Integer> findSection(ListEntry entry) {
        for (int i = 0; i < mNotifSections.size(); i++) {
            NotifSection sectioner = mNotifSections.get(i);
            if (sectioner.isInSection(entry)) {
                return new Pair<>(sectioner, i);
            }
        }
        return new Pair<>(sDefaultSection, mNotifSections.size());
    }

    private void rebuildListIfBefore(@PipelineState.StateName int state) {
        mPipelineState.requireIsBefore(state);
        if (mPipelineState.is(STATE_IDLE)) {
@@ -803,16 +849,13 @@ public class ShadeListBuilder implements Dumpable {
        void onRenderList(List<ListEntry> entries);
    }

    private static class DefaultSectionsProvider extends SectionsProvider {
        DefaultSectionsProvider() {
            super("DefaultSectionsProvider");
        }

    private static final NotifSection sDefaultSection =
            new NotifSection("DefaultSection") {
                @Override
        public int getSection(ListEntry entry) {
            return 0;
        }
                public boolean isInSection(ListEntry entry) {
                    return true;
                }
            };

    private static final String TAG = "NotifListBuilderImpl";

+5 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator;

import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;

/**
@@ -28,4 +29,8 @@ public interface Coordinator {
     * Coordinators should register their listeners and {@link Pluggable}s to the pipeline.
     */
    void attach(NotifPipeline pipeline);

    default NotifSection getSection() {
        return null;
    }
}
Loading