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

Commit d39ebf24 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] Fix PreferenceHierarchy add after/before
  [Catalyst] Allow specify order in hierarchy
  [Catalyst] Add PreferenceBindingFactory.bind
parents f7ee5f7c 715a4b56
Loading
Loading
Loading
Loading
+64 −26
Original line number Diff line number Diff line
@@ -17,7 +17,15 @@
package com.android.settingslib.metadata

/** A node in preference hierarchy that is associated with [PreferenceMetadata]. */
open class PreferenceHierarchyNode internal constructor(val metadata: PreferenceMetadata)
open class PreferenceHierarchyNode internal constructor(val metadata: PreferenceMetadata) {
    /**
     * Preference order in the hierarchy.
     *
     * When a preference appears on different screens, different order values could be specified.
     */
    var order: Int? = null
        internal set
}

/**
 * Preference hierarchy describes the structure of preferences recursively.
@@ -30,9 +38,7 @@ class PreferenceHierarchy internal constructor(metadata: PreferenceMetadata) :
    private val children = mutableListOf<PreferenceHierarchyNode>()

    /** Adds a preference to the hierarchy. */
    operator fun PreferenceMetadata.unaryPlus() {
        children.add(PreferenceHierarchyNode(this))
    }
    operator fun PreferenceMetadata.unaryPlus() = +PreferenceHierarchyNode(this)

    /**
     * Adds preference screen with given key (as a placeholder) to the hierarchy.
@@ -45,35 +51,67 @@ class PreferenceHierarchy internal constructor(metadata: PreferenceMetadata) :
     *
     * @throws NullPointerException if screen is not registered to [PreferenceScreenRegistry]
     */
    operator fun String.unaryPlus() {
        children.add(PreferenceHierarchyNode(PreferenceScreenRegistry[this]!!))
    }
    operator fun String.unaryPlus() = +PreferenceHierarchyNode(PreferenceScreenRegistry[this]!!)

    operator fun PreferenceHierarchyNode.unaryPlus() = also { children.add(it) }

    /** Specifies preference order in the hierarchy. */
    infix fun PreferenceHierarchyNode.order(order: Int) = apply { this.order = order }

    /** Adds a preference to the hierarchy. */
    fun add(metadata: PreferenceMetadata) {
        children.add(PreferenceHierarchyNode(metadata))
    @JvmOverloads
    fun add(metadata: PreferenceMetadata, order: Int? = null) {
        PreferenceHierarchyNode(metadata).also {
            it.order = order
            children.add(it)
        }
    }

    /** Adds a preference to the hierarchy before a specific preference. */
    /** Adds a preference to the hierarchy before given key. */
    fun addBefore(key: String, metadata: PreferenceMetadata) {
        var foundIndex = children.indexOfFirst { it.metadata.key == key }
        if (foundIndex == -1) foundIndex = children.size
        children.add(foundIndex, PreferenceHierarchyNode(metadata))
        val (list, index) = findPreference(key) ?: (children to children.size)
        list.add(index, PreferenceHierarchyNode(metadata))
    }

    /** Adds a preference group to the hierarchy before given key. */
    fun addGroupBefore(key: String, metadata: PreferenceMetadata): PreferenceHierarchy {
        val (list, index) = findPreference(key) ?: (children to children.size)
        return PreferenceHierarchy(metadata).also { list.add(index, it) }
    }

    /** Adds a preference to the hierarchy after a specific preference. */
    /** Adds a preference to the hierarchy after given key. */
    fun addAfter(key: String, metadata: PreferenceMetadata) {
        var foundIndex = children.indexOfFirst { it.metadata.key == key }
        if (foundIndex == -1) foundIndex = children.size else foundIndex++
        children.add(foundIndex, PreferenceHierarchyNode(metadata))
        val (list, index) = findPreference(key) ?: (children to children.size - 1)
        list.add(index + 1, PreferenceHierarchyNode(metadata))
    }

    /** Adds a preference group to the hierarchy after given key. */
    fun addGroupAfter(key: String, metadata: PreferenceMetadata): PreferenceHierarchy {
        val (list, index) = findPreference(key) ?: (children to children.size - 1)
        return PreferenceHierarchy(metadata).also { list.add(index + 1, it) }
    }

    private fun findPreference(key: String): Pair<MutableList<PreferenceHierarchyNode>, Int>? {
        children.forEachIndexed { index, node ->
            if (node.metadata.key == key) return children to index
            if (node is PreferenceHierarchy) {
                val result = node.findPreference(key)
                if (result != null) return result
            }
        }
        return null
    }

    /** Adds a preference group to the hierarchy. */
    operator fun PreferenceGroup.unaryPlus() = PreferenceHierarchy(this).also { children.add(it) }

    /** Adds a preference group and returns its preference hierarchy. */
    fun addGroup(metadata: PreferenceGroup): PreferenceHierarchy =
        PreferenceHierarchy(metadata).also { children.add(it) }
    @JvmOverloads
    fun addGroup(metadata: PreferenceGroup, order: Int? = null): PreferenceHierarchy =
        PreferenceHierarchy(metadata).also {
            this.order = order
            children.add(it)
        }

    /**
     * Adds preference screen with given key (as a placeholder) to the hierarchy.
@@ -91,7 +129,7 @@ class PreferenceHierarchy internal constructor(metadata: PreferenceMetadata) :
    }

    /** Extensions to add more preferences to the hierarchy. */
    operator fun plusAssign(init: PreferenceHierarchy.() -> Unit) = init(this)
    operator fun PreferenceHierarchy.plusAssign(init: PreferenceHierarchy.() -> Unit) = init(this)

    /** Traversals preference hierarchy and applies given action. */
    fun forEach(action: (PreferenceHierarchyNode) -> Unit) {
@@ -117,17 +155,17 @@ class PreferenceHierarchy internal constructor(metadata: PreferenceMetadata) :
        return null
    }

    /** Returns all the [PreferenceMetadata]s appear in the hierarchy. */
    fun getAllPreferences(): List<PreferenceMetadata> =
        mutableListOf<PreferenceMetadata>().also { getAllPreferences(it) }
    /** Returns all the [PreferenceHierarchyNode]s appear in the hierarchy. */
    fun getAllPreferences(): List<PreferenceHierarchyNode> =
        mutableListOf<PreferenceHierarchyNode>().also { getAllPreferences(it) }

    private fun getAllPreferences(result: MutableList<PreferenceMetadata>) {
        result.add(metadata)
    private fun getAllPreferences(result: MutableList<PreferenceHierarchyNode>) {
        result.add(this)
        for (child in children) {
            if (child is PreferenceHierarchy) {
                child.getAllPreferences(result)
            } else {
                result.add(child.metadata)
                result.add(child)
            }
        }
    }
+1 −4
Original line number Diff line number Diff line
@@ -19,10 +19,10 @@ package com.android.settingslib.metadata
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.annotation.AnyThread
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment

/**
 * Interface provides preference metadata (title, summary, icon, etc.).
@@ -134,9 +134,6 @@ interface PreferenceMetadata {
    /** Returns preference intent. */
    fun intent(context: Context): Intent? = null

    /** Returns preference order. */
    fun order(context: Context): Int? = null

    /**
     * Returns the preference title.
     *
+0 −1
Original line number Diff line number Diff line
@@ -80,7 +80,6 @@ interface PreferenceBinding {
            preference.isVisible =
                (this as? PreferenceAvailabilityProvider)?.isAvailable(context) != false
            preference.isPersistent = isPersistent(context)
            metadata.order(context)?.let { preference.order = it }
            // PreferenceRegistry will notify dependency change, so we do not need to set
            // dependency here. This simplifies dependency management and avoid the
            // IllegalStateException when call Preference.setDependency
+19 −0
Original line number Diff line number Diff line
@@ -16,14 +16,33 @@

package com.android.settingslib.preference

import androidx.preference.Preference
import com.android.settingslib.metadata.MainSwitchPreference
import com.android.settingslib.metadata.PreferenceGroup
import com.android.settingslib.metadata.PreferenceHierarchyNode
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.SwitchPreference

/** Factory to map [PreferenceMetadata] to [PreferenceBinding]. */
interface PreferenceBindingFactory {

    /**
     * Binds [Preference] and its associated [PreferenceMetadata] with given [PreferenceBinding]
     * (`getPreferenceBinding(metadata)` is used if [preferenceBinding] is `null`).
     *
     * Subclass could override this callback to handle common binding logic. For instance,
     * restricted preference with policy transparency.
     */
    fun bind(
        preference: Preference,
        node: PreferenceHierarchyNode,
        preferenceBinding: PreferenceBinding? = null,
    ) {
        val binding = (preferenceBinding ?: getPreferenceBinding(node.metadata)) ?: return
        binding.bind(preference, node.metadata)
        node.order?.let { preference.order = it }
    }

    /** Returns the [PreferenceBinding] associated with the [PreferenceMetadata]. */
    fun getPreferenceBinding(metadata: PreferenceMetadata): PreferenceBinding?
}
+1 −1
Original line number Diff line number Diff line
@@ -129,7 +129,7 @@ open class PreferenceFragment :
    }

    protected fun getPreferenceKeysInHierarchy(): Set<String> =
        preferenceScreenBindingHelper?.getPreferences()?.map { it.key }?.toSet() ?: setOf()
        preferenceScreenBindingHelper?.getPreferences()?.map { it.metadata.key }?.toSet() ?: setOf()

    companion object {
        private const val TAG = "PreferenceFragment"
Loading