blob: 6e75c0375afc088f7fc3e6c8b787e4953d68a6ef [file] [log] [blame]
Eliot Courtney2b4c3a02017-11-27 13:27:46 +09001/*
2 * Copyright (C) 2017 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;
18
Ned Burnsb3b4bd32019-06-27 19:36:58 -040019import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
20
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090021import android.content.Context;
22import android.content.res.Resources;
Ned Burnsb3b4bd32019-06-27 19:36:58 -040023import android.os.Handler;
Lucas Dupin16013822018-05-17 18:00:16 -070024import android.os.Trace;
Selim Cinek6f0a62a2019-04-09 18:40:12 -070025import android.os.UserHandle;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090026import android.util.Log;
27import android.view.View;
28import android.view.ViewGroup;
29
30import com.android.systemui.R;
Selim Cinekfdf80332019-03-07 17:29:55 -080031import com.android.systemui.bubbles.BubbleData;
Beverly80110912019-02-13 12:20:57 -050032import com.android.systemui.plugins.statusbar.StatusBarStateController;
Selim Cinek6f0a62a2019-04-09 18:40:12 -070033import com.android.systemui.statusbar.notification.DynamicPrivacyController;
Rohan Shah20790b82018-07-02 17:21:04 -070034import com.android.systemui.statusbar.notification.NotificationEntryManager;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090035import com.android.systemui.statusbar.notification.VisualStabilityManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050036import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Rohan Shah20790b82018-07-02 17:21:04 -070037import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
38import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
Selim Cinekb0fada62019-06-17 19:03:59 -070039import com.android.systemui.statusbar.phone.KeyguardBypassController;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090040import com.android.systemui.statusbar.phone.NotificationGroupManager;
Jason Monk297c04e2018-08-23 17:16:59 -040041import com.android.systemui.statusbar.phone.ShadeController;
Ned Burnsd4a69f72019-06-19 19:49:19 -040042import com.android.systemui.util.Assert;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090043
44import java.util.ArrayList;
45import java.util.HashMap;
46import java.util.List;
47import java.util.Stack;
48
Jason Monk27d01a622018-12-10 15:57:09 -050049import javax.inject.Inject;
Ned Burnsb3b4bd32019-06-27 19:36:58 -040050import javax.inject.Named;
Jason Monk27d01a622018-12-10 15:57:09 -050051import javax.inject.Singleton;
52
Jason Monk09f4d372018-12-20 15:30:54 -050053import dagger.Lazy;
54
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090055/**
56 * NotificationViewHierarchyManager manages updating the view hierarchy of notification views based
57 * on their group structure. For example, if a notification becomes bundled with another,
58 * NotificationViewHierarchyManager will update the view hierarchy to reflect that. It also will
59 * tell NotificationListContainer which notifications to display, and inform it of changes to those
60 * notifications that might affect their display.
61 */
Jason Monk27d01a622018-12-10 15:57:09 -050062@Singleton
Selim Cinek6f0a62a2019-04-09 18:40:12 -070063public class NotificationViewHierarchyManager implements DynamicPrivacyController.Listener {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090064 private static final String TAG = "NotificationViewHierarchyManager";
65
Ned Burnsb3b4bd32019-06-27 19:36:58 -040066 private final Handler mHandler;
67
Evan Laird94492852018-10-25 13:43:01 -040068 //TODO: change this top <Entry, List<Entry>>?
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090069 private final HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>>
70 mTmpChildOrderMap = new HashMap<>();
Eliot Courtney6c313d32017-12-14 19:57:51 +090071
72 // Dependencies:
Jason Monk09f4d372018-12-20 15:30:54 -050073 protected final NotificationLockscreenUserManager mLockscreenUserManager;
74 protected final NotificationGroupManager mGroupManager;
75 protected final VisualStabilityManager mVisualStabilityManager;
Beverly80110912019-02-13 12:20:57 -050076 private final SysuiStatusBarStateController mStatusBarStateController;
Jason Monk09f4d372018-12-20 15:30:54 -050077 private final NotificationEntryManager mEntryManager;
Jason Monk297c04e2018-08-23 17:16:59 -040078
79 // Lazy
Jason Monk09f4d372018-12-20 15:30:54 -050080 private final Lazy<ShadeController> mShadeController;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090081
82 /**
83 * {@code true} if notifications not part of a group should by default be rendered in their
84 * expanded state. If {@code false}, then only the first notification will be expanded if
85 * possible.
86 */
87 private final boolean mAlwaysExpandNonGroupedNotification;
Selim Cinekfdf80332019-03-07 17:29:55 -080088 private final BubbleData mBubbleData;
Selim Cinek6f0a62a2019-04-09 18:40:12 -070089 private final DynamicPrivacyController mDynamicPrivacyController;
Selim Cinekb0fada62019-06-17 19:03:59 -070090 private final KeyguardBypassController mBypassController;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090091
92 private NotificationPresenter mPresenter;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090093 private NotificationListContainer mListContainer;
94
Ned Burnsd4a69f72019-06-19 19:49:19 -040095 // Used to help track down re-entrant calls to our update methods, which will cause bugs.
96 private boolean mPerformingUpdate;
Ned Burnsb3b4bd32019-06-27 19:36:58 -040097 // Hack to get around re-entrant call in onDynamicPrivacyChanged() until we can track down
98 // the problem.
99 private boolean mIsHandleDynamicPrivacyChangeScheduled;
Ned Burnsd4a69f72019-06-19 19:49:19 -0400100
Jason Monk27d01a622018-12-10 15:57:09 -0500101 @Inject
Jason Monk09f4d372018-12-20 15:30:54 -0500102 public NotificationViewHierarchyManager(Context context,
Ned Burnsb3b4bd32019-06-27 19:36:58 -0400103 @Named(MAIN_HANDLER_NAME) Handler mainHandler,
Jason Monk09f4d372018-12-20 15:30:54 -0500104 NotificationLockscreenUserManager notificationLockscreenUserManager,
105 NotificationGroupManager groupManager,
106 VisualStabilityManager visualStabilityManager,
Beverly80110912019-02-13 12:20:57 -0500107 StatusBarStateController statusBarStateController,
Jason Monk09f4d372018-12-20 15:30:54 -0500108 NotificationEntryManager notificationEntryManager,
Selim Cinekfdf80332019-03-07 17:29:55 -0800109 Lazy<ShadeController> shadeController,
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700110 BubbleData bubbleData,
Selim Cinekb0fada62019-06-17 19:03:59 -0700111 KeyguardBypassController bypassController,
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700112 DynamicPrivacyController privacyController) {
Ned Burnsb3b4bd32019-06-27 19:36:58 -0400113 mHandler = mainHandler;
Jason Monk09f4d372018-12-20 15:30:54 -0500114 mLockscreenUserManager = notificationLockscreenUserManager;
Selim Cinekb0fada62019-06-17 19:03:59 -0700115 mBypassController = bypassController;
Jason Monk09f4d372018-12-20 15:30:54 -0500116 mGroupManager = groupManager;
117 mVisualStabilityManager = visualStabilityManager;
Beverly80110912019-02-13 12:20:57 -0500118 mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
Jason Monk09f4d372018-12-20 15:30:54 -0500119 mEntryManager = notificationEntryManager;
Jason Monk09f4d372018-12-20 15:30:54 -0500120 mShadeController = shadeController;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900121 Resources res = context.getResources();
122 mAlwaysExpandNonGroupedNotification =
123 res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications);
Selim Cinekfdf80332019-03-07 17:29:55 -0800124 mBubbleData = bubbleData;
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700125 mDynamicPrivacyController = privacyController;
126 privacyController.addListener(this);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900127 }
128
129 public void setUpWithPresenter(NotificationPresenter presenter,
Jason Monk297c04e2018-08-23 17:16:59 -0400130 NotificationListContainer listContainer) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900131 mPresenter = presenter;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900132 mListContainer = listContainer;
133 }
134
135 /**
136 * Updates the visual representation of the notifications.
137 */
Evan Laird94492852018-10-25 13:43:01 -0400138 //TODO: Rewrite this to focus on Entries, or some other data object instead of views
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900139 public void updateNotificationViews() {
Ned Burnsd4a69f72019-06-19 19:49:19 -0400140 Assert.isMainThread();
141 beginUpdate();
142
Ned Burnsf81c4c42019-01-07 14:10:43 -0500143 ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900144 .getActiveNotifications();
145 ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
146 final int N = activeNotifications.size();
147 for (int i = 0; i < N; i++) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500148 NotificationEntry ent = activeNotifications.get(i);
Selim Cinekfdf80332019-03-07 17:29:55 -0800149 if (ent.isRowDismissed() || ent.isRowRemoved()
Mark Renouf71a3af62019-04-08 15:02:54 -0400150 || (mBubbleData.hasBubbleWithKey(ent.key) && !ent.showInShadeWhenBubble())) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900151 // we don't want to update removed notifications because they could
152 // temporarily become children if they were isolated before.
153 continue;
154 }
Mady Mellor5549dd22018-11-06 18:07:34 -0800155
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900156 int userId = ent.notification.getUserId();
157
158 // Display public version of the notification if we need to redact.
159 // TODO: This area uses a lot of calls into NotificationLockscreenUserManager.
160 // We can probably move some of this code there.
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700161 int currentUserId = mLockscreenUserManager.getCurrentUserId();
162 boolean devicePublic = mLockscreenUserManager.isLockscreenPublicMode(currentUserId);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900163 boolean userPublic = devicePublic
164 || mLockscreenUserManager.isLockscreenPublicMode(userId);
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700165 if (userPublic && mDynamicPrivacyController.isDynamicallyUnlocked()
166 && (userId == currentUserId || userId == UserHandle.USER_ALL
167 || !mLockscreenUserManager.needsSeparateWorkChallenge(userId))) {
168 userPublic = false;
169 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900170 boolean needsRedaction = mLockscreenUserManager.needsRedaction(ent);
171 boolean sensitive = userPublic && needsRedaction;
172 boolean deviceSensitive = devicePublic
173 && !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700174 currentUserId);
Selim Cinekb2c5dc52019-06-24 15:46:52 -0700175 ent.setSensitive(sensitive, deviceSensitive);
Evan Laird94492852018-10-25 13:43:01 -0400176 ent.getRow().setNeedsRedaction(needsRedaction);
177 if (mGroupManager.isChildInGroupWithSummary(ent.notification)) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500178 NotificationEntry summary = mGroupManager.getGroupSummary(ent.notification);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900179 List<ExpandableNotificationRow> orderedChildren =
Evan Laird94492852018-10-25 13:43:01 -0400180 mTmpChildOrderMap.get(summary.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900181 if (orderedChildren == null) {
182 orderedChildren = new ArrayList<>();
Evan Laird94492852018-10-25 13:43:01 -0400183 mTmpChildOrderMap.put(summary.getRow(), orderedChildren);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900184 }
Evan Laird94492852018-10-25 13:43:01 -0400185 orderedChildren.add(ent.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900186 } else {
Evan Laird94492852018-10-25 13:43:01 -0400187 toShow.add(ent.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900188 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900189 }
190
Rohan Shah524cf7b2018-03-15 14:40:02 -0700191 ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900192 for (int i=0; i< mListContainer.getContainerChildCount(); i++) {
193 View child = mListContainer.getContainerChildAt(i);
194 if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
Rohan Shah524cf7b2018-03-15 14:40:02 -0700195 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
196
197 // Blocking helper is effectively a detached view. Don't bother removing it from the
198 // layout.
199 if (!row.isBlockingHelperShowing()) {
200 viewsToRemove.add((ExpandableNotificationRow) child);
201 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900202 }
203 }
204
Rohan Shah524cf7b2018-03-15 14:40:02 -0700205 for (ExpandableNotificationRow viewToRemove : viewsToRemove) {
206 if (mGroupManager.isChildInGroupWithSummary(viewToRemove.getStatusBarNotification())) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900207 // we are only transferring this notification to its parent, don't generate an
208 // animation
209 mListContainer.setChildTransferInProgress(true);
210 }
Rohan Shah524cf7b2018-03-15 14:40:02 -0700211 if (viewToRemove.isSummaryWithChildren()) {
212 viewToRemove.removeAllChildren();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900213 }
Rohan Shah524cf7b2018-03-15 14:40:02 -0700214 mListContainer.removeContainerView(viewToRemove);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900215 mListContainer.setChildTransferInProgress(false);
216 }
217
218 removeNotificationChildren();
219
220 for (int i = 0; i < toShow.size(); i++) {
221 View v = toShow.get(i);
222 if (v.getParent() == null) {
223 mVisualStabilityManager.notifyViewAddition(v);
224 mListContainer.addContainerView(v);
Selim Cinekfdf80332019-03-07 17:29:55 -0800225 } else if (!mListContainer.containsView(v)) {
226 // the view is added somewhere else. Let's make sure
227 // the ordering works properly below, by excluding these
228 toShow.remove(v);
229 i--;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900230 }
231 }
232
233 addNotificationChildrenAndSort();
234
235 // So after all this work notifications still aren't sorted correctly.
236 // Let's do that now by advancing through toShow and mListContainer in
237 // lock-step, making sure mListContainer matches what we see in toShow.
238 int j = 0;
239 for (int i = 0; i < mListContainer.getContainerChildCount(); i++) {
240 View child = mListContainer.getContainerChildAt(i);
241 if (!(child instanceof ExpandableNotificationRow)) {
242 // We don't care about non-notification views.
243 continue;
244 }
Rohan Shah524cf7b2018-03-15 14:40:02 -0700245 if (((ExpandableNotificationRow) child).isBlockingHelperShowing()) {
246 // Don't count/reorder notifications that are showing the blocking helper!
247 continue;
248 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900249
250 ExpandableNotificationRow targetChild = toShow.get(j);
251 if (child != targetChild) {
252 // Oops, wrong notification at this position. Put the right one
253 // here and advance both lists.
254 if (mVisualStabilityManager.canReorderNotification(targetChild)) {
255 mListContainer.changeViewPosition(targetChild, i);
256 } else {
257 mVisualStabilityManager.addReorderingAllowedCallback(mEntryManager);
258 }
259 }
260 j++;
261
262 }
263
264 mVisualStabilityManager.onReorderingFinished();
265 // clear the map again for the next usage
266 mTmpChildOrderMap.clear();
267
Ned Burnsd4a69f72019-06-19 19:49:19 -0400268 updateRowStatesInternal();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900269
270 mListContainer.onNotificationViewUpdateFinished();
Ned Burnsd4a69f72019-06-19 19:49:19 -0400271
272 endUpdate();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900273 }
274
275 private void addNotificationChildrenAndSort() {
276 // Let's now add all notification children which are missing
277 boolean orderChanged = false;
278 for (int i = 0; i < mListContainer.getContainerChildCount(); i++) {
279 View view = mListContainer.getContainerChildAt(i);
280 if (!(view instanceof ExpandableNotificationRow)) {
281 // We don't care about non-notification views.
282 continue;
283 }
284
285 ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
286 List<ExpandableNotificationRow> children = parent.getNotificationChildren();
287 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
288
289 for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
290 childIndex++) {
291 ExpandableNotificationRow childView = orderedChildren.get(childIndex);
292 if (children == null || !children.contains(childView)) {
293 if (childView.getParent() != null) {
294 Log.wtf(TAG, "trying to add a notification child that already has " +
295 "a parent. class:" + childView.getParent().getClass() +
296 "\n child: " + childView);
297 // This shouldn't happen. We can recover by removing it though.
298 ((ViewGroup) childView.getParent()).removeView(childView);
299 }
300 mVisualStabilityManager.notifyViewAddition(childView);
301 parent.addChildNotification(childView, childIndex);
302 mListContainer.notifyGroupChildAdded(childView);
303 }
304 }
305
306 // Finally after removing and adding has been performed we can apply the order.
307 orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager,
308 mEntryManager);
309 }
310 if (orderChanged) {
311 mListContainer.generateChildOrderChangedEvent();
312 }
313 }
314
315 private void removeNotificationChildren() {
316 // First let's remove all children which don't belong in the parents
317 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
318 for (int i = 0; i < mListContainer.getContainerChildCount(); i++) {
319 View view = mListContainer.getContainerChildAt(i);
320 if (!(view instanceof ExpandableNotificationRow)) {
321 // We don't care about non-notification views.
322 continue;
323 }
324
325 ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
326 List<ExpandableNotificationRow> children = parent.getNotificationChildren();
327 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
328
329 if (children != null) {
330 toRemove.clear();
331 for (ExpandableNotificationRow childRow : children) {
332 if ((orderedChildren == null
333 || !orderedChildren.contains(childRow))
334 && !childRow.keepInParent()) {
335 toRemove.add(childRow);
336 }
337 }
338 for (ExpandableNotificationRow remove : toRemove) {
339 parent.removeChildNotification(remove);
340 if (mEntryManager.getNotificationData().get(
341 remove.getStatusBarNotification().getKey()) == null) {
342 // We only want to add an animation if the view is completely removed
343 // otherwise it's just a transfer
344 mListContainer.notifyGroupChildRemoved(remove,
345 parent.getChildrenContainer());
346 }
347 }
348 }
349 }
350 }
351
352 /**
353 * Updates expanded, dimmed and locked states of notification rows.
354 */
355 public void updateRowStates() {
Ned Burnsd4a69f72019-06-19 19:49:19 -0400356 Assert.isMainThread();
357 beginUpdate();
358 updateRowStatesInternal();
359 endUpdate();
360 }
361
362 private void updateRowStatesInternal() {
Lucas Dupin16013822018-05-17 18:00:16 -0700363 Trace.beginSection("NotificationViewHierarchyManager#updateRowStates");
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900364 final int N = mListContainer.getContainerChildCount();
365
366 int visibleNotifications = 0;
Jason Monk297c04e2018-08-23 17:16:59 -0400367 boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900368 int maxNotifications = -1;
Selim Cinekb0fada62019-06-17 19:03:59 -0700369 if (onKeyguard && !mBypassController.getBypassEnabled()) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900370 maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
371 }
372 mListContainer.setMaxDisplayedNotifications(maxNotifications);
373 Stack<ExpandableNotificationRow> stack = new Stack<>();
374 for (int i = N - 1; i >= 0; i--) {
375 View child = mListContainer.getContainerChildAt(i);
376 if (!(child instanceof ExpandableNotificationRow)) {
377 continue;
378 }
379 stack.push((ExpandableNotificationRow) child);
380 }
381 while(!stack.isEmpty()) {
382 ExpandableNotificationRow row = stack.pop();
Ned Burnsf81c4c42019-01-07 14:10:43 -0500383 NotificationEntry entry = row.getEntry();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900384 boolean isChildNotification =
385 mGroupManager.isChildInGroupWithSummary(entry.notification);
386
Jason Monk297c04e2018-08-23 17:16:59 -0400387 row.setOnKeyguard(onKeyguard);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900388
Jason Monk297c04e2018-08-23 17:16:59 -0400389 if (!onKeyguard) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900390 // If mAlwaysExpandNonGroupedNotification is false, then only expand the
391 // very first notification and if it's not a child of grouped notifications.
392 row.setSystemExpanded(mAlwaysExpandNonGroupedNotification
393 || (visibleNotifications == 0 && !isChildNotification
394 && !row.isLowPriority()));
395 }
396
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900397 int userId = entry.notification.getUserId();
398 boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
Evan Laird94492852018-10-25 13:43:01 -0400399 entry.notification) && !entry.isRowRemoved();
Ned Burns8c1b7632019-07-19 14:26:15 -0400400 boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry);
Selim Cinek3bf2d202018-10-16 17:30:05 -0700401 if (!showOnKeyguard) {
402 // min priority notifications should show if their summary is showing
403 if (mGroupManager.isChildInGroupWithSummary(entry.notification)) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500404 NotificationEntry summary = mGroupManager.getLogicalGroupSummary(
Selim Cinek3bf2d202018-10-16 17:30:05 -0700405 entry.notification);
Ned Burns8c1b7632019-07-19 14:26:15 -0400406 if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(summary)) {
Selim Cinek3bf2d202018-10-16 17:30:05 -0700407 showOnKeyguard = true;
408 }
409 }
410 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900411 if (suppressedSummary
Pavel Grafov65152632018-03-26 15:14:45 +0100412 || mLockscreenUserManager.shouldHideNotifications(userId)
Jason Monk297c04e2018-08-23 17:16:59 -0400413 || (onKeyguard && !showOnKeyguard)) {
Evan Laird94492852018-10-25 13:43:01 -0400414 entry.getRow().setVisibility(View.GONE);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900415 } else {
Evan Laird94492852018-10-25 13:43:01 -0400416 boolean wasGone = entry.getRow().getVisibility() == View.GONE;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900417 if (wasGone) {
Evan Laird94492852018-10-25 13:43:01 -0400418 entry.getRow().setVisibility(View.VISIBLE);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900419 }
Evan Laird94492852018-10-25 13:43:01 -0400420 if (!isChildNotification && !entry.getRow().isRemoved()) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900421 if (wasGone) {
422 // notify the scroller of a child addition
Evan Laird94492852018-10-25 13:43:01 -0400423 mListContainer.generateAddAnimation(entry.getRow(),
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900424 !showOnKeyguard /* fromMoreCard */);
425 }
426 visibleNotifications++;
427 }
428 }
429 if (row.isSummaryWithChildren()) {
430 List<ExpandableNotificationRow> notificationChildren =
431 row.getNotificationChildren();
432 int size = notificationChildren.size();
433 for (int i = size - 1; i >= 0; i--) {
434 stack.push(notificationChildren.get(i));
435 }
436 }
Dan Sandler83b70a02018-01-24 23:20:18 -0500437
Julia Reynoldsfc640012018-02-21 12:25:27 -0500438 row.showAppOpsIcons(entry.mActiveAppOps);
Gus Prevas7306b902018-12-11 10:57:06 -0500439 row.setLastAudiblyAlertedMs(entry.lastAudiblyAlertedMs);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900440 }
441
Lucas Dupin16013822018-05-17 18:00:16 -0700442 Trace.beginSection("NotificationPresenter#onUpdateRowStates");
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900443 mPresenter.onUpdateRowStates();
Lucas Dupin16013822018-05-17 18:00:16 -0700444 Trace.endSection();
445 Trace.endSection();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900446 }
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700447
448 @Override
449 public void onDynamicPrivacyChanged() {
Ned Burnsb3b4bd32019-06-27 19:36:58 -0400450 if (mPerformingUpdate) {
451 Log.w(TAG, "onDynamicPrivacyChanged made a re-entrant call");
452 }
453 // This listener can be called from updateNotificationViews() via a convoluted listener
454 // chain, so we post here to prevent a re-entrant call. See b/136186188
455 // TODO: Refactor away the need for this
456 if (!mIsHandleDynamicPrivacyChangeScheduled) {
457 mIsHandleDynamicPrivacyChangeScheduled = true;
458 mHandler.post(this::onHandleDynamicPrivacyChanged);
459 }
460 }
461
462 private void onHandleDynamicPrivacyChanged() {
463 mIsHandleDynamicPrivacyChangeScheduled = false;
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700464 updateNotificationViews();
465 }
Ned Burnsd4a69f72019-06-19 19:49:19 -0400466
467 private void beginUpdate() {
468 if (mPerformingUpdate) {
Ned Burnsbddd3f12019-06-28 12:54:25 -0400469 Log.wtf(TAG, "Re-entrant code during update", new Exception());
Ned Burnsd4a69f72019-06-19 19:49:19 -0400470 }
471 mPerformingUpdate = true;
472 }
473
474 private void endUpdate() {
475 if (!mPerformingUpdate) {
Ned Burnsbddd3f12019-06-28 12:54:25 -0400476 Log.wtf(TAG, "Manager state has become desynced", new Exception());
Ned Burnsd4a69f72019-06-19 19:49:19 -0400477 }
478 mPerformingUpdate = false;
479 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900480}