Merge "Support entry_info query in EntryProvider; Change id of page & entry as a val instead of a function."
This commit is contained in:
@@ -54,7 +54,7 @@ fun createSettingsPage(
|
||||
parameter: List<NamedNavArgument> = emptyList(),
|
||||
arguments: Bundle? = null
|
||||
): SettingsPage {
|
||||
return SettingsPage(
|
||||
return SettingsPage.create(
|
||||
name = SppName.name,
|
||||
displayName = SppName.displayName,
|
||||
parameter = parameter,
|
||||
|
||||
@@ -153,7 +153,7 @@ open class DebugActivity(
|
||||
"${pageWithEntry.page.displayName} (${pageWithEntry.entries.size})"
|
||||
override val summary = pageWithEntry.page.formatArguments().toState()
|
||||
override val onClick =
|
||||
navigator(route = ROUTE_PAGE + "/${pageWithEntry.page.id()}")
|
||||
navigator(route = ROUTE_PAGE + "/${pageWithEntry.page.id}")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,7 @@ open class DebugActivity(
|
||||
val id = arguments!!.getString(PARAM_NAME_PAGE_ID, "")
|
||||
val pageWithEntry = entryRepository.getPageWithEntry(id)!!
|
||||
RegularScaffold(title = "Page - ${pageWithEntry.page.displayName}") {
|
||||
Text(text = "id = ${pageWithEntry.page.id()}")
|
||||
Text(text = "id = ${pageWithEntry.page.id}")
|
||||
Text(text = pageWithEntry.page.formatArguments())
|
||||
Text(text = "Entry size: ${pageWithEntry.entries.size}")
|
||||
Preference(model = object : PreferenceModel {
|
||||
@@ -206,7 +206,7 @@ open class DebugActivity(
|
||||
override val title = entry.displayTitle()
|
||||
override val summary =
|
||||
"${entry.fromPage?.displayName} -> ${entry.toPage?.displayName}".toState()
|
||||
override val onClick = navigator(route = ROUTE_ENTRY + "/${entry.id()}")
|
||||
override val onClick = navigator(route = ROUTE_ENTRY + "/${entry.id}")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,9 @@ import com.android.settingslib.spa.framework.common.SettingsPage
|
||||
* For gallery, AuthorityPath = com.android.spa.gallery.provider
|
||||
* For SettingsGoogle, AuthorityPath = com.android.settings.spa.provider
|
||||
* Some examples:
|
||||
* $ adb shell content query --uri content://<AuthorityPath>/page_start
|
||||
* $ adb shell content query --uri content://<AuthorityPath>/page_debug
|
||||
* $ adb shell content query --uri content://<AuthorityPath>/page_info
|
||||
* $ adb shell content query --uri content://<AuthorityPath>/entry_info
|
||||
*/
|
||||
open class EntryProvider(
|
||||
private val entryRepository: SettingsEntryRepository,
|
||||
@@ -50,6 +51,7 @@ open class EntryProvider(
|
||||
* Enum to define all column names in provider.
|
||||
*/
|
||||
enum class ColumnEnum(val id: String) {
|
||||
// Columns related to page
|
||||
PAGE_ID("pageId"),
|
||||
PAGE_NAME("pageName"),
|
||||
PAGE_ROUTE("pageRoute"),
|
||||
@@ -57,6 +59,13 @@ open class EntryProvider(
|
||||
PAGE_ENTRY_COUNT("entryCount"),
|
||||
HAS_RUNTIME_PARAM("hasRuntimeParam"),
|
||||
PAGE_START_ADB("pageStartAdb"),
|
||||
|
||||
// Columns related to entry
|
||||
ENTRY_ID("entryId"),
|
||||
ENTRY_NAME("entryName"),
|
||||
ENTRY_ROUTE("entryRoute"),
|
||||
ENTRY_TITLE("entryTitle"),
|
||||
ENTRY_SEARCH_KEYWORD("entrySearchKw"),
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,12 +76,15 @@ open class EntryProvider(
|
||||
val queryMatchCode: Int,
|
||||
val columnNames: List<ColumnEnum>
|
||||
) {
|
||||
PAGE_START_COMMAND(
|
||||
"page_start", 1,
|
||||
// For debug
|
||||
PAGE_DEBUG_QUERY(
|
||||
"page_debug", 1,
|
||||
listOf(ColumnEnum.PAGE_START_ADB)
|
||||
),
|
||||
|
||||
// page related queries.
|
||||
PAGE_INFO_QUERY(
|
||||
"page_info", 2,
|
||||
"page_info", 100,
|
||||
listOf(
|
||||
ColumnEnum.PAGE_ID,
|
||||
ColumnEnum.PAGE_NAME,
|
||||
@@ -82,9 +94,24 @@ open class EntryProvider(
|
||||
ColumnEnum.HAS_RUNTIME_PARAM,
|
||||
)
|
||||
),
|
||||
|
||||
// entry related queries
|
||||
ENTRY_INFO_QUERY(
|
||||
"entry_info", 200,
|
||||
listOf(
|
||||
ColumnEnum.ENTRY_ID,
|
||||
ColumnEnum.ENTRY_NAME,
|
||||
ColumnEnum.ENTRY_ROUTE,
|
||||
ColumnEnum.ENTRY_TITLE,
|
||||
ColumnEnum.ENTRY_SEARCH_KEYWORD,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private var uriMatcher: UriMatcher? = null
|
||||
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
|
||||
private fun addUri(authority: String, query: QueryEnum) {
|
||||
uriMatcher.addURI(authority, query.queryPath, query.queryMatchCode)
|
||||
}
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
|
||||
TODO("Implement this to handle requests to delete one or more rows")
|
||||
@@ -115,18 +142,10 @@ open class EntryProvider(
|
||||
}
|
||||
|
||||
override fun attachInfo(context: Context?, info: ProviderInfo?) {
|
||||
uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
|
||||
if (info != null) {
|
||||
uriMatcher!!.addURI(
|
||||
info.authority,
|
||||
QueryEnum.PAGE_START_COMMAND.queryPath,
|
||||
QueryEnum.PAGE_START_COMMAND.queryMatchCode
|
||||
)
|
||||
uriMatcher!!.addURI(
|
||||
info.authority,
|
||||
QueryEnum.PAGE_INFO_QUERY.queryPath,
|
||||
QueryEnum.PAGE_INFO_QUERY.queryMatchCode
|
||||
)
|
||||
addUri(info.authority, QueryEnum.PAGE_DEBUG_QUERY)
|
||||
addUri(info.authority, QueryEnum.PAGE_INFO_QUERY)
|
||||
addUri(info.authority, QueryEnum.ENTRY_INFO_QUERY)
|
||||
}
|
||||
super.attachInfo(context, info)
|
||||
}
|
||||
@@ -139,9 +158,10 @@ open class EntryProvider(
|
||||
sortOrder: String?
|
||||
): Cursor? {
|
||||
return try {
|
||||
when (uriMatcher!!.match(uri)) {
|
||||
QueryEnum.PAGE_START_COMMAND.queryMatchCode -> queryPageStartCommand()
|
||||
when (uriMatcher.match(uri)) {
|
||||
QueryEnum.PAGE_DEBUG_QUERY.queryMatchCode -> queryPageDebug()
|
||||
QueryEnum.PAGE_INFO_QUERY.queryMatchCode -> queryPageInfo()
|
||||
QueryEnum.ENTRY_INFO_QUERY.queryMatchCode -> queryEntryInfo()
|
||||
else -> throw UnsupportedOperationException("Unknown Uri $uri")
|
||||
}
|
||||
} catch (e: UnsupportedOperationException) {
|
||||
@@ -152,8 +172,8 @@ open class EntryProvider(
|
||||
}
|
||||
}
|
||||
|
||||
private fun queryPageStartCommand(): Cursor {
|
||||
val cursor = MatrixCursor(QueryEnum.PAGE_START_COMMAND.getColumns())
|
||||
private fun queryPageDebug(): Cursor {
|
||||
val cursor = MatrixCursor(QueryEnum.PAGE_DEBUG_QUERY.getColumns())
|
||||
for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
|
||||
val command = createBrowsePageAdbCommand(pageWithEntry.page)
|
||||
if (command != null) {
|
||||
@@ -168,7 +188,7 @@ open class EntryProvider(
|
||||
for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
|
||||
val page = pageWithEntry.page
|
||||
cursor.newRow()
|
||||
.add(ColumnEnum.PAGE_ID.id, page.id())
|
||||
.add(ColumnEnum.PAGE_ID.id, page.id)
|
||||
.add(ColumnEnum.PAGE_NAME.id, page.displayName)
|
||||
.add(ColumnEnum.PAGE_ROUTE.id, page.buildRoute())
|
||||
.add(ColumnEnum.PAGE_ENTRY_COUNT.id, pageWithEntry.entries.size)
|
||||
@@ -181,6 +201,24 @@ open class EntryProvider(
|
||||
return cursor
|
||||
}
|
||||
|
||||
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.buildRoute())
|
||||
.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 {
|
||||
if (context == null || browseActivityClass == null || page.hasRuntimeParam())
|
||||
return Intent()
|
||||
|
||||
@@ -32,6 +32,9 @@ const val ROOT_ENTRY_NAME = "ROOT"
|
||||
* Defines data of a Settings entry.
|
||||
*/
|
||||
data class SettingsEntry(
|
||||
// The unique id of this entry, which is computed by name + owner + fromPage + toPage.
|
||||
val id: String,
|
||||
|
||||
// The name of the page, which is used to compute the unique id, and need to be stable.
|
||||
private val name: String,
|
||||
|
||||
@@ -72,14 +75,9 @@ data class SettingsEntry(
|
||||
*/
|
||||
private val uiLayoutImpl: (@Composable (arguments: Bundle?) -> Unit) = {},
|
||||
) {
|
||||
// The unique id of this entry, which is computed by name + owner + fromPage + toPage.
|
||||
fun id(): String {
|
||||
return "$name:${owner.id()}(${fromPage?.id()}-${toPage?.id()})".toHashId()
|
||||
}
|
||||
|
||||
fun formatContent(): String {
|
||||
val content = listOf(
|
||||
"id = ${id()}",
|
||||
"id = $id",
|
||||
"owner = ${owner.formatDisplayTitle()}",
|
||||
"linkFrom = ${fromPage?.formatDisplayTitle()}",
|
||||
"linkTo = ${toPage?.formatDisplayTitle()}",
|
||||
@@ -99,7 +97,7 @@ data class SettingsEntry(
|
||||
}
|
||||
|
||||
fun buildRoute(): String {
|
||||
return containerPage().buildRoute(id())
|
||||
return containerPage().buildRoute(id)
|
||||
}
|
||||
|
||||
fun hasRuntimeParam(): Boolean {
|
||||
@@ -121,14 +119,13 @@ data class SettingsEntry(
|
||||
@Composable
|
||||
fun UiLayout(runtimeArguments: Bundle? = null) {
|
||||
val context = LocalContext.current
|
||||
val entryId = remember { id() }
|
||||
val highlight = rememberSaveable {
|
||||
mutableStateOf(runtimeArguments?.getString(HIGHLIGHT_ENTRY_PARAM_NAME) == entryId)
|
||||
mutableStateOf(runtimeArguments?.getString(HIGHLIGHT_ENTRY_PARAM_NAME) == id)
|
||||
}
|
||||
if (highlight.value) {
|
||||
highlight.value = false
|
||||
// TODO: Add highlight entry logic
|
||||
Toast.makeText(context, "entry $entryId highlighted", Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(context, "entry $id highlighted", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
uiLayoutImpl(fullArgument(runtimeArguments))
|
||||
}
|
||||
@@ -151,6 +148,7 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
|
||||
|
||||
fun build(): SettingsEntry {
|
||||
return SettingsEntry(
|
||||
id = id(),
|
||||
name = name,
|
||||
owner = owner,
|
||||
displayName = displayName,
|
||||
@@ -206,6 +204,11 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
|
||||
return this
|
||||
}
|
||||
|
||||
// The unique id of this entry, which is computed by name + owner + fromPage + toPage.
|
||||
private fun id(): String {
|
||||
return "$name:${owner.id}(${fromPage?.id}-${toPage?.id})".toHashId()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
|
||||
return SettingsEntryBuilder(entryName, owner)
|
||||
|
||||
@@ -44,26 +44,23 @@ class SettingsEntryRepository(sppRepository: SettingsPageProviderRepository) {
|
||||
val entryQueue = LinkedList<SettingsEntry>()
|
||||
for (page in sppRepository.getAllRootPages()) {
|
||||
val rootEntry = SettingsEntryBuilder.createRoot(owner = page).build()
|
||||
val rootEntryId = rootEntry.id()
|
||||
if (!entryMap.containsKey(rootEntryId)) {
|
||||
if (!entryMap.containsKey(rootEntry.id)) {
|
||||
entryQueue.push(rootEntry)
|
||||
entryMap.put(rootEntryId, rootEntry)
|
||||
entryMap.put(rootEntry.id, rootEntry)
|
||||
}
|
||||
}
|
||||
|
||||
while (entryQueue.isNotEmpty() && entryMap.size < MAX_ENTRY_SIZE) {
|
||||
val entry = entryQueue.pop()
|
||||
val page = entry.toPage
|
||||
val pageId = page?.id()
|
||||
if (pageId == null || pageWithEntryMap.containsKey(pageId)) continue
|
||||
if (page == null || pageWithEntryMap.containsKey(page.id)) continue
|
||||
val spp = sppRepository.getProviderOrNull(page.name) ?: continue
|
||||
val newEntries = spp.buildEntry(page.arguments)
|
||||
pageWithEntryMap[pageId] = SettingsPageWithEntry(page, newEntries)
|
||||
pageWithEntryMap[page.id] = SettingsPageWithEntry(page, newEntries)
|
||||
for (newEntry in newEntries) {
|
||||
val newEntryId = newEntry.id()
|
||||
if (!entryMap.containsKey(newEntryId)) {
|
||||
if (!entryMap.containsKey(newEntry.id)) {
|
||||
entryQueue.push(newEntry)
|
||||
entryMap.put(newEntryId, newEntry)
|
||||
entryMap.put(newEntry.id, newEntry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ import com.android.settingslib.spa.framework.util.navLink
|
||||
* Defines data to identify a Settings page.
|
||||
*/
|
||||
data class SettingsPage(
|
||||
// The unique id of this page, which is computed by name + normalized(arguments)
|
||||
val id: String,
|
||||
|
||||
// The name of the page, which is used to compute the unique id, and need to be stable.
|
||||
val name: String,
|
||||
|
||||
@@ -41,17 +44,28 @@ data class SettingsPage(
|
||||
companion object {
|
||||
fun create(
|
||||
name: String,
|
||||
displayName: String? = null,
|
||||
parameter: List<NamedNavArgument> = emptyList(),
|
||||
arguments: Bundle? = null
|
||||
): SettingsPage {
|
||||
return SettingsPage(name, name, parameter, arguments)
|
||||
return SettingsPage(
|
||||
id = id(name, parameter, arguments),
|
||||
name = name,
|
||||
displayName = displayName ?: name,
|
||||
parameter = parameter,
|
||||
arguments = arguments
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// The unique id of this page, which is computed by name + normalized(arguments)
|
||||
fun id(): String {
|
||||
val normArguments = parameter.normalize(arguments)
|
||||
return "$name:${normArguments?.toString()}".toHashId()
|
||||
// The unique id of this page, which is computed by name + normalized(arguments)
|
||||
private fun id(
|
||||
name: String,
|
||||
parameter: List<NamedNavArgument> = emptyList(),
|
||||
arguments: Bundle? = null
|
||||
): String {
|
||||
val normArguments = parameter.normalize(arguments)
|
||||
return "$name:${normArguments?.toString()}".toHashId()
|
||||
}
|
||||
}
|
||||
|
||||
// Returns if this Settings Page is created by the given Spp.
|
||||
@@ -114,5 +128,5 @@ private fun List<NamedNavArgument>.hasRuntimeParam(arguments: Bundle? = null): B
|
||||
}
|
||||
|
||||
fun String.toHashId(): String {
|
||||
return this.hashCode().toString(36)
|
||||
return this.hashCode().toUInt().toString(36)
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ internal class TogglePermissionAppInfoPageProvider(
|
||||
override val parameter = PAGE_PARAMETER
|
||||
|
||||
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
|
||||
val owner = SettingsPage.create(name, parameter, arguments)
|
||||
val owner = SettingsPage.create(name, parameter = parameter, arguments = arguments)
|
||||
val entryList = mutableListOf<SettingsEntry>()
|
||||
entryList.add(
|
||||
SettingsEntryBuilder.create(ENTRY_NAME, owner).setIsAllowSearch(false).build()
|
||||
@@ -108,7 +108,10 @@ internal class TogglePermissionAppInfoPageProvider(
|
||||
|
||||
fun buildPageData(permissionType: String): SettingsPage {
|
||||
return SettingsPage.create(
|
||||
PAGE_NAME, PAGE_PARAMETER, bundleOf(PERMISSION to permissionType))
|
||||
name = PAGE_NAME,
|
||||
parameter = PAGE_PARAMETER,
|
||||
arguments = bundleOf(PERMISSION to permissionType)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ internal class TogglePermissionAppListPageProvider(
|
||||
|
||||
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
|
||||
val permissionType = parameter.getStringArg(PERMISSION, arguments)!!
|
||||
val appListPage = SettingsPage.create(name, parameter, arguments)
|
||||
val appListPage = SettingsPage.create(name, parameter = parameter, arguments = arguments)
|
||||
val appInfoPage = TogglePermissionAppInfoPageProvider.buildPageData(permissionType)
|
||||
val entryList = mutableListOf<SettingsEntry>()
|
||||
// TODO: add more categories, such as personal, work, cloned, etc.
|
||||
@@ -117,7 +117,10 @@ internal class TogglePermissionAppListPageProvider(
|
||||
listModelSupplier: (Context) -> TogglePermissionAppListModel<out AppRecord>,
|
||||
): SettingsEntryBuilder {
|
||||
val appListPage = SettingsPage.create(
|
||||
PAGE_NAME, PAGE_PARAMETER, bundleOf(PERMISSION to permissionType))
|
||||
name = PAGE_NAME,
|
||||
parameter = PAGE_PARAMETER,
|
||||
arguments = bundleOf(PERMISSION to permissionType)
|
||||
)
|
||||
return SettingsEntryBuilder.createInject(owner = appListPage).setIsAllowSearch(false)
|
||||
.setUiLayoutFn {
|
||||
val listModel = rememberContext(listModelSupplier)
|
||||
|
||||
Reference in New Issue
Block a user