• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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
18 
19 import androidx.lifecycle.Observer
20 import com.android.systemui.dagger.SysUISingleton
21 import com.android.systemui.dagger.qualifiers.Main
22 import com.android.systemui.util.Assert
23 import com.android.systemui.util.ListenerSet
24 import com.android.systemui.util.isNotEmpty
25 import com.android.systemui.util.traceSection
26 import java.util.Collections.unmodifiableList
27 import java.util.concurrent.Executor
28 import java.util.concurrent.atomic.AtomicReference
29 import javax.inject.Inject
30 
31 /** Writeable implementation of [NotifLiveDataStore] */
32 @SysUISingleton
33 class NotifLiveDataStoreImpl @Inject constructor(
34     @Main private val mainExecutor: Executor
35 ) : NotifLiveDataStore {
36     private val hasActiveNotifsPrivate = NotifLiveDataImpl(
37         name = "hasActiveNotifs",
38         initialValue = false,
39         mainExecutor
40     )
41     private val activeNotifCountPrivate = NotifLiveDataImpl(
42         name = "activeNotifCount",
43         initialValue = 0,
44         mainExecutor
45     )
46     private val activeNotifListPrivate = NotifLiveDataImpl(
47         name = "activeNotifList",
48         initialValue = listOf<NotificationEntry>(),
49         mainExecutor
50     )
51 
52     override val hasActiveNotifs: NotifLiveData<Boolean> = hasActiveNotifsPrivate
53     override val activeNotifCount: NotifLiveData<Int> = activeNotifCountPrivate
54     override val activeNotifList: NotifLiveData<List<NotificationEntry>> = activeNotifListPrivate
55 
56     /** Set the latest flattened list of notification entries. */
57     fun setActiveNotifList(flatEntryList: List<NotificationEntry>) {
58         traceSection("NotifLiveDataStore.setActiveNotifList") {
59             Assert.isMainThread()
60             val unmodifiableCopy = unmodifiableList(flatEntryList.toList())
61             // This ensures we set all values before dispatching to any observers
62             listOf(
63                 activeNotifListPrivate.setValueAndProvideDispatcher(unmodifiableCopy),
64                 activeNotifCountPrivate.setValueAndProvideDispatcher(unmodifiableCopy.size),
65                 hasActiveNotifsPrivate.setValueAndProvideDispatcher(unmodifiableCopy.isNotEmpty())
66             ).forEach { dispatcher -> dispatcher.invoke() }
67         }
68     }
69 }
70 
71 /** Read-write implementation of [NotifLiveData] */
72 class NotifLiveDataImpl<T>(
73     private val name: String,
74     initialValue: T,
75     @Main private val mainExecutor: Executor
76 ) : NotifLiveData<T> {
77     private val syncObservers = ListenerSet<Observer<T>>()
78     private val asyncObservers = ListenerSet<Observer<T>>()
79     private val atomicValue = AtomicReference(initialValue)
80     private var lastAsyncValue: T? = null
81 
dispatchToAsyncObserversnull82     private fun dispatchToAsyncObservers() {
83         val value = atomicValue.get()
84         if (lastAsyncValue != value) {
85             lastAsyncValue = value
86             traceSection("NotifLiveData($name).dispatchToAsyncObservers") {
87                 asyncObservers.forEach { it.onChanged(value) }
88             }
89         }
90     }
91 
92     /**
93      * Access or set the current value.
94      *
95      * When setting, sync observers will be dispatched synchronously, and a task will be posted to
96      * dispatch the value to async observers.
97      */
98     override var value: T
99         get() = atomicValue.get()
100         set(value) = setValueAndProvideDispatcher(value).invoke()
101 
102     /**
103      * Set the value, and return a function that when invoked will dispatch to the observers.
104      *
105      * This is intended to allow multiple instances with related data to be updated together and
106      * have their dispatchers invoked after all data has been updated.
107      */
setValueAndProvideDispatchernull108     fun setValueAndProvideDispatcher(value: T): () -> Unit {
109         val oldValue = atomicValue.getAndSet(value)
110         if (oldValue != value) {
111             return {
112                 if (syncObservers.isNotEmpty()) {
113                     traceSection("NotifLiveData($name).dispatchToSyncObservers") {
114                         syncObservers.forEach { it.onChanged(value) }
115                     }
116                 }
117                 if (asyncObservers.isNotEmpty()) {
118                     mainExecutor.execute(::dispatchToAsyncObservers)
119                 }
120             }
121         }
122         return {}
123     }
124 
addSyncObservernull125     override fun addSyncObserver(observer: Observer<T>) {
126         syncObservers.addIfAbsent(observer)
127     }
128 
addAsyncObservernull129     override fun addAsyncObserver(observer: Observer<T>) {
130         asyncObservers.addIfAbsent(observer)
131     }
132 
removeObservernull133     override fun removeObserver(observer: Observer<T>) {
134         syncObservers.remove(observer)
135         asyncObservers.remove(observer)
136     }
137 }