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 }