diff options
author | Selim Cinek <cinek@google.com> | 2015-02-20 17:46:07 +0100 |
---|---|---|
committer | Selim Cinek <cinek@google.com> | 2015-03-12 16:04:52 -0700 |
commit | 25fd4e2be731fe893685faa48828d8fa4526cb1a (patch) | |
tree | 0f5d7282777b304dcf203d521d0e35a41ec7f764 /packages/SystemUI | |
parent | abf60bb20f5e84574b91747effcd675f596cbb1e (diff) | |
download | frameworks_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')
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); } |