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 android.service.notification.NotificationListenerService 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.dagger.qualifiers.Main 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.NotificationEntry 25 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener 26 import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource 27 import java.util.concurrent.Executor 28 import javax.inject.Inject 29 30 /** 31 * A coordinator which provides callbacks to a view surfaces for various events relevant to the 32 * shade, such as when the user removes a notification, or when the shade is emptied. 33 */ 34 // TODO(b/204468557): Move to @CoordinatorScope 35 @SysUISingleton 36 class ShadeEventCoordinator @Inject internal constructor( 37 @Main private val mMainExecutor: Executor, 38 private val mLogger: ShadeEventCoordinatorLogger 39 ) : Coordinator, NotifShadeEventSource { 40 private var mNotifRemovedByUserCallback: Runnable? = null 41 private var mShadeEmptiedCallback: Runnable? = null 42 private var mEntryRemoved = false 43 private var mEntryRemovedByUser = false 44 attachnull45 override fun attach(pipeline: NotifPipeline) { 46 pipeline.addCollectionListener(mNotifCollectionListener) 47 pipeline.addOnBeforeRenderListListener(this::onBeforeRenderList) 48 } 49 50 private val mNotifCollectionListener = object : NotifCollectionListener { onEntryRemovednull51 override fun onEntryRemoved(entry: NotificationEntry, reason: Int) { 52 mEntryRemoved = true 53 mEntryRemovedByUser = 54 reason == NotificationListenerService.REASON_CLICK || 55 reason == NotificationListenerService.REASON_CANCEL_ALL || 56 reason == NotificationListenerService.REASON_CANCEL 57 } 58 } 59 setNotifRemovedByUserCallbacknull60 override fun setNotifRemovedByUserCallback(callback: Runnable) { 61 check(mNotifRemovedByUserCallback == null) { "mNotifRemovedByUserCallback already set" } 62 mNotifRemovedByUserCallback = callback 63 } 64 setShadeEmptiedCallbacknull65 override fun setShadeEmptiedCallback(callback: Runnable) { 66 check(mShadeEmptiedCallback == null) { "mShadeEmptiedCallback already set" } 67 mShadeEmptiedCallback = callback 68 } 69 onBeforeRenderListnull70 private fun onBeforeRenderList(entries: List<ListEntry>) { 71 if (mEntryRemoved && entries.isEmpty()) { 72 mLogger.logShadeEmptied() 73 // TODO(b/206023518): This was bad. Do not copy this. 74 mShadeEmptiedCallback?.let { mMainExecutor.execute(it) } 75 } 76 if (mEntryRemoved && mEntryRemovedByUser) { 77 mLogger.logNotifRemovedByUser() 78 // TODO(b/206023518): This was bad. Do not copy this. 79 mNotifRemovedByUserCallback?.let { mMainExecutor.execute(it) } 80 } 81 mEntryRemoved = false 82 mEntryRemovedByUser = false 83 } 84 }