/* * Copyright (C) 2015 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.phone; import android.app.Notification; import android.service.notification.StatusBarNotification; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.StatusBarState; import java.util.HashMap; import java.util.HashSet; /** * A class to handle notifications and their corresponding groups. */ public class NotificationGroupManager { private final HashMap mGroupMap = new HashMap<>(); private OnGroupChangeListener mListener; private int mBarState = -1; public void setOnGroupChangeListener(OnGroupChangeListener listener) { mListener = listener; } public boolean isGroupExpanded(StatusBarNotification sbn) { NotificationGroup group = mGroupMap.get(sbn.getGroupKey()); if (group == null) { return false; } return group.expanded; } public void setGroupExpanded(StatusBarNotification sbn, boolean expanded) { NotificationGroup group = mGroupMap.get(sbn.getGroupKey()); if (group == null) { return; } setGroupExpanded(group, expanded); } private void setGroupExpanded(NotificationGroup group, boolean expanded) { group.expanded = expanded; if (group.summary != null) { mListener.onGroupExpansionChanged(group.summary.row, expanded); } } public void onEntryRemoved(NotificationData.Entry removed) { onEntryRemovedInternal(removed, removed.notification); } /** * An entry was removed. * * @param removed the removed entry * @param sbn the notification the entry has, which doesn't need to be the same as it's internal * notification */ private void onEntryRemovedInternal(NotificationData.Entry removed, final StatusBarNotification sbn) { Notification notif = sbn.getNotification(); String groupKey = sbn.getGroupKey(); final NotificationGroup group = mGroupMap.get(groupKey); if (notif.isGroupSummary()) { group.summary = null; } else { group.children.remove(removed); } if (group.children.isEmpty()) { if (group.summary == null) { mGroupMap.remove(groupKey); } else { if (group.expanded) { // only the summary is left. Change it to unexpanded in a few ms. We do this to // avoid raceconditions removed.row.post(new Runnable() { @Override public void run() { if (group.children.isEmpty()) { setGroupExpanded(sbn, false); } } }); } else { group.summary.row.updateExpandButton(); } } } } public void onEntryAdded(NotificationData.Entry added) { StatusBarNotification sbn = added.notification; Notification notif = sbn.getNotification(); String groupKey = sbn.getGroupKey(); NotificationGroup group = mGroupMap.get(groupKey); if (group == null) { group = new NotificationGroup(); mGroupMap.put(groupKey, group); } if (notif.isGroupSummary()) { group.summary = added; group.expanded = added.row.areChildrenExpanded(); if (!group.children.isEmpty()) { mListener.onGroupCreatedFromChildren(group); } } else { group.children.add(added); if (group.summary != null && group.children.size() == 1 && !group.expanded) { group.summary.row.updateExpandButton(); } } } public void onEntryUpdated(NotificationData.Entry entry, StatusBarNotification oldNotification) { if (mGroupMap.get(oldNotification.getGroupKey()) != null) { onEntryRemovedInternal(entry, oldNotification); } onEntryAdded(entry); } public boolean isVisible(StatusBarNotification sbn) { if (!sbn.getNotification().isGroupChild()) { return true; } NotificationGroup group = mGroupMap.get(sbn.getGroupKey()); if (group != null && (group.expanded || group.summary == null)) { return true; } return false; } public boolean hasGroupChildren(StatusBarNotification sbn) { if (areGroupsProhibited()) { return false; } if (!sbn.getNotification().isGroupSummary()) { return false; } NotificationGroup group = mGroupMap.get(sbn.getGroupKey()); if (group == null) { return false; } return !group.children.isEmpty(); } public void setStatusBarState(int newState) { if (mBarState == newState) { return; } boolean prohibitedBefore = areGroupsProhibited(); mBarState = newState; boolean nowProhibited = areGroupsProhibited(); if (nowProhibited != prohibitedBefore) { if (nowProhibited) { for (NotificationGroup group : mGroupMap.values()) { if (group.expanded) { setGroupExpanded(group, false); } } } mListener.onGroupsProhibitedChanged(); } } private boolean areGroupsProhibited() { return mBarState == StatusBarState.KEYGUARD; } /** * @return whether a given notification is a child in a group which has a summary */ public boolean isChildInGroupWithSummary(StatusBarNotification sbn) { if (!sbn.getNotification().isGroupChild()) { return false; } NotificationGroup group = mGroupMap.get(sbn.getGroupKey()); if (group == null || group.summary == null) { return false; } return true; } public ExpandableNotificationRow getGroupSummary(StatusBarNotification sbn) { NotificationGroup group = mGroupMap.get(sbn.getGroupKey()); return group == null ? null : group.summary == null ? null : group.summary.row; } public static class NotificationGroup { public final HashSet children = new HashSet<>(); public NotificationData.Entry summary; public boolean expanded; } public interface OnGroupChangeListener { /** * The expansion of a group has changed. * * @param changedRow the row for which the expansion has changed, which is also the summary * @param expanded a boolean indicating the new expanded state */ void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded); /** * Children group policy has changed and children may no be prohibited or allowed. */ void onGroupsProhibitedChanged(); /** * A group of children just received a summary notification and should therefore become * children of it. * * @param group the group created */ void onGroupCreatedFromChildren(NotificationGroup group); } }