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