From acaa911e6b5ddcb45b400ef68130934d1fe04086 Mon Sep 17 00:00:00 2001 From: Kevin Han Date: Mon, 9 Mar 2020 17:12:53 -0700 Subject: [PATCH 1/2] Bind children dynamically in new pipeline (1/2) Don't bother inflating group children that won't be visible and filter it from the notification list we give to NotificationViewHierarchyManager. Bug: 145748993 Test: atest SystemUITests Change-Id: I97696070aea93f5cf3c188a391db651ba802d080 --- .../coordinator/PreparationCoordinator.java | 126 ++++++++++++++---- .../collection/GroupEntryHelper.java | 42 ++++++ .../PreparationCoordinatorTest.java | 49 ++++++- 3 files changed, 190 insertions(+), 27 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index 0e8dd5e24e910..5a34f297c85a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -16,11 +16,15 @@ package com.android.systemui.statusbar.notification.collection.coordinator; +import static com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED; + import android.annotation.IntDef; import android.os.RemoteException; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; +import android.util.ArraySet; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; @@ -40,6 +44,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; @@ -60,22 +65,47 @@ public class PreparationCoordinator implements Coordinator { private final NotifInflationErrorManager mNotifErrorManager; private final NotifViewBarn mViewBarn; private final Map mInflationStates = new ArrayMap<>(); + + /** + * The set of notifications that are currently inflating something. Note that this is + * separate from inflation state as a view could either be uninflated or inflated and still be + * inflating something. + */ + private final Set mInflatingNotifs = new ArraySet<>(); + private final IStatusBarService mStatusBarService; + /** + * The number of children in a group we actually keep inflated since we don't actually show + * all the children and don't need every child inflated at all times. + */ + private final int mChildBindCutoff; + @Inject public PreparationCoordinator( PreparationCoordinatorLogger logger, NotifInflaterImpl notifInflater, NotifInflationErrorManager errorManager, NotifViewBarn viewBarn, - IStatusBarService service - ) { + IStatusBarService service) { + this(logger, notifInflater, errorManager, viewBarn, service, CHILD_BIND_CUTOFF); + } + + @VisibleForTesting + PreparationCoordinator( + PreparationCoordinatorLogger logger, + NotifInflaterImpl notifInflater, + NotifInflationErrorManager errorManager, + NotifViewBarn viewBarn, + IStatusBarService service, + int childBindCutoff) { mLogger = logger; mNotifInflater = notifInflater; mNotifErrorManager = errorManager; mNotifErrorManager.addInflationErrorListener(mInflationErrorListener); mViewBarn = viewBarn; mStatusBarService = service; + mChildBindCutoff = childBindCutoff; } @Override @@ -96,6 +126,8 @@ public class PreparationCoordinator implements Coordinator { @Override public void onEntryUpdated(NotificationEntry entry) { + abortInflation(entry, "entryUpdated"); + mInflatingNotifs.remove(entry); @InflationState int state = getInflationState(entry); if (state == STATE_INFLATED) { mInflationStates.put(entry, STATE_INFLATED_INVALID); @@ -113,6 +145,7 @@ public class PreparationCoordinator implements Coordinator { @Override public void onEntryCleanUp(NotificationEntry entry) { mInflationStates.remove(entry); + mInflatingNotifs.remove(entry); mViewBarn.removeViewForEntry(entry); } }; @@ -133,23 +166,11 @@ public class PreparationCoordinator implements Coordinator { private final NotifFilter mNotifInflatingFilter = new NotifFilter(TAG + "Inflating") { /** - * Filters out notifications that haven't been inflated yet + * Filters out notifications that aren't inflated */ @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { - @InflationState int state = getInflationState(entry); - return (state != STATE_INFLATED) && (state != STATE_INFLATED_INVALID); - } - }; - - private final NotifInflater.InflationCallback mInflationCallback = - new NotifInflater.InflationCallback() { - @Override - public void onInflationFinished(NotificationEntry entry) { - mLogger.logNotifInflated(entry.getKey()); - mViewBarn.registerViewForEntry(entry, entry.getRow()); - mInflationStates.put(entry, STATE_INFLATED); - mNotifInflatingFilter.invalidateList(); + return !isInflated(entry); } }; @@ -187,19 +208,41 @@ public class PreparationCoordinator implements Coordinator { ListEntry entry = entries.get(i); if (entry instanceof GroupEntry) { GroupEntry groupEntry = (GroupEntry) entry; - inflateNotifRequiredViews(groupEntry.getSummary()); - List children = groupEntry.getChildren(); - for (int j = 0, groupSize = children.size(); j < groupSize; j++) { - inflateNotifRequiredViews(children.get(j)); - } + inflateRequiredGroupViews(groupEntry); } else { NotificationEntry notifEntry = (NotificationEntry) entry; - inflateNotifRequiredViews(notifEntry); + inflateRequiredNotifViews(notifEntry); } } } - private void inflateNotifRequiredViews(NotificationEntry entry) { + private void inflateRequiredGroupViews(GroupEntry groupEntry) { + NotificationEntry summary = groupEntry.getSummary(); + List children = groupEntry.getChildren(); + inflateRequiredNotifViews(summary); + for (int j = 0; j < children.size(); j++) { + NotificationEntry child = children.get(j); + boolean childShouldBeBound = j < mChildBindCutoff; + if (childShouldBeBound) { + inflateRequiredNotifViews(child); + } else { + if (mInflatingNotifs.contains(child)) { + abortInflation(child, "Past last visible group child"); + } + if (isInflated(child)) { + // TODO: May want to put an animation hint here so view manager knows to treat + // this differently from a regular removal animation + freeNotifViews(child); + } + } + } + } + + private void inflateRequiredNotifViews(NotificationEntry entry) { + if (mInflatingNotifs.contains(entry)) { + // Already inflating this entry + return; + } @InflationState int state = mInflationStates.get(entry); switch (state) { case STATE_UNINFLATED: @@ -217,16 +260,38 @@ public class PreparationCoordinator implements Coordinator { private void inflateEntry(NotificationEntry entry, String reason) { abortInflation(entry, reason); - mNotifInflater.inflateViews(entry, mInflationCallback); + mInflatingNotifs.add(entry); + mNotifInflater.inflateViews(entry, this::onInflationFinished); } private void rebind(NotificationEntry entry, String reason) { - mNotifInflater.rebindViews(entry, mInflationCallback); + mInflatingNotifs.add(entry); + mNotifInflater.rebindViews(entry, this::onInflationFinished); } private void abortInflation(NotificationEntry entry, String reason) { mLogger.logInflationAborted(entry.getKey(), reason); entry.abortTask(); + mInflatingNotifs.remove(entry); + } + + private void onInflationFinished(NotificationEntry entry) { + mLogger.logNotifInflated(entry.getKey()); + mInflatingNotifs.remove(entry); + mViewBarn.registerViewForEntry(entry, entry.getRow()); + mInflationStates.put(entry, STATE_INFLATED); + mNotifInflatingFilter.invalidateList(); + } + + private void freeNotifViews(NotificationEntry entry) { + mViewBarn.removeViewForEntry(entry); + entry.setRow(null); + mInflationStates.put(entry, STATE_UNINFLATED); + } + + private boolean isInflated(NotificationEntry entry) { + @InflationState int state = getInflationState(entry); + return (state == STATE_INFLATED) || (state == STATE_INFLATED_INVALID); } private @InflationState int getInflationState(NotificationEntry entry) { @@ -241,7 +306,7 @@ public class PreparationCoordinator implements Coordinator { value = {STATE_UNINFLATED, STATE_INFLATED_INVALID, STATE_INFLATED, STATE_ERROR}) @interface InflationState {} - /** The notification has never been inflated before. */ + /** The notification has no views attached. */ private static final int STATE_UNINFLATED = 0; /** The notification is inflated. */ @@ -255,4 +320,13 @@ public class PreparationCoordinator implements Coordinator { /** The notification errored out while inflating */ private static final int STATE_ERROR = -1; + + /** + * How big the buffer of extra views we keep around to be ready to show when we do need to + * dynamically inflate a row. + */ + private static final int EXTRA_VIEW_BUFFER_COUNT = 1; + + private static final int CHILD_BIND_CUTOFF = + NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED + EXTRA_VIEW_BUFFER_COUNT; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java new file mode 100644 index 0000000000000..038dd17a98142 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java @@ -0,0 +1,42 @@ +/* + * 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; + +import java.util.List; + +/** + * Helper class to provide methods for test classes that need {@link GroupEntry}'s for their tests. + */ +public class GroupEntryHelper { + /** + * Create a group entry for testing purposes. + * @param groupKey group key for the group and all its entries + * @param summary summary notification for group + * @param children group's children notifications + */ + public static final GroupEntry createGroup( + String groupKey, + NotificationEntry summary, + List children) { + GroupEntry groupEntry = new GroupEntry(groupKey); + groupEntry.setSummary(summary); + for (NotificationEntry child : children) { + groupEntry.addChild(child); + } + return groupEntry; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java index 35b31c01fd9cd..faf9da3aca8b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -32,6 +33,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.collection.GroupEntry; +import com.android.systemui.statusbar.notification.collection.GroupEntryHelper; import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotifViewBarn; @@ -50,6 +53,7 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; import java.util.List; @SmallTest @@ -57,6 +61,8 @@ import java.util.List; @TestableLooper.RunWithLooper public class PreparationCoordinatorTest extends SysuiTestCase { private static final String TEST_MESSAGE = "TEST_MESSAGE"; + private static final String TEST_GROUP_KEY = "TEST_GROUP_KEY"; + private static final int TEST_CHILD_BIND_CUTOFF = 9; private PreparationCoordinator mCoordinator; private NotifCollectionListener mCollectionListener; @@ -88,7 +94,8 @@ public class PreparationCoordinatorTest extends SysuiTestCase { mNotifInflater, mErrorManager, mock(NotifViewBarn.class), - mService); + mService, + TEST_CHILD_BIND_CUTOFF); ArgumentCaptor filterCaptor = ArgumentCaptor.forClass(NotifFilter.class); mCoordinator.attach(mNotifPipeline); @@ -175,4 +182,44 @@ public class PreparationCoordinatorTest extends SysuiTestCase { // THEN it isn't filtered from shade list assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0)); } + + @Test + public void testCutoffGroupChildrenNotInflated() { + // WHEN there is a new notification group is posted + int id = 0; + NotificationEntry summary = new NotificationEntryBuilder() + .setOverrideGroupKey(TEST_GROUP_KEY) + .setId(id++) + .build(); + List children = new ArrayList<>(); + for (int i = 0; i < TEST_CHILD_BIND_CUTOFF + 1; i++) { + NotificationEntry child = new NotificationEntryBuilder() + .setOverrideGroupKey(TEST_GROUP_KEY) + .setId(id++) + .build(); + children.add(child); + } + GroupEntry groupEntry = GroupEntryHelper.createGroup(TEST_GROUP_KEY, summary, children); + + mCollectionListener.onEntryInit(summary); + for (NotificationEntry entry : children) { + mCollectionListener.onEntryInit(entry); + } + + mCollectionListener.onEntryAdded(summary); + for (NotificationEntry entry : children) { + mCollectionListener.onEntryAdded(entry); + } + + mBeforeFilterListener.onBeforeFinalizeFilter(List.of(groupEntry)); + + // THEN we inflate up to the cut-off only + for (int i = 0; i < children.size(); i++) { + if (i < TEST_CHILD_BIND_CUTOFF) { + verify(mNotifInflater).inflateViews(eq(children.get(i)), any()); + } else { + verify(mNotifInflater, never()).inflateViews(eq(children.get(i)), any()); + } + } + } } From 43077f971b9c5b86010483ba9468b8ba3bc3f851 Mon Sep 17 00:00:00 2001 From: Kevin Han Date: Fri, 28 Feb 2020 12:51:53 -0800 Subject: [PATCH 2/2] Bind children dynamically in new pipeline (2/2) Support setting a logical child count on the notification group view. Since we are filtering out the notifications and their views entirely in the new pipeline, we can't just use the number of children views on the notification group view to determine the "+X" value in the group view UX for how many children are in the unexanded group. So instead we set this value directly. Bug: 145748993 Test: add notification group and see overflow values are accurate in both old and new pipeline Change-Id: I60bc58994a77bc3801f062dedc41faaee1d48494 --- .../systemui/bubbles/BubbleController.java | 2 +- .../statusbar/NotificationHeaderUtil.java | 2 +- .../NotificationViewHierarchyManager.java | 21 +-- .../NotificationEntryManager.java | 2 +- .../notification/collection/GroupEntry.java | 20 +++ .../collection/NotifViewManager.kt | 7 +- .../collection/NotificationEntry.java | 13 +- .../coordinator/PreparationCoordinator.java | 1 + .../row/ExpandableNotificationRow.java | 55 ++++---- .../notification/row/ExpandableView.java | 2 +- .../stack/NotificationChildrenContainer.java | 121 ++++++++++-------- .../stack/NotificationListItem.java | 5 +- .../stack/NotificationStackScrollLayout.java | 8 +- .../stack/StackScrollAlgorithm.java | 2 +- .../bubbles/BubbleControllerTest.java | 2 +- .../NewNotifPipelineBubbleControllerTest.java | 2 +- .../row/ExpandableNotificationRowTest.java | 3 +- ...NotificationBlockingHelperManagerTest.java | 2 +- 18 files changed, 159 insertions(+), 111 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 669a86b8a7429..7bdeb1cfa75d7 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -1110,7 +1110,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi private void handleSummaryDismissalInterception(NotificationEntry summary) { // current children in the row: - final List children = summary.getChildren(); + final List children = summary.getAttachedNotifChildren(); if (children != null) { for (int i = 0; i < children.size(); i++) { NotificationEntry child = children.get(i); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java index ba3db09374221..670a65f55844c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java @@ -148,7 +148,7 @@ public class NotificationHeaderUtil { } public void updateChildrenHeaderAppearance() { - List notificationChildren = mRow.getNotificationChildren(); + List notificationChildren = mRow.getAttachedChildren(); if (notificationChildren == null) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index 1297f996b7432..37fc13e2df5be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -307,17 +307,20 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle } ExpandableNotificationRow parent = (ExpandableNotificationRow) view; - List children = parent.getNotificationChildren(); + List children = parent.getAttachedChildren(); List orderedChildren = mTmpChildOrderMap.get(parent.getEntry()); - - for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size(); - childIndex++) { + if (orderedChildren == null) { + // Not a group + continue; + } + parent.setUntruncatedChildCount(orderedChildren.size()); + for (int childIndex = 0; childIndex < orderedChildren.size(); childIndex++) { ExpandableNotificationRow childView = orderedChildren.get(childIndex).getRow(); if (children == null || !children.contains(childView)) { if (childView.getParent() != null) { - Log.wtf(TAG, "trying to add a notification child that already has " + - "a parent. class:" + childView.getParent().getClass() + - "\n child: " + childView); + Log.wtf(TAG, "trying to add a notification child that already has " + + "a parent. class:" + childView.getParent().getClass() + + "\n child: " + childView); // This shouldn't happen. We can recover by removing it though. ((ViewGroup) childView.getParent()).removeView(childView); } @@ -349,7 +352,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle } ExpandableNotificationRow parent = (ExpandableNotificationRow) view; - List children = parent.getNotificationChildren(); + List children = parent.getAttachedChildren(); List orderedChildren = mTmpChildOrderMap.get(parent.getEntry()); if (children != null) { @@ -454,7 +457,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle } if (row.isSummaryWithChildren()) { List notificationChildren = - row.getNotificationChildren(); + row.getAttachedChildren(); int size = notificationChildren.size(); for (int i = size - 1; i >= 0; i--) { stack.push(notificationChildren.get(i)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index d37e16b176200..3cf076578dffa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -515,7 +515,7 @@ public class NotificationEntryManager implements // always cancelled. We only remove them if they were dismissed by the user. return; } - List childEntries = entry.getChildren(); + List childEntries = entry.getAttachedNotifChildren(); if (childEntries == null) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java index 2c747bdcf7b69..81494eddd989b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator; import java.util.ArrayList; import java.util.Collections; @@ -36,6 +37,7 @@ public class GroupEntry extends ListEntry { private final List mUnmodifiableChildren = Collections.unmodifiableList(mChildren); + private int mUntruncatedChildCount; @VisibleForTesting public GroupEntry(String key) { @@ -62,6 +64,24 @@ public class GroupEntry extends ListEntry { mSummary = summary; } + /** + * @see #getUntruncatedChildCount() + */ + public void setUntruncatedChildCount(int childCount) { + mUntruncatedChildCount = childCount; + } + + /** + * Get the untruncated number of children from the data model, including those that will not + * have views bound. This includes children that {@link PreparationCoordinator} will filter out + * entirely when they are beyond the last visible child. + * + * TODO: This should move to some shared class between the model and view hierarchy + */ + public int getUntruncatedChildCount() { + return mUntruncatedChildCount; + } + void clearChildren() { mChildren.clear(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt index cf670bd5a424a..339809e0770b9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt @@ -113,7 +113,7 @@ class NotifViewManager @Inject constructor( } else if (entries[idx] is GroupEntry) { // A top-level entry exists. If it's a group, diff the children val groupChildren = (entries[idx] as GroupEntry).children - listItem.notificationChildren?.forEach { listChild -> + listItem.attachedChildren?.forEach { listChild -> if (!groupChildren.contains(listChild.entry)) { listItem.removeChildNotification(listChild) @@ -155,8 +155,8 @@ class NotifViewManager @Inject constructor( for ((idx, childEntry) in entry.children.withIndex()) { val childListItem = rowRegistry.requireView(childEntry) // Child hasn't been added yet. add it! - if (listItem.notificationChildren == null || - !listItem.notificationChildren.contains(childListItem)) { + if (listItem.attachedChildren == null || + !listItem.attachedChildren.contains(childListItem)) { // TODO: old code here just Log.wtf()'d here. This might wreak havoc if (childListItem.view.parent != null) { throw IllegalStateException("trying to add a notification child that " + @@ -179,6 +179,7 @@ class NotifViewManager @Inject constructor( stabilityManager, null /*TODO: stability callback */ ) + listItem.setUntruncatedChildCount(entry.untruncatedChildCount) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 749c3e4c9d0d3..5236385b3716f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -434,13 +434,18 @@ public final class NotificationEntry extends ListEntry { mRowController = controller; } - @Nullable - public List getChildren() { + /** + * Get the children that are actually attached to this notification's row. + * + * TODO: Seems like most callers here should probably be using + * {@link com.android.systemui.statusbar.phone.NotificationGroupManager#getChildren} + */ + public @Nullable List getAttachedNotifChildren() { if (row == null) { return null; } - List rowChildren = row.getNotificationChildren(); + List rowChildren = row.getAttachedChildren(); if (rowChildren == null) { return null; } @@ -748,7 +753,7 @@ public final class NotificationEntry extends ListEntry { return false; } - List children = getChildren(); + List children = getAttachedNotifChildren(); if (children != null && children.size() > 0) { for (int i = 0; i < children.size(); i++) { NotificationEntry child = children.get(i); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index 5a34f297c85a9..4159d43e34ec5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -208,6 +208,7 @@ public class PreparationCoordinator implements Coordinator { ListEntry entry = entries.get(i); if (entry instanceof GroupEntry) { GroupEntry groupEntry = (GroupEntry) entry; + groupEntry.setUntruncatedChildCount(groupEntry.getChildren().size()); inflateRequiredGroupViews(groupEntry); } else { NotificationEntry notifEntry = (NotificationEntry) entry; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 998230f205ab0..fd5cd58ea3465 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -410,7 +410,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView()); setIconAnimationRunningForChild(running, mChildrenContainer.getLowPriorityHeaderView()); List notificationChildren = - mChildrenContainer.getNotificationChildren(); + mChildrenContainer.getAttachedChildren(); for (int i = 0; i < notificationChildren.size(); i++) { ExpandableNotificationRow child = notificationChildren.get(i); child.setIconAnimationRunning(running); @@ -559,7 +559,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (mNotificationParent != null) { mNotificationParent.updateChildrenHeaderAppearance(); } - onChildrenCountChanged(); + onAttachedChildrenCountChanged(); // The public layouts expand button is always visible mPublicLayout.updateExpandButtons(true); updateLimits(); @@ -762,6 +762,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mMustStayOnScreen = false; } + /** + * @see NotificationChildrenContainer#setUntruncatedChildCount(int) + */ + public void setUntruncatedChildCount(int childCount) { + if (mChildrenContainer == null) { + mChildrenContainerStub.inflate(); + } + mChildrenContainer.setUntruncatedChildCount(childCount); + } + /** * Add a child notification to this view. * @@ -773,7 +783,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mChildrenContainerStub.inflate(); } mChildrenContainer.addNotification(row, childIndex); - onChildrenCountChanged(); + onAttachedChildrenCountChanged(); row.setIsChildInGroup(true, this); } @@ -792,7 +802,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (mChildrenContainer != null) { mChildrenContainer.removeNotification(row); } - onChildrenCountChanged(); + onAttachedChildrenCountChanged(); row.setIsChildInGroup(false, null); row.setBottomRoundness(0.0f, false /* animate */); } @@ -886,15 +896,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mChildrenExpanded; } - public List getNotificationChildren() { - return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren(); - } - - public int getNumberOfNotificationChildren() { - if (mChildrenContainer == null) { - return 0; - } - return mChildrenContainer.getNotificationChildren().size(); + public List getAttachedChildren() { + return mChildrenContainer == null ? null : mChildrenContainer.getAttachedChildren(); } /** @@ -1028,7 +1031,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setChronometerRunning(running, mPublicLayout); if (mChildrenContainer != null) { List notificationChildren = - mChildrenContainer.getNotificationChildren(); + mChildrenContainer.getAttachedChildren(); for (int i = 0; i < notificationChildren.size(); i++) { ExpandableNotificationRow child = notificationChildren.get(i); child.setChronometerRunning(running); @@ -1228,7 +1231,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mUpdateBackgroundOnUpdate = true; reInflateViews(); if (mChildrenContainer != null) { - for (ExpandableNotificationRow child : mChildrenContainer.getNotificationChildren()) { + for (ExpandableNotificationRow child : mChildrenContainer.getAttachedChildren()) { child.onUiModeChanged(); } } @@ -1286,8 +1289,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } public void removeAllChildren() { - List notificationChildren - = mChildrenContainer.getNotificationChildren(); + List notificationChildren = + mChildrenContainer.getAttachedChildren(); ArrayList clonedList = new ArrayList<>(notificationChildren); for (int i = 0; i < clonedList.size(); i++) { ExpandableNotificationRow row = clonedList.get(i); @@ -1297,7 +1300,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mChildrenContainer.removeNotification(row); row.setIsChildInGroup(false, null); } - onChildrenCountChanged(); + onAttachedChildrenCountChanged(); } @Override @@ -1308,7 +1311,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void setForceUnlocked(boolean forceUnlocked) { mForceUnlocked = forceUnlocked; if (mIsSummaryWithChildren) { - List notificationChildren = getNotificationChildren(); + List notificationChildren = getAttachedChildren(); for (ExpandableNotificationRow child : notificationChildren) { child.setForceUnlocked(forceUnlocked); } @@ -1324,7 +1327,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mEntry.getIcons().getStatusBarIcon().setDismissed(); if (isChildInGroup()) { List notificationChildren = - mNotificationParent.getNotificationChildren(); + mNotificationParent.getAttachedChildren(); int i = notificationChildren.indexOf(this); if (i != -1 && i < notificationChildren.size() - 1) { mChildAfterViewWhenDismissed = notificationChildren.get(i + 1); @@ -2328,7 +2331,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mGroupManager.isGroupExpanded(mEntry.getSbn()); } - private void onChildrenCountChanged() { + private void onAttachedChildrenCountChanged() { mIsSummaryWithChildren = mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0; if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) { @@ -2361,7 +2364,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // If this is a summary, then add in the children notification channels for the // same user and pkg. if (mIsSummaryWithChildren) { - final List childrenRows = getNotificationChildren(); + final List childrenRows = getAttachedChildren(); final int numChildren = childrenRows.size(); for (int i = 0; i < numChildren; i++) { final ExpandableNotificationRow childRow = childrenRows.get(i); @@ -2468,7 +2471,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mHideSensitiveForIntrinsicHeight = hideSensitive; if (mIsSummaryWithChildren) { List notificationChildren = - mChildrenContainer.getNotificationChildren(); + mChildrenContainer.getAttachedChildren(); for (int i = 0; i < notificationChildren.size(); i++) { ExpandableNotificationRow child = notificationChildren.get(i); child.setHideSensitiveForIntrinsicHeight(hideSensitive); @@ -2806,7 +2809,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView updateBackgroundForGroupState(); if (mIsSummaryWithChildren) { List notificationChildren = - mChildrenContainer.getNotificationChildren(); + mChildrenContainer.getAttachedChildren(); for (int i = 0; i < notificationChildren.size(); i++) { ExpandableNotificationRow child = notificationChildren.get(i); child.updateBackgroundForGroupState(); @@ -2831,7 +2834,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mShowNoBackground = !mShowGroupBackgroundWhenExpanded && isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked(); mChildrenContainer.updateHeaderForExpansion(mShowNoBackground); - List children = mChildrenContainer.getNotificationChildren(); + List children = mChildrenContainer.getAttachedChildren(); for (int i = 0; i < children.size(); i++) { children.get(i).updateBackgroundForGroupState(); } @@ -3241,7 +3244,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView pw.print(", alpha: " + mChildrenContainer.getAlpha()); pw.print(", translationY: " + mChildrenContainer.getTranslationY()); pw.println(); - List notificationChildren = getNotificationChildren(); + List notificationChildren = getAttachedChildren(); pw.println(" Children: " + notificationChildren.size()); pw.println(" {"); for(ExpandableNotificationRow child : notificationChildren) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index ee3b753ab9265..5797944298d4b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -590,7 +590,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { // handling reset for child notifications if (this instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) this; - List children = row.getNotificationChildren(); + List children = row.getAttachedChildren(); if (row.isSummaryWithChildren() && children != null) { for (ExpandableNotificationRow childRow : children) { childRow.resetViewState(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 400e794b820b2..351a3ef46decc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -65,7 +65,7 @@ public class NotificationChildrenContainer extends ViewGroup { }.setDuration(200); private final List mDividers = new ArrayList<>(); - private final List mChildren = new ArrayList<>(); + private final List mAttachedChildren = new ArrayList<>(); private final HybridGroupManager mHybridGroupManager; private int mChildPadding; private int mDividerHeight; @@ -105,6 +105,7 @@ public class NotificationChildrenContainer extends ViewGroup { private int mTranslationForHeader; private int mCurrentHeaderTranslation = 0; private float mHeaderVisibleAmount = 1.0f; + private int mUntruncatedChildCount; public NotificationChildrenContainer(Context context) { this(context, null); @@ -153,9 +154,10 @@ public class NotificationChildrenContainer extends ViewGroup { @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { - int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED); + int childCount = + Math.min(mAttachedChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED); for (int i = 0; i < childCount; i++) { - View child = mChildren.get(i); + View child = mAttachedChildren.get(i); // We need to layout all children even the GONE ones, such that the heights are // calculated correctly as they are used to calculate how many we can fit on the screen child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight()); @@ -195,11 +197,12 @@ public class NotificationChildrenContainer extends ViewGroup { } int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY); int height = mNotificationHeaderMargin + mNotificatonTopPadding; - int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED); + int childCount = + Math.min(mAttachedChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED); int collapsedChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */); int overflowIndex = childCount > collapsedChildren ? collapsedChildren - 1 : -1; for (int i = 0; i < childCount; i++) { - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); // We need to measure all children even the GONE ones, such that the heights are // calculated correctly as they are used to calculate how many we can fit on the screen. boolean isOverflow = i == overflowIndex; @@ -241,6 +244,16 @@ public class NotificationChildrenContainer extends ViewGroup { localY < (mRealHeight + slop); } + /** + * Set the untruncated number of children in the group so that the view can update the UI + * appropriately. Note that this may differ from the number of views attached as truncated + * children will not have views. + */ + public void setUntruncatedChildCount(int childCount) { + mUntruncatedChildCount = childCount; + updateGroupOverflow(); + } + /** * Add a child notification to this view. * @@ -248,8 +261,8 @@ public class NotificationChildrenContainer extends ViewGroup { * @param childIndex the index to add it at, if -1 it will be added at the end */ public void addNotification(ExpandableNotificationRow row, int childIndex) { - int newIndex = childIndex < 0 ? mChildren.size() : childIndex; - mChildren.add(newIndex, row); + int newIndex = childIndex < 0 ? mAttachedChildren.size() : childIndex; + mAttachedChildren.add(newIndex, row); addView(row); row.setUserLocked(mUserLocked); @@ -257,7 +270,6 @@ public class NotificationChildrenContainer extends ViewGroup { addView(divider); mDividers.add(newIndex, divider); - updateGroupOverflow(); row.setContentTransformationAmount(0, false /* isLastChild */); // It doesn't make sense to keep old animations around, lets cancel them! ExpandableViewState viewState = row.getViewState(); @@ -268,8 +280,8 @@ public class NotificationChildrenContainer extends ViewGroup { } public void removeNotification(ExpandableNotificationRow row) { - int childIndex = mChildren.indexOf(row); - mChildren.remove(row); + int childIndex = mAttachedChildren.indexOf(row); + mAttachedChildren.remove(row); removeView(row); final View divider = mDividers.remove(childIndex); @@ -284,7 +296,6 @@ public class NotificationChildrenContainer extends ViewGroup { row.setSystemChildExpanded(false); row.setUserLocked(false); - updateGroupOverflow(); if (!row.isRemoved()) { mHeaderUtil.restoreNotificationHeader(row); } @@ -294,7 +305,7 @@ public class NotificationChildrenContainer extends ViewGroup { * @return The number of notification children in the container. */ public int getNotificationChildCount() { - return mChildren.size(); + return mAttachedChildren.size(); } public void recreateNotificationHeader(OnClickListener listener) { @@ -364,10 +375,9 @@ public class NotificationChildrenContainer extends ViewGroup { } public void updateGroupOverflow() { - int childCount = mChildren.size(); int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */); - if (childCount > maxAllowedVisibleChildren) { - int number = childCount - maxAllowedVisibleChildren; + if (mUntruncatedChildCount > maxAllowedVisibleChildren) { + int number = mUntruncatedChildCount - maxAllowedVisibleChildren; mOverflowNumber = mHybridGroupManager.bindOverflowNumber(mOverflowNumber, number); if (mGroupOverFlowState == null) { mGroupOverFlowState = new ViewState(); @@ -401,8 +411,11 @@ public class NotificationChildrenContainer extends ViewGroup { R.layout.notification_children_divider, this, false); } - public List getNotificationChildren() { - return mChildren; + /** + * Get notification children that are attached currently. + */ + public List getAttachedChildren() { + return mAttachedChildren; } /** @@ -420,13 +433,13 @@ public class NotificationChildrenContainer extends ViewGroup { return false; } boolean result = false; - for (int i = 0; i < mChildren.size() && i < childOrder.size(); i++) { - ExpandableNotificationRow child = mChildren.get(i); + for (int i = 0; i < mAttachedChildren.size() && i < childOrder.size(); i++) { + ExpandableNotificationRow child = mAttachedChildren.get(i); ExpandableNotificationRow desiredChild = (ExpandableNotificationRow) childOrder.get(i); if (child != desiredChild) { if (visualStabilityManager.canReorderNotification(desiredChild)) { - mChildren.remove(desiredChild); - mChildren.add(i, desiredChild); + mAttachedChildren.remove(desiredChild); + mAttachedChildren.add(i, desiredChild); result = true; } else { visualStabilityManager.addReorderingAllowedCallback(callback); @@ -442,9 +455,9 @@ public class NotificationChildrenContainer extends ViewGroup { // we don't modify it the group is expanded or if we are expanding it return; } - int size = mChildren.size(); + int size = mAttachedChildren.size(); for (int i = 0; i < size; i++) { - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); child.setSystemChildExpanded(i == 0 && size == 1); } } @@ -468,7 +481,7 @@ public class NotificationChildrenContainer extends ViewGroup { } int intrinsicHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation; int visibleChildren = 0; - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); boolean firstChild = true; float expandFactor = 0; if (mUserLocked) { @@ -499,7 +512,7 @@ public class NotificationChildrenContainer extends ViewGroup { } firstChild = false; } - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); intrinsicHeight += child.getIntrinsicHeight(); visibleChildren++; } @@ -518,7 +531,7 @@ public class NotificationChildrenContainer extends ViewGroup { * @param ambientState the ambient state containing ambient information */ public void updateState(ExpandableViewState parentState, AmbientState ambientState) { - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); int yPosition = mNotificationHeaderMargin + mCurrentHeaderTranslation; boolean firstChild = true; int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(); @@ -535,7 +548,7 @@ public class NotificationChildrenContainer extends ViewGroup { && !mContainingNotification.isGroupExpansionChanging(); int launchTransitionCompensation = 0; for (int i = 0; i < childCount; i++) { - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); if (!firstChild) { if (expandingToExpandedGroup) { yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight, @@ -586,7 +599,7 @@ public class NotificationChildrenContainer extends ViewGroup { } if (mOverflowNumber != null) { - ExpandableNotificationRow overflowView = mChildren.get(Math.min( + ExpandableNotificationRow overflowView = mAttachedChildren.get(Math.min( getMaxAllowedVisibleChildren(true /* likeCollapsed */), childCount) - 1); mGroupOverFlowState.copyFrom(overflowView.getViewState()); @@ -672,7 +685,7 @@ public class NotificationChildrenContainer extends ViewGroup { /** Applies state to children. */ public void applyState() { - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); ViewState tmpState = new ViewState(); float expandFraction = 0.0f; if (mUserLocked) { @@ -683,7 +696,7 @@ public class NotificationChildrenContainer extends ViewGroup { || (mContainingNotification.isGroupExpansionChanging() && !mHideDividersDuringExpand); for (int i = 0; i < childCount; i++) { - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); ExpandableViewState viewState = child.getViewState(); viewState.applyToView(child); @@ -716,10 +729,10 @@ public class NotificationChildrenContainer extends ViewGroup { if (mContainingNotification.hasExpandingChild()) { return; } - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); int layoutEnd = mContainingNotification.getActualHeight() - mClipBottomAmount; for (int i = 0; i < childCount; i++) { - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); if (child.getVisibility() == GONE) { continue; } @@ -754,7 +767,7 @@ public class NotificationChildrenContainer extends ViewGroup { /** Animate to a given state. */ public void startAnimationToState(AnimationProperties properties) { - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); ViewState tmpState = new ViewState(); float expandFraction = getGroupExpandFraction(); final boolean dividersVisible = mUserLocked && !showingAsLowPriority() @@ -762,7 +775,7 @@ public class NotificationChildrenContainer extends ViewGroup { || (mContainingNotification.isGroupExpansionChanging() && !mHideDividersDuringExpand); for (int i = childCount - 1; i >= 0; i--) { - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); ExpandableViewState viewState = child.getViewState(); viewState.animateTo(child, properties); @@ -799,9 +812,9 @@ public class NotificationChildrenContainer extends ViewGroup { public ExpandableNotificationRow getViewAtPosition(float y) { // find the view under the pointer, accounting for GONE views - final int count = mChildren.size(); + final int count = mAttachedChildren.size(); for (int childIdx = 0; childIdx < count; childIdx++) { - ExpandableNotificationRow slidingChild = mChildren.get(childIdx); + ExpandableNotificationRow slidingChild = mAttachedChildren.get(childIdx); float childTop = slidingChild.getTranslationY(); float top = childTop + slidingChild.getClipTopAmount(); float bottom = childTop + slidingChild.getActualHeight(); @@ -818,9 +831,9 @@ public class NotificationChildrenContainer extends ViewGroup { if (mNotificationHeader != null) { mNotificationHeader.setExpanded(childrenExpanded); } - final int count = mChildren.size(); + final int count = mAttachedChildren.size(); for (int childIdx = 0; childIdx < count; childIdx++) { - ExpandableNotificationRow child = mChildren.get(childIdx); + ExpandableNotificationRow child = mAttachedChildren.get(childIdx); child.setChildrenExpanded(childrenExpanded, false); } updateHeaderTouchability(); @@ -919,12 +932,12 @@ public class NotificationChildrenContainer extends ViewGroup { private void startChildAlphaAnimations(boolean toVisible) { float target = toVisible ? 1.0f : 0.0f; float start = 1.0f - target; - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); for (int i = 0; i < childCount; i++) { if (i >= NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED) { break; } - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); child.setAlpha(start); ViewState viewState = new ViewState(); viewState.initFrom(child); @@ -979,12 +992,12 @@ public class NotificationChildrenContainer extends ViewGroup { int maxContentHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation + mNotificatonTopPadding; int visibleChildren = 0; - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); for (int i = 0; i < childCount; i++) { if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) { break; } - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); float childHeight = child.isExpanded(true /* allowOnKeyguard */) ? child.getMaxExpandHeight() : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */); @@ -1006,9 +1019,9 @@ public class NotificationChildrenContainer extends ViewGroup { boolean showingLowPriority = showingAsLowPriority(); updateHeaderTransformation(); int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */); - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); for (int i = 0; i < childCount; i++) { - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); float childHeight; if (showingLowPriority) { childHeight = child.getShowingLayout().getMinHeight(false /* likeGroupExpanded */); @@ -1042,13 +1055,13 @@ public class NotificationChildrenContainer extends ViewGroup { int intrinsicHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation + mNotificatonTopPadding + mDividerHeight; int visibleChildren = 0; - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */); for (int i = 0; i < childCount; i++) { if (visibleChildren >= maxAllowedVisibleChildren) { break; } - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); float childHeight = child.isExpanded(true /* allowOnKeyguard */) ? child.getMaxExpandHeight() : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */); @@ -1097,7 +1110,7 @@ public class NotificationChildrenContainer extends ViewGroup { int minExpandHeight = mNotificationHeaderMargin + headerTranslation; int visibleChildren = 0; boolean firstChild = true; - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); for (int i = 0; i < childCount; i++) { if (visibleChildren >= maxAllowedVisibleChildren) { break; @@ -1107,7 +1120,7 @@ public class NotificationChildrenContainer extends ViewGroup { } else { firstChild = false; } - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); minExpandHeight += child.getSingleLineView().getHeight(); visibleChildren++; } @@ -1149,9 +1162,9 @@ public class NotificationChildrenContainer extends ViewGroup { if (!mUserLocked) { updateHeaderVisibility(false /* animate */); } - int childCount = mChildren.size(); + int childCount = mAttachedChildren.size(); for (int i = 0; i < childCount; i++) { - ExpandableNotificationRow child = mChildren.get(i); + ExpandableNotificationRow child = mAttachedChildren.get(i); child.setUserLocked(userLocked && !showingAsLowPriority()); } updateHeaderTouchability(); @@ -1172,8 +1185,8 @@ public class NotificationChildrenContainer extends ViewGroup { int position = mNotificationHeaderMargin + mCurrentHeaderTranslation + mNotificatonTopPadding; - for (int i = 0; i < mChildren.size(); i++) { - ExpandableNotificationRow child = mChildren.get(i); + for (int i = 0; i < mAttachedChildren.size(); i++) { + ExpandableNotificationRow child = mAttachedChildren.get(i); boolean notGone = child.getVisibility() != View.GONE; if (notGone) { position += mDividerHeight; @@ -1251,8 +1264,8 @@ public class NotificationChildrenContainer extends ViewGroup { public void setCurrentBottomRoundness(float currentBottomRoundness) { boolean last = true; - for (int i = mChildren.size() - 1; i >= 0; i--) { - ExpandableNotificationRow child = mChildren.get(i); + for (int i = mAttachedChildren.size() - 1; i >= 0; i--) { + ExpandableNotificationRow child = mAttachedChildren.get(i); if (child.getVisibility() == View.GONE) { continue; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java index 8991abe52ce1a..c2dd2296aa17b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java @@ -43,7 +43,7 @@ public interface NotificationListItem { // This generic is kind of ugly - we should change this once the old VHM is gone /** @return list of the children of this item */ - List getNotificationChildren(); + List getAttachedChildren(); /** remove all children from this list item */ void removeAllChildren(); @@ -54,6 +54,9 @@ public interface NotificationListItem { /** add an item as a child */ void addChildNotification(NotificationListItem child, int childIndex); + /** set the child count view should display */ + void setUntruncatedChildCount(int count); + /** Update the order of the children with the new list */ boolean applyChildOrder( List childOrderList, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 6054b507185e6..5655d8fd021b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -2377,7 +2377,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd ExpandableNotificationRow row = (ExpandableNotificationRow) child; if (row.isSummaryWithChildren() && row.areChildrenExpanded()) { List notificationChildren = - row.getNotificationChildren(); + row.getAttachedChildren(); for (int childIndex = 0; childIndex < notificationChildren.size(); childIndex++) { ExpandableNotificationRow rowChild = notificationChildren.get(childIndex); @@ -4638,7 +4638,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd ExpandableNotificationRow row = (ExpandableNotificationRow) view; row.setHeadsUpAnimatingAway(false); if (row.isSummaryWithChildren()) { - for (ExpandableNotificationRow child : row.getNotificationChildren()) { + for (ExpandableNotificationRow child : row.getAttachedChildren()) { child.setHeadsUpAnimatingAway(false); } } @@ -5598,7 +5598,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd && (!hasClipBounds || mTmpRect.height() > 0)) { parentVisible = true; } - List children = row.getNotificationChildren(); + List children = row.getAttachedChildren(); if (children != null) { for (ExpandableNotificationRow childRow : children) { if (includeChildInDismissAll(row, selection)) { @@ -6388,7 +6388,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd if (parent != null && parent.areChildrenExpanded() && (parent.areGutsExposed() || mSwipeHelper.getExposedMenuView() == parent - || (parent.getNotificationChildren().size() == 1 + || (parent.getAttachedChildren().size() == 1 && parent.getEntry().isClearable()))) { // In this case the group is expanded and showing the menu for the // group, further interaction should apply to the group, not any diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 9646c01c8c419..1a15377566e21 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -297,7 +297,7 @@ public class StackScrollAlgorithm { ExpandableNotificationRow row = (ExpandableNotificationRow) v; // handle the notgoneIndex for the children as well - List children = row.getNotificationChildren(); + List children = row.getAttachedChildren(); if (row.isSummaryWithChildren() && children != null) { for (ExpandableNotificationRow childRow : children) { if (childRow.getVisibility() != View.GONE) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index e472de3494664..52fa144c7655a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -928,7 +928,7 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleController.handleDismissalInterception(groupSummary.getEntry()); // THEN only the NON-bubble children are dismissed - List childrenRows = groupSummary.getNotificationChildren(); + List childrenRows = groupSummary.getAttachedChildren(); verify(mNotificationEntryManager, times(1)).performRemoveNotification( childrenRows.get(0).getEntry().getSbn(), REASON_GROUP_SUMMARY_CANCELED); verify(mNotificationEntryManager, times(1)).performRemoveNotification( diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index 5f4f2ef04c1de..dfcda509b2f2c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -793,7 +793,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mBubbleController.handleDismissalInterception(groupSummary.getEntry()); // THEN only the NON-bubble children are dismissed - List childrenRows = groupSummary.getNotificationChildren(); + List childrenRows = groupSummary.getAttachedChildren(); verify(mNotifCallback, times(1)).removeNotification( childrenRows.get(0).getEntry(), REASON_GROUP_SUMMARY_CANCELED); verify(mNotifCallback, times(1)).removeNotification( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 43dcbe30f3c33..2684cc29aa93e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -41,7 +41,6 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.util.ArraySet; -import android.view.NotificationHeaderView; import android.view.View; import androidx.test.filters.SmallTest; @@ -302,7 +301,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { @Test public void testGetNumUniqueChildren_multiChannel() { List childRows = - mGroupRow.getChildrenContainer().getNotificationChildren(); + mGroupRow.getChildrenContainer().getAttachedChildren(); // Give each child a unique channel id/name. int i = 0; for (ExpandableNotificationRow childRow : childRows) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java index 7c8328d59a514..5aeb43fbd9590 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java @@ -143,7 +143,7 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase { public void testPerhapsShowBlockingHelper_notShownForMultiChannelGroup() throws Exception { ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(10); int i = 0; - for (ExpandableNotificationRow childRow : groupRow.getNotificationChildren()) { + for (ExpandableNotificationRow childRow : groupRow.getAttachedChildren()) { modifyRanking(childRow.getEntry()) .setChannel( new NotificationChannel(