Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java +32 −19 Original line number Original line Diff line number Diff line Loading @@ -35,6 +35,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.MainThread; import android.annotation.MainThread; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.Trace; import android.os.Trace; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; Loading Loading @@ -704,13 +705,17 @@ public class ShadeListBuilder implements Dumpable { // having its summary promoted, regardless of how many children it has // having its summary promoted, regardless of how many children it has Set<String> groupsWithChildrenLostToStability = Set<String> groupsWithChildrenLostToStability = getGroupsWithChildrenLostToStability(shadeList); getGroupsWithChildrenLostToStability(shadeList); // Like groups which lost a child to stability, any group which lost a child to promotion // Groups with children lost to stability are exempt from summary promotion. // is exempt from having its summary promoted when it has no attached children. ArraySet<String> groupsExemptFromSummaryPromotion = Set<String> groupsWithChildrenLostToPromotionOrStability = new ArraySet<>(groupsWithChildrenLostToStability); getGroupsWithChildrenLostToPromotion(shadeList); // Any group which lost a child to filtering or promotion is exempt from having its summary groupsWithChildrenLostToPromotionOrStability.addAll(groupsWithChildrenLostToStability); // promoted when it has no attached children. getGroupsWithChildrenLostToFiltering(groupsExemptFromSummaryPromotion); for (int i = 0; i < shadeList.size(); i++) { getGroupsWithChildrenLostToPromotion(shadeList, groupsExemptFromSummaryPromotion); // Iterate backwards, so that we can remove elements without affecting indices of // yet-to-be-accessed entries. for (int i = shadeList.size() - 1; i >= 0; i--) { final ListEntry tle = shadeList.get(i); final ListEntry tle = shadeList.get(i); if (tle instanceof GroupEntry) { if (tle instanceof GroupEntry) { Loading @@ -719,7 +724,7 @@ public class ShadeListBuilder implements Dumpable { final boolean hasSummary = group.getSummary() != null; final boolean hasSummary = group.getSummary() != null; if (hasSummary && children.size() == 0) { if (hasSummary && children.size() == 0) { if (groupsWithChildrenLostToPromotionOrStability.contains(group.getKey())) { if (groupsExemptFromSummaryPromotion.contains(group.getKey())) { // This group lost a child on this run to promotion or stability, so it is // This group lost a child on this run to promotion or stability, so it is // exempt from having its summary promoted to the top level, so prune it. // exempt from having its summary promoted to the top level, so prune it. // It has no children, so it will just vanish. // It has no children, so it will just vanish. Loading @@ -728,14 +733,10 @@ public class ShadeListBuilder implements Dumpable { // For any other summary with no children, promote the summary. // For any other summary with no children, promote the summary. pruneGroupAtIndexAndPromoteSummary(shadeList, group, i); pruneGroupAtIndexAndPromoteSummary(shadeList, group, i); } } i--; // The node we visited is gone, so be sure to visit this index again. } else if (!hasSummary) { } else if (!hasSummary) { // If the group doesn't provide a summary, ignore it and add // If the group doesn't provide a summary, ignore it and add // any children it may have directly to top-level. // any children it may have directly to top-level. pruneGroupAtIndexAndPromoteAnyChildren(shadeList, group, i); pruneGroupAtIndexAndPromoteAnyChildren(shadeList, group, i); i--; // The node we visited is gone, so be sure to visit this index again. } else if (children.size() < MIN_CHILDREN_FOR_GROUP) { } else if (children.size() < MIN_CHILDREN_FOR_GROUP) { // This group has a summary and insufficient, but nonzero children. // This group has a summary and insufficient, but nonzero children. checkState(hasSummary, "group must have summary at this point"); checkState(hasSummary, "group must have summary at this point"); Loading @@ -760,8 +761,6 @@ public class ShadeListBuilder implements Dumpable { // The group is too small, ignore it and add // The group is too small, ignore it and add // its children (if any) directly to top-level. // its children (if any) directly to top-level. pruneGroupAtIndexAndPromoteAnyChildren(shadeList, group, i); pruneGroupAtIndexAndPromoteAnyChildren(shadeList, group, i); i--; // The node we visited is gone, so be sure to visit this index again. } } } } } } Loading Loading @@ -867,18 +866,32 @@ public class ShadeListBuilder implements Dumpable { * * * These groups will be exempt from appearing without any children. * These groups will be exempt from appearing without any children. */ */ @NonNull private void getGroupsWithChildrenLostToPromotion(List<ListEntry> shadeList, Set<String> out) { private Set<String> getGroupsWithChildrenLostToPromotion(List<ListEntry> shadeList) { ArraySet<String> groupsWithChildrenLostToPromotion = new ArraySet<>(); for (int i = 0; i < shadeList.size(); i++) { for (int i = 0; i < shadeList.size(); i++) { final ListEntry tle = shadeList.get(i); final ListEntry tle = shadeList.get(i); if (tle.getAttachState().getPromoter() != null) { if (tle.getAttachState().getPromoter() != null) { // This top-level-entry was part of a group, but was promoted out of it. // This top-level-entry was part of a group, but was promoted out of it. final String groupKey = tle.getRepresentativeEntry().getSbn().getGroupKey(); final String groupKey = tle.getRepresentativeEntry().getSbn().getGroupKey(); groupsWithChildrenLostToPromotion.add(groupKey); out.add(groupKey); } } } /** * Collect the keys of any groups which have already lost a child to a {@link NotifFilter} * this run. * * These groups will be exempt from appearing without any children. */ private void getGroupsWithChildrenLostToFiltering(Set<String> out) { for (ListEntry tle : mAllEntries) { StatusBarNotification sbn = tle.getRepresentativeEntry().getSbn(); if (sbn.isGroup() && !sbn.getNotification().isGroupSummary() && tle.getAttachState().getExcludingFilter() != null) { out.add(sbn.getGroup()); } } } } return groupsWithChildrenLostToPromotion; } } /** /** Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +19 −0 Original line number Original line Diff line number Diff line Loading @@ -1450,6 +1450,25 @@ public class ShadeListBuilderTest extends SysuiTestCase { ); ); } } @Test public void testGroupWithChildRemovedByFilterIsPrunedWhenOtherwiseEmpty() { // GIVEN a group with only one child addGroupSummary(0, PACKAGE_1, GROUP_1); addGroupChild(1, PACKAGE_1, GROUP_1); dispatchBuild(); // NOTICE that the group is pruned and the child is moved to the top level verifyBuiltList( notif(1) // group with only one child is promoted ); // WHEN the only child is filtered mFinalizeFilter.mIndicesToFilter.add(1); dispatchBuild(); // THEN the new list should be empty (the group summary should not be promoted) verifyBuiltList(); } @Test @Test public void testFinalizeFilteredSummaryPromotesChildren() { public void testFinalizeFilteredSummaryPromotesChildren() { // GIVEN a group with only one child was already drawn // GIVEN a group with only one child was already drawn Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java +32 −19 Original line number Original line Diff line number Diff line Loading @@ -35,6 +35,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.MainThread; import android.annotation.MainThread; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.Trace; import android.os.Trace; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; Loading Loading @@ -704,13 +705,17 @@ public class ShadeListBuilder implements Dumpable { // having its summary promoted, regardless of how many children it has // having its summary promoted, regardless of how many children it has Set<String> groupsWithChildrenLostToStability = Set<String> groupsWithChildrenLostToStability = getGroupsWithChildrenLostToStability(shadeList); getGroupsWithChildrenLostToStability(shadeList); // Like groups which lost a child to stability, any group which lost a child to promotion // Groups with children lost to stability are exempt from summary promotion. // is exempt from having its summary promoted when it has no attached children. ArraySet<String> groupsExemptFromSummaryPromotion = Set<String> groupsWithChildrenLostToPromotionOrStability = new ArraySet<>(groupsWithChildrenLostToStability); getGroupsWithChildrenLostToPromotion(shadeList); // Any group which lost a child to filtering or promotion is exempt from having its summary groupsWithChildrenLostToPromotionOrStability.addAll(groupsWithChildrenLostToStability); // promoted when it has no attached children. getGroupsWithChildrenLostToFiltering(groupsExemptFromSummaryPromotion); for (int i = 0; i < shadeList.size(); i++) { getGroupsWithChildrenLostToPromotion(shadeList, groupsExemptFromSummaryPromotion); // Iterate backwards, so that we can remove elements without affecting indices of // yet-to-be-accessed entries. for (int i = shadeList.size() - 1; i >= 0; i--) { final ListEntry tle = shadeList.get(i); final ListEntry tle = shadeList.get(i); if (tle instanceof GroupEntry) { if (tle instanceof GroupEntry) { Loading @@ -719,7 +724,7 @@ public class ShadeListBuilder implements Dumpable { final boolean hasSummary = group.getSummary() != null; final boolean hasSummary = group.getSummary() != null; if (hasSummary && children.size() == 0) { if (hasSummary && children.size() == 0) { if (groupsWithChildrenLostToPromotionOrStability.contains(group.getKey())) { if (groupsExemptFromSummaryPromotion.contains(group.getKey())) { // This group lost a child on this run to promotion or stability, so it is // This group lost a child on this run to promotion or stability, so it is // exempt from having its summary promoted to the top level, so prune it. // exempt from having its summary promoted to the top level, so prune it. // It has no children, so it will just vanish. // It has no children, so it will just vanish. Loading @@ -728,14 +733,10 @@ public class ShadeListBuilder implements Dumpable { // For any other summary with no children, promote the summary. // For any other summary with no children, promote the summary. pruneGroupAtIndexAndPromoteSummary(shadeList, group, i); pruneGroupAtIndexAndPromoteSummary(shadeList, group, i); } } i--; // The node we visited is gone, so be sure to visit this index again. } else if (!hasSummary) { } else if (!hasSummary) { // If the group doesn't provide a summary, ignore it and add // If the group doesn't provide a summary, ignore it and add // any children it may have directly to top-level. // any children it may have directly to top-level. pruneGroupAtIndexAndPromoteAnyChildren(shadeList, group, i); pruneGroupAtIndexAndPromoteAnyChildren(shadeList, group, i); i--; // The node we visited is gone, so be sure to visit this index again. } else if (children.size() < MIN_CHILDREN_FOR_GROUP) { } else if (children.size() < MIN_CHILDREN_FOR_GROUP) { // This group has a summary and insufficient, but nonzero children. // This group has a summary and insufficient, but nonzero children. checkState(hasSummary, "group must have summary at this point"); checkState(hasSummary, "group must have summary at this point"); Loading @@ -760,8 +761,6 @@ public class ShadeListBuilder implements Dumpable { // The group is too small, ignore it and add // The group is too small, ignore it and add // its children (if any) directly to top-level. // its children (if any) directly to top-level. pruneGroupAtIndexAndPromoteAnyChildren(shadeList, group, i); pruneGroupAtIndexAndPromoteAnyChildren(shadeList, group, i); i--; // The node we visited is gone, so be sure to visit this index again. } } } } } } Loading Loading @@ -867,18 +866,32 @@ public class ShadeListBuilder implements Dumpable { * * * These groups will be exempt from appearing without any children. * These groups will be exempt from appearing without any children. */ */ @NonNull private void getGroupsWithChildrenLostToPromotion(List<ListEntry> shadeList, Set<String> out) { private Set<String> getGroupsWithChildrenLostToPromotion(List<ListEntry> shadeList) { ArraySet<String> groupsWithChildrenLostToPromotion = new ArraySet<>(); for (int i = 0; i < shadeList.size(); i++) { for (int i = 0; i < shadeList.size(); i++) { final ListEntry tle = shadeList.get(i); final ListEntry tle = shadeList.get(i); if (tle.getAttachState().getPromoter() != null) { if (tle.getAttachState().getPromoter() != null) { // This top-level-entry was part of a group, but was promoted out of it. // This top-level-entry was part of a group, but was promoted out of it. final String groupKey = tle.getRepresentativeEntry().getSbn().getGroupKey(); final String groupKey = tle.getRepresentativeEntry().getSbn().getGroupKey(); groupsWithChildrenLostToPromotion.add(groupKey); out.add(groupKey); } } } /** * Collect the keys of any groups which have already lost a child to a {@link NotifFilter} * this run. * * These groups will be exempt from appearing without any children. */ private void getGroupsWithChildrenLostToFiltering(Set<String> out) { for (ListEntry tle : mAllEntries) { StatusBarNotification sbn = tle.getRepresentativeEntry().getSbn(); if (sbn.isGroup() && !sbn.getNotification().isGroupSummary() && tle.getAttachState().getExcludingFilter() != null) { out.add(sbn.getGroup()); } } } } return groupsWithChildrenLostToPromotion; } } /** /** Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +19 −0 Original line number Original line Diff line number Diff line Loading @@ -1450,6 +1450,25 @@ public class ShadeListBuilderTest extends SysuiTestCase { ); ); } } @Test public void testGroupWithChildRemovedByFilterIsPrunedWhenOtherwiseEmpty() { // GIVEN a group with only one child addGroupSummary(0, PACKAGE_1, GROUP_1); addGroupChild(1, PACKAGE_1, GROUP_1); dispatchBuild(); // NOTICE that the group is pruned and the child is moved to the top level verifyBuiltList( notif(1) // group with only one child is promoted ); // WHEN the only child is filtered mFinalizeFilter.mIndicesToFilter.add(1); dispatchBuild(); // THEN the new list should be empty (the group summary should not be promoted) verifyBuiltList(); } @Test @Test public void testFinalizeFilteredSummaryPromotesChildren() { public void testFinalizeFilteredSummaryPromotesChildren() { // GIVEN a group with only one child was already drawn // GIVEN a group with only one child was already drawn Loading