Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 29082769 authored by Jacky Wang's avatar Jacky Wang
Browse files

[Catalyst] Provide AbstractKeyedDataObservable

Bug: 325144964
Flag: EXEMPT library
Test: manual
Change-Id: I2721a34e80efcae47c34703042d183f940fe8af5
parent 2c015f02
Loading
Loading
Loading
Loading
+60 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import androidx.collection.MutableScatterMap
import com.google.errorprone.annotations.CanIgnoreReturnValue
import java.util.WeakHashMap
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicInteger

/**
 * Callback to be informed of changes in [KeyedObservable] object.
@@ -203,13 +204,71 @@ open class KeyedDataObservable<K> : KeyedObservable<K> {
        }
    }

    fun hasAnyObserver(): Boolean {
    open fun hasAnyObserver(): Boolean {
        synchronized(observers) { if (observers.isNotEmpty()) return true }
        synchronized(keyedObservers) { if (keyedObservers.isNotEmpty()) return true }
        return false
    }
}

/** [KeyedDataObservable] that maintains a counter for the observers. */
abstract class AbstractKeyedDataObservable<K> : KeyedDataObservable<K>() {
    /**
     * Counter of observers.
     *
     * The value is accurate only when [addObserver] and [removeObserver] are invoked in pairs.
     */
    private val counter = AtomicInteger()

    override fun addObserver(observer: KeyedObserver<K?>, executor: Executor) =
        if (super.addObserver(observer, executor)) {
            onObserverAdded()
            true
        } else {
            false
        }

    override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor) =
        if (super.addObserver(key, observer, executor)) {
            onObserverAdded()
            true
        } else {
            false
        }

    private fun onObserverAdded() {
        if (counter.getAndIncrement() == 0) onFirstObserverAdded()
    }

    /** Callbacks when the first observer is just added. */
    protected abstract fun onFirstObserverAdded()

    override fun removeObserver(observer: KeyedObserver<K?>) =
        if (super.removeObserver(observer)) {
            onObserverRemoved()
            true
        } else {
            false
        }

    override fun removeObserver(key: K, observer: KeyedObserver<K>) =
        if (super.removeObserver(key, observer)) {
            onObserverRemoved()
            true
        } else {
            false
        }

    private fun onObserverRemoved() {
        if (counter.decrementAndGet() == 0) onLastObserverRemoved()
    }

    /** Callbacks when the last observer is just removed. */
    protected abstract fun onLastObserverRemoved()

    override fun hasAnyObserver() = counter.get() > 0
}

/** [KeyedObservable] with no-op implementations for all interfaces. */
open class NoOpKeyedObservable<K> : KeyedObservable<K> {

+5 −50
Original line number Diff line number Diff line
@@ -20,21 +20,10 @@ import android.content.ContentResolver
import android.database.ContentObserver
import android.net.Uri
import android.util.Log
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicInteger

/** Base class of the Settings provider data stores. */
abstract class SettingsStore(protected val contentResolver: ContentResolver) :
    KeyedDataObservable<String>(), KeyValueStore {

    /**
     * Counter of observers.
     *
     * The value is accurate only when [addObserver] and [removeObserver] are called correctly. When
     * an observer is not removed (and its weak reference is garbage collected), the content
     * observer is not unregistered but this is not a big deal.
     */
    private val counter = AtomicInteger()
    AbstractKeyedDataObservable<String>(), KeyValueStore {

    private val contentObserver =
        object : ContentObserver(HandlerExecutor.main) {
@@ -48,49 +37,15 @@ abstract class SettingsStore(protected val contentResolver: ContentResolver) :
            }
        }

    override fun addObserver(observer: KeyedObserver<String?>, executor: Executor) =
        if (super.addObserver(observer, executor)) {
            onObserverAdded()
            true
        } else {
            false
        }

    override fun addObserver(key: String, observer: KeyedObserver<String>, executor: Executor) =
        if (super.addObserver(key, observer, executor)) {
            onObserverAdded()
            true
        } else {
            false
        }

    private fun onObserverAdded() {
        if (counter.getAndIncrement() != 0) return
        Log.i(tag, "registerContentObserver")
        contentResolver.registerContentObserver(uri, true, contentObserver)
    }

    /** The URI to watch for any key change. */
    protected abstract val uri: Uri

    override fun removeObserver(observer: KeyedObserver<String?>) =
        if (super.removeObserver(observer)) {
            onObserverRemoved()
            true
        } else {
            false
        }

    override fun removeObserver(key: String, observer: KeyedObserver<String>) =
        if (super.removeObserver(key, observer)) {
            onObserverRemoved()
            true
        } else {
            false
    override fun onFirstObserverAdded() {
        Log.i(tag, "registerContentObserver")
        contentResolver.registerContentObserver(uri, true, contentObserver)
    }

    private fun onObserverRemoved() {
        if (counter.decrementAndGet() != 0) return
    override fun onLastObserverRemoved() {
        Log.i(tag, "unregisterContentObserver")
        contentResolver.unregisterContentObserver(contentObserver)
    }