blob: 4dbd8545efb9bc0a9da16325fe0353656eaa9080 [file] [log] [blame]
Kevin01a53cb2018-11-09 18:19:54 -08001/*
2 * Copyright (C) 2018 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.annotation.NonNull;
Ned Burns1dd6b402019-01-02 15:25:23 -050020import android.annotation.Nullable;
Kevin01a53cb2018-11-09 18:19:54 -080021import android.app.Notification;
22import android.os.SystemClock;
23import android.service.notification.StatusBarNotification;
24import android.util.ArrayMap;
25
Gus Prevasca1b6f72018-12-28 10:53:11 -050026import com.android.internal.statusbar.NotificationVisibility;
Kevin01a53cb2018-11-09 18:19:54 -080027import com.android.systemui.Dependency;
Beverly8fdb5332019-02-04 14:29:49 -050028import com.android.systemui.plugins.statusbar.StatusBarStateController;
29import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
Kevin01a53cb2018-11-09 18:19:54 -080030import com.android.systemui.statusbar.AlertingNotificationManager;
31import com.android.systemui.statusbar.AmbientPulseManager;
32import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener;
33import com.android.systemui.statusbar.InflationTask;
Gus Prevasd65c2db2018-12-18 17:13:38 -050034import com.android.systemui.statusbar.notification.NotificationEntryListener;
Ned Burns3d6b3962018-12-07 21:26:00 -050035import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050036import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Ned Burns1a5e22f2019-02-14 15:11:52 -050037import com.android.systemui.statusbar.notification.row.NotificationContentInflater.AsyncInflationTask;
38import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
Kevin01a53cb2018-11-09 18:19:54 -080039import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
40import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
41import com.android.systemui.statusbar.policy.HeadsUpManager;
42import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
43
44import java.util.ArrayList;
Kevin01a53cb2018-11-09 18:19:54 -080045import java.util.Objects;
46
Jason Monk27d01a622018-12-10 15:57:09 -050047import javax.inject.Inject;
48import javax.inject.Singleton;
49
Kevin01a53cb2018-11-09 18:19:54 -080050/**
51 * A helper class dealing with the alert interactions between {@link NotificationGroupManager},
52 * {@link HeadsUpManager}, {@link AmbientPulseManager}. In particular, this class deals with keeping
53 * the correct notification in a group alerting based off the group suppression.
54 */
Jason Monk27d01a622018-12-10 15:57:09 -050055@Singleton
Ned Burns3d6b3962018-12-07 21:26:00 -050056public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,
57 OnAmbientChangedListener, StateListener {
Kevin01a53cb2018-11-09 18:19:54 -080058
59 private static final long ALERT_TRANSFER_TIMEOUT = 300;
60
61 /**
62 * The list of entries containing group alert metadata for each group. Keyed by group key.
63 */
64 private final ArrayMap<String, GroupAlertEntry> mGroupAlertEntries = new ArrayMap<>();
65
66 /**
67 * The list of entries currently inflating that should alert after inflation. Keyed by
68 * notification key.
69 */
70 private final ArrayMap<String, PendingAlertInfo> mPendingAlerts = new ArrayMap<>();
71
72 private HeadsUpManager mHeadsUpManager;
73 private final AmbientPulseManager mAmbientPulseManager =
74 Dependency.get(AmbientPulseManager.class);
75 private final NotificationGroupManager mGroupManager =
76 Dependency.get(NotificationGroupManager.class);
77
Ned Burns3d6b3962018-12-07 21:26:00 -050078 private NotificationEntryManager mEntryManager;
Kevin01a53cb2018-11-09 18:19:54 -080079
80 private boolean mIsDozing;
81
Jason Monk27d01a622018-12-10 15:57:09 -050082 @Inject
Kevin01a53cb2018-11-09 18:19:54 -080083 public NotificationGroupAlertTransferHelper() {
Jason Monkaf08c152018-12-04 11:12:39 -050084 Dependency.get(StatusBarStateController.class).addCallback(this);
Kevin01a53cb2018-11-09 18:19:54 -080085 }
86
Ned Burns3d6b3962018-12-07 21:26:00 -050087 /** Causes the TransferHelper to register itself as a listener to the appropriate classes. */
88 public void bind(NotificationEntryManager entryManager,
89 NotificationGroupManager groupManager) {
90 if (mEntryManager != null) {
91 throw new IllegalStateException("Already bound.");
92 }
93
94 // TODO(b/119637830): It would be good if GroupManager already had all pending notifications
95 // as normal children (i.e. add notifications to GroupManager before inflation) so that we
96 // don't have to have this dependency. We'd also have to worry less about the suppression
97 // not being up to date.
98 mEntryManager = entryManager;
99
Gus Prevasd65c2db2018-12-18 17:13:38 -0500100 mEntryManager.addNotificationEntryListener(mNotificationEntryListener);
Ned Burns3d6b3962018-12-07 21:26:00 -0500101 groupManager.addOnGroupChangeListener(mOnGroupChangeListener);
102 }
103
Kevin4b8bbda2018-11-19 14:36:31 -0800104 /**
105 * Whether or not a notification has transferred its alert state to the notification and
106 * the notification should alert after inflating.
107 *
108 * @param entry notification to check
109 * @return true if the entry was transferred to and should inflate + alert
110 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500111 public boolean isAlertTransferPending(@NonNull NotificationEntry entry) {
Kevin4b8bbda2018-11-19 14:36:31 -0800112 PendingAlertInfo alertInfo = mPendingAlerts.get(entry.key);
113 return alertInfo != null && alertInfo.isStillValid();
114 }
115
Kevin01a53cb2018-11-09 18:19:54 -0800116 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
117 mHeadsUpManager = headsUpManager;
118 }
119
Kevin01a53cb2018-11-09 18:19:54 -0800120 @Override
121 public void onStateChanged(int newState) {}
122
123 @Override
124 public void onDozingChanged(boolean isDozing) {
125 if (mIsDozing != isDozing) {
126 for (GroupAlertEntry groupAlertEntry : mGroupAlertEntries.values()) {
127 groupAlertEntry.mLastAlertTransferTime = 0;
128 groupAlertEntry.mAlertSummaryOnNextAddition = false;
129 }
130 }
131 mIsDozing = isDozing;
132 }
133
Ned Burns3d6b3962018-12-07 21:26:00 -0500134 private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() {
135 @Override
136 public void onGroupCreated(NotificationGroup group, String groupKey) {
137 mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group));
138 }
Kevin01a53cb2018-11-09 18:19:54 -0800139
Ned Burns3d6b3962018-12-07 21:26:00 -0500140 @Override
141 public void onGroupRemoved(NotificationGroup group, String groupKey) {
142 mGroupAlertEntries.remove(groupKey);
143 }
Kevin01a53cb2018-11-09 18:19:54 -0800144
Ned Burns3d6b3962018-12-07 21:26:00 -0500145 @Override
146 public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {
147 AlertingNotificationManager alertManager = getActiveAlertManager();
148 if (suppressed) {
149 if (alertManager.isAlerting(group.summary.key)) {
150 handleSuppressedSummaryAlerted(group.summary, alertManager);
Kevin01a53cb2018-11-09 18:19:54 -0800151 }
Kevin01a53cb2018-11-09 18:19:54 -0800152 } else {
Ned Burns3d6b3962018-12-07 21:26:00 -0500153 // Group summary can be null if we are no longer suppressed because the summary was
154 // removed. In that case, we don't need to alert the summary.
155 if (group.summary == null) {
156 return;
157 }
158 GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey(
159 group.summary.notification));
160 // Group is no longer suppressed. We should check if we need to transfer the alert
161 // back to the summary now that it's no longer suppressed.
162 if (groupAlertEntry.mAlertSummaryOnNextAddition) {
163 if (!alertManager.isAlerting(group.summary.key)) {
164 alertNotificationWhenPossible(group.summary, alertManager);
165 }
166 groupAlertEntry.mAlertSummaryOnNextAddition = false;
167 } else {
168 checkShouldTransferBack(groupAlertEntry);
169 }
Kevin01a53cb2018-11-09 18:19:54 -0800170 }
171 }
Ned Burns3d6b3962018-12-07 21:26:00 -0500172 };
Kevin01a53cb2018-11-09 18:19:54 -0800173
174 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500175 public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
Kevin01a53cb2018-11-09 18:19:54 -0800176 onAlertStateChanged(entry, isAmbient, mAmbientPulseManager);
177 }
178
179 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500180 public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
Kevin01a53cb2018-11-09 18:19:54 -0800181 onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);
182 }
183
Ned Burnsf81c4c42019-01-07 14:10:43 -0500184 private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting,
Kevin01a53cb2018-11-09 18:19:54 -0800185 AlertingNotificationManager alertManager) {
186 if (isAlerting && mGroupManager.isSummaryOfSuppressedGroup(entry.notification)) {
187 handleSuppressedSummaryAlerted(entry, alertManager);
188 }
189 }
190
Gus Prevasd65c2db2018-12-18 17:13:38 -0500191 private final NotificationEntryListener mNotificationEntryListener =
192 new NotificationEntryListener() {
Ned Burns3d6b3962018-12-07 21:26:00 -0500193 // Called when a new notification has been posted but is not inflated yet. We use this to
194 // see as early as we can if we need to abort a transfer.
195 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500196 public void onPendingEntryAdded(NotificationEntry entry) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500197 String groupKey = mGroupManager.getGroupKey(entry.notification);
198 GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
199 if (groupAlertEntry != null) {
200 checkShouldTransferBack(groupAlertEntry);
Kevin01a53cb2018-11-09 18:19:54 -0800201 }
202 }
Kevin01a53cb2018-11-09 18:19:54 -0800203
Ned Burns3d6b3962018-12-07 21:26:00 -0500204 // Called when the entry's reinflation has finished. If there is an alert pending, we
205 // then show the alert.
206 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500207 public void onEntryReinflated(NotificationEntry entry) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500208 PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
209 if (alertInfo != null) {
210 if (alertInfo.isStillValid()) {
211 alertNotificationWhenPossible(entry, getActiveAlertManager());
212 } else {
213 // The transfer is no longer valid. Free the content.
214 entry.getRow().freeContentViewWhenSafe(
215 alertInfo.mAlertManager.getContentFlag());
216 }
217 }
Kevin01a53cb2018-11-09 18:19:54 -0800218 }
Ned Burns3d6b3962018-12-07 21:26:00 -0500219
220 @Override
Gus Prevasf37435a2018-12-20 15:40:01 -0500221 public void onEntryRemoved(
Ned Burnsf81c4c42019-01-07 14:10:43 -0500222 @Nullable NotificationEntry entry,
Gus Prevasca1b6f72018-12-28 10:53:11 -0500223 NotificationVisibility visibility,
Gus Prevasdca2be52018-12-21 11:25:10 -0500224 boolean removedByUser) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500225 // Removes any alerts pending on this entry. Note that this will not stop any inflation
226 // tasks started by a transfer, so this should only be used as clean-up for when
227 // inflation is stopped and the pending alert no longer needs to happen.
Ned Burnsef2ef6c2019-01-02 16:48:08 -0500228 mPendingAlerts.remove(entry.key);
Ned Burns3d6b3962018-12-07 21:26:00 -0500229 }
230 };
Kevin01a53cb2018-11-09 18:19:54 -0800231
232 /**
233 * Gets the number of new notifications pending inflation that will be added to the group
234 * but currently aren't and should not alert.
235 *
236 * @param group group to check
237 * @return the number of new notifications that will be added to the group
238 */
239 private int getPendingChildrenNotAlerting(@NonNull NotificationGroup group) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500240 if (mEntryManager == null) {
Kevin01a53cb2018-11-09 18:19:54 -0800241 return 0;
242 }
243 int number = 0;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500244 Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
245 for (NotificationEntry entry : values) {
Kevin01a53cb2018-11-09 18:19:54 -0800246 if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) {
247 number++;
248 }
249 }
250 return number;
251 }
252
253 /**
254 * Checks if the pending inflations will add children to this group.
255 *
256 * @param group group to check
257 * @return true if a pending notification will add to this group
258 */
259 private boolean pendingInflationsWillAddChildren(@NonNull NotificationGroup group) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500260 if (mEntryManager == null) {
Kevin01a53cb2018-11-09 18:19:54 -0800261 return false;
262 }
Ned Burnsf81c4c42019-01-07 14:10:43 -0500263 Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
264 for (NotificationEntry entry : values) {
Kevin01a53cb2018-11-09 18:19:54 -0800265 if (isPendingNotificationInGroup(entry, group)) {
266 return true;
267 }
268 }
269 return false;
270 }
271
272 /**
273 * Checks if a new pending notification will be added to the group.
274 *
275 * @param entry pending notification
276 * @param group group to check
277 * @return true if the notification will add to the group, false o/w
278 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500279 private boolean isPendingNotificationInGroup(@NonNull NotificationEntry entry,
Kevin01a53cb2018-11-09 18:19:54 -0800280 @NonNull NotificationGroup group) {
281 String groupKey = mGroupManager.getGroupKey(group.summary.notification);
282 return mGroupManager.isGroupChild(entry.notification)
283 && Objects.equals(mGroupManager.getGroupKey(entry.notification), groupKey)
284 && !group.children.containsKey(entry.key);
285 }
286
287 /**
288 * Handles the scenario where a summary that has been suppressed is alerted. A suppressed
289 * summary should for all intents and purposes be invisible to the user and as a result should
290 * not alert. When this is the case, it is our responsibility to pass the alert to the
291 * appropriate child which will be the representative notification alerting for the group.
292 *
293 * @param summary the summary that is suppressed and alerting
294 * @param alertManager the alert manager that manages the alerting summary
295 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500296 private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary,
Kevin01a53cb2018-11-09 18:19:54 -0800297 @NonNull AlertingNotificationManager alertManager) {
298 StatusBarNotification sbn = summary.notification;
299 GroupAlertEntry groupAlertEntry =
300 mGroupAlertEntries.get(mGroupManager.getGroupKey(sbn));
301 if (!mGroupManager.isSummaryOfSuppressedGroup(summary.notification)
302 || !alertManager.isAlerting(sbn.getKey())
303 || groupAlertEntry == null) {
304 return;
305 }
306
307 if (pendingInflationsWillAddChildren(groupAlertEntry.mGroup)) {
308 // New children will actually be added to this group, let's not transfer the alert.
309 return;
310 }
311
Ned Burnsf81c4c42019-01-07 14:10:43 -0500312 NotificationEntry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next();
Kevin01a53cb2018-11-09 18:19:54 -0800313 if (child != null) {
Evan Laird94492852018-10-25 13:43:01 -0400314 if (child.getRow().keepInParent()
315 || child.isRowRemoved()
316 || child.isRowDismissed()) {
Kevin01a53cb2018-11-09 18:19:54 -0800317 // The notification is actually already removed. No need to alert it.
318 return;
319 }
320 if (!alertManager.isAlerting(child.key) && onlySummaryAlerts(summary)) {
321 groupAlertEntry.mLastAlertTransferTime = SystemClock.elapsedRealtime();
322 }
323 transferAlertState(summary, child, alertManager);
324 }
325 }
326
327 /**
328 * Transfers the alert state one entry to another. We remove the alert from the first entry
329 * immediately to have the incorrect one up as short as possible. The second should alert
330 * when possible.
331 *
332 * @param fromEntry entry to transfer alert from
333 * @param toEntry entry to transfer to
334 * @param alertManager alert manager for the alert type
335 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500336 private void transferAlertState(@NonNull NotificationEntry fromEntry, @NonNull NotificationEntry toEntry,
Kevin01a53cb2018-11-09 18:19:54 -0800337 @NonNull AlertingNotificationManager alertManager) {
338 alertManager.removeNotification(fromEntry.key, true /* releaseImmediately */);
339 alertNotificationWhenPossible(toEntry, alertManager);
340 }
341
342 /**
343 * Determines if we need to transfer the alert back to the summary from the child and does
344 * so if needed.
345 *
346 * This can happen since notification groups are not delivered as a whole unit and it is
347 * possible we erroneously transfer the alert from the summary to the child even though
348 * more children are coming. Thus, if a child is added within a certain timeframe after we
349 * transfer, we back out and alert the summary again.
350 *
351 * @param groupAlertEntry group alert entry to check
352 */
353 private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) {
354 if (SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime
355 < ALERT_TRANSFER_TIMEOUT) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500356 NotificationEntry summary = groupAlertEntry.mGroup.summary;
Kevin01a53cb2018-11-09 18:19:54 -0800357 AlertingNotificationManager alertManager = getActiveAlertManager();
358
359 if (!onlySummaryAlerts(summary)) {
360 return;
361 }
Ned Burnsf81c4c42019-01-07 14:10:43 -0500362 ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.notification);
Kevin01a53cb2018-11-09 18:19:54 -0800363 int numChildren = children.size();
364 int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup);
365 numChildren += numPendingChildren;
366 if (numChildren <= 1) {
367 return;
368 }
369 boolean releasedChild = false;
370 for (int i = 0; i < children.size(); i++) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500371 NotificationEntry entry = children.get(i);
Kevin01a53cb2018-11-09 18:19:54 -0800372 if (onlySummaryAlerts(entry) && alertManager.isAlerting(entry.key)) {
373 releasedChild = true;
374 alertManager.removeNotification(entry.key, true /* releaseImmediately */);
375 }
376 if (mPendingAlerts.containsKey(entry.key)) {
377 // This is the child that would've been removed if it was inflated.
378 releasedChild = true;
379 mPendingAlerts.get(entry.key).mAbortOnInflation = true;
380 }
381 }
382 if (releasedChild && !alertManager.isAlerting(summary.key)) {
383 boolean notifyImmediately = (numChildren - numPendingChildren) > 1;
384 if (notifyImmediately) {
385 alertNotificationWhenPossible(summary, alertManager);
386 } else {
387 // Should wait until the pending child inflates before alerting.
388 groupAlertEntry.mAlertSummaryOnNextAddition = true;
389 }
390 groupAlertEntry.mLastAlertTransferTime = 0;
391 }
392 }
393 }
394
395 /**
396 * Tries to alert the notification. If its content view is not inflated, we inflate and continue
397 * when the entry finishes inflating the view.
398 *
399 * @param entry entry to show
400 * @param alertManager alert manager for the alert type
401 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500402 private void alertNotificationWhenPossible(@NonNull NotificationEntry entry,
Kevin01a53cb2018-11-09 18:19:54 -0800403 @NonNull AlertingNotificationManager alertManager) {
404 @InflationFlag int contentFlag = alertManager.getContentFlag();
Evan Laird94492852018-10-25 13:43:01 -0400405 if (!entry.getRow().isInflationFlagSet(contentFlag)) {
Kevin4b8bbda2018-11-19 14:36:31 -0800406 mPendingAlerts.put(entry.key, new PendingAlertInfo(entry, alertManager));
Evan Laird94492852018-10-25 13:43:01 -0400407 entry.getRow().updateInflationFlag(contentFlag, true /* shouldInflate */);
408 entry.getRow().inflateViews();
Kevin01a53cb2018-11-09 18:19:54 -0800409 return;
410 }
411 if (alertManager.isAlerting(entry.key)) {
412 alertManager.updateNotification(entry.key, true /* alert */);
413 } else {
414 alertManager.showNotification(entry);
415 }
416 }
417
418 private AlertingNotificationManager getActiveAlertManager() {
419 return mIsDozing ? mAmbientPulseManager : mHeadsUpManager;
420 }
421
Ned Burnsf81c4c42019-01-07 14:10:43 -0500422 private boolean onlySummaryAlerts(NotificationEntry entry) {
Kevin01a53cb2018-11-09 18:19:54 -0800423 return entry.notification.getNotification().getGroupAlertBehavior()
424 == Notification.GROUP_ALERT_SUMMARY;
425 }
426
427 /**
428 * Information about a pending alert used to determine if the alert is still needed when
429 * inflation completes.
430 */
431 private class PendingAlertInfo {
Kevin4b8bbda2018-11-19 14:36:31 -0800432 /**
433 * The alert manager when the transfer is initiated.
434 */
Kevin01a53cb2018-11-09 18:19:54 -0800435 final AlertingNotificationManager mAlertManager;
Kevin4b8bbda2018-11-19 14:36:31 -0800436
437 /**
438 * The original notification when the transfer is initiated. This is used to determine if
439 * the transfer is still valid if the notification is updated.
440 */
441 final StatusBarNotification mOriginalNotification;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500442 final NotificationEntry mEntry;
Kevin4b8bbda2018-11-19 14:36:31 -0800443
Kevin01a53cb2018-11-09 18:19:54 -0800444 /**
445 * The notification is still pending inflation but we've decided that we no longer need
446 * the content view (e.g. suppression might have changed and we decided we need to transfer
447 * back). However, there is no way to abort just this inflation if other inflation requests
448 * have started (see {@link AsyncInflationTask#supersedeTask(InflationTask)}). So instead
449 * we just flag it as aborted and free when it's inflated.
450 */
451 boolean mAbortOnInflation;
452
Ned Burnsf81c4c42019-01-07 14:10:43 -0500453 PendingAlertInfo(NotificationEntry entry, AlertingNotificationManager alertManager) {
Kevin4b8bbda2018-11-19 14:36:31 -0800454 mOriginalNotification = entry.notification;
455 mEntry = entry;
Kevin01a53cb2018-11-09 18:19:54 -0800456 mAlertManager = alertManager;
457 }
458
459 /**
460 * Whether or not the pending alert is still valid and should still alert after inflation.
461 *
462 * @return true if the pending alert should still occur, false o/w
463 */
464 private boolean isStillValid() {
465 if (mAbortOnInflation) {
466 // Notification is aborted due to the transfer being explicitly cancelled
467 return false;
468 }
469 if (mAlertManager != getActiveAlertManager()) {
470 // Alert manager has changed
471 return false;
472 }
Kevin4b8bbda2018-11-19 14:36:31 -0800473 if (mEntry.notification.getGroupKey() != mOriginalNotification.getGroupKey()) {
474 // Groups have changed
475 return false;
476 }
477 if (mEntry.notification.getNotification().isGroupSummary()
478 != mOriginalNotification.getNotification().isGroupSummary()) {
479 // Notification has changed from group summary to not or vice versa
480 return false;
481 }
Kevin01a53cb2018-11-09 18:19:54 -0800482 return true;
483 }
484 }
485
486 /**
487 * Contains alert metadata for the notification group used to determine when/how the alert
488 * should be transferred.
489 */
490 private static class GroupAlertEntry {
491 /**
492 * The time when the last alert transfer from summary to child happened.
493 */
494 long mLastAlertTransferTime;
495 boolean mAlertSummaryOnNextAddition;
496 final NotificationGroup mGroup;
497
498 GroupAlertEntry(NotificationGroup group) {
499 this.mGroup = group;
500 }
501 }
502}