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

Commit 3f3e8824 authored by Zekan Qian's avatar Zekan Qian
Browse files

Add search related attributes of SettingsEntry.

Add search related API in EntryProvider.

Bug: 244122804
Test: manual - build Gallery & SettingsGoogle
Change-Id: I6217509c4d1f9211fa4ce8ef10e8524fcc531506
parent 6908999c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ object ArgumentPageProvider : SettingsPageProvider {
            createEntry(owner, EntryEnum.STRING_PARAM)
                // Set attributes
                .setIsAllowSearch(true)
                .setIsSearchDataDynamic(true)
                .setSearchDataFn { ArgumentPageModel.genStringParamSearchData() }
                .setUiLayoutFn {
                    // Set ui rendering
@@ -66,6 +67,7 @@ object ArgumentPageProvider : SettingsPageProvider {
            createEntry(owner, EntryEnum.INT_PARAM)
                // Set attributes
                .setIsAllowSearch(true)
                .setIsSearchDataDynamic(true)
                .setSearchDataFn { ArgumentPageModel.genIntParamSearchData() }
                .setUiLayoutFn {
                    // Set ui rendering
+5 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.settingslib.spa.framework

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
@@ -36,7 +37,8 @@ import com.android.settingslib.spa.framework.compose.localNavController
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.framework.util.navRoute

const val NULL_PAGE_NAME = "NULL"
private const val TAG = "BrowseActivity"
private const val NULL_PAGE_NAME = "NULL"

/**
 * The Activity to render ALL SPA pages, and handles jumps between SPA pages.
@@ -54,6 +56,7 @@ open class BrowseActivity(spaEnvironment: SpaEnvironment) : ComponentActivity()
    override fun onCreate(savedInstanceState: Bundle?) {
        setTheme(R.style.Theme_SpaLib_DayNight)
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate")

        setContent {
            SettingsTheme {
@@ -72,8 +75,7 @@ open class BrowseActivity(spaEnvironment: SpaEnvironment) : ComponentActivity()
                    composable(
                        route = page.name + page.parameter.navRoute(),
                        arguments = page.parameter,
                    ) { navBackStackEntry -> page.Page(navBackStackEntry.arguments)
                    }
                    ) { navBackStackEntry -> page.Page(navBackStackEntry.arguments) }
                }
            }
            InitialDestinationNavigator()
+12 −8
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.HomeScaffold
import com.android.settingslib.spa.widget.scaffold.RegularScaffold

private const val TAG = "DebugActivity"
private const val ROUTE_ROOT = "root"
private const val ROUTE_All_PAGES = "pages"
private const val ROUTE_All_ENTRIES = "entries"
@@ -68,7 +69,7 @@ open class DebugActivity(private val spaEnvironment: SpaEnvironment) : Component
    override fun onCreate(savedInstanceState: Bundle?) {
        setTheme(R.style.Theme_SpaLib_DayNight)
        super.onCreate(savedInstanceState)
        displayDebugMessage()
        Log.d(TAG, "onCreate")

        setContent {
            SettingsTheme {
@@ -91,14 +92,13 @@ open class DebugActivity(private val spaEnvironment: SpaEnvironment) : Component
                    val entryCount = cursor.getInt(query, EntryProvider.ColumnEnum.PAGE_ENTRY_COUNT)
                    val hasRuntimeParam =
                        cursor.getBoolean(query, EntryProvider.ColumnEnum.HAS_RUNTIME_PARAM)
                    Log.d(
                        "DEBUG ACTIVITY", "Page Info: $route ($entryCount) " +
                    val message = "Page Info: $route ($entryCount) " +
                        (if (hasRuntimeParam) "with" else "no") + "-runtime-params"
                    )
                    Log.d(TAG, message)
                }
            }
        } catch (e: Exception) {
            Log.e("DEBUG ACTIVITY", "Provider querying exception:", e)
            Log.e(TAG, "Provider querying exception:", e)
        }
    }

@@ -139,6 +139,10 @@ open class DebugActivity(private val spaEnvironment: SpaEnvironment) : Component
                override val title = "List All Entries (${allEntry.size})"
                override val onClick = navigator(route = ROUTE_All_ENTRIES)
            })
            Preference(object : PreferenceModel {
                override val title = "Query EntryProvider"
                override val onClick = { displayDebugMessage() }
            })
        }
    }

@@ -219,7 +223,7 @@ open class DebugActivity(private val spaEnvironment: SpaEnvironment) : Component
            putExtra(KEY_DESTINATION, route)
        }
        return {
            Log.d("DEBUG ACTIVITY", "Open page: $route")
            Log.d(TAG, "OpenPage: $route")
            context.startActivity(intent)
        }
    }
@@ -234,7 +238,7 @@ open class DebugActivity(private val spaEnvironment: SpaEnvironment) : Component
            putExtra(KEY_HIGHLIGHT_ENTRY, entry.id)
        }
        return {
            Log.d("DEBUG ACTIVITY", "Open entry: $route")
            Log.d(TAG, "OpenEntry: $route")
            context.startActivity(intent)
        }
    }
+114 −11
Original line number Diff line number Diff line
@@ -28,9 +28,12 @@ import android.database.Cursor
import android.database.MatrixCursor
import android.net.Uri
import android.util.Log
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SpaEnvironment

private const val TAG = "EntryProvider"

/**
 * The content provider to return entry related data, which can be used for search and hierarchy.
 * One can query the provider result by:
@@ -39,8 +42,12 @@ import com.android.settingslib.spa.framework.common.SpaEnvironment
 * For SettingsGoogle, AuthorityPath = com.android.settings.spa.provider
 * Some examples:
 *   $ adb shell content query --uri content://<AuthorityPath>/page_debug
 *   $ adb shell content query --uri content://<AuthorityPath>/entry_debug
 *   $ adb shell content query --uri content://<AuthorityPath>/page_info
 *   $ adb shell content query --uri content://<AuthorityPath>/entry_info
 *   $ adb shell content query --uri content://<AuthorityPath>/search_sitemap
 *   $ adb shell content query --uri content://<AuthorityPath>/search_static
 *   $ adb shell content query --uri content://<AuthorityPath>/search_dynamic
 */
open class EntryProvider(spaEnvironment: SpaEnvironment) : ContentProvider() {
    private val entryRepository by spaEnvironment.entryRepository
@@ -63,6 +70,11 @@ open class EntryProvider(spaEnvironment: SpaEnvironment) : ContentProvider() {
        ENTRY_ID("entryId"),
        ENTRY_NAME("entryName"),
        ENTRY_ROUTE("entryRoute"),
        ENTRY_INTENT_URI("entryIntent"),
        ENTRY_HIERARCHY_PATH("entryPath"),
        ENTRY_START_ADB("entryStartAdb"),

        // Columns related to search
        ENTRY_TITLE("entryTitle"),
        ENTRY_SEARCH_KEYWORD("entrySearchKw"),
    }
@@ -80,6 +92,10 @@ open class EntryProvider(spaEnvironment: SpaEnvironment) : ContentProvider() {
            "page_debug", 1,
            listOf(ColumnEnum.PAGE_START_ADB)
        ),
        ENTRY_DEBUG_QUERY(
            "entry_debug", 2,
            listOf(ColumnEnum.ENTRY_START_ADB)
        ),

        // page related queries.
        PAGE_INFO_QUERY(
@@ -101,10 +117,34 @@ open class EntryProvider(spaEnvironment: SpaEnvironment) : ContentProvider() {
                ColumnEnum.ENTRY_ID,
                ColumnEnum.ENTRY_NAME,
                ColumnEnum.ENTRY_ROUTE,
                ColumnEnum.ENTRY_INTENT_URI,
            )
        ),

        // Search related queries
        SEARCH_SITEMAP_QUERY(
            "search_sitemap", 300,
            listOf(
                ColumnEnum.ENTRY_ID,
                ColumnEnum.ENTRY_HIERARCHY_PATH,
            )
        ),
        SEARCH_STATIC_DATA_QUERY(
            "search_static", 301,
            listOf(
                ColumnEnum.ENTRY_ID,
                ColumnEnum.ENTRY_TITLE,
                ColumnEnum.ENTRY_SEARCH_KEYWORD,
            )
        ),
        SEARCH_DYNAMIC_DATA_QUERY(
            "search_dynamic", 302,
            listOf(
                ColumnEnum.ENTRY_ID,
                ColumnEnum.ENTRY_TITLE,
                ColumnEnum.ENTRY_SEARCH_KEYWORD,
            )
        ),
    }

    private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
@@ -137,14 +177,19 @@ open class EntryProvider(spaEnvironment: SpaEnvironment) : ContentProvider() {
    }

    override fun onCreate(): Boolean {
        Log.d(TAG, "onCreate")
        return true
    }

    override fun attachInfo(context: Context?, info: ProviderInfo?) {
        if (info != null) {
            addUri(info.authority, QueryEnum.PAGE_DEBUG_QUERY)
            addUri(info.authority, QueryEnum.ENTRY_DEBUG_QUERY)
            addUri(info.authority, QueryEnum.PAGE_INFO_QUERY)
            addUri(info.authority, QueryEnum.ENTRY_INFO_QUERY)
            addUri(info.authority, QueryEnum.SEARCH_SITEMAP_QUERY)
            addUri(info.authority, QueryEnum.SEARCH_STATIC_DATA_QUERY)
            addUri(info.authority, QueryEnum.SEARCH_DYNAMIC_DATA_QUERY)
        }
        super.attachInfo(context, info)
    }
@@ -159,14 +204,18 @@ open class EntryProvider(spaEnvironment: SpaEnvironment) : ContentProvider() {
        return try {
            when (uriMatcher.match(uri)) {
                QueryEnum.PAGE_DEBUG_QUERY.queryMatchCode -> queryPageDebug()
                QueryEnum.ENTRY_DEBUG_QUERY.queryMatchCode -> queryEntryDebug()
                QueryEnum.PAGE_INFO_QUERY.queryMatchCode -> queryPageInfo()
                QueryEnum.ENTRY_INFO_QUERY.queryMatchCode -> queryEntryInfo()
                QueryEnum.SEARCH_SITEMAP_QUERY.queryMatchCode -> querySearchSitemap()
                QueryEnum.SEARCH_STATIC_DATA_QUERY.queryMatchCode -> querySearchStaticData()
                QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.queryMatchCode -> querySearchDynamicData()
                else -> throw UnsupportedOperationException("Unknown Uri $uri")
            }
        } catch (e: UnsupportedOperationException) {
            throw e
        } catch (e: Exception) {
            Log.e("EntryProvider", "Provider querying exception:", e)
            Log.e(TAG, "Provider querying exception:", e)
            null
        }
    }
@@ -182,6 +231,17 @@ open class EntryProvider(spaEnvironment: SpaEnvironment) : ContentProvider() {
        return cursor
    }

    private fun queryEntryDebug(): Cursor {
        val cursor = MatrixCursor(QueryEnum.ENTRY_DEBUG_QUERY.getColumns())
        for (entry in entryRepository.getAllEntries()) {
            val command = createBrowsePageAdbCommand(entry.containerPage(), entry.id)
            if (command != null) {
                cursor.newRow().add(ColumnEnum.ENTRY_START_ADB.id, command)
            }
        }
        return cursor
    }

    private fun queryPageInfo(): Cursor {
        val cursor = MatrixCursor(QueryEnum.PAGE_INFO_QUERY.getColumns())
        for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
@@ -203,36 +263,79 @@ open class EntryProvider(spaEnvironment: SpaEnvironment) : ContentProvider() {
    private fun queryEntryInfo(): Cursor {
        val cursor = MatrixCursor(QueryEnum.ENTRY_INFO_QUERY.getColumns())
        for (entry in entryRepository.getAllEntries()) {
            // We can add runtime arguments if necessary
            val searchData = entry.getSearchData()
            cursor.newRow()
                .add(ColumnEnum.ENTRY_ID.id, entry.id)
                .add(ColumnEnum.ENTRY_NAME.id, entry.displayName)
                .add(ColumnEnum.ENTRY_ROUTE.id, entry.containerPage().buildRoute())
                .add(
                    ColumnEnum.ENTRY_INTENT_URI.id,
                    createBrowsePageIntent(entry.containerPage(), entry.id).toUri(URI_INTENT_SCHEME)
                )
        }
        return cursor
    }

    private fun querySearchSitemap(): Cursor {
        val cursor = MatrixCursor(QueryEnum.SEARCH_SITEMAP_QUERY.getColumns())
        for (entry in entryRepository.getAllEntries()) {
            if (!entry.isAllowSearch) continue
            cursor.newRow()
                .add(ColumnEnum.ENTRY_ID.id, entry.id)
                .add(ColumnEnum.ENTRY_HIERARCHY_PATH.id, entryRepository.getEntryPath(entry.id))
        }
        return cursor
    }

    private fun querySearchStaticData(): Cursor {
        val cursor = MatrixCursor(QueryEnum.SEARCH_STATIC_DATA_QUERY.getColumns())
        for (entry in entryRepository.getAllEntries()) {
            if (!entry.isAllowSearch || entry.isSearchDataDynamic) continue
            fetchSearchData(entry, cursor)
        }
        return cursor
    }

    private fun querySearchDynamicData(): Cursor {
        val cursor = MatrixCursor(QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.getColumns())
        for (entry in entryRepository.getAllEntries()) {
            if (!entry.isAllowSearch || !entry.isSearchDataDynamic) continue
            fetchSearchData(entry, cursor)
        }
        return cursor
    }

    private fun fetchSearchData(entry: SettingsEntry, cursor: MatrixCursor) {
        // Fetch search data. We can add runtime arguments later if necessary
        val searchData = entry.getSearchData()
        cursor.newRow()
            .add(ColumnEnum.ENTRY_ID.id, entry.id)
            .add(ColumnEnum.ENTRY_TITLE.id, searchData?.title ?: "")
            .add(
                ColumnEnum.ENTRY_SEARCH_KEYWORD.id,
                searchData?.keyword ?: emptyList<String>()
            )
    }
        return cursor
    }

    private fun createBrowsePageIntent(page: SettingsPage): Intent {
    private fun createBrowsePageIntent(page: SettingsPage, entryId: String? = null): Intent {
        if (context == null || page.hasRuntimeParam())
            return Intent()

        return Intent().setComponent(ComponentName(context!!, browseActivityClass)).apply {
            putExtra(BrowseActivity.KEY_DESTINATION, page.buildRoute())
            if (entryId != null) {
                putExtra(BrowseActivity.KEY_HIGHLIGHT_ENTRY, entryId)
            }
        }
    }

    private fun createBrowsePageAdbCommand(page: SettingsPage): String? {
    private fun createBrowsePageAdbCommand(page: SettingsPage, entryId: String? = null): String? {
        if (context == null || page.hasRuntimeParam()) return null
        val packageName = context!!.packageName
        val activityName = browseActivityClass.name.replace(packageName, "")
        return "adb shell am start -n $packageName/$activityName" +
            " -e ${BrowseActivity.KEY_DESTINATION} ${page.buildRoute()}"
        val destinationParam = " -e ${BrowseActivity.KEY_DESTINATION} ${page.buildRoute()}"
        val highlightParam =
            if (entryId != null) " -e ${BrowseActivity.KEY_HIGHLIGHT_ENTRY} $entryId" else ""
        return "adb shell am start -n $packageName/$activityName$destinationParam$highlightParam"
    }
}

+8 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ data class SettingsEntry(
     * ========================================
     */
    val isAllowSearch: Boolean = false,
    val isSearchDataDynamic: Boolean = false,

    /**
     * ========================================
@@ -134,6 +135,7 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings

    // Attributes
    private var isAllowSearch: Boolean = false
    private var isSearchDataDynamic: Boolean = false

    // Functions
    private var searchDataFn: (arguments: Bundle?) -> EntrySearchData? = { null }
@@ -152,6 +154,7 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings

            // attributes
            isAllowSearch = isAllowSearch,
            isSearchDataDynamic = isSearchDataDynamic,

            // functions
            searchDataImpl = searchDataFn,
@@ -178,6 +181,11 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
        return this
    }

    fun setIsSearchDataDynamic(isDynamic: Boolean): SettingsEntryBuilder {
        this.isSearchDataDynamic = isDynamic
        return this
    }

    fun setMacro(fn: (arguments: Bundle?) -> EntryMacro): SettingsEntryBuilder {
        setSearchDataFn { fn(it).getSearchData() }
        setUiLayoutFn {
Loading