1 /* 2 * Copyright (C) 2021 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 17 package com.android.systemui.statusbar.notification.collection.coordinator 18 19 import com.android.app.tracing.traceSection 20 import com.android.server.notification.Flags.screenshareNotificationHiding 21 import com.android.systemui.Flags.screenshareNotificationHidingBugFix 22 import com.android.systemui.statusbar.notification.collection.ListEntry 23 import com.android.systemui.statusbar.notification.collection.NotifPipeline 24 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope 25 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl 26 import com.android.systemui.statusbar.notification.collection.render.NotifStackController 27 import com.android.systemui.statusbar.notification.collection.render.NotifStats 28 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor 29 import com.android.systemui.statusbar.notification.domain.interactor.RenderNotificationListInteractor 30 import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor 31 import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor 32 import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT 33 import com.android.systemui.statusbar.phone.NotificationIconAreaController 34 import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController 35 import javax.inject.Inject 36 37 /** 38 * A small coordinator which updates the notif stack (the view layer which holds notifications) with 39 * high-level data after the stack is populated with the final entries. 40 */ 41 @CoordinatorScope 42 class StackCoordinator 43 @Inject 44 internal constructor( 45 private val groupExpansionManagerImpl: GroupExpansionManagerImpl, 46 private val notificationIconAreaController: NotificationIconAreaController, 47 private val renderListInteractor: RenderNotificationListInteractor, 48 private val activeNotificationsInteractor: ActiveNotificationsInteractor, 49 private val sensitiveNotificationProtectionController: 50 SensitiveNotificationProtectionController, 51 ) : Coordinator { 52 attachnull53 override fun attach(pipeline: NotifPipeline) { 54 pipeline.addOnAfterRenderListListener(::onAfterRenderList) 55 groupExpansionManagerImpl.attach(pipeline) 56 } 57 onAfterRenderListnull58 fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) = 59 traceSection("StackCoordinator.onAfterRenderList") { 60 val notifStats = calculateNotifStats(entries) 61 if (FooterViewRefactor.isEnabled) { 62 activeNotificationsInteractor.setNotifStats(notifStats) 63 } else { 64 controller.setNotifStats(notifStats) 65 } 66 if (NotificationIconContainerRefactor.isEnabled || FooterViewRefactor.isEnabled) { 67 renderListInteractor.setRenderedList(entries) 68 } 69 if (!NotificationIconContainerRefactor.isEnabled) { 70 notificationIconAreaController.updateNotificationIcons(entries) 71 } 72 } 73 calculateNotifStatsnull74 private fun calculateNotifStats(entries: List<ListEntry>): NotifStats { 75 var hasNonClearableAlertingNotifs = false 76 var hasClearableAlertingNotifs = false 77 var hasNonClearableSilentNotifs = false 78 var hasClearableSilentNotifs = false 79 val isSensitiveContentProtectionActive = screenshareNotificationHiding() && 80 screenshareNotificationHidingBugFix() && 81 sensitiveNotificationProtectionController.isSensitiveStateActive 82 entries.forEach { 83 val section = checkNotNull(it.section) { "Null section for ${it.key}" } 84 val entry = checkNotNull(it.representativeEntry) { "Null notif entry for ${it.key}" } 85 val isSilent = section.bucket == BUCKET_SILENT 86 // NOTE: NotificationEntry.isClearable will internally check group children to ensure 87 // the group itself definitively clearable. 88 val isClearable = !isSensitiveContentProtectionActive && entry.isClearable 89 when { 90 isSilent && isClearable -> hasClearableSilentNotifs = true 91 isSilent && !isClearable -> hasNonClearableSilentNotifs = true 92 !isSilent && isClearable -> hasClearableAlertingNotifs = true 93 !isSilent && !isClearable -> hasNonClearableAlertingNotifs = true 94 } 95 } 96 return NotifStats( 97 numActiveNotifs = entries.size, 98 hasNonClearableAlertingNotifs = hasNonClearableAlertingNotifs, 99 hasClearableAlertingNotifs = hasClearableAlertingNotifs, 100 hasNonClearableSilentNotifs = hasNonClearableSilentNotifs, 101 hasClearableSilentNotifs = hasClearableSilentNotifs 102 ) 103 } 104 } 105