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

Commit b64467be authored by Zekan Qian's avatar Zekan Qian Committed by Android (Google) Code Review
Browse files

Merge "Add search related attributes of SettingsEntry. Add search related API in EntryProvider."

parents 810d7b23 3f3e8824
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