• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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