• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.systemui.statusbar.notification.collection.coordinator
17 
18 import android.util.ArraySet
19 import com.android.systemui.Dumpable
20 import com.android.systemui.dump.DumpManager
21 import com.android.systemui.statusbar.notification.collection.EntryAdapter
22 import com.android.systemui.statusbar.notification.collection.NotifPipeline
23 import com.android.systemui.statusbar.notification.collection.NotificationEntry
24 import com.android.systemui.statusbar.notification.collection.PipelineEntry
25 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
26 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
27 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
28 import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener
29 import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
30 import com.android.systemui.statusbar.notification.row.NotificationGuts
31 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
32 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
33 import com.android.systemui.util.asIndenting
34 import com.android.systemui.util.printCollection
35 import com.android.systemui.util.println
36 import com.android.systemui.util.withIncreasedIndent
37 import java.io.PrintWriter
38 import javax.inject.Inject
39 
40 private const val TAG = "GutsCoordinator"
41 
42 /**
43  * Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline. Specifically,
44  * this just adds the lifetime extension necessary to keep guts from disappearing.
45  */
46 @CoordinatorScope
47 class GutsCoordinator
48 @Inject
49 constructor(
50     private val notifGutsViewManager: NotifGutsViewManager,
51     private val logger: GutsCoordinatorLogger,
52     dumpManager: DumpManager,
53 ) : Coordinator, Dumpable {
54 
55     /** Keys of any Notifications for which we've been told the guts are open */
56     private val notifsWithOpenGuts = ArraySet<String>()
57 
58     /** Keys of any Notifications we've extended the lifetime for, based on guts */
59     private val notifsExtendingLifetime = ArraySet<String>()
60 
61     /** Callback for ending lifetime extension */
62     private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null
63 
64     init {
65         dumpManager.registerDumpable(this)
66     }
67 
attachnull68     override fun attach(pipeline: NotifPipeline) {
69         notifGutsViewManager.setGutsListener(mGutsListener)
70         pipeline.addNotificationLifetimeExtender(mLifetimeExtender)
71     }
72 
dumpnull73     override fun dump(pw: PrintWriter, args: Array<String>) =
74         pw.asIndenting().run {
75             withIncreasedIndent {
76                 printCollection("notifsWithOpenGuts", notifsWithOpenGuts)
77                 printCollection("notifsExtendingLifetime", notifsExtendingLifetime)
78                 println("onEndLifetimeExtensionCallback", onEndLifetimeExtensionCallback)
79             }
80         }
81 
82     private val mLifetimeExtender: NotifLifetimeExtender =
83         object : NotifLifetimeExtender {
getNamenull84             override fun getName(): String {
85                 return TAG
86             }
87 
setCallbacknull88             override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
89                 onEndLifetimeExtensionCallback = callback
90             }
91 
maybeExtendLifetimenull92             override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
93                 val isShowingGuts = isCurrentlyShowingGuts(entry)
94                 if (isShowingGuts) {
95                     notifsExtendingLifetime.add(entry.key)
96                 }
97                 return isShowingGuts
98             }
99 
cancelLifetimeExtensionnull100             override fun cancelLifetimeExtension(entry: NotificationEntry) {
101                 notifsExtendingLifetime.remove(entry.key)
102             }
103         }
104 
105     private val mGutsListener: NotifGutsViewListener =
106         object : NotifGutsViewListener {
onGutsOpennull107             override fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts) {
108                 NotificationBundleUi.assertInLegacyMode()
109                 logger.logGutsOpened(entry.key, guts)
110                 if (guts.isLeavebehind) {
111                     // leave-behind guts should not extend the lifetime of the notification
112                     closeGutsAndEndLifetimeExtension(entry)
113                 } else {
114                     notifsWithOpenGuts.add(entry.key)
115                 }
116             }
117 
onGutsClosenull118             override fun onGutsClose(entry: NotificationEntry) {
119                 NotificationBundleUi.assertInLegacyMode()
120                 logger.logGutsClosed(entry.key)
121                 closeGutsAndEndLifetimeExtension(entry)
122             }
123 
onGutsOpennull124             override fun onGutsOpen(entryAdapter: EntryAdapter, guts: NotificationGuts) {
125                 NotificationBundleUi.isUnexpectedlyInLegacyMode()
126                 logger.logGutsOpened(entryAdapter.key, guts)
127                 if (guts.isLeavebehind) {
128                     // leave-behind guts should not extend the lifetime of the notification
129                     closeGutsAndEndLifetimeExtension(entryAdapter)
130                 } else {
131                     notifsWithOpenGuts.add(entryAdapter.key)
132                 }
133             }
134 
onGutsClosenull135             override fun onGutsClose(entryAdapter: EntryAdapter) {
136                 NotificationBundleUi.isUnexpectedlyInLegacyMode()
137                 logger.logGutsClosed(entryAdapter.key)
138                 closeGutsAndEndLifetimeExtension(entryAdapter)
139             }
140         }
141 
isCurrentlyShowingGutsnull142     private fun isCurrentlyShowingGuts(entry: PipelineEntry) =
143         notifsWithOpenGuts.contains(entry.key)
144 
145     private fun closeGutsAndEndLifetimeExtension(entry: NotificationEntry) {
146         notifsWithOpenGuts.remove(entry.key)
147         if (notifsExtendingLifetime.remove(entry.key)) {
148             onEndLifetimeExtensionCallback?.onEndLifetimeExtension(mLifetimeExtender, entry)
149         }
150     }
151 
closeGutsAndEndLifetimeExtensionnull152     private fun closeGutsAndEndLifetimeExtension(entryAdapter: EntryAdapter) {
153         notifsWithOpenGuts.remove(entryAdapter.key)
154         if (notifsExtendingLifetime.remove(entryAdapter.key)) {
155             entryAdapter.endLifetimeExtension(onEndLifetimeExtensionCallback, mLifetimeExtender)
156         }
157     }
158 }
159