Merge "Support page open in DebugActivity"

This commit is contained in:
Zekan Qian
2022-09-09 10:16:16 +00:00
committed by Android (Google) Code Review
8 changed files with 104 additions and 20 deletions

View File

@@ -18,4 +18,4 @@ package com.android.settingslib.spa.gallery
import com.android.settingslib.spa.framework.DebugActivity
class GalleryDebugActivity : DebugActivity(SpaEnvironment.EntryRepository)
class GalleryDebugActivity : DebugActivity(SpaEnvironment.EntryRepository, MainActivity::class.java)

View File

@@ -68,7 +68,10 @@ object ArgumentPageProvider : SettingsPageProvider {
private fun buildInjectEntry(arguments: Bundle?): SettingsEntryBuilder? {
if (!ArgumentPageModel.isValidArgument(arguments)) return null
return SettingsEntryBuilder.createInject(SettingsPage.create(name, parameter, arguments))
return SettingsEntryBuilder.createInject(
entryName = ArgumentPageModel.getInjectEntryName(arguments),
owner = SettingsPage.create(name, parameter, arguments)
)
// Set attributes
.setIsAllowSearch(false)
.setUiLayoutFn {

View File

@@ -22,6 +22,7 @@ import androidx.compose.runtime.Composable
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavType
import androidx.navigation.navArgument
import com.android.settingslib.spa.framework.BrowseActivity
import com.android.settingslib.spa.framework.common.PageModel
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.stateOf
@@ -63,6 +64,10 @@ class ArgumentPageModel : PageModel() {
return (stringParam != null && listOf("foo", "bar").contains(stringParam))
}
fun getInjectEntryName(arguments: Bundle?): String {
return "${name}_${parameter.getStringArg(STRING_PARAM_NAME, arguments)}"
}
@Composable
fun create(arguments: Bundle?): ArgumentPageModel {
val pageModel: ArgumentPageModel = viewModel(key = arguments.toString())
@@ -75,12 +80,14 @@ class ArgumentPageModel : PageModel() {
private var arguments: Bundle? = null
private var stringParam: String? = null
private var intParam: Int? = null
private var highlightName: String? = null
override fun initialize(arguments: Bundle?) {
logMsg("init with args " + arguments.toString())
this.arguments = arguments
stringParam = parameter.getStringArg(STRING_PARAM_NAME, arguments)
intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
highlightName = arguments?.getString(BrowseActivity.HIGHLIGHT_ENTRY_PARAM_NAME)
}
@Composable

View File

@@ -26,7 +26,9 @@ import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.android.settingslib.spa.R
import com.android.settingslib.spa.framework.common.ROOT_PAGE_NAME
import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
import com.android.settingslib.spa.framework.compose.localNavController
import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -48,22 +50,28 @@ open class BrowseActivity(
@Composable
private fun MainContent() {
val destination = intent?.getStringExtra(KEY_DESTINATION)
val destination =
intent?.getStringExtra(KEY_DESTINATION) ?: sppRepository.getDefaultStartPageName()
val navController = rememberNavController()
CompositionLocalProvider(navController.localNavController()) {
NavHost(navController, sppRepository.getDefaultStartPageName()) {
NavHost(navController, ROOT_PAGE_NAME) {
composable(ROOT_PAGE_NAME) {}
for (page in sppRepository.getAllProviders()) {
composable(
route = page.name + page.parameter.navRoute(),
arguments = page.parameter,
route = page.name + page.parameter.navRoute() +
"?$HIGHLIGHT_ENTRY_PARAM_NAME={$HIGHLIGHT_ENTRY_PARAM_NAME}",
arguments = page.parameter + listOf(
// add optional parameters
navArgument(HIGHLIGHT_ENTRY_PARAM_NAME) { defaultValue = "null" }
),
) { navBackStackEntry ->
page.Page(navBackStackEntry.arguments)
}
}
}
if (!destination.isNullOrEmpty()) {
if (destination.isNotEmpty()) {
LaunchedEffect(Unit) {
navController.navigate(destination) {
popUpTo(navController.graph.findStartDestination().id) {
@@ -77,5 +85,6 @@ open class BrowseActivity(
companion object {
const val KEY_DESTINATION = "spa:SpaActivity:destination"
const val HIGHLIGHT_ENTRY_PARAM_NAME = "highlightEntry"
}
}

View File

@@ -16,20 +16,25 @@
package com.android.settingslib.spa.framework
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.android.settingslib.spa.R
import com.android.settingslib.spa.framework.BrowseActivity.Companion.KEY_DESTINATION
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryRepository
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.compose.localNavController
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.toState
@@ -48,7 +53,8 @@ private const val PARAM_NAME_PAGE_ID = "pid"
private const val PARAM_NAME_ENTRY_ID = "eid"
open class DebugActivity(
private val entryRepository: SettingsEntryRepository
private val entryRepository: SettingsEntryRepository,
private val browseActivityClass: Class<*>,
) : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.Theme_SpaLib_DayNight)
@@ -87,7 +93,7 @@ open class DebugActivity(
@Composable
fun RootPage() {
HomeScaffold(title = "Entry Debug") {
HomeScaffold(title = "Settings Debug") {
Preference(object : PreferenceModel {
override val title = "List All Pages"
override val onClick = navigator(route = ROUTE_All_PAGES)
@@ -128,6 +134,10 @@ open class DebugActivity(
RegularScaffold(title = "Page ${pageWithEntry.page.displayName}") {
Text(text = pageWithEntry.page.formatArguments())
Text(text = "Entry size: ${pageWithEntry.entries.size}")
Preference(model = object : PreferenceModel {
override val title = "open page"
override val onClick = openPage(pageWithEntry.page)
})
EntryList(pageWithEntry.entries)
}
}
@@ -137,7 +147,11 @@ open class DebugActivity(
val id = arguments!!.getInt(PARAM_NAME_ENTRY_ID)
val entry = entryRepository.getEntry(id)!!
RegularScaffold(title = "Entry ${entry.displayName}") {
Text (text = entry.formatAll())
Preference(model = object : PreferenceModel {
override val title = "open entry"
override val onClick = openEntry(entry)
})
Text(text = entry.formatAll())
}
}
@@ -152,4 +166,30 @@ open class DebugActivity(
})
}
}
@Composable
private fun openPage(page: SettingsPage): () -> Unit {
val route = page.buildRoute()
val context = LocalContext.current
val intent = Intent(context, browseActivityClass).apply {
putExtra(KEY_DESTINATION, route)
}
return {
Log.d("DEBUG ACTIVITY", "Open page: $route")
context.startActivity(intent)
}
}
@Composable
private fun openEntry(entry: SettingsEntry): () -> Unit {
val route = entry.buildRoute()
val context = LocalContext.current
val intent = Intent(context, browseActivityClass).apply {
putExtra(KEY_DESTINATION, route)
}
return {
Log.d("DEBUG ACTIVITY", "Open entry: $route")
context.startActivity(intent)
}
}
}

View File

@@ -19,10 +19,13 @@ 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.BrowseActivity
import com.android.settingslib.spa.framework.util.navLink
import com.android.settingslib.spa.framework.util.normalize
const val INJECT_ENTRY_NAME = "INJECT"
const val ROOT_ENTRY_NAME = "ROOT"
const val ROOT_PAGE_NAME = "Root"
/**
* Defines data of one Settings entry for Settings search.
@@ -38,7 +41,7 @@ data class UiData(val title: String = "")
* Defines data to identify a Settings page.
*/
data class SettingsPage(
// The unique id of this page, which is computed by name + arguments
// The unique id of this page, which is computed by name + normalized(arguments)
val id: Int,
// The name of the page, which is used to compute the unique id, and need to be stable.
@@ -48,6 +51,9 @@ data class SettingsPage(
// By default, it is the same as name.
val displayName: String,
// Defined parameters of this page.
val parameter: List<NamedNavArgument> = emptyList(),
// The arguments of this page.
val arguments: Bundle? = null,
) {
@@ -62,13 +68,23 @@ data class SettingsPage(
}
fun formatArguments(): String {
if (arguments == null || arguments.isEmpty) return "[No arguments]"
return arguments.toString().removeRange(0, 6)
val normalizedArguments = parameter.normalize(arguments)
if (normalizedArguments == null || normalizedArguments.isEmpty) return "[No arguments]"
return normalizedArguments.toString().removeRange(0, 6)
}
fun formatAll(): String {
return "$displayName ${formatArguments()}"
}
fun buildRoute(highlightEntryName: String? = null): String {
val highlightParam =
if (highlightEntryName == null)
""
else
"?${BrowseActivity.HIGHLIGHT_ENTRY_PARAM_NAME}=$highlightEntryName"
return name + parameter.navLink(arguments) + highlightParam
}
}
/**
@@ -133,6 +149,12 @@ data class SettingsEntry(
)
return content.joinToString("\n")
}
fun buildRoute(): String {
// Open entry in its fromPage.
val page = fromPage ?: owner
return page.buildRoute(name)
}
}
data class SettingsPageWithEntry(
@@ -153,7 +175,8 @@ class SettingsPageBuilder(
id = "$name:${normArguments?.toString()}".toUniqueId(),
name = name,
displayName = displayName ?: name,
arguments = normArguments,
parameter = parameter,
arguments = arguments,
)
}
@@ -234,12 +257,14 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
return create(entryName, owner).setLink(toPage = owner)
}
fun createInject(owner: SettingsPage): SettingsEntryBuilder {
return createLinkTo(INJECT_ENTRY_NAME, owner)
fun createInject(owner: SettingsPage, entryName: String? = null): SettingsEntryBuilder {
val name = entryName ?: "${INJECT_ENTRY_NAME}_${owner.name}"
return createLinkTo(name, owner)
}
fun createRoot(page: SettingsPage): SettingsEntryBuilder {
return createLinkTo(ROOT_ENTRY_NAME, page)
fun createRoot(owner: SettingsPage, entryName: String? = null): SettingsEntryBuilder {
val name = entryName ?: "${ROOT_ENTRY_NAME}_${owner.name}"
return createLinkTo(name, owner)
}
}
}

View File

@@ -38,7 +38,7 @@ class SettingsEntryRepository(sppRepository: SettingsPageProviderRepository) {
val entryQueue = LinkedList<SettingsEntry>()
for (page in sppRepository.getAllRootPages()) {
val rootEntry = SettingsEntryBuilder.createRoot(page).build()
val rootEntry = SettingsEntryBuilder.createRoot(owner = page).build()
if (!entryMap.containsKey(rootEntry.id)) {
entryQueue.push(rootEntry)
entryMap.put(rootEntry.id, rootEntry)

View File

@@ -110,7 +110,7 @@ internal class TogglePermissionAppListPageProvider(
internal fun buildInjectEntry(permissionType: String): SettingsEntryBuilder {
val appListPage = SettingsPage.create(
PAGE_NAME, PAGE_PARAMETER, bundleOf(PERMISSION to permissionType))
return SettingsEntryBuilder.createInject(appListPage).setIsAllowSearch(false)
return SettingsEntryBuilder.createInject(owner = appListPage).setIsAllowSearch(false)
}
}
}