summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI
diff options
context:
space:
mode:
authorSelim Cinek <cinek@google.com>2015-02-20 17:46:07 +0100
committerSelim Cinek <cinek@google.com>2015-03-12 16:04:52 -0700
commit25fd4e2be731fe893685faa48828d8fa4526cb1a (patch)
tree0f5d7282777b304dcf203d521d0e35a41ec7f764 /packages/SystemUI
parentabf60bb20f5e84574b91747effcd675f596cbb1e (diff)
downloadframeworks_base-25fd4e2be731fe893685faa48828d8fa4526cb1a.zip
frameworks_base-25fd4e2be731fe893685faa48828d8fa4526cb1a.tar.gz
frameworks_base-25fd4e2be731fe893685faa48828d8fa4526cb1a.tar.bz2
Introduced a group manager to manage group notifications
Bug: 15869874 Change-Id: I1bbcd9e5a2b8dae62bd8d93908dacc5d8fc08887
Diffstat (limited to 'packages/SystemUI')
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java232
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java1
4 files changed, 258 insertions, 25 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 9dbda7d..6b2e546 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -97,6 +97,7 @@ import com.android.systemui.SystemUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.phone.NavigationBarView;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
import com.android.systemui.statusbar.policy.PreviewInflater;
@@ -156,6 +157,8 @@ public abstract class BaseStatusBar extends SystemUI implements
protected NotificationData mNotificationData;
protected NotificationStackScrollLayout mStackScroller;
+ protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
+
// for heads up notifications
protected HeadsUpNotificationView mHeadsUpNotificationView;
protected int mHeadsUpNotificationDecay;
@@ -438,8 +441,7 @@ public abstract class BaseStatusBar extends SystemUI implements
// Ignore children of notifications that have a summary, since we're not
// going to show them anyway. This is true also when the summary is canceled,
// because children are automatically canceled by NoMan in that case.
- if (n.isGroupChild() &&
- mNotificationData.isGroupWithSummary(sbn.getGroupKey())) {
+ if (mGroupManager.isChildInGroupWithSummary(sbn)) {
if (DEBUG) {
Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
}
@@ -707,6 +709,11 @@ public abstract class BaseStatusBar extends SystemUI implements
return null;
}
+ @Override
+ public NotificationGroupManager getGroupManager() {
+ return mGroupManager;
+ }
+
/**
* Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
* @param action A dismiss action that is called if it's safe to start the activity.
@@ -2016,6 +2023,7 @@ public abstract class BaseStatusBar extends SystemUI implements
&& publicUnchanged) {
if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
oldEntry.notification = notification;
+ mGroupManager.onEntryUpdated(oldEntry, oldNotification);
try {
if (oldEntry.icon != null) {
// Update the icon
@@ -2074,6 +2082,7 @@ public abstract class BaseStatusBar extends SystemUI implements
if (!shouldInterrupt) {
if (DEBUG) Log.d(TAG, "releasing heads up for key: " + key);
oldEntry.notification = notification;
+ mGroupManager.onEntryUpdated(oldEntry, oldNotification);
mHeadsUpNotificationView.release();
return;
}
@@ -2087,6 +2096,7 @@ public abstract class BaseStatusBar extends SystemUI implements
} else {
if (DEBUG) Log.d(TAG, "rebuilding update in place for key: " + key);
oldEntry.notification = notification;
+ mGroupManager.onEntryUpdated(oldEntry, oldNotification);
final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
notification.getUser(),
n.icon,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 34c458a..7e68c10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -22,9 +22,10 @@ import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.view.View;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -91,10 +92,12 @@ public class NotificationData {
private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
private final ArrayList<Entry> mSortedAndFiltered = new ArrayList<>();
- private ArraySet<String> mGroupsWithSummaries = new ArraySet<>();
+
+ private NotificationGroupManager mGroupManager;
private RankingMap mRankingMap;
private final Ranking mTmpRanking = new Ranking();
+
private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
private final Ranking mRankingA = new Ranking();
private final Ranking mRankingB = new Ranking();
@@ -141,6 +144,7 @@ public class NotificationData {
public NotificationData(Environment environment) {
mEnvironment = environment;
+ mGroupManager = environment.getGroupManager();
}
/**
@@ -163,12 +167,14 @@ public class NotificationData {
public void add(Entry entry, RankingMap ranking) {
mEntries.put(entry.notification.getKey(), entry);
updateRankingAndSort(ranking);
+ mGroupManager.onEntryAdded(entry);
}
public Entry remove(String key, RankingMap ranking) {
Entry removed = mEntries.remove(key);
if (removed == null) return null;
updateRankingAndSort(ranking);
+ mGroupManager.onEntryRemoved(removed);
return removed;
}
@@ -203,7 +209,6 @@ public class NotificationData {
// anything changed, and this class should call back the UI so it updates itself.
public void filterAndSort() {
mSortedAndFiltered.clear();
- mGroupsWithSummaries.clear();
final int N = mEntries.size();
for (int i = 0; i < N; i++) {
@@ -214,32 +219,12 @@ public class NotificationData {
continue;
}
- if (sbn.getNotification().isGroupSummary()) {
- mGroupsWithSummaries.add(sbn.getGroupKey());
- }
mSortedAndFiltered.add(entry);
}
- // Second pass: Filter out group children with summary.
- if (!mGroupsWithSummaries.isEmpty()) {
- final int M = mSortedAndFiltered.size();
- for (int i = M - 1; i >= 0; i--) {
- Entry ent = mSortedAndFiltered.get(i);
- StatusBarNotification sbn = ent.notification;
- if (sbn.getNotification().isGroupChild() &&
- mGroupsWithSummaries.contains(sbn.getGroupKey())) {
- mSortedAndFiltered.remove(i);
- }
- }
- }
-
Collections.sort(mSortedAndFiltered, mRankingComparator);
}
- public boolean isGroupWithSummary(String groupKey) {
- return mGroupsWithSummaries.contains(groupKey);
- }
-
boolean shouldFilterOut(StatusBarNotification sbn) {
if (!(mEnvironment.isDeviceProvisioned() ||
showNotificationEvenIfUnprovisioned(sbn))) {
@@ -254,6 +239,10 @@ public class NotificationData {
mEnvironment.shouldHideSensitiveContents(sbn.getUserId())) {
return true;
}
+
+ if (mGroupManager.isChildInGroupWithSummary(sbn)) {
+ return true;
+ }
return false;
}
@@ -328,5 +317,6 @@ public class NotificationData {
public boolean isDeviceProvisioned();
public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
public String getCurrentMediaNotificationKey();
+ public NotificationGroupManager getGroupManager();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
new file mode 100644
index 0000000..5214ab4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -0,0 +1,232 @@
+/*
+ * 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;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A class to handle notifications and their corresponding groups.
+ */
+public class NotificationGroupManager {
+
+ private final HashMap<String, NotificationGroup> 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);
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+
+ 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;
+ if (!group.children.isEmpty()) {
+ mListener.onGroupCreatedFromChildren(group);
+ }
+ } else {
+ group.children.add(added);
+ }
+ }
+
+ 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) {
+ 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<NotificationData.Entry> 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);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9da60e8..e5eb747 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3379,6 +3379,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
mState = state;
+ mGroupManager.setStatusBarState(state);
mStatusBarWindowManager.setStatusBarState(state);
}