Merge "Make mPendingNotifications truly private"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AlertTransferListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AlertTransferListener.java
new file mode 100644
index 0000000..13e991b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AlertTransferListener.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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.notification;
+
+/**
+ * Listener interface for when NotificationEntryManager needs to tell
+ * NotificationGroupAlertTransferHelper things. Will eventually grow to be a general-purpose
+ * listening interface for the NotificationEntryManager.
+ */
+public interface AlertTransferListener {
+ /**
+ * Called when a new notification is posted. At this point, the notification is "pending": its
+ * views haven't been inflated yet and most of the system pretends like it doesn't exist yet.
+ */
+ void onPendingEntryAdded(NotificationData.Entry entry);
+
+ /**
+ * Called when an existing notification's views are reinflated (usually due to an update being
+ * posted to that notification).
+ */
+ void onEntryReinflated(NotificationData.Entry entry);
+
+ /**
+ * Called when a notification has been removed (either because the user swiped it away or
+ * because the developer retracted it).
+ */
+ void onEntryRemoved(NotificationData.Entry entry);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 16a3849..e1b381b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -61,7 +61,6 @@
import com.android.systemui.Dumpable;
import com.android.systemui.EventLogTags;
import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.bubbles.BubbleController;
@@ -83,7 +82,6 @@
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -117,8 +115,6 @@
private final NotificationGroupManager mGroupManager =
Dependency.get(NotificationGroupManager.class);
- private final NotificationGroupAlertTransferHelper mGroupAlertTransferHelper =
- Dependency.get(NotificationGroupAlertTransferHelper.class);
private final NotificationGutsManager mGutsManager =
Dependency.get(NotificationGutsManager.class);
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
@@ -157,6 +153,7 @@
= new ArrayList<>();
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private NotificationViewHierarchyManager.StatusBarStateListener mStatusBarStateListener;
+ @Nullable private AlertTransferListener mAlertTransferListener;
private final class NotificationClicker implements View.OnClickListener {
@@ -258,12 +255,10 @@
mMessagingUtil = new NotificationMessagingUtil(context);
mBubbleController.setDismissListener(this /* bubbleEventListener */);
mNotificationData = new NotificationData();
- Dependency.get(InitController.class).addPostInitTask(this::onPostInit);
}
- private void onPostInit() {
- mGroupAlertTransferHelper.setPendingEntries(mPendingNotifications);
- mGroupManager.addOnGroupChangeListener(mGroupAlertTransferHelper);
+ public void setAlertTransferListener(AlertTransferListener listener) {
+ mAlertTransferListener = listener;
}
/**
@@ -587,7 +582,9 @@
mVisualStabilityManager.onLowPriorityUpdated(entry);
mPresenter.updateNotificationViews();
}
- mGroupAlertTransferHelper.onInflationFinished(entry);
+ if (mAlertTransferListener != null) {
+ mAlertTransferListener.onEntryReinflated(entry);
+ }
}
}
entry.setLowPriorityStateUpdated(false);
@@ -600,8 +597,12 @@
private void removeNotificationInternal(String key,
@Nullable NotificationListenerService.RankingMap ranking, boolean forceRemove) {
+ final NotificationData.Entry entry = mNotificationData.get(key);
+
abortExistingInflation(key);
- mGroupAlertTransferHelper.cleanUpPendingAlertInfo(key);
+ if (mAlertTransferListener != null) {
+ mAlertTransferListener.onEntryRemoved(entry);
+ }
// Attempt to remove notifications from their alert managers (heads up, ambient pulse).
// Though the remove itself may fail, it lets the manager know to remove as soon as
@@ -620,8 +621,6 @@
mAmbientPulseManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
}
- NotificationData.Entry entry = mNotificationData.get(key);
-
if (entry == null) {
mCallback.onNotificationRemoved(key, null /* old */);
return;
@@ -846,7 +845,9 @@
mNotificationData.getImportance(key));
mPendingNotifications.put(key, shadeEntry);
- mGroupAlertTransferHelper.onPendingEntryAdded(shadeEntry);
+ if (mAlertTransferListener != null) {
+ mAlertTransferListener.onPendingEntryAdded(shadeEntry);
+ }
}
@VisibleForTesting
@@ -1231,6 +1232,15 @@
}
/**
+ * @return An iterator for all "pending" notifications. Pending notifications are newly-posted
+ * notifications whose views have not yet been inflated. In general, the system pretends like
+ * these don't exist, although there are a couple exceptions.
+ */
+ public Iterable<NotificationData.Entry> getPendingNotificationsIterator() {
+ return mPendingNotifications.values();
+ }
+
+ /**
* Callback for NotificationEntryManager.
*/
public interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index 2a68fa5..dd81c4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -29,7 +29,9 @@
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.notification.AlertTransferListener;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater.AsyncInflationTask;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
@@ -38,8 +40,6 @@
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
import java.util.Objects;
/**
@@ -47,8 +47,8 @@
* {@link HeadsUpManager}, {@link AmbientPulseManager}. In particular, this class deals with keeping
* the correct notification in a group alerting based off the group suppression.
*/
-public class NotificationGroupAlertTransferHelper implements OnGroupChangeListener,
- OnHeadsUpChangedListener, OnAmbientChangedListener, StateListener {
+public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,
+ OnAmbientChangedListener, StateListener {
private static final long ALERT_TRANSFER_TIMEOUT = 300;
@@ -69,15 +69,7 @@
private final NotificationGroupManager mGroupManager =
Dependency.get(NotificationGroupManager.class);
- // TODO(b/119637830): It would be good if GroupManager already had all pending notifications as
- // normal children (i.e. add notifications to GroupManager before inflation) so that we don't
- // have to have this dependency. We'd also have to worry less about the suppression not being up
- // to date.
- /**
- * Notifications that are currently inflating for the first time. Used to remove an incorrectly
- * alerting notification faster.
- */
- private HashMap<String, Entry> mPendingNotifications;
+ private NotificationEntryManager mEntryManager;
private boolean mIsDozing;
@@ -85,6 +77,23 @@
Dependency.get(StatusBarStateController.class).addCallback(this);
}
+ /** Causes the TransferHelper to register itself as a listener to the appropriate classes. */
+ public void bind(NotificationEntryManager entryManager,
+ NotificationGroupManager groupManager) {
+ if (mEntryManager != null) {
+ throw new IllegalStateException("Already bound.");
+ }
+
+ // TODO(b/119637830): It would be good if GroupManager already had all pending notifications
+ // as normal children (i.e. add notifications to GroupManager before inflation) so that we
+ // don't have to have this dependency. We'd also have to worry less about the suppression
+ // not being up to date.
+ mEntryManager = entryManager;
+
+ mEntryManager.setAlertTransferListener(mAlertTransferListener);
+ groupManager.addOnGroupChangeListener(mOnGroupChangeListener);
+ }
+
/**
* Whether or not a notification has transferred its alert state to the notification and
* the notification should alert after inflating.
@@ -97,25 +106,10 @@
return alertInfo != null && alertInfo.isStillValid();
}
- /**
- * Removes any alerts pending on this entry. Note that this will not stop any inflation tasks
- * started by a transfer, so this should only be used as clean-up for when inflation is stopped
- * and the pending alert no longer needs to happen.
- *
- * @param key notification key that may have info that needs to be cleaned up
- */
- public void cleanUpPendingAlertInfo(@NonNull String key) {
- mPendingAlerts.remove(key);
- }
-
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
mHeadsUpManager = headsUpManager;
}
- public void setPendingEntries(HashMap<String, Entry> pendingNotifications) {
- mPendingNotifications = pendingNotifications;
- }
-
@Override
public void onStateChanged(int newState) {}
@@ -130,43 +124,45 @@
mIsDozing = isDozing;
}
- @Override
- public void onGroupCreated(NotificationGroup group, String groupKey) {
- mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group));
- }
+ private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() {
+ @Override
+ public void onGroupCreated(NotificationGroup group, String groupKey) {
+ mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group));
+ }
- @Override
- public void onGroupRemoved(NotificationGroup group, String groupKey) {
- mGroupAlertEntries.remove(groupKey);
- }
+ @Override
+ public void onGroupRemoved(NotificationGroup group, String groupKey) {
+ mGroupAlertEntries.remove(groupKey);
+ }
- @Override
- public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {
- AlertingNotificationManager alertManager = getActiveAlertManager();
- if (suppressed) {
- if (alertManager.isAlerting(group.summary.key)) {
- handleSuppressedSummaryAlerted(group.summary, alertManager);
- }
- } else {
- // Group summary can be null if we are no longer suppressed because the summary was
- // removed. In that case, we don't need to alert the summary.
- if (group.summary == null) {
- return;
- }
- GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey(
- group.summary.notification));
- // Group is no longer suppressed. We should check if we need to transfer the alert
- // back to the summary now that it's no longer suppressed.
- if (groupAlertEntry.mAlertSummaryOnNextAddition) {
- if (!alertManager.isAlerting(group.summary.key)) {
- alertNotificationWhenPossible(group.summary, alertManager);
+ @Override
+ public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {
+ AlertingNotificationManager alertManager = getActiveAlertManager();
+ if (suppressed) {
+ if (alertManager.isAlerting(group.summary.key)) {
+ handleSuppressedSummaryAlerted(group.summary, alertManager);
}
- groupAlertEntry.mAlertSummaryOnNextAddition = false;
} else {
- checkShouldTransferBack(groupAlertEntry);
+ // Group summary can be null if we are no longer suppressed because the summary was
+ // removed. In that case, we don't need to alert the summary.
+ if (group.summary == null) {
+ return;
+ }
+ GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey(
+ group.summary.notification));
+ // Group is no longer suppressed. We should check if we need to transfer the alert
+ // back to the summary now that it's no longer suppressed.
+ if (groupAlertEntry.mAlertSummaryOnNextAddition) {
+ if (!alertManager.isAlerting(group.summary.key)) {
+ alertNotificationWhenPossible(group.summary, alertManager);
+ }
+ groupAlertEntry.mAlertSummaryOnNextAddition = false;
+ } else {
+ checkShouldTransferBack(groupAlertEntry);
+ }
}
}
- }
+ };
@Override
public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
@@ -185,37 +181,42 @@
}
}
- /**
- * Called when the entry's reinflation has finished. If there is an alert pending, we then
- * show the alert.
- *
- * @param entry entry whose inflation has finished
- */
- public void onInflationFinished(@NonNull Entry entry) {
- PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
- if (alertInfo != null) {
- if (alertInfo.isStillValid()) {
- alertNotificationWhenPossible(entry, getActiveAlertManager());
- } else {
- // The transfer is no longer valid. Free the content.
- entry.getRow().freeContentViewWhenSafe(alertInfo.mAlertManager.getContentFlag());
+ private final AlertTransferListener mAlertTransferListener = new AlertTransferListener() {
+ // Called when a new notification has been posted but is not inflated yet. We use this to
+ // see as early as we can if we need to abort a transfer.
+ @Override
+ public void onPendingEntryAdded(Entry entry) {
+ String groupKey = mGroupManager.getGroupKey(entry.notification);
+ GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
+ if (groupAlertEntry != null) {
+ checkShouldTransferBack(groupAlertEntry);
}
}
- }
- /**
- * Called when a new notification has been posted but is not inflated yet. We use this to see
- * as early as we can if we need to abort a transfer.
- *
- * @param entry entry that has been added
- */
- public void onPendingEntryAdded(@NonNull Entry entry) {
- String groupKey = mGroupManager.getGroupKey(entry.notification);
- GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
- if (groupAlertEntry != null) {
- checkShouldTransferBack(groupAlertEntry);
+ // Called when the entry's reinflation has finished. If there is an alert pending, we
+ // then show the alert.
+ @Override
+ public void onEntryReinflated(Entry entry) {
+ PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
+ if (alertInfo != null) {
+ if (alertInfo.isStillValid()) {
+ alertNotificationWhenPossible(entry, getActiveAlertManager());
+ } else {
+ // The transfer is no longer valid. Free the content.
+ entry.getRow().freeContentViewWhenSafe(
+ alertInfo.mAlertManager.getContentFlag());
+ }
+ }
}
- }
+
+ @Override
+ public void onEntryRemoved(Entry entry) {
+ // Removes any alerts pending on this entry. Note that this will not stop any inflation
+ // tasks started by a transfer, so this should only be used as clean-up for when
+ // inflation is stopped and the pending alert no longer needs to happen.
+ mPendingAlerts.remove(entry.key);
+ }
+ };
/**
* Gets the number of new notifications pending inflation that will be added to the group
@@ -225,11 +226,11 @@
* @return the number of new notifications that will be added to the group
*/
private int getPendingChildrenNotAlerting(@NonNull NotificationGroup group) {
- if (mPendingNotifications == null) {
+ if (mEntryManager == null) {
return 0;
}
int number = 0;
- Collection<Entry> values = mPendingNotifications.values();
+ Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
for (Entry entry : values) {
if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) {
number++;
@@ -245,10 +246,10 @@
* @return true if a pending notification will add to this group
*/
private boolean pendingInflationsWillAddChildren(@NonNull NotificationGroup group) {
- if (mPendingNotifications == null) {
+ if (mEntryManager == null) {
return false;
}
- Collection<Entry> values = mPendingNotifications.values();
+ Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
for (Entry entry : values) {
if (isPendingNotificationInGroup(entry, group)) {
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1d6a1e8..a508f1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -628,6 +628,8 @@
mBubbleController = Dependency.get(BubbleController.class);
mBubbleController.setExpandListener(mBubbleExpandListener);
+ mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
+
mColorExtractor.addOnColorsChangedListener(this);
mStatusBarStateController.addCallback(this, StatusBarStateController.RANK_STATUS_BAR);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index c3bc511..ee39e10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -32,14 +32,19 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.statusbar.notification.AlertTransferListener;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -49,13 +54,15 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
- @Rule
- public MockitoRule rule = MockitoJUnit.rule();
+ @Rule public MockitoRule rule = MockitoJUnit.rule();
private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper;
private NotificationGroupManager mGroupManager;
private AmbientPulseManager mAmbientPulseManager;
private HeadsUpManager mHeadsUpManager;
+ @Mock private NotificationEntryManager mNotificationEntryManager;
+ @Captor private ArgumentCaptor<AlertTransferListener> mListenerCaptor;
+ private AlertTransferListener mAlertTransferListener;
private final HashMap<String, Entry> mPendingEntries = new HashMap<>();
private final NotificationGroupTestHelper mGroupTestHelper =
new NotificationGroupTestHelper(mContext);
@@ -67,15 +74,19 @@
mDependency.injectTestDependency(AmbientPulseManager.class, mAmbientPulseManager);
mHeadsUpManager = new HeadsUpManager(mContext) {};
+ when(mNotificationEntryManager.getPendingNotificationsIterator())
+ .thenReturn(mPendingEntries.values());
+
mGroupManager = new NotificationGroupManager();
mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
mGroupManager.setHeadsUpManager(mHeadsUpManager);
mGroupAlertTransferHelper = new NotificationGroupAlertTransferHelper();
mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
- mGroupAlertTransferHelper.setPendingEntries(mPendingEntries);
- mGroupManager.addOnGroupChangeListener(mGroupAlertTransferHelper);
+ mGroupAlertTransferHelper.bind(mNotificationEntryManager, mGroupManager);
+ verify(mNotificationEntryManager).setAlertTransferListener(mListenerCaptor.capture());
+ mAlertTransferListener = mListenerCaptor.getValue();
mHeadsUpManager.addListener(mGroupAlertTransferHelper);
mAmbientPulseManager.addListener(mGroupAlertTransferHelper);
}
@@ -110,7 +121,7 @@
// Add second child notification so that summary is no longer suppressed.
mPendingEntries.put(childEntry2.key, childEntry2);
- mGroupAlertTransferHelper.onPendingEntryAdded(childEntry2);
+ mAlertTransferListener.onPendingEntryAdded(childEntry2);
mGroupManager.onEntryAdded(childEntry2);
// The alert state should transfer back to the summary as there is now more than one
@@ -137,7 +148,7 @@
// Add second child notification so that summary is no longer suppressed.
mPendingEntries.put(childEntry2.key, childEntry2);
- mGroupAlertTransferHelper.onPendingEntryAdded(childEntry2);
+ mAlertTransferListener.onPendingEntryAdded(childEntry2);
mGroupManager.onEntryAdded(childEntry2);
// Dozing changed so no reason to re-alert summary.
@@ -175,7 +186,7 @@
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(true);
- mGroupAlertTransferHelper.onInflationFinished(childEntry);
+ mAlertTransferListener.onEntryReinflated(childEntry);
// Alert is immediately removed from summary, and we show child as its content is inflated.
assertFalse(mHeadsUpManager.isAlerting(summaryEntry.key));
@@ -199,13 +210,13 @@
// Add second child notification so that summary is no longer suppressed.
mPendingEntries.put(childEntry2.key, childEntry2);
- mGroupAlertTransferHelper.onPendingEntryAdded(childEntry2);
+ mAlertTransferListener.onPendingEntryAdded(childEntry2);
mGroupManager.onEntryAdded(childEntry2);
// Child entry finishes its inflation.
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(true);
- mGroupAlertTransferHelper.onInflationFinished(childEntry);
+ mAlertTransferListener.onEntryReinflated(childEntry);
verify(childEntry.getRow(), times(1)).freeContentViewWhenSafe(mHeadsUpManager
.getContentFlag());
@@ -225,7 +236,7 @@
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
- mGroupAlertTransferHelper.cleanUpPendingAlertInfo(childEntry.key);
+ mAlertTransferListener.onEntryRemoved(childEntry);
assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
}