summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Devarshi Bhatt <devarshimb@google.com> 2024-05-31 07:57:37 +0000
committer Devarshi Bhatt <devarshimb@google.com> 2024-07-03 07:37:54 +0000
commit34329106824e9e66b58b80821e8d6f5279a3f77b (patch)
treef3b6ddd288834bb8e426f475294444551939075f
parent3a26daa11d61240f1bab41bf072b6d8fc2dc9f68 (diff)
Add async registerCO API in SettingsProxy.
Add new suspend API for kotlin and a Java API launching a new coroutine for each existing register/unregister ContentObserver API in SettingsProxy and UserSettingsProxy. Added a new API in the SettingsProxy interface that provides the dispatcher to be used while calling the above async methods. Each individual implementation can decide which dispatcher to use based on the injected parameter. Test: make SystemUIGoogle, atest SettingsProxyTest, atest UserSettingsProxyTest Bug: 330299944 Flag: NONE new async APIs and existing APIs kept unmodified. Change-Id: Ia6e0f0e20a9eee314c8e00138c94a73702a62c3e
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt136
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt188
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt117
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt220
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java5
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java5
9 files changed, 703 insertions, 8 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
index 42389f0ae627..4438763aa765 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
@@ -23,16 +23,23 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.provider.Settings;
+import com.android.systemui.dagger.qualifiers.Background;
+
+import kotlinx.coroutines.CoroutineDispatcher;
+
import javax.inject.Inject;
// use UserHandle.USER_SYSTEM everywhere
@SuppressLint("StaticSettingsProvider")
class GlobalSettingsImpl implements GlobalSettings {
private final ContentResolver mContentResolver;
+ private final CoroutineDispatcher mBgDispatcher;
@Inject
- GlobalSettingsImpl(ContentResolver contentResolver) {
+ GlobalSettingsImpl(ContentResolver contentResolver,
+ @Background CoroutineDispatcher bgDispatcher) {
mContentResolver = contentResolver;
+ mBgDispatcher = bgDispatcher;
}
@Override
@@ -46,6 +53,11 @@ class GlobalSettingsImpl implements GlobalSettings {
}
@Override
+ public CoroutineDispatcher getBackgroundDispatcher() {
+ return mBgDispatcher;
+ }
+
+ @Override
public String getString(String name) {
return Settings.Global.getString(mContentResolver, name);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
index 6532ce8ddf7d..38ad5d0d0cab 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
@@ -22,18 +22,24 @@ import android.provider.Settings;
import androidx.annotation.NonNull;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.UserTracker;
+import kotlinx.coroutines.CoroutineDispatcher;
+
import javax.inject.Inject;
class SecureSettingsImpl implements SecureSettings {
private final ContentResolver mContentResolver;
private final UserTracker mUserTracker;
+ private final CoroutineDispatcher mBgDispatcher;
@Inject
- SecureSettingsImpl(ContentResolver contentResolver, UserTracker userTracker) {
+ SecureSettingsImpl(ContentResolver contentResolver, UserTracker userTracker,
+ @Background CoroutineDispatcher bgDispatcher) {
mContentResolver = contentResolver;
mUserTracker = userTracker;
+ mBgDispatcher = bgDispatcher;
}
@Override
@@ -52,6 +58,11 @@ class SecureSettingsImpl implements SecureSettings {
}
@Override
+ public CoroutineDispatcher getBackgroundDispatcher() {
+ return mBgDispatcher;
+ }
+
+ @Override
public String getStringForUser(String name, int userHandle) {
return Settings.Secure.getStringForUser(mContentResolver, name,
getRealUserHandle(userHandle));
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
index d92127cf97cb..160ae869d94d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
@@ -20,6 +20,10 @@ import android.database.ContentObserver
import android.net.Uri
import android.provider.Settings.SettingNotFoundException
import com.android.app.tracing.TraceUtils.trace
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/**
* Used to interact with mainly with Settings.Global, but can also be used for Settings.System and
@@ -40,6 +44,12 @@ interface SettingsProxy {
fun getContentResolver(): ContentResolver
/**
+ * Returns the background [CoroutineDispatcher] that the async APIs will use for a specific
+ * implementation.
+ */
+ val backgroundDispatcher: CoroutineDispatcher
+
+ /**
* Construct the content URI for a particular name/value pair, useful for monitoring changes
* with a ContentObserver.
*
@@ -57,6 +67,29 @@ interface SettingsProxy {
registerContentObserverSync(getUriFor(name), settingsObserver)
}
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * suspend API corresponding to [registerContentObserver] to ensure that [ContentObserver]
+ * registration happens on a worker thread. Caller may wrap the API in an async block if they
+ * wish to synchronize execution.
+ */
+ suspend fun registerContentObserver(name: String, settingsObserver: ContentObserver) {
+ withContext(backgroundDispatcher) {
+ registerContentObserverSync(getUriFor(name), settingsObserver)
+ }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserver] for Java usage.
+ */
+ fun registerContentObserverAsync(name: String, settingsObserver: ContentObserver) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverSync(getUriFor(name), settingsObserver)
+ }
+
/** Convenience wrapper around [ContentResolver.registerContentObserver].' */
fun registerContentObserverSync(uri: Uri, settingsObserver: ContentObserver) =
registerContentObserverSync(uri, false, settingsObserver)
@@ -64,6 +97,27 @@ interface SettingsProxy {
/**
* Convenience wrapper around [ContentResolver.registerContentObserver].'
*
+ * suspend API corresponding to [registerContentObserver] to ensure that [ContentObserver]
+ * registration happens on a worker thread. Caller may wrap the API in an async block if they
+ * wish to synchronize execution.
+ */
+ suspend fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) {
+ withContext(backgroundDispatcher) { registerContentObserverSync(uri, settingsObserver) }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserver] for Java usage.
+ */
+ fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverSync(uri, settingsObserver)
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
* Implicitly calls [getUriFor] on the passed in name.
*/
fun registerContentObserverSync(
@@ -72,6 +126,37 @@ interface SettingsProxy {
settingsObserver: ContentObserver
) = registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * suspend API corresponding to [registerContentObserver] to ensure that [ContentObserver]
+ * registration happens on a worker thread. Caller may wrap the API in an async block if they
+ * wish to synchronize execution.
+ */
+ suspend fun registerContentObserver(
+ name: String,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver
+ ) {
+ withContext(backgroundDispatcher) {
+ registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
+ }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserver] for Java usage.
+ */
+ fun registerContentObserverAsync(
+ name: String,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
+ }
+
/** Convenience wrapper around [ContentResolver.registerContentObserver].' */
fun registerContentObserverSync(
uri: Uri,
@@ -84,6 +169,37 @@ interface SettingsProxy {
}
}
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * suspend API corresponding to [registerContentObserver] to ensure that [ContentObserver]
+ * registration happens on a worker thread. Caller may wrap the API in an async block if they
+ * wish to synchronize execution.
+ */
+ suspend fun registerContentObserver(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver
+ ) {
+ withContext(backgroundDispatcher) {
+ registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
+ }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserver] for Java usage.
+ */
+ fun registerContentObserverAsync(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
+ }
+
/** See [ContentResolver.unregisterContentObserver]. */
fun unregisterContentObserverSync(settingsObserver: ContentObserver) {
trace({ "SP#unregisterObserver" }) {
@@ -92,6 +208,26 @@ interface SettingsProxy {
}
/**
+ * Convenience wrapper around [ContentResolver.unregisterContentObserver].'
+ *
+ * API corresponding to [unregisterContentObserver] for Java usage to ensure that
+ * [ContentObserver] un-registration happens on a worker thread. Caller may wrap the API in an
+ * async block if they wish to synchronize execution.
+ */
+ suspend fun unregisterContentObserver(settingsObserver: ContentObserver) {
+ withContext(backgroundDispatcher) { unregisterContentObserverSync(settingsObserver) }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.unregisterContentObserver].'
+ *
+ * API corresponding to [unregisterContentObserver] for Java usage to ensure that
+ * [ContentObserver] registration happens on a worker thread.
+ */
+ fun unregisterContentObserverAsync(settingsObserver: ContentObserver) =
+ CoroutineScope(backgroundDispatcher).launch { unregisterContentObserver(settingsObserver) }
+
+ /**
* Look up a name in the database.
*
* @param name to look up in the table
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
index 658b2992bfad..68cc753bc48a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
@@ -22,18 +22,24 @@ import android.provider.Settings;
import androidx.annotation.NonNull;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.UserTracker;
+import kotlinx.coroutines.CoroutineDispatcher;
+
import javax.inject.Inject;
class SystemSettingsImpl implements SystemSettings {
private final ContentResolver mContentResolver;
private final UserTracker mUserTracker;
+ private final CoroutineDispatcher mBgCoroutineDispatcher;
@Inject
- SystemSettingsImpl(ContentResolver contentResolver, UserTracker userTracker) {
+ SystemSettingsImpl(ContentResolver contentResolver, UserTracker userTracker,
+ @Background CoroutineDispatcher bgDispatcher) {
mContentResolver = contentResolver;
mUserTracker = userTracker;
+ mBgCoroutineDispatcher = bgDispatcher;
}
@Override
@@ -52,6 +58,11 @@ class SystemSettingsImpl implements SystemSettings {
}
@Override
+ public CoroutineDispatcher getBackgroundDispatcher() {
+ return mBgCoroutineDispatcher;
+ }
+
+ @Override
public String getStringForUser(String name, int userHandle) {
return Settings.System.getStringForUser(mContentResolver, name,
getRealUserHandle(userHandle));
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
index ed65f1ae1667..3bf5b6511eb3 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
@@ -16,6 +16,7 @@
package com.android.systemui.util.settings
import android.annotation.UserIdInt
+import android.content.ContentResolver
import android.database.ContentObserver
import android.net.Uri
import android.os.UserHandle
@@ -26,6 +27,9 @@ import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloat
import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloatOrThrow
import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrThrow
import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrUseDefault
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/**
* Used to interact with per-user Settings.Secure and Settings.System settings (but not
@@ -66,6 +70,17 @@ interface UserSettingsProxy : SettingsProxy {
registerContentObserverForUserSync(uri, settingsObserver, userId)
}
+ override suspend fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) {
+ withContext(backgroundDispatcher) {
+ registerContentObserverForUserSync(uri, settingsObserver, userId)
+ }
+ }
+
+ override fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverForUserSync(uri, settingsObserver, userId)
+ }
+
/** Convenience wrapper around [ContentResolver.registerContentObserver].' */
override fun registerContentObserverSync(
uri: Uri,
@@ -75,6 +90,30 @@ interface UserSettingsProxy : SettingsProxy {
registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
}
+ override suspend fun registerContentObserver(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver
+ ) {
+ withContext(backgroundDispatcher) {
+ registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
+ }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserverForUser] for Java usage.
+ */
+ override fun registerContentObserverAsync(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
+ }
+
/**
* Convenience wrapper around [ContentResolver.registerContentObserver]
*
@@ -88,6 +127,37 @@ interface UserSettingsProxy : SettingsProxy {
registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
}
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * suspend API corresponding to [registerContentObserverForUser] to ensure that
+ * [ContentObserver] registration happens on a worker thread. Caller may wrap the API in an
+ * async block if they wish to synchronize execution.
+ */
+ suspend fun registerContentObserverForUser(
+ name: String,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) {
+ withContext(backgroundDispatcher) {
+ registerContentObserverForUserSync(name, settingsObserver, userHandle)
+ }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserverForUser] for Java usage.
+ */
+ fun registerContentObserverForUserAsync(
+ name: String,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
+ }
+
/** Convenience wrapper around [ContentResolver.registerContentObserver] */
fun registerContentObserverForUserSync(
uri: Uri,
@@ -98,6 +168,37 @@ interface UserSettingsProxy : SettingsProxy {
}
/**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * suspend API corresponding to [registerContentObserverForUser] to ensure that
+ * [ContentObserver] registration happens on a worker thread. Caller may wrap the API in an
+ * async block if they wish to synchronize execution.
+ */
+ suspend fun registerContentObserverForUser(
+ uri: Uri,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) {
+ withContext(backgroundDispatcher) {
+ registerContentObserverForUserSync(uri, settingsObserver, userHandle)
+ }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserverForUser] for Java usage.
+ */
+ fun registerContentObserverForUserAsync(
+ uri: Uri,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverForUserSync(uri, settingsObserver, userHandle)
+ }
+
+ /**
* Convenience wrapper around [ContentResolver.registerContentObserver]
*
* Implicitly calls [getUriFor] on the passed in name.
@@ -116,6 +217,50 @@ interface UserSettingsProxy : SettingsProxy {
)
}
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * suspend API corresponding to [registerContentObserverForUser] to ensure that
+ * [ContentObserver] registration happens on a worker thread. Caller may wrap the API in an
+ * async block if they wish to synchronize execution.
+ */
+ suspend fun registerContentObserverForUser(
+ name: String,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) {
+ withContext(backgroundDispatcher) {
+ registerContentObserverForUserSync(
+ name,
+ notifyForDescendants,
+ settingsObserver,
+ userHandle
+ )
+ }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserverForUser] for Java usage.
+ */
+ fun registerContentObserverForUserAsync(
+ name: String,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) {
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverForUserSync(
+ getUriFor(name),
+ notifyForDescendants,
+ settingsObserver,
+ userHandle
+ )
+ }
+ }
+
/** Convenience wrapper around [ContentResolver.registerContentObserver] */
fun registerContentObserverForUserSync(
uri: Uri,
@@ -136,6 +281,49 @@ interface UserSettingsProxy : SettingsProxy {
}
/**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * suspend API corresponding to [registerContentObserverForUser] to ensure that
+ * [ContentObserver] registration happens on a worker thread. Caller may wrap the API in an
+ * async block if they wish to synchronize execution.
+ */
+ suspend fun registerContentObserverForUser(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) {
+ withContext(backgroundDispatcher) {
+ registerContentObserverForUserSync(
+ uri,
+ notifyForDescendants,
+ settingsObserver,
+ getRealUserHandle(userHandle)
+ )
+ }
+ }
+
+ /**
+ * Convenience wrapper around [ContentResolver.registerContentObserver].'
+ *
+ * API corresponding to [registerContentObserverForUser] for Java usage.
+ */
+ fun registerContentObserverForUserAsync(
+ uri: Uri,
+ notifyForDescendants: Boolean,
+ settingsObserver: ContentObserver,
+ userHandle: Int
+ ) =
+ CoroutineScope(backgroundDispatcher).launch {
+ registerContentObserverForUserSync(
+ uri,
+ notifyForDescendants,
+ settingsObserver,
+ userHandle
+ )
+ }
+
+ /**
* Look up a name in the database.
*
* @param name to look up in the table
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
index ef8d51a23dc2..dd791e764e01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
@@ -27,6 +27,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test
@@ -41,12 +46,16 @@ import org.mockito.kotlin.eq
@TestableLooper.RunWithLooper
class SettingsProxyTest : SysuiTestCase() {
+ private val testDispatcher = StandardTestDispatcher()
+
private lateinit var mSettings: SettingsProxy
private lateinit var mContentObserver: ContentObserver
+ private lateinit var testScope: TestScope
@Before
fun setUp() {
- mSettings = FakeSettingsProxy()
+ testScope = TestScope(testDispatcher)
+ mSettings = FakeSettingsProxy(testDispatcher)
mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {}
}
@@ -58,6 +67,23 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
+ fun registerContentObserverSuspend_inputString_success() =
+ testScope.runTest {
+ mSettings.registerContentObserver(TEST_SETTING, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
+ }
+
+ @Test
+ fun registerContentObserverAsync_inputString_success() {
+ mSettings.registerContentObserverAsync(TEST_SETTING, mContentObserver)
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
+ }
+ }
+
+ @Test
fun registerContentObserver_inputString_notifyForDescendants_true() {
mSettings.registerContentObserverSync(
TEST_SETTING,
@@ -69,6 +95,31 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
+ fun registerContentObserverSuspend_inputString_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserver(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
+ }
+
+ @Test
+ fun registerContentObserverAsync_inputString_notifyForDescendants_true() {
+ mSettings.registerContentObserverAsync(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
+ }
+ }
+
+ @Test
fun registerContentObserver_inputUri_success() {
mSettings.registerContentObserverSync(TEST_SETTING_URI, mContentObserver)
verify(mSettings.getContentResolver())
@@ -76,6 +127,23 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
+ fun registerContentObserverSuspend_inputUri_success() =
+ testScope.runTest {
+ mSettings.registerContentObserver(TEST_SETTING_URI, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
+ }
+
+ @Test
+ fun registerContentObserverAsync_inputUri_success() {
+ mSettings.registerContentObserverAsync(TEST_SETTING_URI, mContentObserver)
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(false), eq(mContentObserver))
+ }
+ }
+
+ @Test
fun registerContentObserver_inputUri_notifyForDescendants_true() {
mSettings.registerContentObserverSync(
TEST_SETTING_URI,
@@ -87,12 +155,52 @@ class SettingsProxyTest : SysuiTestCase() {
}
@Test
- fun unregisterContentObserver() {
+ fun registerContentObserverSuspend_inputUri_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserver(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
+ }
+
+ @Test
+ fun registerContentObserverAsync_inputUri_notifyForDescendants_true() {
+ mSettings.registerContentObserverAsync(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver
+ )
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
+ }
+ }
+
+ @Test
+ fun unregisterContentObserverSync() {
mSettings.unregisterContentObserverSync(mContentObserver)
verify(mSettings.getContentResolver()).unregisterContentObserver(eq(mContentObserver))
}
@Test
+ fun unregisterContentObserverSuspend_inputString_success() =
+ testScope.runTest {
+ mSettings.unregisterContentObserver(mContentObserver)
+ verify(mSettings.getContentResolver()).unregisterContentObserver(eq(mContentObserver))
+ }
+
+ @Test
+ fun unregisterContentObserverAsync_inputString_success() {
+ mSettings.unregisterContentObserverAsync(mContentObserver)
+ testScope.launch {
+ verify(mSettings.getContentResolver()).unregisterContentObserver(eq(mContentObserver))
+ }
+ }
+
+ @Test
fun getString_keyPresent_returnValidValue() {
mSettings.putString(TEST_SETTING, "test")
assertThat(mSettings.getString(TEST_SETTING)).isEqualTo("test")
@@ -199,13 +307,16 @@ class SettingsProxyTest : SysuiTestCase() {
assertThat(mSettings.getFloat(TEST_SETTING, 2.5F)).isEqualTo(2.5F)
}
- private class FakeSettingsProxy : SettingsProxy {
+ private class FakeSettingsProxy(val testDispatcher: CoroutineDispatcher) : SettingsProxy {
private val mContentResolver = mock(ContentResolver::class.java)
private val settingToValueMap: MutableMap<String, String> = mutableMapOf()
override fun getContentResolver() = mContentResolver
+ override val backgroundDispatcher: CoroutineDispatcher
+ get() = testDispatcher
+
override fun getUriFor(name: String) =
Uri.parse(StringBuilder().append("content://settings/").append(name).toString())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
index c08ca7d1bdc1..e3e20c8ed501 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
@@ -30,6 +30,11 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.UserTracker
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test
@@ -45,8 +50,10 @@ import org.mockito.kotlin.eq
class UserSettingsProxyTest : SysuiTestCase() {
private var mUserTracker = FakeUserTracker()
- private var mSettings: UserSettingsProxy = FakeUserSettingsProxy(mUserTracker)
+ private val testDispatcher = StandardTestDispatcher()
+ private var mSettings: UserSettingsProxy = FakeUserSettingsProxy(mUserTracker, testDispatcher)
private var mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {}
+ private lateinit var testScope: TestScope
@Before
fun setUp() {
@@ -54,6 +61,7 @@ class UserSettingsProxyTest : SysuiTestCase() {
listOf(UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_MAIN)),
selectedUserIndex = 0
)
+ testScope = TestScope(testDispatcher)
}
@Test
@@ -73,6 +81,41 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
+ fun registerContentObserverForUserSuspend_inputString_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUser(
+ TEST_SETTING,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+
+ @Test
+ fun registerContentObserverForUserAsync_inputString_success() {
+ mSettings.registerContentObserverForUserAsync(
+ TEST_SETTING,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+ }
+
+ @Test
fun registerContentObserverForUser_inputString_notifyForDescendants_true() {
mSettings.registerContentObserverForUserSync(
TEST_SETTING,
@@ -90,6 +133,45 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
+ fun registerContentObserverForUserSuspend_inputString_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUser(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(
+ true,
+ ),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+
+ @Test
+ fun registerContentObserverForUserAsync_inputString_notifyForDescendants_true() {
+ mSettings.registerContentObserverForUserAsync(
+ TEST_SETTING,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(true),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+ }
+
+ @Test
fun registerContentObserverForUser_inputUri_success() {
mSettings.registerContentObserverForUserSync(
TEST_SETTING_URI,
@@ -106,6 +188,41 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
+ fun registerContentObserverForUserSuspend_inputUri_success() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUser(
+ TEST_SETTING_URI,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+
+ @Test
+ fun registerContentObserverForUserAsync_inputUri_success() {
+ mSettings.registerContentObserverForUserAsync(
+ TEST_SETTING_URI,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+ }
+
+ @Test
fun registerContentObserverForUser_inputUri_notifyForDescendants_true() {
mSettings.registerContentObserverForUserSync(
TEST_SETTING_URI,
@@ -123,6 +240,45 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
+ fun registerContentObserverForUserSuspend_inputUri_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserverForUser(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(
+ true,
+ ),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+
+ @Test
+ fun registerContentObserverForUserAsync_inputUri_notifyForDescendants_true() {
+ mSettings.registerContentObserverForUserAsync(
+ TEST_SETTING_URI,
+ notifyForDescendants = true,
+ mContentObserver,
+ mUserTracker.userId
+ )
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(true),
+ eq(mContentObserver),
+ eq(MAIN_USER_ID)
+ )
+ }
+ }
+
+ @Test
fun registerContentObserver_inputUri_success() {
mSettings.registerContentObserverSync(TEST_SETTING_URI, mContentObserver)
verify(mSettings.getContentResolver())
@@ -130,6 +286,33 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
+ fun registerContentObserverSuspend_inputUri_success() =
+ testScope.runTest {
+ mSettings.registerContentObserver(TEST_SETTING_URI, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(0)
+ )
+ }
+
+ @Test
+ fun registerContentObserverAsync_inputUri_success() {
+ mSettings.registerContentObserverAsync(TEST_SETTING_URI, mContentObserver)
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(0)
+ )
+ }
+ }
+
+ @Test
fun registerContentObserver_inputUri_notifyForDescendants_true() {
mSettings.registerContentObserverSync(
TEST_SETTING_URI,
@@ -141,6 +324,33 @@ class UserSettingsProxyTest : SysuiTestCase() {
}
@Test
+ fun registerContentObserverSuspend_inputUri_notifyForDescendants_true() =
+ testScope.runTest {
+ mSettings.registerContentObserver(TEST_SETTING_URI, mContentObserver)
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(0)
+ )
+ }
+
+ @Test
+ fun registerContentObserverAsync_inputUri_notifyForDescendants_true() {
+ mSettings.registerContentObserverAsync(TEST_SETTING_URI, mContentObserver)
+ testScope.launch {
+ verify(mSettings.getContentResolver())
+ .registerContentObserver(
+ eq(TEST_SETTING_URI),
+ eq(false),
+ eq(mContentObserver),
+ eq(0)
+ )
+ }
+ }
+
+ @Test
fun getString_keyPresent_returnValidValue() {
mSettings.putString(TEST_SETTING, "test")
assertThat(mSettings.getString(TEST_SETTING)).isEqualTo("test")
@@ -300,7 +510,10 @@ class UserSettingsProxyTest : SysuiTestCase() {
*
* This class uses a mock of [ContentResolver] to test the [ContentObserver] registration APIs.
*/
- private class FakeUserSettingsProxy(override val userTracker: UserTracker) : UserSettingsProxy {
+ private class FakeUserSettingsProxy(
+ override val userTracker: UserTracker,
+ val testDispatcher: CoroutineDispatcher
+ ) : UserSettingsProxy {
private val mContentResolver = mock(ContentResolver::class.java)
private val userIdToSettingsValueMap: MutableMap<Int, MutableMap<String, String>> =
@@ -311,6 +524,9 @@ class UserSettingsProxyTest : SysuiTestCase() {
override fun getUriFor(name: String) =
Uri.parse(StringBuilder().append(URI_PREFIX).append(name).toString())
+ override val backgroundDispatcher: CoroutineDispatcher
+ get() = testDispatcher
+
override fun getStringForUser(name: String, userHandle: Int) =
userIdToSettingsValueMap[userHandle]?.get(name) ?: ""
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
index 1da7fb001d8e..476b7d8376c8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
@@ -54,6 +54,11 @@ public class FakeGlobalSettings implements GlobalSettings {
}
@Override
+ public CoroutineDispatcher getBackgroundDispatcher() {
+ return mDispatcher;
+ }
+
+ @Override
public void registerContentObserverSync(Uri uri, boolean notifyDescendants,
ContentObserver settingsObserver) {
List<ContentObserver> observers;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java
index 04c0af728147..e35da11ff034 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.java
@@ -78,6 +78,11 @@ public class FakeSettings implements SecureSettings, SystemSettings {
}
@Override
+ public CoroutineDispatcher getBackgroundDispatcher() {
+ return mDispatcher;
+ }
+
+ @Override
public void registerContentObserverForUserSync(Uri uri, boolean notifyDescendants,
ContentObserver settingsObserver, int userHandle) {
List<ContentObserver> observers;