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

Commit 78e030e1 authored by Selim Cinek's avatar Selim Cinek Committed by android-build-merger
Browse files

Merge "Fixed an issue where the wrong notification would be heads upped" into pi-dev

am: fbdd1f7d

Change-Id: I007934cfb8bd971e77291a56958fb55e1bfc5c3e
parents 94dae642 fbdd1f7d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -2768,6 +2768,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        return mNotificationViewState;
    }

    public NotificationViewState getViewState() {
        return mNotificationViewState;
    }

    @Override
    public boolean isAboveShelf() {
        return !isOnKeyguard()
+2 −0
Original line number Diff line number Diff line
@@ -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
+153 −0
Original line number Diff line number Diff line
@@ -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() {
+6 −0
Original line number Diff line number Diff line
@@ -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) {
+1 −0
Original line number Diff line number Diff line
@@ -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);