Loading packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBoolean.kt +12 −3 Original line number Diff line number Diff line Loading @@ -21,16 +21,25 @@ import android.content.Context import android.provider.Settings import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map fun Context.settingsGlobalBoolean(name: String, defaultValue: Boolean = false): ReadWriteProperty<Any?, Boolean> = SettingsGlobalBooleanDelegate(this, name, defaultValue) fun Context.settingsGlobalBoolean( name: String, defaultValue: Boolean = false, ): ReadWriteProperty<Any?, Boolean> = SettingsGlobalBooleanDelegate(this, name, defaultValue) fun Context.settingsGlobalBooleanFlow(name: String, defaultValue: Boolean = false): Flow<Boolean> { val value by settingsGlobalBoolean(name, defaultValue) return settingsGlobalChangeFlow(name).map { value }.distinctUntilChanged() return settingsGlobalChangeFlow(name) .map { value } .distinctUntilChanged() .conflate() .flowOn(Dispatchers.Default) } private class SettingsGlobalBooleanDelegate( Loading packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBoolean.kt +12 −3 Original line number Diff line number Diff line Loading @@ -22,16 +22,25 @@ import android.provider.Settings import com.android.settingslib.spaprivileged.database.contentChangeFlow import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map fun Context.settingsSecureBoolean(name: String, defaultValue: Boolean = false): ReadWriteProperty<Any?, Boolean> = SettingsSecureBooleanDelegate(this, name, defaultValue) fun Context.settingsSecureBoolean( name: String, defaultValue: Boolean = false, ): ReadWriteProperty<Any?, Boolean> = SettingsSecureBooleanDelegate(this, name, defaultValue) fun Context.settingsSecureBooleanFlow(name: String, defaultValue: Boolean = false): Flow<Boolean> { val value by settingsSecureBoolean(name, defaultValue) return contentChangeFlow(Settings.Secure.getUriFor(name)).map { value }.distinctUntilChanged() return contentChangeFlow(Settings.Secure.getUriFor(name)) .map { value } .distinctUntilChanged() .conflate() .flowOn(Dispatchers.Default) } private class SettingsSecureBooleanDelegate( Loading packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureString.kt 0 → 100644 +60 −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.spaprivileged.settingsprovider import android.content.ContentResolver import android.content.Context import android.provider.Settings import com.android.settingslib.spaprivileged.database.contentChangeFlow import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map fun Context.settingsSecureString( name: String, defaultValue: String = "" ): ReadWriteProperty<Any?, String> = SettingsSecureStringDelegate(this, name, defaultValue) fun Context.settingsSecureStringFlow(name: String, defaultValue: String = ""): Flow<String> { val value by settingsSecureString(name, defaultValue) return contentChangeFlow(Settings.Secure.getUriFor(name)) .map { value } .distinctUntilChanged() .conflate() .flowOn(Dispatchers.Default) } private class SettingsSecureStringDelegate( context: Context, private val name: String, private val defaultValue: String = "", ) : ReadWriteProperty<Any?, String> { private val contentResolver: ContentResolver = context.contentResolver override fun getValue(thisRef: Any?, property: KProperty<*>): String = Settings.Secure.getString(contentResolver, name) ?: defaultValue override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { Settings.Secure.putString(contentResolver, name, value) } } packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt 0 → 100644 +92 −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.spaprivileged.settingsprovider import android.content.Context import android.provider.Settings import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull import com.android.settingslib.spa.testutils.toListWithTimeout import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class SettingsSecureStringTest { private val context: Context = ApplicationProvider.getApplicationContext() @Test fun getValue_returnCorrectValue() { Settings.Secure.putString(context.contentResolver, TEST_NAME, VALUE) val value by context.settingsSecureString(TEST_NAME) assertThat(value).isEqualTo(VALUE) } @Test fun setValue_correctValueSet() { var value by context.settingsSecureString(TEST_NAME) value = VALUE assertThat(Settings.Secure.getString(context.contentResolver, TEST_NAME)).isEqualTo(VALUE) } @Test fun settingsSecureStringFlow_valueNotChanged() = runBlocking { var value by context.settingsSecureString(TEST_NAME) value = VALUE val flow = context.settingsSecureStringFlow(TEST_NAME) assertThat(flow.firstWithTimeoutOrNull()).isEqualTo(VALUE) } @Test fun settingsSecureStringFlow_collectAfterValueChanged_onlyKeepLatest() = runBlocking { var value by context.settingsSecureString(TEST_NAME) value = "" val flow = context.settingsSecureStringFlow(TEST_NAME) value = VALUE assertThat(flow.firstWithTimeoutOrNull()).isEqualTo(VALUE) } @Test fun settingsSecureStringFlow_collectBeforeValueChanged_getBoth() = runBlocking { var value by context.settingsSecureString(TEST_NAME) value = "" val listDeferred = async { context.settingsSecureStringFlow(TEST_NAME).toListWithTimeout() } delay(100) value = VALUE assertThat(listDeferred.await()).containsAtLeast("", VALUE).inOrder() } private companion object { const val TEST_NAME = "test_string_delegate" const val VALUE = "value" } } Loading
packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBoolean.kt +12 −3 Original line number Diff line number Diff line Loading @@ -21,16 +21,25 @@ import android.content.Context import android.provider.Settings import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map fun Context.settingsGlobalBoolean(name: String, defaultValue: Boolean = false): ReadWriteProperty<Any?, Boolean> = SettingsGlobalBooleanDelegate(this, name, defaultValue) fun Context.settingsGlobalBoolean( name: String, defaultValue: Boolean = false, ): ReadWriteProperty<Any?, Boolean> = SettingsGlobalBooleanDelegate(this, name, defaultValue) fun Context.settingsGlobalBooleanFlow(name: String, defaultValue: Boolean = false): Flow<Boolean> { val value by settingsGlobalBoolean(name, defaultValue) return settingsGlobalChangeFlow(name).map { value }.distinctUntilChanged() return settingsGlobalChangeFlow(name) .map { value } .distinctUntilChanged() .conflate() .flowOn(Dispatchers.Default) } private class SettingsGlobalBooleanDelegate( Loading
packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBoolean.kt +12 −3 Original line number Diff line number Diff line Loading @@ -22,16 +22,25 @@ import android.provider.Settings import com.android.settingslib.spaprivileged.database.contentChangeFlow import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map fun Context.settingsSecureBoolean(name: String, defaultValue: Boolean = false): ReadWriteProperty<Any?, Boolean> = SettingsSecureBooleanDelegate(this, name, defaultValue) fun Context.settingsSecureBoolean( name: String, defaultValue: Boolean = false, ): ReadWriteProperty<Any?, Boolean> = SettingsSecureBooleanDelegate(this, name, defaultValue) fun Context.settingsSecureBooleanFlow(name: String, defaultValue: Boolean = false): Flow<Boolean> { val value by settingsSecureBoolean(name, defaultValue) return contentChangeFlow(Settings.Secure.getUriFor(name)).map { value }.distinctUntilChanged() return contentChangeFlow(Settings.Secure.getUriFor(name)) .map { value } .distinctUntilChanged() .conflate() .flowOn(Dispatchers.Default) } private class SettingsSecureBooleanDelegate( Loading
packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureString.kt 0 → 100644 +60 −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.spaprivileged.settingsprovider import android.content.ContentResolver import android.content.Context import android.provider.Settings import com.android.settingslib.spaprivileged.database.contentChangeFlow import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map fun Context.settingsSecureString( name: String, defaultValue: String = "" ): ReadWriteProperty<Any?, String> = SettingsSecureStringDelegate(this, name, defaultValue) fun Context.settingsSecureStringFlow(name: String, defaultValue: String = ""): Flow<String> { val value by settingsSecureString(name, defaultValue) return contentChangeFlow(Settings.Secure.getUriFor(name)) .map { value } .distinctUntilChanged() .conflate() .flowOn(Dispatchers.Default) } private class SettingsSecureStringDelegate( context: Context, private val name: String, private val defaultValue: String = "", ) : ReadWriteProperty<Any?, String> { private val contentResolver: ContentResolver = context.contentResolver override fun getValue(thisRef: Any?, property: KProperty<*>): String = Settings.Secure.getString(contentResolver, name) ?: defaultValue override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { Settings.Secure.putString(contentResolver, name, value) } }
packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt 0 → 100644 +92 −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.spaprivileged.settingsprovider import android.content.Context import android.provider.Settings import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull import com.android.settingslib.spa.testutils.toListWithTimeout import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class SettingsSecureStringTest { private val context: Context = ApplicationProvider.getApplicationContext() @Test fun getValue_returnCorrectValue() { Settings.Secure.putString(context.contentResolver, TEST_NAME, VALUE) val value by context.settingsSecureString(TEST_NAME) assertThat(value).isEqualTo(VALUE) } @Test fun setValue_correctValueSet() { var value by context.settingsSecureString(TEST_NAME) value = VALUE assertThat(Settings.Secure.getString(context.contentResolver, TEST_NAME)).isEqualTo(VALUE) } @Test fun settingsSecureStringFlow_valueNotChanged() = runBlocking { var value by context.settingsSecureString(TEST_NAME) value = VALUE val flow = context.settingsSecureStringFlow(TEST_NAME) assertThat(flow.firstWithTimeoutOrNull()).isEqualTo(VALUE) } @Test fun settingsSecureStringFlow_collectAfterValueChanged_onlyKeepLatest() = runBlocking { var value by context.settingsSecureString(TEST_NAME) value = "" val flow = context.settingsSecureStringFlow(TEST_NAME) value = VALUE assertThat(flow.firstWithTimeoutOrNull()).isEqualTo(VALUE) } @Test fun settingsSecureStringFlow_collectBeforeValueChanged_getBoth() = runBlocking { var value by context.settingsSecureString(TEST_NAME) value = "" val listDeferred = async { context.settingsSecureStringFlow(TEST_NAME).toListWithTimeout() } delay(100) value = VALUE assertThat(listDeferred.await()).containsAtLeast("", VALUE).inOrder() } private companion object { const val TEST_NAME = "test_string_delegate" const val VALUE = "value" } }