blob: bbef1c031ff57510d6f4f48eca886af3e9834520 [file] [log] [blame]
Selim Cinek25fd4e2b2015-02-20 17:46:07 +01001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.statusbar.phone;
18
19import android.app.Notification;
20import android.service.notification.StatusBarNotification;
21
22import com.android.systemui.statusbar.ExpandableNotificationRow;
23import com.android.systemui.statusbar.NotificationData;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +010024
25import java.util.HashMap;
26import java.util.HashSet;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +010027
28/**
29 * A class to handle notifications and their corresponding groups.
30 */
31public class NotificationGroupManager {
32
33 private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
34 private OnGroupChangeListener mListener;
35 private int mBarState = -1;
36
37 public void setOnGroupChangeListener(OnGroupChangeListener listener) {
38 mListener = listener;
39 }
40
41 public boolean isGroupExpanded(StatusBarNotification sbn) {
42 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
43 if (group == null) {
44 return false;
45 }
46 return group.expanded;
47 }
48
49 public void setGroupExpanded(StatusBarNotification sbn, boolean expanded) {
50 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
51 if (group == null) {
52 return;
53 }
54 setGroupExpanded(group, expanded);
55 }
56
57 private void setGroupExpanded(NotificationGroup group, boolean expanded) {
58 group.expanded = expanded;
59 if (group.summary != null) {
60 mListener.onGroupExpansionChanged(group.summary.row, expanded);
61 }
62 }
63
64 public void onEntryRemoved(NotificationData.Entry removed) {
65 onEntryRemovedInternal(removed, removed.notification);
66 }
67
68 /**
69 * An entry was removed.
70 *
71 * @param removed the removed entry
72 * @param sbn the notification the entry has, which doesn't need to be the same as it's internal
73 * notification
74 */
75 private void onEntryRemovedInternal(NotificationData.Entry removed,
76 final StatusBarNotification sbn) {
77 Notification notif = sbn.getNotification();
78 String groupKey = sbn.getGroupKey();
79 final NotificationGroup group = mGroupMap.get(groupKey);
Selim Cinek0b4aeab2015-09-01 17:07:38 -070080 if (group == null) {
81 // When an app posts 2 different notifications as summary of the same group, then a
82 // cancellation of the first notification removes this group.
83 // This situation is not supported and we will not allow such notifications anymore in
84 // the close future. See b/23676310 for reference.
85 return;
86 }
Selim Cinek25fd4e2b2015-02-20 17:46:07 +010087 if (notif.isGroupSummary()) {
88 group.summary = null;
89 } else {
90 group.children.remove(removed);
91 }
92 if (group.children.isEmpty()) {
93 if (group.summary == null) {
94 mGroupMap.remove(groupKey);
Selim Cinek83bc7832015-10-22 13:26:54 -070095 } else if (!group.expanded) {
96 group.summary.row.updateNotificationHeader();
Selim Cinek25fd4e2b2015-02-20 17:46:07 +010097 }
98 }
99 }
100
101 public void onEntryAdded(NotificationData.Entry added) {
102 StatusBarNotification sbn = added.notification;
103 Notification notif = sbn.getNotification();
104 String groupKey = sbn.getGroupKey();
105 NotificationGroup group = mGroupMap.get(groupKey);
106 if (group == null) {
107 group = new NotificationGroup();
108 mGroupMap.put(groupKey, group);
109 }
110 if (notif.isGroupSummary()) {
111 group.summary = added;
Selim Cinekb5605e52015-02-20 18:21:41 +0100112 group.expanded = added.row.areChildrenExpanded();
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100113 if (!group.children.isEmpty()) {
114 mListener.onGroupCreatedFromChildren(group);
115 }
116 } else {
117 group.children.add(added);
Selim Cinekb5605e52015-02-20 18:21:41 +0100118 if (group.summary != null && group.children.size() == 1 && !group.expanded) {
Selim Cinekeef84282015-10-30 16:28:00 -0700119 group.summary.row.updateNotificationHeader();
Selim Cinekb5605e52015-02-20 18:21:41 +0100120 }
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100121 }
122 }
123
124 public void onEntryUpdated(NotificationData.Entry entry,
125 StatusBarNotification oldNotification) {
126 if (mGroupMap.get(oldNotification.getGroupKey()) != null) {
127 onEntryRemovedInternal(entry, oldNotification);
128 }
129 onEntryAdded(entry);
130 }
131
132 public boolean isVisible(StatusBarNotification sbn) {
133 if (!sbn.getNotification().isGroupChild()) {
134 return true;
135 }
136 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
Selim Cinekacf52ba2015-07-07 14:54:10 -0700137 if (group != null && (group.expanded || group.summary == null)) {
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100138 return true;
139 }
140 return false;
141 }
142
143 public boolean hasGroupChildren(StatusBarNotification sbn) {
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100144 if (!sbn.getNotification().isGroupSummary()) {
145 return false;
146 }
147 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
148 if (group == null) {
149 return false;
150 }
151 return !group.children.isEmpty();
152 }
153
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100154 /**
155 * @return whether a given notification is a child in a group which has a summary
156 */
157 public boolean isChildInGroupWithSummary(StatusBarNotification sbn) {
158 if (!sbn.getNotification().isGroupChild()) {
159 return false;
160 }
161 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
162 if (group == null || group.summary == null) {
163 return false;
164 }
165 return true;
166 }
167
Selim Cinek263398f2015-10-21 17:40:23 -0700168 /**
169 * @return whether a given notification is a summary in a group which has children
170 */
171 public boolean isSummaryOfGroup(StatusBarNotification sbn) {
172 if (sbn.getNotification().isGroupChild()) {
173 return false;
174 }
175 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
176 if (group == null) {
177 return false;
178 }
179 return !group.children.isEmpty();
180 }
181
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100182 public ExpandableNotificationRow getGroupSummary(StatusBarNotification sbn) {
183 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
184 return group == null ? null
185 : group.summary == null ? null
186 : group.summary.row;
187 }
188
Selim Cinek83bc7832015-10-22 13:26:54 -0700189 public void onEntryHeadsUped(NotificationData.Entry headsUp) {
190 // TODO: handle this nicely
191 }
192
193 public void toggleGroupExpansion(StatusBarNotification sbn) {
194 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
195 if (group == null) {
196 return;
197 }
198 setGroupExpanded(group, !group.expanded);
199 }
200
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100201 public static class NotificationGroup {
202 public final HashSet<NotificationData.Entry> children = new HashSet<>();
203 public NotificationData.Entry summary;
204 public boolean expanded;
205 }
206
207 public interface OnGroupChangeListener {
208 /**
209 * The expansion of a group has changed.
210 *
211 * @param changedRow the row for which the expansion has changed, which is also the summary
212 * @param expanded a boolean indicating the new expanded state
213 */
214 void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded);
215
216 /**
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100217 * A group of children just received a summary notification and should therefore become
218 * children of it.
219 *
220 * @param group the group created
221 */
222 void onGroupCreatedFromChildren(NotificationGroup group);
223 }
224}