1 /*
2  * Copyright (C) 2020 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.init
18 
19 import android.service.notification.StatusBarNotification
20 import com.android.systemui.dagger.SysUISingleton
21 import com.android.systemui.people.widget.PeopleSpaceWidgetManager
22 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
23 import com.android.systemui.flags.FeatureFlags
24 import com.android.systemui.statusbar.NotificationListener
25 import com.android.systemui.statusbar.NotificationPresenter
26 import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
27 import com.android.systemui.statusbar.notification.NotificationActivityStarter
28 import com.android.systemui.statusbar.notification.NotificationClicker
29 import com.android.systemui.statusbar.notification.NotificationEntryManager
30 import com.android.systemui.statusbar.notification.NotificationListController
31 import com.android.systemui.statusbar.notification.collection.NotifPipeline
32 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
33 import com.android.systemui.statusbar.notification.collection.TargetSdkResolver
34 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
35 import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer
36 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
37 import com.android.systemui.statusbar.notification.interruption.HeadsUpController
38 import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
39 import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer
40 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
41 import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper
42 import com.android.systemui.statusbar.phone.StatusBar
43 import com.android.systemui.statusbar.policy.DeviceProvisionedController
44 import com.android.systemui.statusbar.policy.HeadsUpManager
45 import com.android.systemui.statusbar.policy.RemoteInputUriController
46 import com.android.wm.shell.bubbles.Bubbles
47 import dagger.Lazy
48 import java.io.FileDescriptor
49 import java.io.PrintWriter
50 import java.util.Optional
51 import javax.inject.Inject
52 
53 /**
54  * Master controller for all notifications-related work
55  *
56  * At the moment exposes a number of event-handler-esque methods; these are for historical reasons.
57  * Once we migrate away from the need for such things, this class becomes primarily a place to do
58  * any initialization work that notifications require.
59  */
60 @SysUISingleton
61 class NotificationsControllerImpl @Inject constructor(
62     private val featureFlags: FeatureFlags,
63     private val notificationListener: NotificationListener,
64     private val entryManager: NotificationEntryManager,
65     private val legacyRanker: NotificationRankingManager,
66     private val notifPipeline: Lazy<NotifPipeline>,
67     private val targetSdkResolver: TargetSdkResolver,
68     private val newNotifPipeline: Lazy<NotifPipelineInitializer>,
69     private val notifBindPipelineInitializer: NotifBindPipelineInitializer,
70     private val deviceProvisionedController: DeviceProvisionedController,
71     private val notificationRowBinder: NotificationRowBinderImpl,
72     private val remoteInputUriController: RemoteInputUriController,
73     private val groupManagerLegacy: Lazy<NotificationGroupManagerLegacy>,
74     private val groupAlertTransferHelper: NotificationGroupAlertTransferHelper,
75     private val headsUpManager: HeadsUpManager,
76     private val headsUpController: HeadsUpController,
77     private val headsUpViewBinder: HeadsUpViewBinder,
78     private val clickerBuilder: NotificationClicker.Builder,
79     private val animatedImageNotificationManager: AnimatedImageNotificationManager,
80     private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager
81 ) : NotificationsController {
82 
83     override fun initialize(
84         statusBar: StatusBar,
85         bubblesOptional: Optional<Bubbles>,
86         presenter: NotificationPresenter,
87         listContainer: NotificationListContainer,
88         notificationActivityStarter: NotificationActivityStarter,
89         bindRowCallback: NotificationRowBinderImpl.BindRowCallback
90     ) {
91         notificationListener.registerAsSystemService()
92 
93         val listController =
94                 NotificationListController(
95                         entryManager,
96                         listContainer,
97                         deviceProvisionedController)
98         listController.bind()
99 
100         notificationRowBinder.setNotificationClicker(
101                 clickerBuilder.build(
102                         Optional.of(statusBar), bubblesOptional, notificationActivityStarter))
103         notificationRowBinder.setUpWithPresenter(
104                 presenter,
105                 listContainer,
106                 bindRowCallback)
107         headsUpViewBinder.setPresenter(presenter)
108         notifBindPipelineInitializer.initialize()
109         animatedImageNotificationManager.bind()
110 
111         if (featureFlags.isNewNotifPipelineEnabled) {
112             newNotifPipeline.get().initialize(
113                     notificationListener,
114                     notificationRowBinder,
115                     listContainer)
116         }
117 
118         if (featureFlags.isNewNotifPipelineRenderingEnabled) {
119             targetSdkResolver.initialize(notifPipeline.get())
120             // TODO
121         } else {
122             targetSdkResolver.initialize(entryManager)
123             remoteInputUriController.attach(entryManager)
124             groupAlertTransferHelper.bind(entryManager, groupManagerLegacy.get())
125             headsUpManager.addListener(groupManagerLegacy.get())
126             headsUpManager.addListener(groupAlertTransferHelper)
127             headsUpController.attach(entryManager, headsUpManager)
128             groupManagerLegacy.get().setHeadsUpManager(headsUpManager)
129             groupAlertTransferHelper.setHeadsUpManager(headsUpManager)
130 
131             entryManager.initialize(notificationListener, legacyRanker)
132         }
133 
134         peopleSpaceWidgetManager.attach(notificationListener)
135     }
136 
137     override fun dump(
138         fd: FileDescriptor,
139         pw: PrintWriter,
140         args: Array<String>,
141         dumpTruck: Boolean
142     ) {
143         if (dumpTruck) {
144             entryManager.dump(pw, "  ")
145         }
146     }
147 
148     // TODO: Convert all functions below this line into listeners instead of public methods
149 
150     override fun requestNotificationUpdate(reason: String) {
151         entryManager.updateNotifications(reason)
152     }
153 
154     override fun resetUserExpandedStates() {
155         for (entry in entryManager.visibleNotifications) {
156             entry.resetUserExpansion()
157         }
158     }
159 
160     override fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) {
161         if (snoozeOption.snoozeCriterion != null) {
162             notificationListener.snoozeNotification(sbn.key, snoozeOption.snoozeCriterion.id)
163         } else {
164             notificationListener.snoozeNotification(
165                     sbn.key,
166                     snoozeOption.minutesToSnoozeFor * 60 * 1000.toLong())
167         }
168     }
169 
170     override fun getActiveNotificationsCount(): Int {
171         return entryManager.activeNotificationsCount
172     }
173 }
174