blob: 4d69f77e744df52cc82c700b0d2a2c07325408d9 [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;
Kevin01a53cb2018-11-09 18:19:54 -080031import com.android.systemui.statusbar.InflationTask;
Gus Prevasd65c2db2018-12-18 17:13:38 -050032import com.android.systemui.statusbar.notification.NotificationEntryListener;
Ned Burns3d6b3962018-12-07 21:26:00 -050033import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050034import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Ned Burns1a5e22f2019-02-14 15:11:52 -050035import com.android.systemui.statusbar.notification.row.NotificationContentInflater.AsyncInflationTask;
36import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
Kevin01a53cb2018-11-09 18:19:54 -080037import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
38import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
39import com.android.systemui.statusbar.policy.HeadsUpManager;
40import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
41
42import java.util.ArrayList;
Kevin01a53cb2018-11-09 18:19:54 -080043import java.util.Objects;
44
Jason Monk27d01a622018-12-10 15:57:09 -050045import javax.inject.Inject;
46import javax.inject.Singleton;
47
Kevin01a53cb2018-11-09 18:19:54 -080048/**
Selim Cinekc3fec682019-06-06 18:11:07 -070049 * A helper class dealing with the alert interactions between {@link NotificationGroupManager} and
50 * {@link HeadsUpManager}. In particular, this class deals with keeping
Kevin01a53cb2018-11-09 18:19:54 -080051 * the correct notification in a group alerting based off the group suppression.
52 */
Jason Monk27d01a622018-12-10 15:57:09 -050053@Singleton
Ned Burns3d6b3962018-12-07 21:26:00 -050054public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,
Selim Cinekc3fec682019-06-06 18:11:07 -070055 StateListener {
Kevin01a53cb2018-11-09 18:19:54 -080056
57 private static final long ALERT_TRANSFER_TIMEOUT = 300;
58
59 /**
60 * The list of entries containing group alert metadata for each group. Keyed by group key.
61 */
62 private final ArrayMap<String, GroupAlertEntry> mGroupAlertEntries = new ArrayMap<>();
63
64 /**
65 * The list of entries currently inflating that should alert after inflation. Keyed by
66 * notification key.
67 */
68 private final ArrayMap<String, PendingAlertInfo> mPendingAlerts = new ArrayMap<>();
69
70 private HeadsUpManager mHeadsUpManager;
Kevin01a53cb2018-11-09 18:19:54 -080071 private final NotificationGroupManager mGroupManager =
72 Dependency.get(NotificationGroupManager.class);
73
Ned Burns3d6b3962018-12-07 21:26:00 -050074 private NotificationEntryManager mEntryManager;
Kevin01a53cb2018-11-09 18:19:54 -080075
76 private boolean mIsDozing;
77
Jason Monk27d01a622018-12-10 15:57:09 -050078 @Inject
Kevin01a53cb2018-11-09 18:19:54 -080079 public NotificationGroupAlertTransferHelper() {
Jason Monkaf08c152018-12-04 11:12:39 -050080 Dependency.get(StatusBarStateController.class).addCallback(this);
Kevin01a53cb2018-11-09 18:19:54 -080081 }
82
Ned Burns3d6b3962018-12-07 21:26:00 -050083 /** Causes the TransferHelper to register itself as a listener to the appropriate classes. */
84 public void bind(NotificationEntryManager entryManager,
85 NotificationGroupManager groupManager) {
86 if (mEntryManager != null) {
87 throw new IllegalStateException("Already bound.");
88 }
89
90 // TODO(b/119637830): It would be good if GroupManager already had all pending notifications
91 // as normal children (i.e. add notifications to GroupManager before inflation) so that we
92 // don't have to have this dependency. We'd also have to worry less about the suppression
93 // not being up to date.
94 mEntryManager = entryManager;
95
Gus Prevasd65c2db2018-12-18 17:13:38 -050096 mEntryManager.addNotificationEntryListener(mNotificationEntryListener);
Ned Burns3d6b3962018-12-07 21:26:00 -050097 groupManager.addOnGroupChangeListener(mOnGroupChangeListener);
98 }
99
Kevin4b8bbda2018-11-19 14:36:31 -0800100 /**
101 * Whether or not a notification has transferred its alert state to the notification and
102 * the notification should alert after inflating.
103 *
104 * @param entry notification to check
105 * @return true if the entry was transferred to and should inflate + alert
106 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500107 public boolean isAlertTransferPending(@NonNull NotificationEntry entry) {
Kevin4b8bbda2018-11-19 14:36:31 -0800108 PendingAlertInfo alertInfo = mPendingAlerts.get(entry.key);
109 return alertInfo != null && alertInfo.isStillValid();
110 }
111
Kevin01a53cb2018-11-09 18:19:54 -0800112 public void setHeadsUpManager(HeadsUpManager headsUpManager) {
113 mHeadsUpManager = headsUpManager;
114 }
115
Kevin01a53cb2018-11-09 18:19:54 -0800116 @Override
117 public void onStateChanged(int newState) {}
118
119 @Override
120 public void onDozingChanged(boolean isDozing) {
121 if (mIsDozing != isDozing) {
122 for (GroupAlertEntry groupAlertEntry : mGroupAlertEntries.values()) {
123 groupAlertEntry.mLastAlertTransferTime = 0;
124 groupAlertEntry.mAlertSummaryOnNextAddition = false;
125 }
126 }
127 mIsDozing = isDozing;
128 }
129
Ned Burns3d6b3962018-12-07 21:26:00 -0500130 private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() {
131 @Override
132 public void onGroupCreated(NotificationGroup group, String groupKey) {
133 mGroupAlertEntries.put(groupKey, new GroupAlertEntry(group));
134 }
Kevin01a53cb2018-11-09 18:19:54 -0800135
Ned Burns3d6b3962018-12-07 21:26:00 -0500136 @Override
137 public void onGroupRemoved(NotificationGroup group, String groupKey) {
138 mGroupAlertEntries.remove(groupKey);
139 }
Kevin01a53cb2018-11-09 18:19:54 -0800140
Ned Burns3d6b3962018-12-07 21:26:00 -0500141 @Override
142 public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500143 if (suppressed) {
Selim Cinekc3fec682019-06-06 18:11:07 -0700144 if (mHeadsUpManager.isAlerting(group.summary.key)) {
145 handleSuppressedSummaryAlerted(group.summary, mHeadsUpManager);
Kevin01a53cb2018-11-09 18:19:54 -0800146 }
Kevin01a53cb2018-11-09 18:19:54 -0800147 } else {
Ned Burns3d6b3962018-12-07 21:26:00 -0500148 // Group summary can be null if we are no longer suppressed because the summary was
149 // removed. In that case, we don't need to alert the summary.
150 if (group.summary == null) {
151 return;
152 }
153 GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey(
154 group.summary.notification));
155 // Group is no longer suppressed. We should check if we need to transfer the alert
156 // back to the summary now that it's no longer suppressed.
157 if (groupAlertEntry.mAlertSummaryOnNextAddition) {
Selim Cinekc3fec682019-06-06 18:11:07 -0700158 if (!mHeadsUpManager.isAlerting(group.summary.key)) {
159 alertNotificationWhenPossible(group.summary, mHeadsUpManager);
Ned Burns3d6b3962018-12-07 21:26:00 -0500160 }
161 groupAlertEntry.mAlertSummaryOnNextAddition = false;
162 } else {
163 checkShouldTransferBack(groupAlertEntry);
164 }
Kevin01a53cb2018-11-09 18:19:54 -0800165 }
166 }
Ned Burns3d6b3962018-12-07 21:26:00 -0500167 };
Kevin01a53cb2018-11-09 18:19:54 -0800168
169 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500170 public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
Kevin01a53cb2018-11-09 18:19:54 -0800171 onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);
172 }
173
Ned Burnsf81c4c42019-01-07 14:10:43 -0500174 private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting,
Kevin01a53cb2018-11-09 18:19:54 -0800175 AlertingNotificationManager alertManager) {
176 if (isAlerting && mGroupManager.isSummaryOfSuppressedGroup(entry.notification)) {
177 handleSuppressedSummaryAlerted(entry, alertManager);
178 }
179 }
180
Gus Prevasd65c2db2018-12-18 17:13:38 -0500181 private final NotificationEntryListener mNotificationEntryListener =
182 new NotificationEntryListener() {
Ned Burns3d6b3962018-12-07 21:26:00 -0500183 // Called when a new notification has been posted but is not inflated yet. We use this to
184 // see as early as we can if we need to abort a transfer.
185 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500186 public void onPendingEntryAdded(NotificationEntry entry) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500187 String groupKey = mGroupManager.getGroupKey(entry.notification);
188 GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
189 if (groupAlertEntry != null) {
190 checkShouldTransferBack(groupAlertEntry);
Kevin01a53cb2018-11-09 18:19:54 -0800191 }
192 }
Kevin01a53cb2018-11-09 18:19:54 -0800193
Ned Burns3d6b3962018-12-07 21:26:00 -0500194 // Called when the entry's reinflation has finished. If there is an alert pending, we
195 // then show the alert.
196 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500197 public void onEntryReinflated(NotificationEntry entry) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500198 PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
199 if (alertInfo != null) {
200 if (alertInfo.isStillValid()) {
Selim Cinekc3fec682019-06-06 18:11:07 -0700201 alertNotificationWhenPossible(entry, mHeadsUpManager);
Ned Burns3d6b3962018-12-07 21:26:00 -0500202 } else {
203 // The transfer is no longer valid. Free the content.
Selim Cinekc3fec682019-06-06 18:11:07 -0700204 entry.getRow().freeContentViewWhenSafe(mHeadsUpManager.getContentFlag());
Ned Burns3d6b3962018-12-07 21:26:00 -0500205 }
206 }
Kevin01a53cb2018-11-09 18:19:54 -0800207 }
Ned Burns3d6b3962018-12-07 21:26:00 -0500208
209 @Override
Gus Prevasf37435a2018-12-20 15:40:01 -0500210 public void onEntryRemoved(
Ned Burnsf81c4c42019-01-07 14:10:43 -0500211 @Nullable NotificationEntry entry,
Gus Prevasca1b6f72018-12-28 10:53:11 -0500212 NotificationVisibility visibility,
Gus Prevasdca2be52018-12-21 11:25:10 -0500213 boolean removedByUser) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500214 // Removes any alerts pending on this entry. Note that this will not stop any inflation
215 // tasks started by a transfer, so this should only be used as clean-up for when
216 // inflation is stopped and the pending alert no longer needs to happen.
Ned Burnsef2ef6c2019-01-02 16:48:08 -0500217 mPendingAlerts.remove(entry.key);
Ned Burns3d6b3962018-12-07 21:26:00 -0500218 }
219 };
Kevin01a53cb2018-11-09 18:19:54 -0800220
221 /**
222 * Gets the number of new notifications pending inflation that will be added to the group
223 * but currently aren't and should not alert.
224 *
225 * @param group group to check
226 * @return the number of new notifications that will be added to the group
227 */
228 private int getPendingChildrenNotAlerting(@NonNull NotificationGroup group) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500229 if (mEntryManager == null) {
Kevin01a53cb2018-11-09 18:19:54 -0800230 return 0;
231 }
232 int number = 0;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500233 Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
234 for (NotificationEntry entry : values) {
Kevin01a53cb2018-11-09 18:19:54 -0800235 if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) {
236 number++;
237 }
238 }
239 return number;
240 }
241
242 /**
243 * Checks if the pending inflations will add children to this group.
244 *
245 * @param group group to check
246 * @return true if a pending notification will add to this group
247 */
248 private boolean pendingInflationsWillAddChildren(@NonNull NotificationGroup group) {
Ned Burns3d6b3962018-12-07 21:26:00 -0500249 if (mEntryManager == null) {
Kevin01a53cb2018-11-09 18:19:54 -0800250 return false;
251 }
Ned Burnsf81c4c42019-01-07 14:10:43 -0500252 Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
253 for (NotificationEntry entry : values) {
Kevin01a53cb2018-11-09 18:19:54 -0800254 if (isPendingNotificationInGroup(entry, group)) {
255 return true;
256 }
257 }
258 return false;
259 }
260
261 /**
262 * Checks if a new pending notification will be added to the group.
263 *
264 * @param entry pending notification
265 * @param group group to check
266 * @return true if the notification will add to the group, false o/w
267 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500268 private boolean isPendingNotificationInGroup(@NonNull NotificationEntry entry,
Kevin01a53cb2018-11-09 18:19:54 -0800269 @NonNull NotificationGroup group) {
270 String groupKey = mGroupManager.getGroupKey(group.summary.notification);
271 return mGroupManager.isGroupChild(entry.notification)
272 && Objects.equals(mGroupManager.getGroupKey(entry.notification), groupKey)
273 && !group.children.containsKey(entry.key);
274 }
275
276 /**
277 * Handles the scenario where a summary that has been suppressed is alerted. A suppressed
278 * summary should for all intents and purposes be invisible to the user and as a result should
279 * not alert. When this is the case, it is our responsibility to pass the alert to the
280 * appropriate child which will be the representative notification alerting for the group.
281 *
282 * @param summary the summary that is suppressed and alerting
283 * @param alertManager the alert manager that manages the alerting summary
284 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500285 private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary,
Kevin01a53cb2018-11-09 18:19:54 -0800286 @NonNull AlertingNotificationManager alertManager) {
287 StatusBarNotification sbn = summary.notification;
288 GroupAlertEntry groupAlertEntry =
289 mGroupAlertEntries.get(mGroupManager.getGroupKey(sbn));
290 if (!mGroupManager.isSummaryOfSuppressedGroup(summary.notification)
291 || !alertManager.isAlerting(sbn.getKey())
292 || groupAlertEntry == null) {
293 return;
294 }
295
296 if (pendingInflationsWillAddChildren(groupAlertEntry.mGroup)) {
297 // New children will actually be added to this group, let's not transfer the alert.
298 return;
299 }
300
Ned Burnsf81c4c42019-01-07 14:10:43 -0500301 NotificationEntry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next();
Kevin01a53cb2018-11-09 18:19:54 -0800302 if (child != null) {
Evan Laird94492852018-10-25 13:43:01 -0400303 if (child.getRow().keepInParent()
304 || child.isRowRemoved()
305 || child.isRowDismissed()) {
Kevin01a53cb2018-11-09 18:19:54 -0800306 // The notification is actually already removed. No need to alert it.
307 return;
308 }
309 if (!alertManager.isAlerting(child.key) && onlySummaryAlerts(summary)) {
310 groupAlertEntry.mLastAlertTransferTime = SystemClock.elapsedRealtime();
311 }
312 transferAlertState(summary, child, alertManager);
313 }
314 }
315
316 /**
317 * Transfers the alert state one entry to another. We remove the alert from the first entry
318 * immediately to have the incorrect one up as short as possible. The second should alert
319 * when possible.
320 *
321 * @param fromEntry entry to transfer alert from
322 * @param toEntry entry to transfer to
323 * @param alertManager alert manager for the alert type
324 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500325 private void transferAlertState(@NonNull NotificationEntry fromEntry, @NonNull NotificationEntry toEntry,
Kevin01a53cb2018-11-09 18:19:54 -0800326 @NonNull AlertingNotificationManager alertManager) {
327 alertManager.removeNotification(fromEntry.key, true /* releaseImmediately */);
328 alertNotificationWhenPossible(toEntry, alertManager);
329 }
330
331 /**
332 * Determines if we need to transfer the alert back to the summary from the child and does
333 * so if needed.
334 *
335 * This can happen since notification groups are not delivered as a whole unit and it is
336 * possible we erroneously transfer the alert from the summary to the child even though
337 * more children are coming. Thus, if a child is added within a certain timeframe after we
338 * transfer, we back out and alert the summary again.
339 *
340 * @param groupAlertEntry group alert entry to check
341 */
342 private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) {
343 if (SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime
344 < ALERT_TRANSFER_TIMEOUT) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500345 NotificationEntry summary = groupAlertEntry.mGroup.summary;
Kevin01a53cb2018-11-09 18:19:54 -0800346
347 if (!onlySummaryAlerts(summary)) {
348 return;
349 }
Ned Burnsf81c4c42019-01-07 14:10:43 -0500350 ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.notification);
Kevin01a53cb2018-11-09 18:19:54 -0800351 int numChildren = children.size();
352 int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup);
353 numChildren += numPendingChildren;
354 if (numChildren <= 1) {
355 return;
356 }
357 boolean releasedChild = false;
358 for (int i = 0; i < children.size(); i++) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500359 NotificationEntry entry = children.get(i);
Selim Cinekc3fec682019-06-06 18:11:07 -0700360 if (onlySummaryAlerts(entry) && mHeadsUpManager.isAlerting(entry.key)) {
Kevin01a53cb2018-11-09 18:19:54 -0800361 releasedChild = true;
Selim Cinekc3fec682019-06-06 18:11:07 -0700362 mHeadsUpManager.removeNotification(entry.key, true /* releaseImmediately */);
Kevin01a53cb2018-11-09 18:19:54 -0800363 }
364 if (mPendingAlerts.containsKey(entry.key)) {
365 // This is the child that would've been removed if it was inflated.
366 releasedChild = true;
367 mPendingAlerts.get(entry.key).mAbortOnInflation = true;
368 }
369 }
Selim Cinekc3fec682019-06-06 18:11:07 -0700370 if (releasedChild && !mHeadsUpManager.isAlerting(summary.key)) {
Kevin01a53cb2018-11-09 18:19:54 -0800371 boolean notifyImmediately = (numChildren - numPendingChildren) > 1;
372 if (notifyImmediately) {
Selim Cinekc3fec682019-06-06 18:11:07 -0700373 alertNotificationWhenPossible(summary, mHeadsUpManager);
Kevin01a53cb2018-11-09 18:19:54 -0800374 } else {
375 // Should wait until the pending child inflates before alerting.
376 groupAlertEntry.mAlertSummaryOnNextAddition = true;
377 }
378 groupAlertEntry.mLastAlertTransferTime = 0;
379 }
380 }
381 }
382
383 /**
384 * Tries to alert the notification. If its content view is not inflated, we inflate and continue
385 * when the entry finishes inflating the view.
386 *
387 * @param entry entry to show
388 * @param alertManager alert manager for the alert type
389 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500390 private void alertNotificationWhenPossible(@NonNull NotificationEntry entry,
Kevin01a53cb2018-11-09 18:19:54 -0800391 @NonNull AlertingNotificationManager alertManager) {
392 @InflationFlag int contentFlag = alertManager.getContentFlag();
Evan Laird94492852018-10-25 13:43:01 -0400393 if (!entry.getRow().isInflationFlagSet(contentFlag)) {
Selim Cinekc3fec682019-06-06 18:11:07 -0700394 mPendingAlerts.put(entry.key, new PendingAlertInfo(entry));
Evan Laird94492852018-10-25 13:43:01 -0400395 entry.getRow().updateInflationFlag(contentFlag, true /* shouldInflate */);
396 entry.getRow().inflateViews();
Kevin01a53cb2018-11-09 18:19:54 -0800397 return;
398 }
399 if (alertManager.isAlerting(entry.key)) {
400 alertManager.updateNotification(entry.key, true /* alert */);
401 } else {
402 alertManager.showNotification(entry);
403 }
404 }
405
Ned Burnsf81c4c42019-01-07 14:10:43 -0500406 private boolean onlySummaryAlerts(NotificationEntry entry) {
Kevin01a53cb2018-11-09 18:19:54 -0800407 return entry.notification.getNotification().getGroupAlertBehavior()
408 == Notification.GROUP_ALERT_SUMMARY;
409 }
410
411 /**
412 * Information about a pending alert used to determine if the alert is still needed when
413 * inflation completes.
414 */
415 private class PendingAlertInfo {
Kevin4b8bbda2018-11-19 14:36:31 -0800416
417 /**
418 * The original notification when the transfer is initiated. This is used to determine if
419 * the transfer is still valid if the notification is updated.
420 */
421 final StatusBarNotification mOriginalNotification;
Ned Burnsf81c4c42019-01-07 14:10:43 -0500422 final NotificationEntry mEntry;
Kevin4b8bbda2018-11-19 14:36:31 -0800423
Kevin01a53cb2018-11-09 18:19:54 -0800424 /**
425 * The notification is still pending inflation but we've decided that we no longer need
426 * the content view (e.g. suppression might have changed and we decided we need to transfer
427 * back). However, there is no way to abort just this inflation if other inflation requests
428 * have started (see {@link AsyncInflationTask#supersedeTask(InflationTask)}). So instead
429 * we just flag it as aborted and free when it's inflated.
430 */
431 boolean mAbortOnInflation;
432
Selim Cinekc3fec682019-06-06 18:11:07 -0700433 PendingAlertInfo(NotificationEntry entry) {
Kevin4b8bbda2018-11-19 14:36:31 -0800434 mOriginalNotification = entry.notification;
435 mEntry = entry;
Kevin01a53cb2018-11-09 18:19:54 -0800436 }
437
438 /**
439 * Whether or not the pending alert is still valid and should still alert after inflation.
440 *
441 * @return true if the pending alert should still occur, false o/w
442 */
443 private boolean isStillValid() {
444 if (mAbortOnInflation) {
445 // Notification is aborted due to the transfer being explicitly cancelled
446 return false;
447 }
Kevin4b8bbda2018-11-19 14:36:31 -0800448 if (mEntry.notification.getGroupKey() != mOriginalNotification.getGroupKey()) {
449 // Groups have changed
450 return false;
451 }
452 if (mEntry.notification.getNotification().isGroupSummary()
453 != mOriginalNotification.getNotification().isGroupSummary()) {
454 // Notification has changed from group summary to not or vice versa
455 return false;
456 }
Kevin01a53cb2018-11-09 18:19:54 -0800457 return true;
458 }
459 }
460
461 /**
462 * Contains alert metadata for the notification group used to determine when/how the alert
463 * should be transferred.
464 */
465 private static class GroupAlertEntry {
466 /**
467 * The time when the last alert transfer from summary to child happened.
468 */
469 long mLastAlertTransferTime;
470 boolean mAlertSummaryOnNextAddition;
471 final NotificationGroup mGroup;
472
473 GroupAlertEntry(NotificationGroup group) {
474 this.mGroup = group;
475 }
476 }
477}