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

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

Merge "[Catalyst] Add PreferenceIndexableProvider" into main

parents 53d1adb1 2655b93a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.metadata.SensitivityLevel.Companion.HIGH_SENSITIVITY
import com.android.settingslib.metadata.SensitivityLevel.Companion.UNKNOWN_SENSITIVITY
import com.android.settingslib.metadata.getPreferenceIcon
import com.android.settingslib.metadata.isPreferenceIndexable
import com.android.settingslib.preference.PreferenceScreenCreator
import com.android.settingslib.preference.PreferenceScreenFactory
import com.android.settingslib.preference.PreferenceScreenProvider
@@ -470,7 +471,7 @@ fun PreferenceMetadata.toProto(
        if (metadata.keywords != 0) keywords = metadata.keywords
        val preferenceExtras = metadata.extras(context)
        preferenceExtras?.let { extras = it.toProto() }
        indexable = metadata.isIndexable(context)
        indexable = metadata.isPreferenceIndexable(context)
        enabled = metadata.isEnabled(context)
        if (metadata is PreferenceAvailabilityProvider) {
            available = metadata.isAvailable(context)
+23 −16
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import androidx.annotation.StringRes
 * - [PreferenceTitleProvider]: provide dynamic title content
 * - [PreferenceSummaryProvider]: provide dynamic summary content (e.g. based on preference value)
 * - [PreferenceIconProvider]: provide dynamic icon content (e.g. based on flag)
 * - [PreferenceIndexableProvider]: provide if it is indexable dynamically
 * - [PreferenceAvailabilityProvider]: provide preference availability (e.g. based on flag)
 * - [PreferenceLifecycleProvider]: provide the lifecycle callbacks and notify state change
 *
@@ -86,6 +87,18 @@ interface PreferenceMetadata {
    val icon: Int
        @DrawableRes get() = 0

    /**
     * Returns if preference is indexable for settings search.
     *
     * The override should return constant value `true` / `false` only, and implement
     * [PreferenceIndexableProvider] if the result is determined dynamically.
     *
     * Note: If [indexable] of a [PreferenceScreenMetadata] returns `false`, all the preferences on
     * the screen are not indexable.
     */
    val indexable: Boolean
        get() = true

    /** Additional keywords for indexing. */
    val keywords: Int
        @StringRes get() = 0
@@ -111,21 +124,6 @@ interface PreferenceMetadata {
     */
    fun tags(context: Context): Array<String> = arrayOf()

    /**
     * Returns if preference is indexable for settings search.
     *
     * Return `false` only when the preference is unavailable for indexing on current device. If it
     * is available on condition, override [PreferenceAvailabilityProvider].
     *
     * Note: If a [PreferenceScreenMetadata.isIndexable] returns `false`, all the preferences on the
     * screen are not indexable.
     */
    fun isIndexable(context: Context): Boolean =
        when (this) {
            is PreferenceGroup -> getPreferenceTitle(context)?.isNotEmpty() == true
            else -> true
        }

    /**
     * Returns if the preference is available on condition, which indicates its availability could
     * be changed at runtime and should not be cached (e.g. for indexing).
@@ -142,6 +140,10 @@ interface PreferenceMetadata {
     *
     * UI framework normally does not allow user to interact with the preference widget when it is
     * disabled.
     *
     * If [PreferenceScreenMetadata.isEnabled] is override and `false` value is returned
     * potentially, [PreferenceIndexableProvider] should be implemented to indicate that the screen
     * might not be accessible and thus no indexable.
     */
    fun isEnabled(context: Context): Boolean = true

@@ -169,7 +171,12 @@ interface PreferenceMetadata {
}

/** Metadata of preference group. */
@AnyThread interface PreferenceGroup : PreferenceMetadata
@AnyThread
interface PreferenceGroup : PreferenceMetadata {

    override val indexable
        get() = title != 0
}

/** Metadata of preference category. */
@AnyThread
+18 −7
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ import kotlinx.coroutines.runBlocking
 * A screen is qualified as indexable only when:
 * - [PreferenceScreenMetadata.hasCompleteHierarchy] is true: hybrid mode is not supported to avoid
 *   potential conflict.
 * - **AND** [PreferenceScreenMetadata.isIndexable] is true.
 * - **AND** [PreferenceScreenMetadata.isPreferenceIndexable] is true.
 * - **AND** [PreferenceScreenMetadata.isFlagEnabled] is true.
 *
 * The strategy to provide indexing data is:
@@ -74,7 +74,7 @@ abstract class PreferenceSearchIndexablesProvider : SearchIndexablesProvider() {
                val isAvailableOnCondition =
                    isParentAvailableOnCondition || metadata.isAvailableOnCondition
                if (
                    metadata.isIndexable(context) &&
                    metadata.isPreferenceIndexable(context) &&
                        (isAvailableOnCondition || metadata.isDynamic) &&
                        !metadata.isScreenEntryPoint(preferenceScreenMetadata)
                ) {
@@ -88,7 +88,7 @@ abstract class PreferenceSearchIndexablesProvider : SearchIndexablesProvider() {
            }
            preferenceScreenMetadata
                .getPreferenceHierarchy(context, coroutineScope)
                .visitRecursively(false)
                .visitRecursively(preferenceScreenMetadata is PreferenceIndexableProvider)
        }
        Log.d(TAG, "dynamicRawData: ${cursor.count} in ${SystemClock.elapsedRealtime() - start}ms")
        return cursor
@@ -104,7 +104,7 @@ abstract class PreferenceSearchIndexablesProvider : SearchIndexablesProvider() {
            fun PreferenceHierarchyNode.visitRecursively() {
                if (metadata.isAvailableOnCondition) return
                if (
                    metadata.isIndexable(context) &&
                    metadata.isPreferenceIndexable(context) &&
                        !metadata.isDynamic &&
                        !metadata.isScreenEntryPoint(preferenceScreenMetadata)
                ) {
@@ -140,10 +140,18 @@ abstract class PreferenceSearchIndexablesProvider : SearchIndexablesProvider() {
                val preferenceScreenMetadata = factory.create(context)
                if (
                    preferenceScreenMetadata.hasCompleteHierarchy() &&
                        preferenceScreenMetadata.isIndexable(context) &&
                        preferenceScreenMetadata.isPreferenceIndexable(context) &&
                        preferenceScreenMetadata.isFlagEnabled(context)
                ) {
                    if (preferenceScreenMetadata.isEnabled(context)) {
                        action(preferenceScreenMetadata, this)
                    } else if (preferenceScreenMetadata !is PreferenceIndexableProvider) {
                        val key = preferenceScreenMetadata.key
                        Log.e(TAG, "Screen $key does not implement PreferenceIndexableProvider")
                    } else {
                        val key = preferenceScreenMetadata.key
                        Log.d(TAG, "Screen $key is disabled thus not indexable")
                    }
                }
            }
        }
@@ -201,7 +209,10 @@ abstract class PreferenceSearchIndexablesProvider : SearchIndexablesProvider() {
     * Dynamic summary is not taken into account because it is not used by settings search now.
     */
    private val PreferenceMetadata.isDynamic: Boolean
        get() = this is PreferenceTitleProvider || this is PreferenceIconProvider
        get() =
            this is PreferenceTitleProvider ||
                this is PreferenceIconProvider ||
                this is PreferenceIndexableProvider

    /**
     * Returns if the preference is an entry point of another screen.
+21 −0
Original line number Diff line number Diff line
@@ -73,6 +73,27 @@ interface PreferenceIconProvider {
    fun getIcon(context: Context): Int
}

/** Interface to provide information for settings search. */
interface PreferenceIndexableProvider {

    /**
     * Returns if preference is indexable for settings search.
     *
     * Return `false` only when the preference is unavailable for indexing on current device.
     *
     * Note:
     * - For [PreferenceScreenMetadata], all the preferences on the screen are not indexable if
     *   [isIndexable] returns `false`.
     * - If [PreferenceScreenMetadata.isEnabled] is implemented, it should also implement this
     *   interface to tell that the screen might be disabled and thus not accessible, in which case
     *   all the preferences on the screen are not indexable.
     * - Implement [PreferenceAvailabilityProvider] if it is available on condition but check
     *   [PreferenceAvailabilityProvider.isAvailable] inside [isIndexable] is optional. Unavailable
     *   preference is always non indexable no matter what [isIndexable] returns.
     */
    fun isIndexable(context: Context): Boolean
}

/** Interface to provide the state of preference availability. */
interface PreferenceAvailabilityProvider {

+9 −0
Original line number Diff line number Diff line
@@ -54,6 +54,15 @@ fun PreferenceMetadata.getPreferenceIcon(context: Context): Int =
        else -> 0
    }

/**
 * Returns whether the preference is indexable.
 *
 * @return [PreferenceIndexableProvider.isIndexable] if implemented, otherwise
 *   [PreferenceMetadata.indexable]
 */
fun PreferenceMetadata.isPreferenceIndexable(context: Context): Boolean =
    if (this is PreferenceIndexableProvider) isIndexable(context) else indexable

/**
 * Performs preference hierarchy operation with a new [CoroutineScope].
 *