Merge "Formalize CoreCoordinators" into udc-dev am: e7482b5c42 am: 1cbefacd3a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22792430

Change-Id: I4bb04791d70d5f604e18e791eb66e04aa2e76ebd
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt
index 8aa6b81..d95d593 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt
@@ -32,7 +32,7 @@
 @SysUISingleton
 class NotifLiveDataStoreImpl @Inject constructor(
     @Main private val mainExecutor: Executor
-) : NotifLiveDataStore {
+) : NotifLiveDataStore, PipelineDumpable {
     private val hasActiveNotifsPrivate = NotifLiveDataImpl(
         name = "hasActiveNotifs",
         initialValue = false,
@@ -66,6 +66,12 @@
             ).forEach { dispatcher -> dispatcher.invoke() }
         }
     }
+
+    override fun dumpPipeline(d: PipelineDumper) {
+        d.dump("activeNotifListPrivate", activeNotifListPrivate)
+        d.dump("activeNotifCountPrivate", activeNotifCountPrivate)
+        d.dump("hasActiveNotifsPrivate", hasActiveNotifsPrivate)
+    }
 }
 
 /** Read-write implementation of [NotifLiveData] */
@@ -73,7 +79,7 @@
     private val name: String,
     initialValue: T,
     @Main private val mainExecutor: Executor
-) : NotifLiveData<T> {
+) : NotifLiveData<T>, PipelineDumpable {
     private val syncObservers = ListenerSet<Observer<T>>()
     private val asyncObservers = ListenerSet<Observer<T>>()
     private val atomicValue = AtomicReference(initialValue)
@@ -134,4 +140,9 @@
         syncObservers.remove(observer)
         asyncObservers.remove(observer)
     }
+
+    override fun dumpPipeline(d: PipelineDumper) {
+        d.dump("syncObservers", syncObservers)
+        d.dump("asyncObservers", asyncObservers)
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CoreCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CoreCoordinator.kt
new file mode 100644
index 0000000..75e461c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CoreCoordinator.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.statusbar.notification.collection.PipelineDumpable
+
+/**
+ * A special type of [Coordinator] that is also a core part of the pipeline, and so is also a
+ * [PipelineDumpable].
+ */
+interface CoreCoordinator : Coordinator, PipelineDumpable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
index 8e307ec..dc8ff63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.PipelineDumper
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
 import com.android.systemui.statusbar.notification.collection.render.requireSummary
 import javax.inject.Inject
@@ -32,13 +33,17 @@
 @CoordinatorScope
 class DataStoreCoordinator @Inject internal constructor(
     private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl
-) : Coordinator {
+) : CoreCoordinator {
 
     override fun attach(pipeline: NotifPipeline) {
         pipeline.addOnAfterRenderListListener { entries, _ -> onAfterRenderList(entries) }
     }
 
-    fun onAfterRenderList(entries: List<ListEntry>) {
+    override fun dumpPipeline(d: PipelineDumper) {
+        d.dump("notifLiveDataStoreImpl", notifLiveDataStoreImpl)
+    }
+
+    private fun onAfterRenderList(entries: List<ListEntry>) {
         val flatEntryList = flattenedEntryList(entries)
         notifLiveDataStoreImpl.setActiveNotifList(flatEntryList)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 02ce0d4..e5953cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.statusbar.notification.collection.coordinator
 
-import com.android.systemui.statusbar.notification.NotifPipelineFlags
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.PipelineDumpable
 import com.android.systemui.statusbar.notification.collection.PipelineDumper
@@ -32,7 +31,6 @@
 
 @CoordinatorScope
 class NotifCoordinatorsImpl @Inject constructor(
-        notifPipelineFlags: NotifPipelineFlags,
         sectionStyleProvider: SectionStyleProvider,
         dataStoreCoordinator: DataStoreCoordinator,
         hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
@@ -61,6 +59,7 @@
         dismissibilityCoordinator: DismissibilityCoordinator,
 ) : NotifCoordinators {
 
+    private val mCoreCoordinators: MutableList<CoreCoordinator> = ArrayList()
     private val mCoordinators: MutableList<Coordinator> = ArrayList()
     private val mOrderedSections: MutableList<NotifSectioner> = ArrayList()
 
@@ -68,11 +67,8 @@
      * Creates all the coordinators.
      */
     init {
-        // TODO(b/208866714): formalize the system by which some coordinators may be required by the
-        //  pipeline, such as this DataStoreCoordinator which cannot be removed, as it's a critical
-        //  glue between the pipeline and parts of SystemUI which depend on pipeline output via the
-        //  NotifLiveDataStore.
-        mCoordinators.add(dataStoreCoordinator)
+        // Attach core coordinators.
+        mCoreCoordinators.add(dataStoreCoordinator)
 
         // Attach normal coordinators.
         mCoordinators.add(hideLocallyDismissedNotifsCoordinator)
@@ -122,6 +118,9 @@
      * [Pluggable]s, [NotifCollectionListener]s and [NotifLifetimeExtender]s.
      */
     override fun attach(pipeline: NotifPipeline) {
+        for (c in mCoreCoordinators) {
+            c.attach(pipeline)
+        }
         for (c in mCoordinators) {
             c.attach(pipeline)
         }
@@ -133,7 +132,8 @@
      * as they are dumped in the RenderStageManager instead.
      */
     override fun dumpPipeline(d: PipelineDumper) = with(d) {
-        dump("coordinators", mCoordinators)
+        dump("core coordinators", mCoreCoordinators)
+        dump("normal coordinators", mCoordinators)
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt b/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
index 4f20067..a47e614 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
@@ -22,34 +22,27 @@
  * A collection of listeners, observers, callbacks, etc.
  *
  * This container is optimized for infrequent mutation and frequent iteration, with thread safety
- * and reentrant-safety guarantees as well.
+ * and reentrant-safety guarantees as well. Specifically, to ensure that
+ * [ConcurrentModificationException] is never thrown, this iterator will not reflect changes made to
+ * the set after the iterator is constructed.
  */
-class ListenerSet<E> : Iterable<E> {
-    private val listeners: CopyOnWriteArrayList<E> = CopyOnWriteArrayList()
+class ListenerSet<E : Any>
+/** Private constructor takes the internal list so that we can use auto-delegation */
+private constructor(private val listeners: CopyOnWriteArrayList<E>) :
+    Collection<E> by listeners, Set<E> {
+
+    /** Create a new instance */
+    constructor() : this(CopyOnWriteArrayList())
 
     /**
-     * A thread-safe, reentrant-safe method to add a listener.
-     * Does nothing if the listener is already in the set.
+     * A thread-safe, reentrant-safe method to add a listener. Does nothing if the listener is
+     * already in the set.
      */
     fun addIfAbsent(element: E): Boolean = listeners.addIfAbsent(element)
 
-    /**
-     * A thread-safe, reentrant-safe method to remove a listener.
-     */
+    /** A thread-safe, reentrant-safe method to remove a listener. */
     fun remove(element: E): Boolean = listeners.remove(element)
-
-    /**
-     * Determine if the listener set is empty
-     */
-    fun isEmpty(): Boolean = listeners.isEmpty()
-
-    /**
-     * Returns an iterator over the listeners currently in the set.  Note that to ensure
-     * [ConcurrentModificationException] is never thrown, this iterator will not reflect changes
-     * made to the set after the iterator is constructed.
-     */
-    override fun iterator(): Iterator<E> = listeners.iterator()
 }
 
 /** Extension to match Collection which is implemented to only be (easily) accessible in kotlin */
-fun <T> ListenerSet<T>.isNotEmpty(): Boolean = !isEmpty()
+fun <T : Any> ListenerSet<T>.isNotEmpty(): Boolean = !isEmpty()