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

Commit 7179c45f authored by Jacky Wang's avatar Jacky Wang Committed by Android (Google) Code Review
Browse files

Merge changes from topic "catalyst" into main

* changes:
  [Catalyst] Introduce PreferenceMetadata.bindingKey
  [Catalyst] Support switch preference hierarchy for PreferenceHierarchyGenerator
parents ee7cfd43 04707f32
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -131,7 +131,7 @@ class PreferenceGetterApiHandler(
            for (coordinate in coordinates) nodes[coordinate.key] = null
            screenMetadata.getPreferenceHierarchy(application, this).forEachRecursivelyAsync {
                val metadata = it.metadata
                val key = metadata.key
                val key = metadata.bindingKey
                if (nodes.containsKey(key)) nodes[key] = it
            }
            for (coordinate in coordinates) {
+6 −5
Original line number Diff line number Diff line
@@ -427,7 +427,7 @@ fun PreferenceMetadata.toProto(
    flags: Int,
) = preferenceProto {
    val metadata = this@toProto
    key = metadata.key
    key = metadata.bindingKey
    if (flags.includeMetadata()) {
        metadata.getTitleTextProto(context, isRoot)?.let { title = it }
        if (metadata.summary != 0) {
@@ -473,13 +473,14 @@ fun PreferenceMetadata.toProto(
    ) {
        val storage = metadata.storage(context)
        value = preferenceValueProto {
            val key = metadata.bindingKey
            when (metadata.valueType) {
                Int::class.javaObjectType -> storage.getInt(metadata.key)?.let { intValue = it }
                Int::class.javaObjectType -> storage.getInt(key)?.let { intValue = it }
                Boolean::class.javaObjectType ->
                    storage.getBoolean(metadata.key)?.let { booleanValue = it }
                    storage.getBoolean(key)?.let { booleanValue = it }
                Float::class.javaObjectType ->
                    storage.getFloat(metadata.key)?.let { floatValue = it }
                Long::class.javaObjectType -> storage.getLong(metadata.key)?.let { longValue = it }
                    storage.getFloat(key)?.let { floatValue = it }
                Long::class.javaObjectType -> storage.getLong(key)?.let { longValue = it }
                else -> {}
            }
        }
+15 −5
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.selects.select

/** A node in preference hierarchy that is associated with [PreferenceMetadata]. */
open class PreferenceHierarchyNode internal constructor(val metadata: PreferenceMetadata) {
@@ -115,8 +116,6 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
     * Adds a sub hierarchy with coroutine.
     *
     * Notes:
     * - [PreferenceLifecycleProvider] is not supported for [PreferenceMetadata] added to the async
     *   hierarchy.
     * - As it is async, coroutine could be finished anytime. Consider specify an order explicitly
     *   to achieve deterministic hierarchy.
     * - The sub hierarchy is flattened into current hierarchy.
@@ -172,7 +171,7 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
    private fun findPreference(key: String): Pair<PreferenceHierarchy, Int>? {
        children.forEachIndexed { index, node ->
            if (node !is PreferenceHierarchyNode) return@forEachIndexed
            if (node.metadata.key == key) return this to index
            if (node.metadata.bindingKey == key) return this to index
            if (node is PreferenceHierarchy) {
                val result = node.findPreference(key)
                if (result != null) return result
@@ -280,6 +279,17 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
        }
    }

    /** Await until any child is available to be processed immediately. */
    suspend fun awaitAnyChild() {
        if (children.isEmpty()) return
        for (child in children) if (child !is Deferred<*>) return
        select<Unit> {
            for (child in children) {
                if (child is Deferred<*>) child.onAwait { it }
            }
        }
    }

    /**
     * Traversals preference hierarchy recursively.
     *
@@ -336,7 +346,7 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
     * Note: sub async hierarchy will not be searched, use [findAsync] if needed.
     */
    fun find(key: String): PreferenceMetadata? {
        if (metadata.key == key) return metadata
        if (metadata.bindingKey == key) return metadata
        for (child in children) {
            if (child is Deferred<*>) continue
            if (child is PreferenceHierarchy) {
@@ -344,7 +354,7 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
                if (result != null) return result
            } else {
                child as PreferenceHierarchyNode
                if (child.metadata.key == key) return child.metadata
                if (child.metadata.bindingKey == key) return child.metadata
            }
        }
        return null
+4 −0
Original line number Diff line number Diff line
@@ -61,6 +61,10 @@ interface PreferenceMetadata {
    /** Preference key. */
    val key: String

    /** Preference key when attached to preference hierarchy. */
    val bindingKey: String
        get() = key

    /**
     * Preference title resource id.
     *
+12 −2
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import kotlinx.coroutines.flow.Flow
 * For parameterized preference screen that relies on additional information (e.g. package name,
 * language code) to build its content, the subclass must:
 * - override [arguments] in constructor
 * - override [bindingKey] to distinguish the preferences on the preference hierarchy
 * - add a static method `fun parameters(context: Context): Flow<Bundle>` (context is optional) to
 *   provide all possible arguments
 */
@@ -115,14 +116,23 @@ interface PreferenceScreenMetadata : PreferenceGroup {
    fun getLaunchIntent(context: Context, metadata: PreferenceMetadata?): Intent? = null
}

/** Generator of [PreferenceHierarchy] based on given type. */
/**
 * Generator of [PreferenceHierarchy] based on given type.
 *
 * This interface should be used together with [PreferenceScreenMetadata] and
 * [PreferenceScreenMetadata.getPreferenceHierarchy] should return [generatePreferenceHierarchy]
 * with default preference hierarchy type.
 *
 * The UI framework could leverage [PreferenceLifecycleContext.switchPreferenceHierarchy] to switch
 * preference hierarchy with given type.
 */
interface PreferenceHierarchyGenerator<T> {

    /** Generates [PreferenceHierarchy] with given type. */
    fun generatePreferenceHierarchy(
        context: Context,
        coroutineScope: CoroutineScope,
        type: T,
        hierarchyType: T,
    ): PreferenceHierarchy
}

Loading