Merge changes I1169beb3,If7c7b737 into rvc-dev

* changes:
  Move preparation coordinator to after grouping
  Add listener hook before finalize filter.
This commit is contained in:
Kevin Han
2020-03-04 01:08:32 +00:00
committed by Android (Google) Code Review
12 changed files with 261 additions and 53 deletions

View File

@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
@@ -63,7 +64,7 @@ import javax.inject.Singleton;
* 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})
* 8. Finalize filters are fired on each notification ({@link #addFinalizeFilter})
* 9. OnBeforeRenderListListeners are fired ({@link #addOnBeforeRenderListListener})
* 9. The list is handed off to the view layer to be rendered
*/
@@ -168,6 +169,14 @@ public class NotifPipeline implements CommonNotifCollection {
mShadeListBuilder.setComparators(comparators);
}
/**
* Called after notifs have been filtered once, grouped, and sorted but before the final
* filtering.
*/
public void addOnBeforeFinalizeFilterListener(OnBeforeFinalizeFilterListener listener) {
mShadeListBuilder.addOnBeforeFinalizeFilterListener(listener);
}
/**
* Registers a filter with the pipeline to filter right before rendering the list (after
* pre-group filtering, grouping, promoting and sorting occurs). Filters are
@@ -175,8 +184,8 @@ public class NotifPipeline implements CommonNotifCollection {
* true, the notification is removed from the pipeline (and no other filters are called on that
* notif).
*/
public void addPreRenderFilter(NotifFilter filter) {
mShadeListBuilder.addPreRenderFilter(filter);
public void addFinalizeFilter(NotifFilter filter) {
mShadeListBuilder.addFinalizeFilter(filter);
}
/**

View File

@@ -18,11 +18,11 @@ package com.android.systemui.statusbar.notification.collection;
import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_STARTED;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FINALIZE_FILTERING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FINALIZING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_GROUPING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_IDLE;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_PRE_GROUP_FILTERING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_PRE_RENDER_FILTERING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_RESETTING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_SORTING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_TRANSFORMING;
@@ -36,6 +36,7 @@ import androidx.annotation.NonNull;
import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
@@ -82,7 +83,7 @@ public class ShadeListBuilder implements Dumpable {
private final List<NotifFilter> mNotifPreGroupFilters = new ArrayList<>();
private final List<NotifPromoter> mNotifPromoters = new ArrayList<>();
private final List<NotifFilter> mNotifPreRenderFilters = new ArrayList<>();
private final List<NotifFilter> mNotifFinalizeFilters = new ArrayList<>();
private final List<NotifComparator> mNotifComparators = new ArrayList<>();
private final List<NotifSection> mNotifSections = new ArrayList<>();
@@ -90,6 +91,8 @@ public class ShadeListBuilder implements Dumpable {
new ArrayList<>();
private final List<OnBeforeSortListener> mOnBeforeSortListeners =
new ArrayList<>();
private final List<OnBeforeFinalizeFilterListener> mOnBeforeFinalizeFilterListeners =
new ArrayList<>();
private final List<OnBeforeRenderListListener> mOnBeforeRenderListListeners =
new ArrayList<>();
@Nullable private OnRenderListListener mOnRenderListListener;
@@ -142,6 +145,13 @@ public class ShadeListBuilder implements Dumpable {
mOnBeforeSortListeners.add(listener);
}
void addOnBeforeFinalizeFilterListener(OnBeforeFinalizeFilterListener listener) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
mOnBeforeFinalizeFilterListeners.add(listener);
}
void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) {
Assert.isMainThread();
@@ -157,12 +167,12 @@ public class ShadeListBuilder implements Dumpable {
filter.setInvalidationListener(this::onPreGroupFilterInvalidated);
}
void addPreRenderFilter(NotifFilter filter) {
void addFinalizeFilter(NotifFilter filter) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
mNotifPreRenderFilters.add(filter);
filter.setInvalidationListener(this::onPreRenderFilterInvalidated);
mNotifFinalizeFilters.add(filter);
filter.setInvalidationListener(this::onFinalizeFilterInvalidated);
}
void addPromoter(NotifPromoter promoter) {
@@ -237,12 +247,12 @@ public class ShadeListBuilder implements Dumpable {
rebuildListIfBefore(STATE_SORTING);
}
private void onPreRenderFilterInvalidated(NotifFilter filter) {
private void onFinalizeFilterInvalidated(NotifFilter filter) {
Assert.isMainThread();
mLogger.logPreRenderFilterInvalidated(filter.getName(), mPipelineState.getState());
mLogger.logFinalizeFilterInvalidated(filter.getName(), mPipelineState.getState());
rebuildListIfBefore(STATE_PRE_RENDER_FILTERING);
rebuildListIfBefore(STATE_FINALIZE_FILTERING);
}
private void onNotifComparatorInvalidated(NotifComparator comparator) {
@@ -298,8 +308,9 @@ public class ShadeListBuilder implements Dumpable {
// 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.
mPipelineState.incrementTo(STATE_PRE_RENDER_FILTERING);
filterNotifs(mNotifList, mNewNotifList, mNotifPreRenderFilters);
dispatchOnBeforeFinalizeFilter(mReadOnlyNotifList);
mPipelineState.incrementTo(STATE_FINALIZE_FILTERING);
filterNotifs(mNotifList, mNewNotifList, mNotifFinalizeFilters);
applyNewNotifList();
pruneIncompleteGroups(mNotifList);
@@ -772,6 +783,12 @@ public class ShadeListBuilder implements Dumpable {
}
}
private void dispatchOnBeforeFinalizeFilter(List<ListEntry> entries) {
for (int i = 0; i < mOnBeforeFinalizeFilterListeners.size(); i++) {
mOnBeforeFinalizeFilterListeners.get(i).onBeforeFinalizeFilter(entries);
}
}
private void dispatchOnBeforeRenderList(List<ListEntry> entries) {
for (int i = 0; i < mOnBeforeRenderListListeners.size(); i++) {
mOnBeforeRenderListListeners.get(i).onBeforeRenderList(entries);

View File

@@ -77,7 +77,7 @@ public class BubbleCoordinator implements Coordinator {
public void attach(NotifPipeline pipeline) {
mNotifPipeline = pipeline;
mNotifPipeline.addNotificationDismissInterceptor(mDismissInterceptor);
mNotifPipeline.addPreRenderFilter(mNotifFilter);
mNotifPipeline.addFinalizeFilter(mNotifFilter);
mBubbleController.addNotifCallback(mNotifCallback);
}

View File

@@ -87,7 +87,7 @@ public class KeyguardCoordinator implements Coordinator {
@Override
public void attach(NotifPipeline pipeline) {
setupInvalidateNotifListCallbacks();
pipeline.addPreRenderFilter(mNotifFilter);
pipeline.addFinalizeFilter(mNotifFilter);
}
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {

View File

@@ -16,31 +16,39 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import android.annotation.IntDef;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import java.util.ArrayList;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Kicks off notification inflation and view rebinding when a notification is added or updated.
* Kicks off core notification inflation and view rebinding when a notification is added or updated.
* Aborts inflation when a notification is removed.
*
* If a notification is not done inflating, this coordinator will filter the notification out
* from the {@link ShadeListBuilder}.
* If a notification was uninflated, this coordinator will filter the notification out from the
* {@link ShadeListBuilder} until it is inflated.
*/
@Singleton
public class PreparationCoordinator implements Coordinator {
@@ -49,7 +57,7 @@ public class PreparationCoordinator implements Coordinator {
private final PreparationCoordinatorLogger mLogger;
private final NotifInflater mNotifInflater;
private final NotifInflationErrorManager mNotifErrorManager;
private final List<NotificationEntry> mPendingNotifications = new ArrayList<>();
private final Map<NotificationEntry, Integer> mInflationStates = new ArrayMap<>();
private final IStatusBarService mStatusBarService;
@Inject
@@ -69,27 +77,44 @@ public class PreparationCoordinator implements Coordinator {
@Override
public void attach(NotifPipeline pipeline) {
pipeline.addCollectionListener(mNotifCollectionListener);
pipeline.addPreRenderFilter(mNotifInflationErrorFilter);
pipeline.addPreRenderFilter(mNotifInflatingFilter);
// Inflate after grouping/sorting since that affects what views to inflate.
pipeline.addOnBeforeFinalizeFilterListener(mOnBeforeFinalizeFilterListener);
pipeline.addFinalizeFilter(mNotifInflationErrorFilter);
pipeline.addFinalizeFilter(mNotifInflatingFilter);
}
private final NotifCollectionListener mNotifCollectionListener = new NotifCollectionListener() {
@Override
public void onEntryAdded(NotificationEntry entry) {
inflateEntry(entry, "entryAdded");
public void onEntryInit(NotificationEntry entry) {
mInflationStates.put(entry, STATE_UNINFLATED);
}
@Override
public void onEntryUpdated(NotificationEntry entry) {
rebind(entry, "entryUpdated");
@InflationState int state = getInflationState(entry);
if (state == STATE_INFLATED) {
mInflationStates.put(entry, STATE_INFLATED_INVALID);
} else if (state == STATE_ERROR) {
// Updated so maybe it won't error out now.
mInflationStates.put(entry, STATE_UNINFLATED);
}
}
@Override
public void onEntryRemoved(NotificationEntry entry, int reason) {
abortInflation(entry, "entryRemoved reason=" + reason);
}
@Override
public void onEntryCleanUp(NotificationEntry entry) {
mInflationStates.remove(entry);
}
};
private final OnBeforeFinalizeFilterListener mOnBeforeFinalizeFilterListener =
entries -> inflateAllRequiredViews(entries);
private final NotifFilter mNotifInflationErrorFilter = new NotifFilter(
TAG + "InflationError") {
/**
@@ -97,10 +122,7 @@ public class PreparationCoordinator implements Coordinator {
*/
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
if (mNotifErrorManager.hasInflationError(entry)) {
return true;
}
return false;
return getInflationState(entry) == STATE_ERROR;
}
};
@@ -110,7 +132,8 @@ public class PreparationCoordinator implements Coordinator {
*/
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
return mPendingNotifications.contains(entry);
@InflationState int state = getInflationState(entry);
return (state != STATE_INFLATED) && (state != STATE_INFLATED_INVALID);
}
};
@@ -119,7 +142,7 @@ public class PreparationCoordinator implements Coordinator {
@Override
public void onInflationFinished(NotificationEntry entry) {
mLogger.logNotifInflated(entry.getKey());
mPendingNotifications.remove(entry);
mInflationStates.put(entry, STATE_INFLATED);
mNotifInflatingFilter.invalidateList();
}
};
@@ -128,7 +151,7 @@ public class PreparationCoordinator implements Coordinator {
new NotifInflationErrorManager.NotifInflationErrorListener() {
@Override
public void onNotifInflationError(NotificationEntry entry, Exception e) {
mPendingNotifications.remove(entry);
mInflationStates.put(entry, STATE_ERROR);
try {
final StatusBarNotification sbn = entry.getSbn();
// report notification inflation errors back up
@@ -152,9 +175,41 @@ public class PreparationCoordinator implements Coordinator {
}
};
private void inflateAllRequiredViews(List<ListEntry> entries) {
for (int i = 0, size = entries.size(); i < size; i++) {
ListEntry entry = entries.get(i);
if (entry instanceof GroupEntry) {
GroupEntry groupEntry = (GroupEntry) entry;
inflateNotifRequiredViews(groupEntry.getSummary());
List<NotificationEntry> children = groupEntry.getChildren();
for (int j = 0, groupSize = children.size(); j < groupSize; j++) {
inflateNotifRequiredViews(children.get(j));
}
} else {
NotificationEntry notifEntry = (NotificationEntry) entry;
inflateNotifRequiredViews(notifEntry);
}
}
}
private void inflateNotifRequiredViews(NotificationEntry entry) {
@InflationState int state = mInflationStates.get(entry);
switch (state) {
case STATE_UNINFLATED:
inflateEntry(entry, "entryAdded");
break;
case STATE_INFLATED_INVALID:
rebind(entry, "entryUpdated");
break;
case STATE_INFLATED:
case STATE_ERROR:
default:
// Nothing to do.
}
}
private void inflateEntry(NotificationEntry entry, String reason) {
abortInflation(entry, reason);
mPendingNotifications.add(entry);
mNotifInflater.inflateViews(entry);
}
@@ -165,6 +220,32 @@ public class PreparationCoordinator implements Coordinator {
private void abortInflation(NotificationEntry entry, String reason) {
mLogger.logInflationAborted(entry.getKey(), reason);
entry.abortTask();
mPendingNotifications.remove(entry);
}
private @InflationState int getInflationState(NotificationEntry entry) {
Integer stateObj = mInflationStates.get(entry);
Objects.requireNonNull(stateObj,
"Asking state of a notification preparation coordinator doesn't know about");
return stateObj;
}
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"STATE_"},
value = {STATE_UNINFLATED, STATE_INFLATED_INVALID, STATE_INFLATED, STATE_ERROR})
@interface InflationState {}
/** The notification has never been inflated before. */
private static final int STATE_UNINFLATED = 0;
/** The notification is inflated. */
private static final int STATE_INFLATED = 1;
/**
* The notification is inflated, but its content may be out-of-date since the notification has
* been updated.
*/
private static final int STATE_INFLATED_INVALID = 2;
/** The notification errored out while inflating */
private static final int STATE_ERROR = -1;
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.collection.listbuilder;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import java.util.List;
/** See {@link NotifPipeline#addOnBeforeFinalizeFilterListener(OnBeforeFinalizeFilterListener)} */
public interface OnBeforeFinalizeFilterListener {
/**
* Called after the notif list has been filtered, grouped, and sorted but before they are
* filtered one last time before rendering.
*
* @param entries The current list of top-level entries. Note that this is a live view into the
* current list and will change whenever the pipeline is rerun.
*/
void onBeforeFinalizeFilter(List<ListEntry> entries);
}

View File

@@ -82,7 +82,7 @@ public class PipelineState {
public static final int STATE_GROUPING = 4;
public static final int STATE_TRANSFORMING = 5;
public static final int STATE_SORTING = 6;
public static final int STATE_PRE_RENDER_FILTERING = 7;
public static final int STATE_FINALIZE_FILTERING = 7;
public static final int STATE_FINALIZING = 8;
@IntDef(prefix = { "STATE_" }, value = {
@@ -93,7 +93,7 @@ public class PipelineState {
STATE_GROUPING,
STATE_TRANSFORMING,
STATE_SORTING,
STATE_PRE_RENDER_FILTERING,
STATE_FINALIZE_FILTERING,
STATE_FINALIZING,
})
@Retention(RetentionPolicy.SOURCE)

View File

@@ -87,12 +87,12 @@ class ShadeListBuilderLogger @Inject constructor(
})
}
fun logPreRenderFilterInvalidated(name: String, pipelineState: Int) {
fun logFinalizeFilterInvalidated(name: String, pipelineState: Int) {
buffer.log(TAG, DEBUG, {
str1 = name
int1 = pipelineState
}, {
"""Pre-render NotifFilter "$str1" invalidated; pipeline state is $int1"""
"""Finalize NotifFilter "$str1" invalidated; pipeline state is $int1"""
})
}

View File

@@ -21,7 +21,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
* Pluggable for participating in notif filtering.
* See {@link NotifPipeline#addPreGroupFilter} and {@link NotifPipeline#addPreRenderFilter}.
* See {@link NotifPipeline#addPreGroupFilter} and {@link NotifPipeline#addFinalizeFilter}.
*/
public abstract class NotifFilter extends Pluggable<NotifFilter> {
protected NotifFilter(String name) {
@@ -37,7 +37,7 @@ public abstract class NotifFilter extends Pluggable<NotifFilter> {
* @param entry The entry in question.
* If this filter is registered via {@link NotifPipeline#addPreGroupFilter},
* this entry will not have any grouping nor sorting information.
* If this filter is registered via {@link NotifPipeline#addPreRenderFilter},
* If this filter is registered via {@link NotifPipeline#addFinalizeFilter},
* this entry will have grouping and sorting information.
* @param now A timestamp in SystemClock.uptimeMillis that represents "now" for the purposes of
* pipeline execution. This value will be the same for all pluggable calls made

View File

@@ -42,6 +42,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
@@ -84,6 +85,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
@Mock private NotifCollection mNotifCollection;
@Spy private OnBeforeTransformGroupsListener mOnBeforeTransformGroupsListener;
@Spy private OnBeforeSortListener mOnBeforeSortListener;
@Spy private OnBeforeFinalizeFilterListener mOnBeforeFinalizeFilterListener;
@Spy private OnBeforeRenderListListener mOnBeforeRenderListListener;
@Spy private OnRenderListListener mOnRenderListListener = list -> mBuiltList = list;
@@ -387,7 +389,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
NotifFilter preGroupFilter = spy(new PackageFilter(PACKAGE_2));
NotifFilter preRenderFilter = spy(new PackageFilter(PACKAGE_2));
mListBuilder.addPreGroupFilter(preGroupFilter);
mListBuilder.addPreRenderFilter(preRenderFilter);
mListBuilder.addFinalizeFilter(preRenderFilter);
// WHEN the pipeline is kicked off on a list of notifs
addNotif(0, PACKAGE_1);
@@ -423,7 +425,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
public void testPreRenderNotifsAreFiltered() {
// GIVEN a NotifFilter that filters out a specific package
NotifFilter filter1 = spy(new PackageFilter(PACKAGE_2));
mListBuilder.addPreRenderFilter(filter1);
mListBuilder.addFinalizeFilter(filter1);
// WHEN the pipeline is kicked off on a list of notifs
addNotif(0, PACKAGE_1);
@@ -454,7 +456,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
final String filterTag = "FILTER_ME";
// GIVEN a NotifFilter that filters out notifications with a tag
NotifFilter filter1 = spy(new NotifFilterWithTag(filterTag));
mListBuilder.addPreRenderFilter(filter1);
mListBuilder.addFinalizeFilter(filter1);
// WHEN the pipeline is kicked off on a list of notifs
addGroupChildWithTag(0, PACKAGE_2, GROUP_1, filterTag);
@@ -742,8 +744,9 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mListBuilder.addOnBeforeSortListener(mOnBeforeSortListener);
mListBuilder.setComparators(Collections.singletonList(comparator));
mListBuilder.setSections(Arrays.asList(section));
mListBuilder.addOnBeforeFinalizeFilterListener(mOnBeforeFinalizeFilterListener);
mListBuilder.addFinalizeFilter(preRenderFilter);
mListBuilder.addOnBeforeRenderListListener(mOnBeforeRenderListListener);
mListBuilder.addPreRenderFilter(preRenderFilter);
// WHEN a few new notifs are added
addNotif(0, PACKAGE_1);
@@ -763,6 +766,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
mOnBeforeSortListener,
section,
comparator,
mOnBeforeFinalizeFilterListener,
preRenderFilter,
mOnBeforeRenderListListener,
mOnRenderListListener);
@@ -777,6 +781,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
inOrder.verify(section, atLeastOnce()).isInSection(any(ListEntry.class));
inOrder.verify(comparator, atLeastOnce())
.compare(any(ListEntry.class), any(ListEntry.class));
inOrder.verify(mOnBeforeFinalizeFilterListener).onBeforeFinalizeFilter(anyList());
inOrder.verify(preRenderFilter, atLeastOnce())
.shouldFilterOut(any(NotificationEntry.class), anyLong());
inOrder.verify(mOnBeforeRenderListListener).onBeforeRenderList(anyList());
@@ -1075,7 +1080,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage
NotifFilter filter = new PackageFilter(PACKAGE_5);
OnBeforeRenderListListener listener = (list) -> filter.invalidateList();
mListBuilder.addPreRenderFilter(filter);
mListBuilder.addFinalizeFilter(filter);
mListBuilder.addOnBeforeRenderListListener(listener);
// WHEN we try to run the pipeline and the PreRenderFilter is invalidated
@@ -1090,7 +1095,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// GIVEN a PreRenderFilter that gets invalidated during the grouping stage
NotifFilter filter = new PackageFilter(PACKAGE_5);
OnBeforeTransformGroupsListener listener = (list) -> filter.invalidateList();
mListBuilder.addPreRenderFilter(filter);
mListBuilder.addFinalizeFilter(filter);
mListBuilder.addOnBeforeTransformGroupsListener(listener);
// WHEN we try to run the pipeline and the filter is invalidated

View File

@@ -88,7 +88,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
mKeyguardCoordinator.attach(mNotifPipeline);
verify(mNotifPipeline, times(1)).addPreRenderFilter(filterCaptor.capture());
verify(mNotifPipeline, times(1)).addFinalizeFilter(filterCaptor.capture());
mKeyguardFilter = filterCaptor.getValue();
}

View File

@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -35,13 +35,16 @@ import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -54,14 +57,22 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
private static final String TEST_MESSAGE = "TEST_MESSAGE";
private PreparationCoordinator mCoordinator;
private NotifCollectionListener mCollectionListener;
private OnBeforeFinalizeFilterListener mBeforeFilterListener;
private NotifFilter mUninflatedFilter;
private NotifFilter mInflationErrorFilter;
private NotifInflaterImpl.InflationCallback mCallback;
private NotifInflationErrorManager mErrorManager;
private NotificationEntry mEntry;
private Exception mInflationError;
@Mock
private NotifPipeline mNotifPipeline;
@Captor private ArgumentCaptor<NotifCollectionListener> mCollectionListenerCaptor;
@Captor private ArgumentCaptor<OnBeforeFinalizeFilterListener> mBeforeFilterListenerCaptor;
@Captor private ArgumentCaptor<NotifInflaterImpl.InflationCallback> mCallbackCaptor;
@Mock private NotifPipeline mNotifPipeline;
@Mock private IStatusBarService mService;
@Mock private NotifInflaterImpl mNotifInflater;
@Before
public void setUp() {
@@ -73,15 +84,28 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
mCoordinator = new PreparationCoordinator(
mock(PreparationCoordinatorLogger.class),
mock(NotifInflaterImpl.class),
mNotifInflater,
mErrorManager,
mService);
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
mCoordinator.attach(mNotifPipeline);
verify(mNotifPipeline, times(2)).addPreRenderFilter(filterCaptor.capture());
verify(mNotifPipeline, times(2)).addFinalizeFilter(filterCaptor.capture());
List<NotifFilter> filters = filterCaptor.getAllValues();
mInflationErrorFilter = filters.get(0);
mUninflatedFilter = filters.get(1);
verify(mNotifPipeline).addCollectionListener(mCollectionListenerCaptor.capture());
mCollectionListener = mCollectionListenerCaptor.getValue();
verify(mNotifPipeline).addOnBeforeFinalizeFilterListener(
mBeforeFilterListenerCaptor.capture());
mBeforeFilterListener = mBeforeFilterListenerCaptor.getValue();
verify(mNotifInflater).setInflationCallback(mCallbackCaptor.capture());
mCallback = mCallbackCaptor.getValue();
mCollectionListener.onEntryInit(mEntry);
}
@Test
@@ -108,4 +132,42 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
// THEN we filter it from the notification list.
assertTrue(mInflationErrorFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void testInflatesNewNotification() {
// WHEN there is a new notification
mCollectionListener.onEntryAdded(mEntry);
mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry));
// THEN we inflate it
verify(mNotifInflater).inflateViews(mEntry);
// THEN we filter it out until it's done inflating.
assertTrue(mUninflatedFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void testRebindsInflatedNotificationsOnUpdate() {
// GIVEN an inflated notification
mCallback.onInflationFinished(mEntry);
// WHEN notification is updated
mCollectionListener.onEntryUpdated(mEntry);
mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry));
// THEN we rebind it
verify(mNotifInflater).rebindViews(mEntry);
// THEN we do not filter it because it's not the first inflation.
assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0));
}
@Test
public void testDoesntFilterInflatedNotifs() {
// WHEN a notification is inflated
mCallback.onInflationFinished(mEntry);
// THEN it isn't filtered from shade list
assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0));
}
}