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.ListEntry 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.coordinator.dagger.CoordinatorScope 25 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender 26 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback 27 import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener 28 import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager 29 import com.android.systemui.statusbar.notification.row.NotificationGuts 30 import com.android.systemui.statusbar.notification.row.NotificationGutsManager 31 import com.android.systemui.util.asIndenting 32 import com.android.systemui.util.printCollection 33 import com.android.systemui.util.println 34 import com.android.systemui.util.withIncreasedIndent 35 import java.io.PrintWriter 36 import javax.inject.Inject 37 38 private const val TAG = "GutsCoordinator" 39 40 /** 41 * Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline. 42 * Specifically, this just adds the lifetime extension necessary to keep guts from disappearing. 43 */ 44 @CoordinatorScope 45 class GutsCoordinator @Inject constructor( 46 private val notifGutsViewManager: NotifGutsViewManager, 47 private val logger: GutsCoordinatorLogger, 48 dumpManager: DumpManager 49 ) : Coordinator, Dumpable { 50 51 /** Keys of any Notifications for which we've been told the guts are open */ 52 private val notifsWithOpenGuts = ArraySet<String>() 53 54 /** Keys of any Notifications we've extended the lifetime for, based on guts */ 55 private val notifsExtendingLifetime = ArraySet<String>() 56 57 /** Callback for ending lifetime extension */ 58 private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null 59 60 init { 61 dumpManager.registerDumpable(this) 62 } 63 attachnull64 override fun attach(pipeline: NotifPipeline) { 65 notifGutsViewManager.setGutsListener(mGutsListener) 66 pipeline.addNotificationLifetimeExtender(mLifetimeExtender) 67 } 68 <lambda>null69 override fun dump(pw: PrintWriter, args: Array<String>) = pw.asIndenting().run { 70 withIncreasedIndent { 71 printCollection("notifsWithOpenGuts", notifsWithOpenGuts) 72 printCollection("notifsExtendingLifetime", notifsExtendingLifetime) 73 println("onEndLifetimeExtensionCallback", onEndLifetimeExtensionCallback) 74 } 75 } 76 77 private val mLifetimeExtender: NotifLifetimeExtender = object : NotifLifetimeExtender { getNamenull78 override fun getName(): String { 79 return TAG 80 } 81 setCallbacknull82 override fun setCallback(callback: OnEndLifetimeExtensionCallback) { 83 onEndLifetimeExtensionCallback = callback 84 } 85 maybeExtendLifetimenull86 override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean { 87 val isShowingGuts = isCurrentlyShowingGuts(entry) 88 if (isShowingGuts) { 89 notifsExtendingLifetime.add(entry.key) 90 } 91 return isShowingGuts 92 } 93 cancelLifetimeExtensionnull94 override fun cancelLifetimeExtension(entry: NotificationEntry) { 95 notifsExtendingLifetime.remove(entry.key) 96 } 97 } 98 99 private val mGutsListener: NotifGutsViewListener = object : NotifGutsViewListener { onGutsOpennull100 override fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts) { 101 logger.logGutsOpened(entry.key, guts) 102 if (guts.isLeavebehind) { 103 // leave-behind guts should not extend the lifetime of the notification 104 closeGutsAndEndLifetimeExtension(entry) 105 } else { 106 notifsWithOpenGuts.add(entry.key) 107 } 108 } 109 onGutsClosenull110 override fun onGutsClose(entry: NotificationEntry) { 111 logger.logGutsClosed(entry.key) 112 closeGutsAndEndLifetimeExtension(entry) 113 } 114 } 115 isCurrentlyShowingGutsnull116 private fun isCurrentlyShowingGuts(entry: ListEntry) = 117 notifsWithOpenGuts.contains(entry.key) 118 119 private fun closeGutsAndEndLifetimeExtension(entry: NotificationEntry) { 120 notifsWithOpenGuts.remove(entry.key) 121 if (notifsExtendingLifetime.remove(entry.key)) { 122 onEndLifetimeExtensionCallback?.onEndLifetimeExtension(mLifetimeExtender, entry) 123 } 124 } 125 } 126