Implement buildEntry API for TogglePermissionAppList

Bug: 244122804
Test: manual - build SettingsGoogle
Change-Id: Ie7c1ac928f90fbeca1d4c88b1b7dcff1e4d22f5a
This commit is contained in:
Zekan Qian
2022-09-06 15:26:43 +08:00
parent 91a8fc8589
commit 74af719738
7 changed files with 118 additions and 67 deletions

View File

@@ -24,7 +24,6 @@ import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.framework.util.normalize
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
@@ -36,7 +35,7 @@ object ArgumentPageProvider : SettingsPageProvider {
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
if (!ArgumentPageModel.isValidArgument(arguments)) return emptyList()
val owner = SettingsPage(name, parameter.normalize(arguments))
val owner = SettingsPage.create(name, parameter, arguments)
val entryList = mutableListOf<SettingsEntry>()
entryList.add(
SettingsEntryBuilder.create("string_param", owner)
@@ -69,7 +68,7 @@ object ArgumentPageProvider : SettingsPageProvider {
private fun buildInjectEntry(arguments: Bundle?): SettingsEntryBuilder? {
if (!ArgumentPageModel.isValidArgument(arguments)) return null
return SettingsEntryBuilder.createInject(name, parameter.normalize(arguments))
return SettingsEntryBuilder.createInject(SettingsPage.create(name, parameter, arguments))
// Set attributes
.setIsAllowSearch(false)
.setUiLayoutFn {
@@ -80,14 +79,8 @@ object ArgumentPageProvider : SettingsPageProvider {
fun buildRootPages(): List<SettingsPage> {
return listOf(
SettingsPage(
ArgumentPageModel.name,
ArgumentPageModel.buildArgument("foo")
),
SettingsPage(
ArgumentPageModel.name,
ArgumentPageModel.buildArgument("bar")
),
SettingsPage.create(name, parameter, ArgumentPageModel.buildArgument("foo")),
SettingsPage.create(name, parameter, ArgumentPageModel.buildArgument("bar")),
)
}

View File

@@ -18,6 +18,8 @@ package com.android.settingslib.spa.framework.common
import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.navigation.NamedNavArgument
import com.android.settingslib.spa.framework.util.normalize
const val INJECT_ENTRY_NAME = "INJECT"
const val ROOT_ENTRY_NAME = "ROOT"
@@ -35,9 +37,20 @@ data class UiData(val title: String = "")
/**
* Defines data to identify a Settings page.
*/
data class SettingsPage(val name: String = "", val args: Bundle? = null) {
data class SettingsPage(val name: String = "", val arguments: Bundle? = null) {
override fun toString(): String {
return name + args?.toString()
val argsStr = arguments?.toString()?.removeRange(0, 6) ?: ""
return name + argsStr
}
companion object {
fun create(
name: String,
parameter: List<NamedNavArgument> = emptyList(),
arguments: Bundle? = null
): SettingsPage {
return SettingsPage(name, parameter.normalize(arguments))
}
}
}
@@ -45,9 +58,14 @@ data class SettingsPage(val name: String = "", val args: Bundle? = null) {
* Defines data of a Settings entry.
*/
data class SettingsEntry(
// The unique id of this entry
// The unique id of this entry.
// By default, it is computed by name + owner + fromPage + toPage
val id: String,
// The display name of this entry, which is used to be shown in hierarchy.
// By default, it is computed by name + owner
val displayName: String,
val name: String,
val owner: SettingsPage,
@@ -89,11 +107,7 @@ data class SettingsEntry(
val uiLayout: (@Composable () -> Unit) = {},
) {
override fun toString(): String {
return listOf(
name,
owner.toString(),
"(${fromPage?.toString()}-${toPage?.toString()})"
).joinToString("-")
return displayName + "(${fromPage?.toString()}->${toPage?.toString()})"
}
}
@@ -102,6 +116,7 @@ data class SettingsEntry(
*/
class SettingsEntryBuilder(private val name: String, private val owner: SettingsPage) {
private var uniqueId: String? = null
private var displayName: String? = null
private var fromPage: SettingsPage? = null
private var toPage: SettingsPage? = null
private var isAllowSearch: Boolean? = null
@@ -112,6 +127,7 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
fun build(): SettingsEntry {
return SettingsEntry(
id = computeUniqueId(),
displayName = computeDisplayName(),
name = name,
owner = owner,
@@ -153,7 +169,9 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
}
private fun computeUniqueId(): String =
uniqueId ?: name + owner.toString() + fromPage?.toString() + toPage?.toString()
uniqueId ?: "$owner:$name" + fromPage?.toString() + toPage?.toString()
private fun computeDisplayName(): String = displayName ?: "$owner:$name"
private fun computeSearchable(): Boolean = isAllowSearch ?: false
@@ -162,33 +180,16 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
return SettingsEntryBuilder(entryName, owner)
}
fun create(
entryName: String,
ownerPageName: String,
ownerPageArgs: Bundle? = null
): SettingsEntryBuilder {
val owner = SettingsPage(ownerPageName, ownerPageArgs)
return create(entryName, owner)
fun createLinkFrom(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
return create(entryName, owner).setLink(fromPage = owner)
}
fun createLinkTo(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
return create(entryName, owner).setLink(toPage = owner)
}
fun createLinkTo(
entryName: String,
ownerPageName: String,
ownerPageArgs: Bundle? = null
): SettingsEntryBuilder {
val owner = SettingsPage(ownerPageName, ownerPageArgs)
return createLinkTo(entryName, owner)
}
fun createInject(
ownerPageName: String,
ownerPageArgs: Bundle? = null
): SettingsEntryBuilder {
return createLinkTo(INJECT_ENTRY_NAME, ownerPageName, ownerPageArgs)
fun createInject(owner: SettingsPage): SettingsEntryBuilder {
return createLinkTo(INJECT_ENTRY_NAME, owner)
}
fun createRoot(page: SettingsPage): SettingsEntryBuilder {

View File

@@ -50,7 +50,7 @@ class SettingsEntryRepository(sppRepository: SettingsPageProviderRepository) {
val page = entry.toPage
if (page == null || pageToEntryListMap.containsKey(page.toString())) continue
val spp = sppRepository.getProviderOrNull(page.name) ?: continue
val newEntries = spp.buildEntry(page.args)
val newEntries = spp.buildEntry(page.arguments)
pageToEntryListMap[page.toString()] = newEntries
for (newEntry in newEntries) {
if (!entryMap.containsKey(newEntry.id)) {

View File

@@ -40,18 +40,23 @@ fun List<NamedNavArgument>.navLink(arguments: Bundle? = null): String {
return argsArray.joinToString("") { arg -> "/$arg" }
}
fun List<NamedNavArgument>.normalize(arguments: Bundle? = null): Bundle {
if (arguments == null) return Bundle.EMPTY
fun List<NamedNavArgument>.normalize(arguments: Bundle? = null): Bundle? {
if (this.isEmpty()) return null
val normArgs = Bundle()
for (navArg in this) {
when (navArg.argument.type) {
NavType.StringType -> {
val value = arguments.getString(navArg.name)
if (value != null) normArgs.putString(navArg.name, value)
val value = arguments?.getString(navArg.name)
if (value != null)
normArgs.putString(navArg.name, value)
else
normArgs.putString("unset_" + navArg.name, null)
}
NavType.IntType -> {
if (arguments.containsKey(navArg.name))
if (arguments != null && arguments.containsKey(navArg.name))
normArgs.putInt(navArg.name, arguments.getInt(navArg.name))
else
normArgs.putString("unset_" + navArg.name, null)
}
}
}

View File

@@ -26,8 +26,12 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.os.bundleOf
import androidx.navigation.NavType
import androidx.navigation.navArgument
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.widget.preference.SwitchPreference
@@ -37,27 +41,37 @@ import com.android.settingslib.spaprivileged.model.app.PackageManagers
import com.android.settingslib.spaprivileged.model.app.toRoute
import kotlinx.coroutines.Dispatchers
private const val NAME = "TogglePermissionAppInfoPage"
private const val ENTRY_NAME = "AllowControl"
private const val PERMISSION = "permission"
private const val PACKAGE_NAME = "packageName"
private const val USER_ID = "userId"
private const val PAGE_NAME = "TogglePermissionAppInfoPage"
private val PAGE_PARAMETER = listOf(
navArgument(PERMISSION) { type = NavType.StringType },
navArgument(PACKAGE_NAME) { type = NavType.StringType },
navArgument(USER_ID) { type = NavType.IntType },
)
internal class TogglePermissionAppInfoPageProvider(
private val appListTemplate: TogglePermissionAppListTemplate,
) : SettingsPageProvider {
override val name = NAME
override val name = PAGE_NAME
override val parameter = listOf(
navArgument(PERMISSION) { type = NavType.StringType },
navArgument(PACKAGE_NAME) { type = NavType.StringType },
navArgument(USER_ID) { type = NavType.IntType },
)
override val parameter = PAGE_PARAMETER
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
val owner = SettingsPage.create(name, parameter, arguments)
val entryList = mutableListOf<SettingsEntry>()
entryList.add(
SettingsEntryBuilder.create(ENTRY_NAME, owner).setIsAllowSearch(false).build()
)
return entryList
}
@Composable
override fun Page(arguments: Bundle?) {
checkNotNull(arguments)
val permissionType = checkNotNull(arguments.getString(PERMISSION))
val packageName = checkNotNull(arguments.getString(PACKAGE_NAME))
val permissionType = arguments?.getString(PERMISSION)!!
val packageName = arguments.getString(PACKAGE_NAME)!!
val userId = arguments.getInt(USER_ID)
val listModel = appListTemplate.rememberModel(permissionType)
TogglePermissionAppInfoPage(listModel, packageName, userId)
@@ -66,7 +80,12 @@ internal class TogglePermissionAppInfoPageProvider(
companion object {
@Composable
internal fun navigator(permissionType: String, app: ApplicationInfo) =
navigator(route = "$NAME/$permissionType/${app.toRoute()}")
navigator(route = "$PAGE_NAME/$permissionType/${app.toRoute()}")
internal fun buildPageId(permissionType: String): SettingsPage {
return SettingsPage.create(
PAGE_NAME, PAGE_PARAMETER, bundleOf(PERMISSION to permissionType))
}
}
}

View File

@@ -21,6 +21,7 @@ import android.content.pm.ApplicationInfo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.res.stringResource
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.rememberContext
import com.android.settingslib.spa.framework.util.asyncMapItem
@@ -52,6 +53,10 @@ interface TogglePermissionAppListProvider {
fun createModel(context: Context): TogglePermissionAppListModel<out AppRecord>
fun buildInjectEntry(): SettingsEntryBuilder {
return TogglePermissionAppListPageProvider.buildInjectEntry(permissionType)
}
@Composable
fun EntryItem() {
val listModel = rememberContext(::createModel)

View File

@@ -25,32 +25,54 @@ import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.os.bundleOf
import androidx.navigation.NavType
import androidx.navigation.navArgument
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.util.getStringArg
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
import kotlinx.coroutines.flow.Flow
private const val NAME = "TogglePermissionAppList"
private const val ENTRY_NAME = "AppList"
private const val PERMISSION = "permission"
private const val PAGE_NAME = "TogglePermissionAppList"
private val PAGE_PARAMETER = listOf(
navArgument(PERMISSION) { type = NavType.StringType },
)
internal class TogglePermissionAppListPageProvider(
private val appListTemplate: TogglePermissionAppListTemplate,
) : SettingsPageProvider {
override val name = NAME
override val name = PAGE_NAME
override val parameter = listOf(
navArgument(PERMISSION) { type = NavType.StringType },
)
override val parameter = PAGE_PARAMETER
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
val permissionType = parameter.getStringArg(PERMISSION, arguments)!!
val appListPage = SettingsPage.create(name, parameter, arguments)
val appInfoPage = TogglePermissionAppInfoPageProvider.buildPageId(permissionType)
val entryList = mutableListOf<SettingsEntry>()
// TODO: add more categories, such as personal, work, cloned, etc.
for (category in listOf("personal")) {
entryList.add(
SettingsEntryBuilder.createLinkFrom("${ENTRY_NAME}_$category", appListPage)
.setLink(toPage = appInfoPage)
.setIsAllowSearch(false)
.build()
)
}
return entryList
}
@Composable
override fun Page(arguments: Bundle?) {
checkNotNull(arguments)
val permissionType = checkNotNull(arguments.getString(PERMISSION))
TogglePermissionAppList(permissionType)
TogglePermissionAppList(arguments?.getString(PERMISSION)!!)
}
@Composable
@@ -80,10 +102,16 @@ internal class TogglePermissionAppListPageProvider(
*
* Expose route to enable enter from non-SPA pages.
*/
internal fun getRoute(permissionType: String) = "$NAME/$permissionType"
internal fun getRoute(permissionType: String) = "$PAGE_NAME/$permissionType"
@Composable
internal fun navigator(permissionType: String) = navigator(route = getRoute(permissionType))
internal fun buildInjectEntry(permissionType: String): SettingsEntryBuilder {
val appListPage = SettingsPage.create(
PAGE_NAME, PAGE_PARAMETER, bundleOf(PERMISSION to permissionType))
return SettingsEntryBuilder.createInject(appListPage).setIsAllowSearch(false)
}
}
}