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 java.io.PrintWriter 32 import javax.inject.Inject 33 34 private const val TAG = "GutsCoordinator" 35 36 /** 37 * Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline. 38 * Specifically, this just adds the lifetime extension necessary to keep guts from disappearing. 39 */ 40 @CoordinatorScope 41 class GutsCoordinator @Inject constructor( 42 private val notifGutsViewManager: NotifGutsViewManager, 43 private val logger: GutsCoordinatorLogger, 44 dumpManager: DumpManager 45 ) : Coordinator, Dumpable { 46 47 /** Keys of any Notifications for which we've been told the guts are open */ 48 private val notifsWithOpenGuts = ArraySet<String>() 49 50 /** Keys of any Notifications we've extended the lifetime for, based on guts */ 51 private val notifsExtendingLifetime = ArraySet<String>() 52 53 /** Callback for ending lifetime extension */ 54 private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null 55 56 init { 57 dumpManager.registerDumpable(TAG, this) 58 } 59 60 override fun attach(pipeline: NotifPipeline) { 61 notifGutsViewManager.setGutsListener(mGutsListener) 62 pipeline.addNotificationLifetimeExtender(mLifetimeExtender) 63 } 64 65 override fun dump(pw: PrintWriter, args: Array<String>) { 66 pw.println(" notifsWithOpenGuts: ${notifsWithOpenGuts.size}") 67 for (key in notifsWithOpenGuts) { 68 pw.println(" * $key") 69 } 70 pw.println(" notifsExtendingLifetime: ${notifsExtendingLifetime.size}") 71 for (key in notifsExtendingLifetime) { 72 pw.println(" * $key") 73 } 74 pw.println(" onEndLifetimeExtensionCallback: $onEndLifetimeExtensionCallback") 75 } 76 77 private val mLifetimeExtender: NotifLifetimeExtender = object : NotifLifetimeExtender { 78 override fun getName(): String { 79 return TAG 80 } 81 82 override fun setCallback(callback: OnEndLifetimeExtensionCallback) { 83 onEndLifetimeExtensionCallback = callback 84 } 85 86 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 94 override fun cancelLifetimeExtension(entry: NotificationEntry) { 95 notifsExtendingLifetime.remove(entry.key) 96 } 97 } 98 99 private val mGutsListener: NotifGutsViewListener = object : NotifGutsViewListener { 100 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 110 override fun onGutsClose(entry: NotificationEntry) { 111 logger.logGutsClosed(entry.key) 112 closeGutsAndEndLifetimeExtension(entry) 113 } 114 } 115 116 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