blob: bf107cecb42b0f692240ba0cf4b2023674830624 [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;
24import com.android.systemui.statusbar.StatusBarState;
25
26import java.util.HashMap;
27import java.util.HashSet;
Selim Cinek25fd4e2b2015-02-20 17:46:07 +010028
29/**
30 * A class to handle notifications and their corresponding groups.
31 */
32public class NotificationGroupManager {
33
34 private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
35 private OnGroupChangeListener mListener;
36 private int mBarState = -1;
37
38 public void setOnGroupChangeListener(OnGroupChangeListener listener) {
39 mListener = listener;
40 }
41
42 public boolean isGroupExpanded(StatusBarNotification sbn) {
43 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
44 if (group == null) {
45 return false;
46 }
47 return group.expanded;
48 }
49
50 public void setGroupExpanded(StatusBarNotification sbn, boolean expanded) {
51 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
52 if (group == null) {
53 return;
54 }
55 setGroupExpanded(group, expanded);
56 }
57
58 private void setGroupExpanded(NotificationGroup group, boolean expanded) {
59 group.expanded = expanded;
60 if (group.summary != null) {
61 mListener.onGroupExpansionChanged(group.summary.row, expanded);
62 }
63 }
64
65 public void onEntryRemoved(NotificationData.Entry removed) {
66 onEntryRemovedInternal(removed, removed.notification);
67 }
68
69 /**
70 * An entry was removed.
71 *
72 * @param removed the removed entry
73 * @param sbn the notification the entry has, which doesn't need to be the same as it's internal
74 * notification
75 */
76 private void onEntryRemovedInternal(NotificationData.Entry removed,
77 final StatusBarNotification sbn) {
78 Notification notif = sbn.getNotification();
79 String groupKey = sbn.getGroupKey();
80 final NotificationGroup group = mGroupMap.get(groupKey);
Selim Cinek0b4aeab2015-09-01 17:07:38 -070081 if (group == null) {
82 // When an app posts 2 different notifications as summary of the same group, then a
83 // cancellation of the first notification removes this group.
84 // This situation is not supported and we will not allow such notifications anymore in
85 // the close future. See b/23676310 for reference.
86 return;
87 }
Selim Cinek25fd4e2b2015-02-20 17:46:07 +010088 if (notif.isGroupSummary()) {
89 group.summary = null;
90 } else {
91 group.children.remove(removed);
92 }
93 if (group.children.isEmpty()) {
94 if (group.summary == null) {
95 mGroupMap.remove(groupKey);
96 } else {
97 if (group.expanded) {
98 // only the summary is left. Change it to unexpanded in a few ms. We do this to
99 // avoid raceconditions
100 removed.row.post(new Runnable() {
101 @Override
102 public void run() {
103 if (group.children.isEmpty()) {
104 setGroupExpanded(sbn, false);
105 }
106 }
107 });
Selim Cinekb5605e52015-02-20 18:21:41 +0100108 } else {
109 group.summary.row.updateExpandButton();
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100110 }
111 }
112 }
113 }
114
115 public void onEntryAdded(NotificationData.Entry added) {
116 StatusBarNotification sbn = added.notification;
117 Notification notif = sbn.getNotification();
118 String groupKey = sbn.getGroupKey();
119 NotificationGroup group = mGroupMap.get(groupKey);
120 if (group == null) {
121 group = new NotificationGroup();
122 mGroupMap.put(groupKey, group);
123 }
124 if (notif.isGroupSummary()) {
125 group.summary = added;
Selim Cinekb5605e52015-02-20 18:21:41 +0100126 group.expanded = added.row.areChildrenExpanded();
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100127 if (!group.children.isEmpty()) {
128 mListener.onGroupCreatedFromChildren(group);
129 }
130 } else {
131 group.children.add(added);
Selim Cinekb5605e52015-02-20 18:21:41 +0100132 if (group.summary != null && group.children.size() == 1 && !group.expanded) {
133 group.summary.row.updateExpandButton();
134 }
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100135 }
136 }
137
138 public void onEntryUpdated(NotificationData.Entry entry,
139 StatusBarNotification oldNotification) {
140 if (mGroupMap.get(oldNotification.getGroupKey()) != null) {
141 onEntryRemovedInternal(entry, oldNotification);
142 }
143 onEntryAdded(entry);
144 }
145
146 public boolean isVisible(StatusBarNotification sbn) {
147 if (!sbn.getNotification().isGroupChild()) {
148 return true;
149 }
150 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
Selim Cinekacf52ba2015-07-07 14:54:10 -0700151 if (group != null && (group.expanded || group.summary == null)) {
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100152 return true;
153 }
154 return false;
155 }
156
157 public boolean hasGroupChildren(StatusBarNotification sbn) {
158 if (areGroupsProhibited()) {
159 return false;
160 }
161 if (!sbn.getNotification().isGroupSummary()) {
162 return false;
163 }
164 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
165 if (group == null) {
166 return false;
167 }
168 return !group.children.isEmpty();
169 }
170
171 public void setStatusBarState(int newState) {
172 if (mBarState == newState) {
173 return;
174 }
175 boolean prohibitedBefore = areGroupsProhibited();
176 mBarState = newState;
177 boolean nowProhibited = areGroupsProhibited();
178 if (nowProhibited != prohibitedBefore) {
179 if (nowProhibited) {
180 for (NotificationGroup group : mGroupMap.values()) {
181 if (group.expanded) {
182 setGroupExpanded(group, false);
183 }
184 }
185 }
186 mListener.onGroupsProhibitedChanged();
187 }
188 }
189
190 private boolean areGroupsProhibited() {
191 return mBarState == StatusBarState.KEYGUARD;
192 }
193
194 /**
195 * @return whether a given notification is a child in a group which has a summary
196 */
197 public boolean isChildInGroupWithSummary(StatusBarNotification sbn) {
198 if (!sbn.getNotification().isGroupChild()) {
199 return false;
200 }
201 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
202 if (group == null || group.summary == null) {
203 return false;
204 }
205 return true;
206 }
207
Selim Cinek263398f2015-10-21 17:40:23 -0700208 /**
209 * @return whether a given notification is a summary in a group which has children
210 */
211 public boolean isSummaryOfGroup(StatusBarNotification sbn) {
212 if (sbn.getNotification().isGroupChild()) {
213 return false;
214 }
215 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
216 if (group == null) {
217 return false;
218 }
219 return !group.children.isEmpty();
220 }
221
Selim Cinek25fd4e2b2015-02-20 17:46:07 +0100222 public ExpandableNotificationRow getGroupSummary(StatusBarNotification sbn) {
223 NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
224 return group == null ? null
225 : group.summary == null ? null
226 : group.summary.row;
227 }
228
229 public static class NotificationGroup {
230 public final HashSet<NotificationData.Entry> children = new HashSet<>();
231 public NotificationData.Entry summary;
232 public boolean expanded;
233 }
234
235 public interface OnGroupChangeListener {
236 /**
237 * The expansion of a group has changed.
238 *
239 * @param changedRow the row for which the expansion has changed, which is also the summary
240 * @param expanded a boolean indicating the new expanded state
241 */
242 void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded);
243
244 /**
245 * Children group policy has changed and children may no be prohibited or allowed.
246 */
247 void onGroupsProhibitedChanged();
248
249 /**
250 * A group of children just received a summary notification and should therefore become
251 * children of it.
252 *
253 * @param group the group created
254 */
255 void onGroupCreatedFromChildren(NotificationGroup group);
256 }
257}