1 /* <lambda>null2 * Copyright (C) 2024 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.settingslib.datastore 18 19 import androidx.annotation.AnyThread 20 import androidx.annotation.GuardedBy 21 import androidx.collection.MutableScatterMap 22 import com.google.errorprone.annotations.CanIgnoreReturnValue 23 import java.util.WeakHashMap 24 import java.util.concurrent.Executor 25 import java.util.concurrent.atomic.AtomicInteger 26 27 /** 28 * Callback to be informed of changes in [KeyedObservable] object. 29 * 30 * The observer is weakly referenced, a strong reference must be kept. 31 */ 32 fun interface KeyedObserver<in K> { 33 /** 34 * Called by [KeyedObservable] in the event of changes. 35 * 36 * This callback will run in the given [Executor] when observer is added. 37 * 38 * @param key key that has been changed 39 * @param reason the reason of change 40 * @see KeyedObservable.addObserver 41 */ 42 fun onKeyChanged(key: K, reason: Int) 43 } 44 45 /** 46 * A key-value observable object allows to observe change with [KeyedObserver]. 47 * 48 * Notes: 49 * - The order in which observers will be notified is unspecified. 50 * - The observer is weakly referenced to avoid memory leaking, the call site must keep a strong 51 * reference of the observer. 52 * - It is possible that the callback may be triggered even there is no real data change. For 53 * example, when data restore/clear happens, it might be too complex to check if data is really 54 * changed, thus all the registered observers are notified directly. 55 */ 56 @AnyThread 57 interface KeyedObservable<K> { 58 /** 59 * Adds an observer for any key. 60 * 61 * The observer will be notified whenever a change happens. The [KeyedObserver.onKeyChanged] 62 * callback will be invoked with specific key that is modified. However, `null` key is passed in 63 * the cases that a bunch of keys are changed simultaneously (e.g. clear data, restore happens). 64 * 65 * @param observer observer to be notified 66 * @param executor executor to run the callback 67 * @return if the observer is newly added 68 */ addObservernull69 @CanIgnoreReturnValue fun addObserver(observer: KeyedObserver<K?>, executor: Executor): Boolean 70 71 /** 72 * Adds an observer on given key. 73 * 74 * The observer will be notified only when the given key is changed. 75 * 76 * @param key key to observe 77 * @param observer observer to be notified 78 * @param executor executor to run the callback 79 * @return if the observer is newly added 80 */ 81 @CanIgnoreReturnValue 82 fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor): Boolean 83 84 /** 85 * Removes observer. 86 * 87 * @return if the observer is found and removed 88 */ 89 @CanIgnoreReturnValue fun removeObserver(observer: KeyedObserver<K?>): Boolean 90 91 /** 92 * Removes observer on given key. 93 * 94 * @return if the observer is found and removed 95 */ 96 @CanIgnoreReturnValue fun removeObserver(key: K, observer: KeyedObserver<K>): Boolean 97 98 /** 99 * Notifies all observers that a change occurs. 100 * 101 * All the any key and keyed observers are notified. 102 * 103 * @param reason reason of the change 104 */ 105 fun notifyChange(reason: Int) 106 107 /** 108 * Notifies observers that a change occurs on given key. 109 * 110 * The any key and specific key observers are notified. 111 * 112 * @param key key of the change 113 * @param reason reason of the change 114 */ 115 fun notifyChange(key: K, reason: Int) 116 } 117 118 /** Delegation of [KeyedObservable]. */ 119 interface KeyedObservableDelegate<K> : KeyedObservable<K> { 120 121 /** [KeyedObservable] to delegate. */ 122 val keyedObservableDelegate: KeyedObservable<K> 123 124 override fun addObserver(observer: KeyedObserver<K?>, executor: Executor): Boolean = 125 keyedObservableDelegate.addObserver(observer, executor) 126 127 override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor): Boolean = 128 keyedObservableDelegate.addObserver(key, observer, executor) 129 130 override fun removeObserver(observer: KeyedObserver<K?>): Boolean = 131 keyedObservableDelegate.removeObserver(observer) 132 133 override fun removeObserver(key: K, observer: KeyedObserver<K>): Boolean = 134 keyedObservableDelegate.removeObserver(key, observer) 135 136 override fun notifyChange(reason: Int): Unit = keyedObservableDelegate.notifyChange(reason) 137 138 override fun notifyChange(key: K, reason: Int): Unit = 139 keyedObservableDelegate.notifyChange(key, reason) 140 } 141 142 /** A thread safe implementation of [KeyedObservable]. */ 143 open class KeyedDataObservable<K> : KeyedObservable<K> { 144 // Instead of @GuardedBy("this"), guarded by itself because KeyedDataObservable object could be 145 // synchronized outside by the holder 146 @GuardedBy("itself") private val observers = WeakHashMap<KeyedObserver<K?>, Executor>() 147 148 @GuardedBy("itself") 149 private val keyedObservers = MutableScatterMap<K, WeakHashMap<KeyedObserver<K>, Executor>>() 150 151 @CanIgnoreReturnValue addObservernull152 override fun addObserver(observer: KeyedObserver<K?>, executor: Executor): Boolean { 153 val oldExecutor = synchronized(observers) { observers.put(observer, executor) } 154 if (oldExecutor != null && oldExecutor != executor) { 155 throw IllegalStateException("Add $observer twice, old=$oldExecutor, new=$executor") 156 } 157 return oldExecutor == null 158 } 159 160 @CanIgnoreReturnValue addObservernull161 override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor): Boolean { 162 val oldExecutor = 163 synchronized(keyedObservers) { 164 keyedObservers.getOrPut(key) { WeakHashMap() }.put(observer, executor) 165 } 166 if (oldExecutor != null && oldExecutor != executor) { 167 throw IllegalStateException("Add $observer twice, old=$oldExecutor, new=$executor") 168 } 169 return oldExecutor == null 170 } 171 172 @CanIgnoreReturnValue removeObservernull173 override fun removeObserver(observer: KeyedObserver<K?>) = 174 synchronized(observers) { observers.remove(observer) } != null 175 176 @CanIgnoreReturnValue removeObservernull177 override fun removeObserver(key: K, observer: KeyedObserver<K>) = 178 synchronized(keyedObservers) { 179 val observers = keyedObservers[key] ?: return false 180 val removed = observers.remove(observer) != null 181 if (removed && observers.isEmpty()) { 182 keyedObservers.remove(key) 183 } 184 removed 185 } 186 notifyChangenull187 override fun notifyChange(reason: Int) { 188 // make a copy to avoid potential ConcurrentModificationException 189 val observers = synchronized(observers) { observers.entries.toTypedArray() } 190 val keyedObservers = synchronized(keyedObservers) { keyedObservers.copy() } 191 for (entry in observers) { 192 val observer = entry.key // avoid reference "entry" 193 entry.value.execute { observer.onKeyChanged(null, reason) } 194 } 195 for (pair in keyedObservers) { 196 val key = pair.first 197 for (entry in pair.second) { 198 val observer = entry.key // avoid reference "entry" 199 entry.value.execute { observer.onKeyChanged(key, reason) } 200 } 201 } 202 } 203 MutableScatterMapnull204 private fun MutableScatterMap<K, WeakHashMap<KeyedObserver<K>, Executor>>.copy(): 205 List<Pair<K, Array<Map.Entry<KeyedObserver<K>, Executor>>>> { 206 val result = ArrayList<Pair<K, Array<Map.Entry<KeyedObserver<K>, Executor>>>>(size) 207 forEach { key, value -> result.add(Pair(key, value.entries.toTypedArray())) } 208 return result 209 } 210 notifyChangenull211 override fun notifyChange(key: K, reason: Int) { 212 // make a copy to avoid potential ConcurrentModificationException 213 val observers = synchronized(observers) { observers.entries.toTypedArray() } 214 val keyedObservers = 215 synchronized(keyedObservers) { keyedObservers[key]?.entries?.toTypedArray() } 216 ?: arrayOf() 217 for (entry in observers) { 218 val observer = entry.key // avoid reference "entry" 219 entry.value.execute { observer.onKeyChanged(key, reason) } 220 } 221 for (entry in keyedObservers) { 222 val observer = entry.key // avoid reference "entry" 223 entry.value.execute { observer.onKeyChanged(key, reason) } 224 } 225 } 226 hasAnyObservernull227 open fun hasAnyObserver(): Boolean { 228 synchronized(observers) { if (observers.isNotEmpty()) return true } 229 synchronized(keyedObservers) { if (keyedObservers.isNotEmpty()) return true } 230 return false 231 } 232 } 233 234 /** [KeyedDataObservable] that maintains a counter for the observers. */ 235 abstract class AbstractKeyedDataObservable<K> : KeyedDataObservable<K>() { 236 /** 237 * Counter of observers. 238 * 239 * The value is accurate only when [addObserver] and [removeObserver] are invoked in pairs. 240 */ 241 private val counter = AtomicInteger() 242 addObservernull243 override fun addObserver(observer: KeyedObserver<K?>, executor: Executor) = 244 if (super.addObserver(observer, executor)) { 245 onObserverAdded() 246 true 247 } else { 248 false 249 } 250 addObservernull251 override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor) = 252 if (super.addObserver(key, observer, executor)) { 253 onObserverAdded() 254 true 255 } else { 256 false 257 } 258 onObserverAddednull259 private fun onObserverAdded() { 260 if (counter.getAndIncrement() == 0) onFirstObserverAdded() 261 } 262 263 /** Callbacks when the first observer is just added. */ onFirstObserverAddednull264 protected abstract fun onFirstObserverAdded() 265 266 override fun removeObserver(observer: KeyedObserver<K?>) = 267 if (super.removeObserver(observer)) { 268 onObserverRemoved() 269 true 270 } else { 271 false 272 } 273 removeObservernull274 override fun removeObserver(key: K, observer: KeyedObserver<K>) = 275 if (super.removeObserver(key, observer)) { 276 onObserverRemoved() 277 true 278 } else { 279 false 280 } 281 onObserverRemovednull282 private fun onObserverRemoved() { 283 if (counter.decrementAndGet() == 0) onLastObserverRemoved() 284 } 285 286 /** Callbacks when the last observer is just removed. */ onLastObserverRemovednull287 protected abstract fun onLastObserverRemoved() 288 289 override fun hasAnyObserver() = counter.get() > 0 290 } 291 292 /** [KeyedObservable] with no-op implementations for all interfaces. */ 293 open class NoOpKeyedObservable<K> : KeyedObservable<K> { 294 295 override fun addObserver(observer: KeyedObserver<K?>, executor: Executor) = true 296 297 override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor) = true 298 299 override fun removeObserver(observer: KeyedObserver<K?>) = true 300 301 override fun removeObserver(key: K, observer: KeyedObserver<K>) = true 302 303 override fun notifyChange(reason: Int) {} 304 305 override fun notifyChange(key: K, reason: Int) {} 306 } 307