blob: d6b87afc53b93b5fa6a639a302c8ff07bd38152b [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
19import android.content.Context;
20import android.content.res.Resources;
Ned Burnsb3b4bd32019-06-27 19:36:58 -040021import android.os.Handler;
Lucas Dupin16013822018-05-17 18:00:16 -070022import android.os.Trace;
Selim Cinek6f0a62a2019-04-09 18:40:12 -070023import android.os.UserHandle;
Beth Thibodeau07d20c32019-10-16 13:45:56 -040024import android.provider.Settings;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090025import android.util.Log;
26import android.view.View;
27import android.view.ViewGroup;
28
29import com.android.systemui.R;
Mady Mellorce23c462019-06-17 17:30:07 -070030import com.android.systemui.bubbles.BubbleController;
Dave Mankofff4736812019-10-18 17:25:50 -040031import com.android.systemui.dagger.qualifiers.MainHandler;
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;
50import javax.inject.Singleton;
51
Jason Monk09f4d372018-12-20 15:30:54 -050052import dagger.Lazy;
53
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090054/**
55 * NotificationViewHierarchyManager manages updating the view hierarchy of notification views based
56 * on their group structure. For example, if a notification becomes bundled with another,
57 * NotificationViewHierarchyManager will update the view hierarchy to reflect that. It also will
58 * tell NotificationListContainer which notifications to display, and inform it of changes to those
59 * notifications that might affect their display.
60 */
Jason Monk27d01a622018-12-10 15:57:09 -050061@Singleton
Selim Cinek6f0a62a2019-04-09 18:40:12 -070062public class NotificationViewHierarchyManager implements DynamicPrivacyController.Listener {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090063 private static final String TAG = "NotificationViewHierarchyManager";
64
Ned Burnsb3b4bd32019-06-27 19:36:58 -040065 private final Handler mHandler;
66
Evan Laird94492852018-10-25 13:43:01 -040067 //TODO: change this top <Entry, List<Entry>>?
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090068 private final HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>>
69 mTmpChildOrderMap = new HashMap<>();
Eliot Courtney6c313d32017-12-14 19:57:51 +090070
71 // Dependencies:
Jason Monk09f4d372018-12-20 15:30:54 -050072 protected final NotificationLockscreenUserManager mLockscreenUserManager;
73 protected final NotificationGroupManager mGroupManager;
74 protected final VisualStabilityManager mVisualStabilityManager;
Beverly80110912019-02-13 12:20:57 -050075 private final SysuiStatusBarStateController mStatusBarStateController;
Jason Monk09f4d372018-12-20 15:30:54 -050076 private final NotificationEntryManager mEntryManager;
Jason Monk297c04e2018-08-23 17:16:59 -040077
78 // Lazy
Jason Monk09f4d372018-12-20 15:30:54 -050079 private final Lazy<ShadeController> mShadeController;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +090080
81 /**
82 * {@code true} if notifications not part of a group should by default be rendered in their
83 * expanded state. If {@code false}, then only the first notification will be expanded if
84 * possible.
85 */
86 private final boolean mAlwaysExpandNonGroupedNotification;
Mady Mellorce23c462019-06-17 17:30:07 -070087 private final BubbleController mBubbleController;
Selim Cinek6f0a62a2019-04-09 18:40:12 -070088 private final DynamicPrivacyController mDynamicPrivacyController;
Selim Cinekb0fada62019-06-17 19:03:59 -070089 private final KeyguardBypassController mBypassController;
Beth Thibodeau07d20c32019-10-16 13:45:56 -040090 private final Context mContext;
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
Dave Mankofff4736812019-10-18 17:25:50 -0400102 public NotificationViewHierarchyManager(Context context, @MainHandler Handler mainHandler,
Jason Monk09f4d372018-12-20 15:30:54 -0500103 NotificationLockscreenUserManager notificationLockscreenUserManager,
104 NotificationGroupManager groupManager,
105 VisualStabilityManager visualStabilityManager,
Beverly80110912019-02-13 12:20:57 -0500106 StatusBarStateController statusBarStateController,
Jason Monk09f4d372018-12-20 15:30:54 -0500107 NotificationEntryManager notificationEntryManager,
Selim Cinekfdf80332019-03-07 17:29:55 -0800108 Lazy<ShadeController> shadeController,
Selim Cinekb0fada62019-06-17 19:03:59 -0700109 KeyguardBypassController bypassController,
Mady Mellorce23c462019-06-17 17:30:07 -0700110 BubbleController bubbleController,
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700111 DynamicPrivacyController privacyController) {
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400112 mContext = context;
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);
Mady Mellorce23c462019-06-17 17:30:07 -0700124 mBubbleController = bubbleController;
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);
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400149 int flag = Settings.System.getInt(mContext.getContentResolver(),
150 "qs_media_player", 0);
151 boolean hideMedia = (flag == 1);
Selim Cinekfdf80332019-03-07 17:29:55 -0800152 if (ent.isRowDismissed() || ent.isRowRemoved()
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400153 || (ent.isMediaNotification() && hideMedia)
Ned Burns00b4b2d2019-10-17 22:09:27 -0400154 || mBubbleController.isBubbleNotificationSuppressedFromShade(ent.getKey())) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900155 // we don't want to update removed notifications because they could
156 // temporarily become children if they were isolated before.
157 continue;
158 }
Mady Mellor5549dd22018-11-06 18:07:34 -0800159
Ned Burns00b4b2d2019-10-17 22:09:27 -0400160 int userId = ent.getSbn().getUserId();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900161
162 // Display public version of the notification if we need to redact.
163 // TODO: This area uses a lot of calls into NotificationLockscreenUserManager.
164 // We can probably move some of this code there.
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700165 int currentUserId = mLockscreenUserManager.getCurrentUserId();
166 boolean devicePublic = mLockscreenUserManager.isLockscreenPublicMode(currentUserId);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900167 boolean userPublic = devicePublic
168 || mLockscreenUserManager.isLockscreenPublicMode(userId);
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700169 if (userPublic && mDynamicPrivacyController.isDynamicallyUnlocked()
170 && (userId == currentUserId || userId == UserHandle.USER_ALL
171 || !mLockscreenUserManager.needsSeparateWorkChallenge(userId))) {
172 userPublic = false;
173 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900174 boolean needsRedaction = mLockscreenUserManager.needsRedaction(ent);
175 boolean sensitive = userPublic && needsRedaction;
176 boolean deviceSensitive = devicePublic
177 && !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700178 currentUserId);
Selim Cinekb2c5dc52019-06-24 15:46:52 -0700179 ent.setSensitive(sensitive, deviceSensitive);
Evan Laird94492852018-10-25 13:43:01 -0400180 ent.getRow().setNeedsRedaction(needsRedaction);
Ned Burns00b4b2d2019-10-17 22:09:27 -0400181 if (mGroupManager.isChildInGroupWithSummary(ent.getSbn())) {
182 NotificationEntry summary = mGroupManager.getGroupSummary(ent.getSbn());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900183 List<ExpandableNotificationRow> orderedChildren =
Evan Laird94492852018-10-25 13:43:01 -0400184 mTmpChildOrderMap.get(summary.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900185 if (orderedChildren == null) {
186 orderedChildren = new ArrayList<>();
Evan Laird94492852018-10-25 13:43:01 -0400187 mTmpChildOrderMap.put(summary.getRow(), orderedChildren);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900188 }
Evan Laird94492852018-10-25 13:43:01 -0400189 orderedChildren.add(ent.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900190 } else {
Evan Laird94492852018-10-25 13:43:01 -0400191 toShow.add(ent.getRow());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900192 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900193 }
194
Rohan Shah524cf7b2018-03-15 14:40:02 -0700195 ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900196 for (int i=0; i< mListContainer.getContainerChildCount(); i++) {
197 View child = mListContainer.getContainerChildAt(i);
198 if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
Rohan Shah524cf7b2018-03-15 14:40:02 -0700199 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
200
201 // Blocking helper is effectively a detached view. Don't bother removing it from the
202 // layout.
203 if (!row.isBlockingHelperShowing()) {
204 viewsToRemove.add((ExpandableNotificationRow) child);
205 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900206 }
207 }
208
Rohan Shah524cf7b2018-03-15 14:40:02 -0700209 for (ExpandableNotificationRow viewToRemove : viewsToRemove) {
210 if (mGroupManager.isChildInGroupWithSummary(viewToRemove.getStatusBarNotification())) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900211 // we are only transferring this notification to its parent, don't generate an
212 // animation
213 mListContainer.setChildTransferInProgress(true);
214 }
Rohan Shah524cf7b2018-03-15 14:40:02 -0700215 if (viewToRemove.isSummaryWithChildren()) {
216 viewToRemove.removeAllChildren();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900217 }
Rohan Shah524cf7b2018-03-15 14:40:02 -0700218 mListContainer.removeContainerView(viewToRemove);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900219 mListContainer.setChildTransferInProgress(false);
220 }
221
222 removeNotificationChildren();
223
224 for (int i = 0; i < toShow.size(); i++) {
225 View v = toShow.get(i);
226 if (v.getParent() == null) {
227 mVisualStabilityManager.notifyViewAddition(v);
228 mListContainer.addContainerView(v);
Selim Cinekfdf80332019-03-07 17:29:55 -0800229 } else if (!mListContainer.containsView(v)) {
230 // the view is added somewhere else. Let's make sure
231 // the ordering works properly below, by excluding these
232 toShow.remove(v);
233 i--;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900234 }
235 }
236
237 addNotificationChildrenAndSort();
238
239 // So after all this work notifications still aren't sorted correctly.
240 // Let's do that now by advancing through toShow and mListContainer in
241 // lock-step, making sure mListContainer matches what we see in toShow.
242 int j = 0;
243 for (int i = 0; i < mListContainer.getContainerChildCount(); i++) {
244 View child = mListContainer.getContainerChildAt(i);
245 if (!(child instanceof ExpandableNotificationRow)) {
246 // We don't care about non-notification views.
247 continue;
248 }
Rohan Shah524cf7b2018-03-15 14:40:02 -0700249 if (((ExpandableNotificationRow) child).isBlockingHelperShowing()) {
250 // Don't count/reorder notifications that are showing the blocking helper!
251 continue;
252 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900253
254 ExpandableNotificationRow targetChild = toShow.get(j);
255 if (child != targetChild) {
256 // Oops, wrong notification at this position. Put the right one
257 // here and advance both lists.
258 if (mVisualStabilityManager.canReorderNotification(targetChild)) {
259 mListContainer.changeViewPosition(targetChild, i);
260 } else {
261 mVisualStabilityManager.addReorderingAllowedCallback(mEntryManager);
262 }
263 }
264 j++;
265
266 }
267
268 mVisualStabilityManager.onReorderingFinished();
269 // clear the map again for the next usage
270 mTmpChildOrderMap.clear();
271
Ned Burnsd4a69f72019-06-19 19:49:19 -0400272 updateRowStatesInternal();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900273
274 mListContainer.onNotificationViewUpdateFinished();
Ned Burnsd4a69f72019-06-19 19:49:19 -0400275
276 endUpdate();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900277 }
278
279 private void addNotificationChildrenAndSort() {
280 // Let's now add all notification children which are missing
281 boolean orderChanged = false;
282 for (int i = 0; i < mListContainer.getContainerChildCount(); i++) {
283 View view = mListContainer.getContainerChildAt(i);
284 if (!(view instanceof ExpandableNotificationRow)) {
285 // We don't care about non-notification views.
286 continue;
287 }
288
289 ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
290 List<ExpandableNotificationRow> children = parent.getNotificationChildren();
291 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
292
293 for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
294 childIndex++) {
295 ExpandableNotificationRow childView = orderedChildren.get(childIndex);
296 if (children == null || !children.contains(childView)) {
297 if (childView.getParent() != null) {
298 Log.wtf(TAG, "trying to add a notification child that already has " +
299 "a parent. class:" + childView.getParent().getClass() +
300 "\n child: " + childView);
301 // This shouldn't happen. We can recover by removing it though.
302 ((ViewGroup) childView.getParent()).removeView(childView);
303 }
304 mVisualStabilityManager.notifyViewAddition(childView);
305 parent.addChildNotification(childView, childIndex);
306 mListContainer.notifyGroupChildAdded(childView);
307 }
308 }
309
310 // Finally after removing and adding has been performed we can apply the order.
311 orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager,
312 mEntryManager);
313 }
314 if (orderChanged) {
315 mListContainer.generateChildOrderChangedEvent();
316 }
317 }
318
319 private void removeNotificationChildren() {
320 // First let's remove all children which don't belong in the parents
321 ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
322 for (int i = 0; i < mListContainer.getContainerChildCount(); i++) {
323 View view = mListContainer.getContainerChildAt(i);
324 if (!(view instanceof ExpandableNotificationRow)) {
325 // We don't care about non-notification views.
326 continue;
327 }
328
329 ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
330 List<ExpandableNotificationRow> children = parent.getNotificationChildren();
331 List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
332
333 if (children != null) {
334 toRemove.clear();
335 for (ExpandableNotificationRow childRow : children) {
336 if ((orderedChildren == null
337 || !orderedChildren.contains(childRow))
338 && !childRow.keepInParent()) {
339 toRemove.add(childRow);
340 }
341 }
342 for (ExpandableNotificationRow remove : toRemove) {
343 parent.removeChildNotification(remove);
344 if (mEntryManager.getNotificationData().get(
345 remove.getStatusBarNotification().getKey()) == null) {
346 // We only want to add an animation if the view is completely removed
347 // otherwise it's just a transfer
348 mListContainer.notifyGroupChildRemoved(remove,
349 parent.getChildrenContainer());
350 }
351 }
352 }
353 }
354 }
355
356 /**
357 * Updates expanded, dimmed and locked states of notification rows.
358 */
359 public void updateRowStates() {
Ned Burnsd4a69f72019-06-19 19:49:19 -0400360 Assert.isMainThread();
361 beginUpdate();
362 updateRowStatesInternal();
363 endUpdate();
364 }
365
366 private void updateRowStatesInternal() {
Lucas Dupin16013822018-05-17 18:00:16 -0700367 Trace.beginSection("NotificationViewHierarchyManager#updateRowStates");
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900368 final int N = mListContainer.getContainerChildCount();
369
370 int visibleNotifications = 0;
Jason Monk297c04e2018-08-23 17:16:59 -0400371 boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900372 int maxNotifications = -1;
Selim Cinekb0fada62019-06-17 19:03:59 -0700373 if (onKeyguard && !mBypassController.getBypassEnabled()) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900374 maxNotifications = mPresenter.getMaxNotificationsWhileLocked(true /* recompute */);
375 }
376 mListContainer.setMaxDisplayedNotifications(maxNotifications);
377 Stack<ExpandableNotificationRow> stack = new Stack<>();
378 for (int i = N - 1; i >= 0; i--) {
379 View child = mListContainer.getContainerChildAt(i);
380 if (!(child instanceof ExpandableNotificationRow)) {
381 continue;
382 }
383 stack.push((ExpandableNotificationRow) child);
384 }
385 while(!stack.isEmpty()) {
386 ExpandableNotificationRow row = stack.pop();
Ned Burnsf81c4c42019-01-07 14:10:43 -0500387 NotificationEntry entry = row.getEntry();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900388 boolean isChildNotification =
Ned Burns00b4b2d2019-10-17 22:09:27 -0400389 mGroupManager.isChildInGroupWithSummary(entry.getSbn());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900390
Jason Monk297c04e2018-08-23 17:16:59 -0400391 row.setOnKeyguard(onKeyguard);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900392
Jason Monk297c04e2018-08-23 17:16:59 -0400393 if (!onKeyguard) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900394 // If mAlwaysExpandNonGroupedNotification is false, then only expand the
395 // very first notification and if it's not a child of grouped notifications.
396 row.setSystemExpanded(mAlwaysExpandNonGroupedNotification
397 || (visibleNotifications == 0 && !isChildNotification
398 && !row.isLowPriority()));
399 }
400
Ned Burns00b4b2d2019-10-17 22:09:27 -0400401 int userId = entry.getSbn().getUserId();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900402 boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
Ned Burns00b4b2d2019-10-17 22:09:27 -0400403 entry.getSbn()) && !entry.isRowRemoved();
Ned Burns8c1b7632019-07-19 14:26:15 -0400404 boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry);
Selim Cinek3bf2d202018-10-16 17:30:05 -0700405 if (!showOnKeyguard) {
406 // min priority notifications should show if their summary is showing
Ned Burns00b4b2d2019-10-17 22:09:27 -0400407 if (mGroupManager.isChildInGroupWithSummary(entry.getSbn())) {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500408 NotificationEntry summary = mGroupManager.getLogicalGroupSummary(
Ned Burns00b4b2d2019-10-17 22:09:27 -0400409 entry.getSbn());
Ned Burns8c1b7632019-07-19 14:26:15 -0400410 if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(summary)) {
Selim Cinek3bf2d202018-10-16 17:30:05 -0700411 showOnKeyguard = true;
412 }
413 }
414 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900415 if (suppressedSummary
Pavel Grafov65152632018-03-26 15:14:45 +0100416 || mLockscreenUserManager.shouldHideNotifications(userId)
Jason Monk297c04e2018-08-23 17:16:59 -0400417 || (onKeyguard && !showOnKeyguard)) {
Evan Laird94492852018-10-25 13:43:01 -0400418 entry.getRow().setVisibility(View.GONE);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900419 } else {
Evan Laird94492852018-10-25 13:43:01 -0400420 boolean wasGone = entry.getRow().getVisibility() == View.GONE;
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900421 if (wasGone) {
Evan Laird94492852018-10-25 13:43:01 -0400422 entry.getRow().setVisibility(View.VISIBLE);
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900423 }
Evan Laird94492852018-10-25 13:43:01 -0400424 if (!isChildNotification && !entry.getRow().isRemoved()) {
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900425 if (wasGone) {
426 // notify the scroller of a child addition
Evan Laird94492852018-10-25 13:43:01 -0400427 mListContainer.generateAddAnimation(entry.getRow(),
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900428 !showOnKeyguard /* fromMoreCard */);
429 }
430 visibleNotifications++;
431 }
432 }
433 if (row.isSummaryWithChildren()) {
434 List<ExpandableNotificationRow> notificationChildren =
435 row.getNotificationChildren();
436 int size = notificationChildren.size();
437 for (int i = size - 1; i >= 0; i--) {
438 stack.push(notificationChildren.get(i));
439 }
440 }
Dan Sandler83b70a02018-01-24 23:20:18 -0500441
Julia Reynoldsfc640012018-02-21 12:25:27 -0500442 row.showAppOpsIcons(entry.mActiveAppOps);
Ned Burns60e94592019-09-06 14:47:25 -0400443 row.setLastAudiblyAlertedMs(entry.getLastAudiblyAlertedMs());
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900444 }
445
Lucas Dupin16013822018-05-17 18:00:16 -0700446 Trace.beginSection("NotificationPresenter#onUpdateRowStates");
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900447 mPresenter.onUpdateRowStates();
Lucas Dupin16013822018-05-17 18:00:16 -0700448 Trace.endSection();
449 Trace.endSection();
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900450 }
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700451
452 @Override
453 public void onDynamicPrivacyChanged() {
Ned Burnsb3b4bd32019-06-27 19:36:58 -0400454 if (mPerformingUpdate) {
455 Log.w(TAG, "onDynamicPrivacyChanged made a re-entrant call");
456 }
457 // This listener can be called from updateNotificationViews() via a convoluted listener
458 // chain, so we post here to prevent a re-entrant call. See b/136186188
459 // TODO: Refactor away the need for this
460 if (!mIsHandleDynamicPrivacyChangeScheduled) {
461 mIsHandleDynamicPrivacyChangeScheduled = true;
462 mHandler.post(this::onHandleDynamicPrivacyChanged);
463 }
464 }
465
466 private void onHandleDynamicPrivacyChanged() {
467 mIsHandleDynamicPrivacyChangeScheduled = false;
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700468 updateNotificationViews();
469 }
Ned Burnsd4a69f72019-06-19 19:49:19 -0400470
471 private void beginUpdate() {
472 if (mPerformingUpdate) {
Ned Burnsbddd3f12019-06-28 12:54:25 -0400473 Log.wtf(TAG, "Re-entrant code during update", new Exception());
Ned Burnsd4a69f72019-06-19 19:49:19 -0400474 }
475 mPerformingUpdate = true;
476 }
477
478 private void endUpdate() {
479 if (!mPerformingUpdate) {
Ned Burnsbddd3f12019-06-28 12:54:25 -0400480 Log.wtf(TAG, "Manager state has become desynced", new Exception());
Ned Burnsd4a69f72019-06-19 19:49:19 -0400481 }
482 mPerformingUpdate = false;
483 }
Eliot Courtney2b4c3a02017-11-27 13:27:46 +0900484}