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

Commit fbda5031 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add Settings Provider data stores" into main

parents a27cfdeb bfdcf16b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ android_library {
        "androidx.annotation_annotation",
        "androidx.collection_collection-ktx",
        "androidx.core_core-ktx",
        "error_prone_annotations",
        "guava",
    ],
    kotlincflags: ["-Xjvm-default=all"],
+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ package com.android.settingslib.datastore
import android.content.SharedPreferences

/** Interface of key-value store. */
interface KeyValueStore {
interface KeyValueStore : KeyedObservable<String> {

    /** Returns if the storage contains persistent value of given key. */
    fun contains(key: String): Boolean
+33 −15
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settingslib.datastore
import androidx.annotation.AnyThread
import androidx.annotation.GuardedBy
import androidx.collection.MutableScatterMap
import com.google.errorprone.annotations.CanIgnoreReturnValue
import java.util.WeakHashMap
import java.util.concurrent.Executor

@@ -62,8 +63,9 @@ interface KeyedObservable<K> {
     *
     * @param observer observer to be notified
     * @param executor executor to run the callback
     * @return if the observer is newly added
     */
    fun addObserver(observer: KeyedObserver<K?>, executor: Executor)
    @CanIgnoreReturnValue fun addObserver(observer: KeyedObserver<K?>, executor: Executor): Boolean

    /**
     * Adds an observer on given key.
@@ -73,14 +75,24 @@ interface KeyedObservable<K> {
     * @param key key to observe
     * @param observer observer to be notified
     * @param executor executor to run the callback
     * @return if the observer is newly added
     */
    fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor)
    @CanIgnoreReturnValue
    fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor): Boolean

    /** Removes observer. */
    fun removeObserver(observer: KeyedObserver<K?>)
    /**
     * Removes observer.
     *
     * @return if the observer is found and removed
     */
    @CanIgnoreReturnValue fun removeObserver(observer: KeyedObserver<K?>): Boolean

    /** Removes observer on given key. */
    fun removeObserver(key: K, observer: KeyedObserver<K>)
    /**
     * Removes observer on given key.
     *
     * @return if the observer is found and removed
     */
    @CanIgnoreReturnValue fun removeObserver(key: K, observer: KeyedObserver<K>): Boolean

    /**
     * Notifies all observers that a change occurs.
@@ -111,14 +123,17 @@ open class KeyedDataObservable<K> : KeyedObservable<K> {
    @GuardedBy("itself")
    private val keyedObservers = MutableScatterMap<K, WeakHashMap<KeyedObserver<K>, Executor>>()

    override fun addObserver(observer: KeyedObserver<K?>, executor: Executor) {
    @CanIgnoreReturnValue
    override fun addObserver(observer: KeyedObserver<K?>, executor: Executor): Boolean {
        val oldExecutor = synchronized(observers) { observers.put(observer, executor) }
        if (oldExecutor != null && oldExecutor != executor) {
            throw IllegalStateException("Add $observer twice, old=$oldExecutor, new=$executor")
        }
        return oldExecutor == null
    }

    override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor) {
    @CanIgnoreReturnValue
    override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor): Boolean {
        val oldExecutor =
            synchronized(keyedObservers) {
                keyedObservers.getOrPut(key) { WeakHashMap() }.put(observer, executor)
@@ -126,19 +141,22 @@ open class KeyedDataObservable<K> : KeyedObservable<K> {
        if (oldExecutor != null && oldExecutor != executor) {
            throw IllegalStateException("Add $observer twice, old=$oldExecutor, new=$executor")
        }
        return oldExecutor == null
    }

    override fun removeObserver(observer: KeyedObserver<K?>) {
        synchronized(observers) { observers.remove(observer) }
    }
    @CanIgnoreReturnValue
    override fun removeObserver(observer: KeyedObserver<K?>) =
        synchronized(observers) { observers.remove(observer) } != null

    override fun removeObserver(key: K, observer: KeyedObserver<K>) {
    @CanIgnoreReturnValue
    override fun removeObserver(key: K, observer: KeyedObserver<K>) =
        synchronized(keyedObservers) {
            val observers = keyedObservers[key]
            if (observers?.remove(observer) != null && observers.isEmpty()) {
            val observers = keyedObservers[key] ?: return false
            val removed = observers.remove(observer) != null
            if (removed && observers.isEmpty()) {
                keyedObservers.remove(key)
            }
        }
            removed
        }

    override fun notifyChange(reason: Int) {
+81 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.datastore

import android.content.ContentResolver
import android.content.Context
import android.provider.Settings.Global
import android.provider.Settings.SettingNotFoundException

/**
 * [KeyValueStore] for [Global] settings.
 *
 * By default, a boolean type `true` value is stored as `1` and `false` value is stored as `0`.
 */
class SettingsGlobalStore private constructor(contentResolver: ContentResolver) :
    SettingsStore(contentResolver) {

    override val tag: String
        get() = "SettingsGlobalStore"

    override fun contains(key: String): Boolean = Global.getString(contentResolver, key) != null

    override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
        try {
            when (valueType) {
                Boolean::class.javaObjectType -> Global.getInt(contentResolver, key) != 0
                Float::class.javaObjectType -> Global.getFloat(contentResolver, key)
                Int::class.javaObjectType -> Global.getInt(contentResolver, key)
                Long::class.javaObjectType -> Global.getLong(contentResolver, key)
                String::class.javaObjectType -> Global.getString(contentResolver, key)
                else -> throw UnsupportedOperationException("Get $key $valueType")
            }
                as T?
        } catch (e: SettingNotFoundException) {
            null
        }

    override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
        if (value == null) {
            Global.putString(contentResolver, key, null)
            return
        }
        when (valueType) {
            Boolean::class.javaObjectType ->
                Global.putInt(contentResolver, key, if (value == true) 1 else 0)
            Float::class.javaObjectType -> Global.putFloat(contentResolver, key, value as Float)
            Int::class.javaObjectType -> Global.putInt(contentResolver, key, value as Int)
            Long::class.javaObjectType -> Global.putLong(contentResolver, key, value as Long)
            String::class.javaObjectType -> Global.putString(contentResolver, key, value as String)
            else -> throw UnsupportedOperationException("Set $key $valueType")
        }
    }

    companion object {
        @Volatile private var instance: SettingsGlobalStore? = null

        @JvmStatic
        fun get(context: Context): SettingsGlobalStore =
            instance
                ?: synchronized(this) {
                    instance
                        ?: SettingsGlobalStore(context.applicationContext.contentResolver).also {
                            instance = it
                        }
                }
    }
}
+81 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.datastore

import android.content.ContentResolver
import android.content.Context
import android.provider.Settings.Secure
import android.provider.Settings.SettingNotFoundException

/**
 * [KeyValueStore] for [Secure] settings.
 *
 * By default, a boolean type `true` value is stored as `1` and `false` value is stored as `0`.
 */
class SettingsSecureStore private constructor(contentResolver: ContentResolver) :
    SettingsStore(contentResolver) {

    override val tag: String
        get() = "SettingsSecureStore"

    override fun contains(key: String): Boolean = Secure.getString(contentResolver, key) != null

    override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
        try {
            when (valueType) {
                Boolean::class.javaObjectType -> Secure.getInt(contentResolver, key) != 0
                Float::class.javaObjectType -> Secure.getFloat(contentResolver, key)
                Int::class.javaObjectType -> Secure.getInt(contentResolver, key)
                Long::class.javaObjectType -> Secure.getLong(contentResolver, key)
                String::class.javaObjectType -> Secure.getString(contentResolver, key)
                else -> throw UnsupportedOperationException("Get $key $valueType")
            }
                as T?
        } catch (e: SettingNotFoundException) {
            null
        }

    override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
        if (value == null) {
            Secure.putString(contentResolver, key, null)
            return
        }
        when (valueType) {
            Boolean::class.javaObjectType ->
                Secure.putInt(contentResolver, key, if (value == true) 1 else 0)
            Float::class.javaObjectType -> Secure.putFloat(contentResolver, key, value as Float)
            Int::class.javaObjectType -> Secure.putInt(contentResolver, key, value as Int)
            Long::class.javaObjectType -> Secure.putLong(contentResolver, key, value as Long)
            String::class.javaObjectType -> Secure.putString(contentResolver, key, value as String)
            else -> throw UnsupportedOperationException("Set $key $valueType")
        }
    }

    companion object {
        @Volatile private var instance: SettingsSecureStore? = null

        @JvmStatic
        fun get(context: Context): SettingsSecureStore =
            instance
                ?: synchronized(this) {
                    instance
                        ?: SettingsSecureStore(context.applicationContext.contentResolver).also {
                            instance = it
                        }
                }
    }
}
Loading