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

Commit 34329106 authored by Devarshi Bhatt's avatar Devarshi Bhatt
Browse files

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
parent 3a26daa1
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -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
@@ -45,6 +52,11 @@ class GlobalSettingsImpl implements GlobalSettings {
        return Settings.Global.getUriFor(name);
    }

    @Override
    public CoroutineDispatcher getBackgroundDispatcher() {
        return mBgDispatcher;
    }

    @Override
    public String getString(String name) {
        return Settings.Global.getString(mContentResolver, name);
+12 −1
Original line number Diff line number Diff line
@@ -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
@@ -51,6 +57,11 @@ class SecureSettingsImpl implements SecureSettings {
        return Settings.Secure.getUriFor(name);
    }

    @Override
    public CoroutineDispatcher getBackgroundDispatcher() {
        return mBgDispatcher;
    }

    @Override
    public String getStringForUser(String name, int userHandle) {
        return Settings.Secure.getStringForUser(mContentResolver, name,
+136 −0
Original line number Diff line number Diff line
@@ -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
@@ -39,6 +43,12 @@ interface SettingsProxy {
    /** Returns the [ContentResolver] this instance was constructed with. */
    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,10 +67,54 @@ 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)

    /**
     * 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].'
     *
@@ -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" }) {
@@ -91,6 +207,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.
     *
+12 −1
Original line number Diff line number Diff line
@@ -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
@@ -51,6 +57,11 @@ class SystemSettingsImpl implements SystemSettings {
        return Settings.System.getUriFor(name);
    }

    @Override
    public CoroutineDispatcher getBackgroundDispatcher() {
        return mBgCoroutineDispatcher;
    }

    @Override
    public String getStringForUser(String name, int userHandle) {
        return Settings.System.getStringForUser(mContentResolver, name,
+188 −0
Original line number Diff line number Diff line
@@ -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,
@@ -97,6 +167,37 @@ interface UserSettingsProxy : SettingsProxy {
        registerContentObserverForUserSync(uri, false, 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(
        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]
     *
@@ -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,
@@ -135,6 +280,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.
     *
Loading