diff options
| author | 2018-05-15 19:04:01 +0000 | |
|---|---|---|
| committer | 2018-05-15 19:04:01 +0000 | |
| commit | fbdd1f7d098c3829a031545776c37c2a0e331b8b (patch) | |
| tree | f2d4069d4169b68adc112c34a143b5ef4b675475 | |
| parent | 49cb81658db123c1e130be3a9f92d4269f3cbb46 (diff) | |
| parent | f93bf3e2cf4f67b6eec2c66278a72f69c923a6da (diff) | |
Merge "Fixed an issue where the wrong notification would be heads upped" into pi-dev
5 files changed, 166 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index c561ae8491b5..b010199b119e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -2768,6 +2768,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mNotificationViewState; } + public NotificationViewState getViewState() { + return mNotificationViewState; + } + @Override public boolean isAboveShelf() { return !isOnKeyguard() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java index 7681530503a9..f14ca71e61f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java @@ -229,6 +229,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mMessagingUtil = new NotificationMessagingUtil(context); mSystemServicesProxy = SystemServicesProxy.getInstance(mContext); + mGroupManager.setPendingEntries(mPendingNotifications); } public void setUpWithPresenter(NotificationPresenter presenter, @@ -739,6 +740,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mNotificationData.getImportance(key)); mPendingNotifications.put(key, shadeEntry); + mGroupManager.onPendingEntryAdded(shadeEntry); } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java index ca65965cc9e6..55ffb3e62e53 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import android.app.Notification; +import android.os.SystemClock; import android.service.notification.StatusBarNotification; import android.support.annotation.Nullable; import android.util.Log; @@ -29,9 +31,11 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Objects; /** * A class to handle notifications and their corresponding groups. @@ -39,12 +43,14 @@ import java.util.Map; public class NotificationGroupManager implements OnHeadsUpChangedListener { private static final String TAG = "NotificationGroupManager"; + private static final long HEADS_UP_TRANSFER_TIMEOUT = 300; private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>(); private OnGroupChangeListener mListener; private int mBarState = -1; private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>(); private HeadsUpManager mHeadsUpManager; private boolean mIsUpdatingUnchangedGroup; + private HashMap<String, NotificationData.Entry> mPendingNotifications; public void setOnGroupChangeListener(OnGroupChangeListener listener) { mListener = listener; @@ -147,6 +153,103 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener { mListener.onGroupCreatedFromChildren(group); } } + cleanUpHeadsUpStatesOnAdd(group, false /* addIsPending */); + } + + public void onPendingEntryAdded(NotificationData.Entry shadeEntry) { + String groupKey = getGroupKey(shadeEntry.notification); + NotificationGroup group = mGroupMap.get(groupKey); + if (group != null) { + cleanUpHeadsUpStatesOnAdd(group, true /* addIsPending */); + } + } + + /** + * Clean up the heads up states when a new child was added. + * @param group The group where a view was added or will be added. + * @param addIsPending True if is the addition still pending or false has it already been added. + */ + private void cleanUpHeadsUpStatesOnAdd(NotificationGroup group, boolean addIsPending) { + if (!addIsPending && group.hunSummaryOnNextAddition) { + if (!mHeadsUpManager.isHeadsUp(group.summary.key)) { + mHeadsUpManager.showNotification(group.summary); + } + group.hunSummaryOnNextAddition = false; + } + // Because notification groups are not delivered as a whole unit, it may happen that a + // group child gets added quite a bit after the summary got posted. Our guidance is, that + // apps should always post the group summary as well and we'll hide it for them if the child + // is the only child in a group. Because of this, we also have to transfer heads up to the + // child, otherwise the invisible summary would be heads-upped. + // This transfer to the child is not always correct in case the app has just posted another + // child in addition to the existing one, but it hasn't arrived in systemUI yet. In such + // a scenario we would transfer the heads up to the old child and the wrong notification + // would be heads-upped. In oder to avoid this, we'll recover from this issue and hun the + // summary again instead of the old child if it's within a certain timeout. + if (SystemClock.elapsedRealtime() - group.lastHeadsUpTransfer < HEADS_UP_TRANSFER_TIMEOUT) { + if (!onlySummaryAlerts(group.summary)) { + return; + } + int numChildren = group.children.size(); + NotificationData.Entry isolatedChild = getIsolatedChild(getGroupKey( + group.summary.notification)); + int numPendingChildren = getPendingChildrenNotAlerting(group); + numChildren += numPendingChildren; + if (isolatedChild != null) { + numChildren++; + } + if (numChildren <= 1) { + return; + } + boolean releasedChild = false; + ArrayList<NotificationData.Entry> children = new ArrayList<>(group.children.values()); + int size = children.size(); + for (int i = 0; i < size; i++) { + NotificationData.Entry entry = children.get(i); + if (onlySummaryAlerts(entry) && entry.row.isHeadsUp()) { + releasedChild = true; + mHeadsUpManager.releaseImmediately(entry.key); + } + } + if (isolatedChild != null && onlySummaryAlerts(isolatedChild) + && isolatedChild.row.isHeadsUp()) { + releasedChild = true; + mHeadsUpManager.releaseImmediately(isolatedChild.key); + } + if (releasedChild && !mHeadsUpManager.isHeadsUp(group.summary.key)) { + boolean notifyImmediately = (numChildren - numPendingChildren) > 1; + if (notifyImmediately) { + mHeadsUpManager.showNotification(group.summary); + } else { + group.hunSummaryOnNextAddition = true; + } + group.lastHeadsUpTransfer = 0; + } + } + } + + private int getPendingChildrenNotAlerting(NotificationGroup group) { + if (mPendingNotifications == null) { + return 0; + } + int number = 0; + String groupKey = getGroupKey(group.summary.notification); + Collection<NotificationData.Entry> values = mPendingNotifications.values(); + for (NotificationData.Entry entry : values) { + if (!isGroupChild(entry.notification)) { + continue; + } + if (!Objects.equals(getGroupKey(entry.notification), groupKey)) { + continue; + } + if (group.children.containsKey(entry.key)) { + continue; + } + if (onlySummaryAlerts(entry)) { + number++; + } + } + return number; } private void onEntryBecomingChild(NotificationData.Entry entry) { @@ -421,8 +524,16 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener { || !entry.row.isHeadsUp()) { return; } + // The parent of a suppressed group got huned, lets hun the child! NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey()); + + if (pendingInflationsWillAddChildren(notificationGroup)) { + // New children will actually be added to this group, let's not transfer the heads + // up + return; + } + if (notificationGroup != null) { Iterator<NotificationData.Entry> iterator = notificationGroup.children.values().iterator(); @@ -438,6 +549,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener { if (mHeadsUpManager.isHeadsUp(child.key)) { mHeadsUpManager.updateNotification(child, true); } else { + if (onlySummaryAlerts(entry)) { + notificationGroup.lastHeadsUpTransfer = SystemClock.elapsedRealtime(); + } mHeadsUpManager.showNotification(child); } } @@ -445,6 +559,35 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener { mHeadsUpManager.releaseImmediately(entry.key); } + private boolean onlySummaryAlerts(NotificationData.Entry entry) { + return entry.notification.getNotification().getGroupAlertBehavior() + == Notification.GROUP_ALERT_SUMMARY; + } + + /** + * Check if the pending inflations will add children to this group. + * @param group The group to check. + */ + private boolean pendingInflationsWillAddChildren(NotificationGroup group) { + if (mPendingNotifications == null) { + return false; + } + Collection<NotificationData.Entry> values = mPendingNotifications.values(); + String groupKey = getGroupKey(group.summary.notification); + for (NotificationData.Entry entry : values) { + if (!isGroupChild(entry.notification)) { + continue; + } + if (!Objects.equals(getGroupKey(entry.notification), groupKey)) { + continue; + } + if (!group.children.containsKey(entry.key)) { + return true; + } + } + return false; + } + private boolean shouldIsolate(StatusBarNotification sbn) { NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey()); return (sbn.isGroup() && !sbn.getNotification().isGroupSummary()) @@ -477,6 +620,10 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener { } } + public void setPendingEntries(HashMap<String, NotificationData.Entry> pendingNotifications) { + mPendingNotifications = pendingNotifications; + } + public static class NotificationGroup { public final HashMap<String, NotificationData.Entry> children = new HashMap<>(); public NotificationData.Entry summary; @@ -485,6 +632,12 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener { * Is this notification group suppressed, i.e its summary is hidden */ public boolean suppressed; + /** + * The time when the last heads transfer from group to child happened, while the summary + * has the flags to heads up on its own. + */ + public long lastHeadsUpTransfer; + public boolean hunSummaryOnNextAddition; @Override public String toString() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java index 55ec142444f2..45fa44ca6126 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java @@ -269,6 +269,12 @@ public class NotificationChildrenContainer extends ViewGroup { updateGroupOverflow(); row.setContentTransformationAmount(0, false /* isLastChild */); + // It doesn't make sense to keep old animations around, lets cancel them! + ExpandableNotificationRow.NotificationViewState viewState = row.getViewState(); + if (viewState != null) { + viewState.cancelAnimations(row); + row.cancelAppearDrawing(); + } } public void removeNotification(ExpandableNotificationRow row) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index f688bb0e376e..ee700197b13d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -3204,6 +3204,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (row.isChildInGroup()) { // We can otherwise get stuck in there if it was just isolated row.setHeadsUpAnimatingAway(false); + continue; } } else { ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(row); |