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

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

Merge "[Catalyst] Take care of isFlagEnabled in PreferenceHierarchy" into main

parents cd50a568 3e6315cd
Loading
Loading
Loading
Loading
+28 −12
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settingslib.metadata
import android.content.Context
import android.content.Context
import android.os.Bundle
import android.os.Bundle
import android.util.Log
import android.util.Log
import androidx.annotation.VisibleForTesting
import java.util.concurrent.CancellationException
import java.util.concurrent.CancellationException
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
@@ -56,7 +57,7 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
     * Each item is either [PreferenceHierarchyNode], [PreferenceHierarchy] or [Deferred] (async sub
     * Each item is either [PreferenceHierarchyNode], [PreferenceHierarchy] or [Deferred] (async sub
     * hierarchy).
     * hierarchy).
     */
     */
    private val children = mutableListOf<Any>()
    @VisibleForTesting internal val children = mutableListOf<Any>()


    internal constructor(context: Context, group: PreferenceGroup) : super(group) {
    internal constructor(context: Context, group: PreferenceGroup) : super(group) {
        this.context = context
        this.context = context
@@ -95,7 +96,7 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
     */
     */
    infix fun String.args(args: Bundle) = createPreferenceScreenHierarchy(this, args)
    infix fun String.args(args: Bundle) = createPreferenceScreenHierarchy(this, args)


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


    /** Specifies preference order in the hierarchy. */
    /** Specifies preference order in the hierarchy. */
    infix fun PreferenceHierarchyNode.order(order: Int) = apply { this.order = order }
    infix fun PreferenceHierarchyNode.order(order: Int) = apply { this.order = order }
@@ -108,10 +109,26 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
    fun add(metadata: PreferenceMetadata, order: Int? = null) {
    fun add(metadata: PreferenceMetadata, order: Int? = null) {
        PreferenceHierarchyNode(metadata).also {
        PreferenceHierarchyNode(metadata).also {
            it.order = order
            it.order = order
            children.add(it)
            add(it)
        }
        }
    }
    }


    private fun add(node: PreferenceHierarchyNode) {
        if (node.isFlagEnabled()) children.add(node)
    }

    private fun add(index: Int, node: PreferenceHierarchyNode) {
        if (node.isFlagEnabled()) children.add(index, node)
    }

    private fun PreferenceHierarchyNode.isFlagEnabled(): Boolean {
        if ((metadata as? PreferenceScreenMetadata)?.isFlagEnabled(context) == false) {
            Log.w(TAG, "$metadata is not added to hierarchy as it is not enabled")
            return false
        }
        return true
    }

    /**
    /**
     * Adds a sub hierarchy with coroutine.
     * Adds a sub hierarchy with coroutine.
     *
     *
@@ -143,25 +160,25 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
    /** Adds a preference to the hierarchy before given key. */
    /** Adds a preference to the hierarchy before given key. */
    fun addBefore(key: String, metadata: PreferenceMetadata) {
    fun addBefore(key: String, metadata: PreferenceMetadata) {
        val (hierarchy, index) = findPreference(key) ?: (this to children.size)
        val (hierarchy, index) = findPreference(key) ?: (this to children.size)
        hierarchy.children.add(index, PreferenceHierarchyNode(metadata))
        hierarchy.add(index, PreferenceHierarchyNode(metadata))
    }
    }


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


    /** Adds a preference to the hierarchy after given key. */
    /** Adds a preference to the hierarchy after given key. */
    fun addAfter(key: String, metadata: PreferenceMetadata) {
    fun addAfter(key: String, metadata: PreferenceMetadata) {
        val (hierarchy, index) = findPreference(key) ?: (this to children.size - 1)
        val (hierarchy, index) = findPreference(key) ?: (this to children.size - 1)
        hierarchy.children.add(index + 1, PreferenceHierarchyNode(metadata))
        hierarchy.add(index + 1, PreferenceHierarchyNode(metadata))
    }
    }


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


    /** Manipulates hierarchy on a preference group with given key. */
    /** Manipulates hierarchy on a preference group with given key. */
@@ -181,15 +198,14 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
    }
    }


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


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


    /**
    /**
@@ -214,7 +230,7 @@ class PreferenceHierarchy : PreferenceHierarchyNode {
    fun addPreferenceScreen(screenKey: String) = addPreferenceScreen(screenKey, null)
    fun addPreferenceScreen(screenKey: String) = addPreferenceScreen(screenKey, null)


    private fun addPreferenceScreen(screenKey: String, args: Bundle?): PreferenceHierarchyNode =
    private fun addPreferenceScreen(screenKey: String, args: Bundle?): PreferenceHierarchyNode =
        createPreferenceScreenHierarchy(screenKey, args).also { children.add(it) }
        createPreferenceScreenHierarchy(screenKey, args).also { add(it) }


    private fun createPreferenceScreenHierarchy(screenKey: String, args: Bundle?) =
    private fun createPreferenceScreenHierarchy(screenKey: String, args: Bundle?) =
        PreferenceHierarchyNode(PreferenceScreenRegistry.create(context, screenKey, args)!!)
        PreferenceHierarchyNode(PreferenceScreenRegistry.create(context, screenKey, args)!!)
+2 −0
Original line number Original line Diff line number Diff line
@@ -14,6 +14,8 @@ android_robolectric_test {
        "SettingsLibMetadata",
        "SettingsLibMetadata",
        "androidx.test.ext.junit",
        "androidx.test.ext.junit",
        "kotlin-parcelize-runtime",
        "kotlin-parcelize-runtime",
        "mockito-robolectric-prebuilt", // mockito deps order matters!
        "mockito-kotlin2",
        "truth",
        "truth",
    ],
    ],
    associates: ["SettingsLibMetadata"],
    associates: ["SettingsLibMetadata"],
+77 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 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.metadata

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub

@RunWith(AndroidJUnit4::class)
class PreferenceHierarchyTest {
    private val context: Context = ApplicationProvider.getApplicationContext()

    private val screen = mock<PreferenceScreenMetadata>()
    private val subScreen = mock<PreferenceScreenMetadata>()
    private val preference = mock<PreferenceMetadata> { on { key } doReturn "key" }

    @Test
    fun addScreen_flagDisabled() {
        subScreen.stub { on { isFlagEnabled(context) } doReturn false }
        val hierarchy =
            screen.preferenceHierarchy(context) {
                +subScreen
                +preference
                add(subScreen, 1)
                addBefore(preference.key, subScreen)
                addAfter(preference.key, subScreen)
                addGroup(subScreen)
                addGroupBefore(preference.key, subScreen)
                addGroupAfter(preference.key, subScreen)
            }
        assertThat(hierarchy.children).hasSize(1)
        (hierarchy.children[0] as PreferenceHierarchyNode).apply {
            assertThat(metadata).isSameInstanceAs(preference)
        }
    }

    @Test
    fun addScreen_flagEnabled() {
        subScreen.stub { on { isFlagEnabled(context) } doReturn true }
        val hierarchy = screen.preferenceHierarchy(context) { +subScreen }
        assertThat(hierarchy.children).hasSize(1)
        (hierarchy.children[0] as PreferenceHierarchyNode).apply {
            assertThat(metadata).isSameInstanceAs(subScreen)
        }
    }

    @Test
    fun addScreen_flagEnabled_withOrder() {
        subScreen.stub { on { isFlagEnabled(context) } doReturn true }
        val hierarchy = screen.preferenceHierarchy(context) { +subScreen order 1 }
        assertThat(hierarchy.children).hasSize(1)
        (hierarchy.children[0] as PreferenceHierarchyNode).apply {
            assertThat(metadata).isSameInstanceAs(subScreen)
            assertThat(order).isEqualTo(1)
        }
    }
}