Merge "Move debug related activity & provider to debug folder."
This commit is contained in:
@@ -34,11 +34,6 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".GalleryDebugActivity"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name=".GalleryEntryProvider"
|
||||
android:authorities="com.android.spa.gallery.provider"
|
||||
@@ -46,5 +41,20 @@
|
||||
android:exported="false">
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
android:name="com.android.settingslib.spa.framework.debug.BlankActivity"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.android.settingslib.spa.framework.debug.DebugActivity"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
<provider
|
||||
android:name="com.android.settingslib.spa.framework.debug.DebugProvider"
|
||||
android:authorities="com.android.spa.gallery.debug"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
</provider>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spa.gallery
|
||||
|
||||
import com.android.settingslib.spa.framework.DebugActivity
|
||||
|
||||
class GalleryDebugActivity : DebugActivity()
|
||||
@@ -16,21 +16,22 @@
|
||||
|
||||
package com.android.settingslib.spa.framework
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.URI_INTENT_SCHEME
|
||||
import android.content.UriMatcher
|
||||
import android.content.pm.ProviderInfo
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import com.android.settingslib.spa.framework.common.ColumnEnum
|
||||
import com.android.settingslib.spa.framework.common.QueryEnum
|
||||
import com.android.settingslib.spa.framework.common.SettingsEntry
|
||||
import com.android.settingslib.spa.framework.common.SettingsPage
|
||||
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
|
||||
import com.android.settingslib.spa.framework.common.addUri
|
||||
import com.android.settingslib.spa.framework.common.getColumns
|
||||
|
||||
private const val TAG = "EntryProvider"
|
||||
|
||||
@@ -39,117 +40,15 @@ private const val TAG = "EntryProvider"
|
||||
* One can query the provider result by:
|
||||
* $ adb shell content query --uri content://<AuthorityPath>/<QueryPath>
|
||||
* For gallery, AuthorityPath = com.android.spa.gallery.provider
|
||||
* For SettingsGoogle, AuthorityPath = com.android.settings.spa.provider
|
||||
* For Settings, 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 : ContentProvider() {
|
||||
private val spaEnvironment get() = SpaEnvironmentFactory.instance
|
||||
|
||||
/**
|
||||
* 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"),
|
||||
PAGE_INTENT_URI("pageIntent"),
|
||||
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_INTENT_URI("entryIntent"),
|
||||
ENTRY_HIERARCHY_PATH("entryPath"),
|
||||
ENTRY_START_ADB("entryStartAdb"),
|
||||
|
||||
// Columns related to search
|
||||
ENTRY_TITLE("entryTitle"),
|
||||
ENTRY_SEARCH_KEYWORD("entrySearchKw"),
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum to define all queries supported in the provider.
|
||||
*/
|
||||
enum class QueryEnum(
|
||||
val queryPath: String,
|
||||
val queryMatchCode: Int,
|
||||
val columnNames: List<ColumnEnum>
|
||||
) {
|
||||
// For debug
|
||||
PAGE_DEBUG_QUERY(
|
||||
"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(
|
||||
"page_info", 100,
|
||||
listOf(
|
||||
ColumnEnum.PAGE_ID,
|
||||
ColumnEnum.PAGE_NAME,
|
||||
ColumnEnum.PAGE_ROUTE,
|
||||
ColumnEnum.PAGE_INTENT_URI,
|
||||
ColumnEnum.PAGE_ENTRY_COUNT,
|
||||
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_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)
|
||||
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")
|
||||
@@ -182,13 +81,9 @@ open class EntryProvider : ContentProvider() {
|
||||
|
||||
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)
|
||||
QueryEnum.SEARCH_SITEMAP_QUERY.addUri(uriMatcher, info.authority)
|
||||
QueryEnum.SEARCH_STATIC_DATA_QUERY.addUri(uriMatcher, info.authority)
|
||||
QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.addUri(uriMatcher, info.authority)
|
||||
}
|
||||
super.attachInfo(context, info)
|
||||
}
|
||||
@@ -202,10 +97,6 @@ open class EntryProvider : ContentProvider() {
|
||||
): Cursor? {
|
||||
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()
|
||||
@@ -219,73 +110,18 @@ open class EntryProvider : ContentProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun queryPageDebug(): Cursor {
|
||||
val entryRepository by spaEnvironment.entryRepository
|
||||
val cursor = MatrixCursor(QueryEnum.PAGE_DEBUG_QUERY.getColumns())
|
||||
for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
|
||||
val command = createBrowsePageAdbCommand(pageWithEntry.page)
|
||||
if (command != null) {
|
||||
cursor.newRow().add(ColumnEnum.PAGE_START_ADB.id, command)
|
||||
}
|
||||
}
|
||||
return cursor
|
||||
}
|
||||
|
||||
private fun queryEntryDebug(): Cursor {
|
||||
val entryRepository by spaEnvironment.entryRepository
|
||||
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 entryRepository by spaEnvironment.entryRepository
|
||||
val cursor = MatrixCursor(QueryEnum.PAGE_INFO_QUERY.getColumns())
|
||||
for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
|
||||
val page = pageWithEntry.page
|
||||
cursor.newRow()
|
||||
.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)
|
||||
.add(ColumnEnum.HAS_RUNTIME_PARAM.id, if (page.hasRuntimeParam()) 1 else 0)
|
||||
.add(
|
||||
ColumnEnum.PAGE_INTENT_URI.id,
|
||||
createBrowsePageIntent(page).toUri(URI_INTENT_SCHEME)
|
||||
)
|
||||
}
|
||||
return cursor
|
||||
}
|
||||
|
||||
private fun queryEntryInfo(): Cursor {
|
||||
val entryRepository by spaEnvironment.entryRepository
|
||||
val cursor = MatrixCursor(QueryEnum.ENTRY_INFO_QUERY.getColumns())
|
||||
for (entry in entryRepository.getAllEntries()) {
|
||||
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 entryRepository by spaEnvironment.entryRepository
|
||||
val cursor = MatrixCursor(QueryEnum.SEARCH_SITEMAP_QUERY.getColumns())
|
||||
for (entry in entryRepository.getAllEntries()) {
|
||||
if (!entry.isAllowSearch) continue
|
||||
val intent = entry.containerPage()
|
||||
.createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id)
|
||||
?: Intent()
|
||||
cursor.newRow()
|
||||
.add(ColumnEnum.ENTRY_ID.id, entry.id)
|
||||
.add(ColumnEnum.ENTRY_HIERARCHY_PATH.id, entryRepository.getEntryPath(entry.id))
|
||||
.add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(Intent.URI_INTENT_SCHEME))
|
||||
}
|
||||
return cursor
|
||||
}
|
||||
@@ -321,54 +157,4 @@ open class EntryProvider : ContentProvider() {
|
||||
searchData?.keyword ?: emptyList<String>()
|
||||
)
|
||||
}
|
||||
|
||||
private fun createBrowsePageIntent(page: SettingsPage, entryId: String? = null): Intent {
|
||||
if (!isPageBrowsable(page)) return Intent()
|
||||
return Intent().setComponent(ComponentName(context!!, spaEnvironment.browseActivityClass!!))
|
||||
.apply {
|
||||
putExtra(BrowseActivity.KEY_DESTINATION, page.buildRoute())
|
||||
if (entryId != null) {
|
||||
putExtra(BrowseActivity.KEY_HIGHLIGHT_ENTRY, entryId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBrowsePageAdbCommand(page: SettingsPage, entryId: String? = null): String? {
|
||||
if (!isPageBrowsable(page)) return null
|
||||
val packageName = context!!.packageName
|
||||
val activityName = spaEnvironment.browseActivityClass!!.name.replace(packageName, "")
|
||||
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"
|
||||
}
|
||||
|
||||
private fun isPageBrowsable(page: SettingsPage): Boolean {
|
||||
return context != null &&
|
||||
spaEnvironment.browseActivityClass != null &&
|
||||
!page.hasRuntimeParam()
|
||||
}
|
||||
}
|
||||
|
||||
fun EntryProvider.QueryEnum.getColumns(): Array<String> {
|
||||
return columnNames.map { it.id }.toTypedArray()
|
||||
}
|
||||
|
||||
fun EntryProvider.QueryEnum.getIndex(name: EntryProvider.ColumnEnum): Int {
|
||||
return columnNames.indexOf(name)
|
||||
}
|
||||
|
||||
fun Cursor.getString(query: EntryProvider.QueryEnum, columnName: EntryProvider.ColumnEnum): String {
|
||||
return this.getString(query.getIndex(columnName))
|
||||
}
|
||||
|
||||
fun Cursor.getInt(query: EntryProvider.QueryEnum, columnName: EntryProvider.ColumnEnum): Int {
|
||||
return this.getInt(query.getIndex(columnName))
|
||||
}
|
||||
|
||||
fun Cursor.getBoolean(
|
||||
query: EntryProvider.QueryEnum,
|
||||
columnName: EntryProvider.ColumnEnum
|
||||
): Boolean {
|
||||
return this.getInt(query.getIndex(columnName)) == 1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spa.framework.common
|
||||
|
||||
import android.content.UriMatcher
|
||||
|
||||
/**
|
||||
* 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"),
|
||||
PAGE_INTENT_URI("pageIntent"),
|
||||
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_INTENT_URI("entryIntent"),
|
||||
ENTRY_HIERARCHY_PATH("entryPath"),
|
||||
ENTRY_START_ADB("entryStartAdb"),
|
||||
|
||||
// Columns related to search
|
||||
ENTRY_TITLE("entryTitle"),
|
||||
ENTRY_SEARCH_KEYWORD("entrySearchKw"),
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum to define all queries supported in the provider.
|
||||
*/
|
||||
enum class QueryEnum(
|
||||
val queryPath: String,
|
||||
val queryMatchCode: Int,
|
||||
val columnNames: List<ColumnEnum>
|
||||
) {
|
||||
// For debug
|
||||
PAGE_DEBUG_QUERY(
|
||||
"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(
|
||||
"page_info", 100,
|
||||
listOf(
|
||||
ColumnEnum.PAGE_ID,
|
||||
ColumnEnum.PAGE_NAME,
|
||||
ColumnEnum.PAGE_ROUTE,
|
||||
ColumnEnum.PAGE_INTENT_URI,
|
||||
ColumnEnum.PAGE_ENTRY_COUNT,
|
||||
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_INTENT_URI,
|
||||
)
|
||||
),
|
||||
|
||||
// Search related queries
|
||||
SEARCH_SITEMAP_QUERY(
|
||||
"search_sitemap", 300,
|
||||
listOf(
|
||||
ColumnEnum.ENTRY_ID,
|
||||
ColumnEnum.ENTRY_HIERARCHY_PATH,
|
||||
ColumnEnum.ENTRY_INTENT_URI,
|
||||
)
|
||||
),
|
||||
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,
|
||||
)
|
||||
),
|
||||
}
|
||||
|
||||
internal fun QueryEnum.getColumns(): Array<String> {
|
||||
return columnNames.map { it.id }.toTypedArray()
|
||||
}
|
||||
|
||||
internal fun QueryEnum.getIndex(name: ColumnEnum): Int {
|
||||
return columnNames.indexOf(name)
|
||||
}
|
||||
|
||||
internal fun QueryEnum.addUri(uriMatcher: UriMatcher, authority: String) {
|
||||
uriMatcher.addURI(authority, queryPath, queryMatchCode)
|
||||
}
|
||||
@@ -16,8 +16,13 @@
|
||||
|
||||
package com.android.settingslib.spa.framework.common
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.navigation.NamedNavArgument
|
||||
import com.android.settingslib.spa.framework.BrowseActivity
|
||||
import com.android.settingslib.spa.framework.util.isRuntimeParam
|
||||
import com.android.settingslib.spa.framework.util.navLink
|
||||
import com.android.settingslib.spa.framework.util.normalize
|
||||
@@ -111,6 +116,41 @@ data class SettingsPage(
|
||||
details = formatDisplayTitle()
|
||||
)
|
||||
}
|
||||
|
||||
fun createBrowseIntent(
|
||||
context: Context?,
|
||||
browseActivityClass: Class<out Activity>?,
|
||||
entryId: String? = null
|
||||
): Intent? {
|
||||
if (!isBrowsable(context, browseActivityClass)) return null
|
||||
return Intent().setComponent(ComponentName(context!!, browseActivityClass!!))
|
||||
.apply {
|
||||
putExtra(BrowseActivity.KEY_DESTINATION, buildRoute())
|
||||
if (entryId != null) {
|
||||
putExtra(BrowseActivity.KEY_HIGHLIGHT_ENTRY, entryId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createBrowseAdbCommand(
|
||||
context: Context?,
|
||||
browseActivityClass: Class<out Activity>?,
|
||||
entryId: String? = null
|
||||
): String? {
|
||||
if (!isBrowsable(context, browseActivityClass)) return null
|
||||
val packageName = context!!.packageName
|
||||
val activityName = browseActivityClass!!.name.replace(packageName, "")
|
||||
val destinationParam = " -e ${BrowseActivity.KEY_DESTINATION} ${buildRoute()}"
|
||||
val highlightParam =
|
||||
if (entryId != null) " -e ${BrowseActivity.KEY_HIGHLIGHT_ENTRY} $entryId" else ""
|
||||
return "adb shell am start -n $packageName/$activityName$destinationParam$highlightParam"
|
||||
}
|
||||
|
||||
fun isBrowsable(context: Context?, browseActivityClass: Class<out Activity>?): Boolean {
|
||||
return context != null &&
|
||||
browseActivityClass != null &&
|
||||
!hasRuntimeParam()
|
||||
}
|
||||
}
|
||||
|
||||
fun String.toHashId(): String {
|
||||
|
||||
@@ -14,12 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spa.framework
|
||||
package com.android.settingslib.spa.framework.debug
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.material3.Text
|
||||
@@ -33,8 +30,6 @@ 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.BrowseActivity.Companion.KEY_HIGHLIGHT_ENTRY
|
||||
import com.android.settingslib.spa.framework.common.LogCategory
|
||||
import com.android.settingslib.spa.framework.common.SettingsEntry
|
||||
import com.android.settingslib.spa.framework.common.SettingsPage
|
||||
@@ -60,11 +55,10 @@ private const val PARAM_NAME_ENTRY_ID = "eid"
|
||||
/**
|
||||
* The Debug Activity to display all Spa Pages & Entries.
|
||||
* One can open the debug activity by:
|
||||
* $ adb shell am start -n <Activity>
|
||||
* For gallery, Activity = com.android.settingslib.spa.gallery/.GalleryDebugActivity
|
||||
* For SettingsGoogle, Activity = com.android.settings/.spa.SpaDebugActivity
|
||||
* $ adb shell am start -n <Package>/com.android.settingslib.spa.framework.debug.DebugActivity
|
||||
* For gallery, Package = com.android.settingslib.spa.gallery
|
||||
*/
|
||||
open class DebugActivity : ComponentActivity() {
|
||||
class DebugActivity : ComponentActivity() {
|
||||
private val spaEnvironment get() = SpaEnvironmentFactory.instance
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -79,30 +73,6 @@ open class DebugActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun displayDebugMessage() {
|
||||
val entryProviderAuthorities = spaEnvironment.entryProviderAuthorities ?: return
|
||||
|
||||
try {
|
||||
val query = EntryProvider.QueryEnum.PAGE_INFO_QUERY
|
||||
contentResolver.query(
|
||||
Uri.parse("content://$entryProviderAuthorities/${query.queryPath}"),
|
||||
null, null, null
|
||||
).use { cursor ->
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
val route = cursor.getString(query, EntryProvider.ColumnEnum.PAGE_ROUTE)
|
||||
val entryCount = cursor.getInt(query, EntryProvider.ColumnEnum.PAGE_ENTRY_COUNT)
|
||||
val hasRuntimeParam =
|
||||
cursor.getBoolean(query, EntryProvider.ColumnEnum.HAS_RUNTIME_PARAM)
|
||||
val message = "Page Info: $route ($entryCount) " +
|
||||
(if (hasRuntimeParam) "with" else "no") + "-runtime-params"
|
||||
spaEnvironment.logger.message(TAG, message, category = LogCategory.FRAMEWORK)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Provider querying exception:", e)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MainContent() {
|
||||
val navController = rememberNavController()
|
||||
@@ -141,11 +111,6 @@ open class DebugActivity : ComponentActivity() {
|
||||
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 enabled = isEntryProviderAvailable().toState()
|
||||
override val onClick = { displayDebugMessage() }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +142,7 @@ open class DebugActivity : ComponentActivity() {
|
||||
|
||||
@Composable
|
||||
fun OnePage(arguments: Bundle?) {
|
||||
val context = LocalContext.current
|
||||
val entryRepository by spaEnvironment.entryRepository
|
||||
val id = arguments!!.getString(PARAM_NAME_PAGE_ID, "")
|
||||
val pageWithEntry = entryRepository.getPageWithEntry(id)!!
|
||||
@@ -186,7 +152,9 @@ open class DebugActivity : ComponentActivity() {
|
||||
Text(text = "Entry size: ${pageWithEntry.entries.size}")
|
||||
Preference(model = object : PreferenceModel {
|
||||
override val title = "open page"
|
||||
override val enabled = isPageClickable(pageWithEntry.page).toState()
|
||||
override val enabled =
|
||||
pageWithEntry.page.isBrowsable(context, spaEnvironment.browseActivityClass)
|
||||
.toState()
|
||||
override val onClick = openPage(pageWithEntry.page)
|
||||
})
|
||||
EntryList(pageWithEntry.entries)
|
||||
@@ -195,6 +163,7 @@ open class DebugActivity : ComponentActivity() {
|
||||
|
||||
@Composable
|
||||
fun OneEntry(arguments: Bundle?) {
|
||||
val context = LocalContext.current
|
||||
val entryRepository by spaEnvironment.entryRepository
|
||||
val id = arguments!!.getString(PARAM_NAME_ENTRY_ID, "")
|
||||
val entry = entryRepository.getEntry(id)!!
|
||||
@@ -202,7 +171,9 @@ open class DebugActivity : ComponentActivity() {
|
||||
RegularScaffold(title = "Entry - ${entry.displayTitle()}") {
|
||||
Preference(model = object : PreferenceModel {
|
||||
override val title = "open entry"
|
||||
override val enabled = isEntryClickable(entry).toState()
|
||||
override val enabled =
|
||||
entry.containerPage().isBrowsable(context, spaEnvironment.browseActivityClass)
|
||||
.toState()
|
||||
override val onClick = openEntry(entry)
|
||||
})
|
||||
Text(text = entryContent)
|
||||
@@ -223,12 +194,10 @@ open class DebugActivity : ComponentActivity() {
|
||||
|
||||
@Composable
|
||||
private fun openPage(page: SettingsPage): (() -> Unit)? {
|
||||
if (!isPageClickable(page)) return null
|
||||
val context = LocalContext.current
|
||||
val intent =
|
||||
page.createBrowseIntent(context, spaEnvironment.browseActivityClass) ?: return null
|
||||
val route = page.buildRoute()
|
||||
val intent = Intent(context, spaEnvironment.browseActivityClass).apply {
|
||||
putExtra(KEY_DESTINATION, route)
|
||||
}
|
||||
return {
|
||||
spaEnvironment.logger.message(
|
||||
TAG, "OpenPage: $route", category = LogCategory.FRAMEWORK
|
||||
@@ -239,13 +208,11 @@ open class DebugActivity : ComponentActivity() {
|
||||
|
||||
@Composable
|
||||
private fun openEntry(entry: SettingsEntry): (() -> Unit)? {
|
||||
if (!isEntryClickable(entry)) return null
|
||||
val context = LocalContext.current
|
||||
val intent = entry.containerPage()
|
||||
.createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id)
|
||||
?: return null
|
||||
val route = entry.containerPage().buildRoute()
|
||||
val intent = Intent(context, spaEnvironment.browseActivityClass).apply {
|
||||
putExtra(KEY_DESTINATION, route)
|
||||
putExtra(KEY_HIGHLIGHT_ENTRY, entry.id)
|
||||
}
|
||||
return {
|
||||
spaEnvironment.logger.message(
|
||||
TAG, "OpenEntry: $route", category = LogCategory.FRAMEWORK
|
||||
@@ -253,17 +220,9 @@ open class DebugActivity : ComponentActivity() {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isEntryProviderAvailable(): Boolean {
|
||||
return spaEnvironment.entryProviderAuthorities != null
|
||||
}
|
||||
|
||||
private fun isPageClickable(page: SettingsPage): Boolean {
|
||||
return spaEnvironment.browseActivityClass != null && !page.hasRuntimeParam()
|
||||
}
|
||||
|
||||
private fun isEntryClickable(entry: SettingsEntry): Boolean {
|
||||
return spaEnvironment.browseActivityClass != null &&
|
||||
!entry.containerPage().hasRuntimeParam()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A blank activity without any page.
|
||||
*/
|
||||
class BlankActivity : ComponentActivity()
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spa.framework.debug
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.URI_INTENT_SCHEME
|
||||
import android.content.UriMatcher
|
||||
import android.content.pm.ProviderInfo
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import com.android.settingslib.spa.framework.common.ColumnEnum
|
||||
import com.android.settingslib.spa.framework.common.QueryEnum
|
||||
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
|
||||
import com.android.settingslib.spa.framework.common.addUri
|
||||
import com.android.settingslib.spa.framework.common.getColumns
|
||||
|
||||
private const val TAG = "DebugProvider"
|
||||
|
||||
/**
|
||||
* The content provider to return debug data.
|
||||
* One can query the provider result by:
|
||||
* $ adb shell content query --uri content://<AuthorityPath>/<QueryPath>
|
||||
* For gallery, AuthorityPath = com.android.spa.gallery.debug
|
||||
* 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
|
||||
*/
|
||||
class DebugProvider : ContentProvider() {
|
||||
private val spaEnvironment get() = SpaEnvironmentFactory.instance
|
||||
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
|
||||
TODO("Implement this to handle requests to delete one or more rows")
|
||||
}
|
||||
|
||||
override fun getType(uri: Uri): String? {
|
||||
TODO(
|
||||
"Implement this to handle requests for the MIME type of the data" +
|
||||
"at the given URI"
|
||||
)
|
||||
}
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri? {
|
||||
TODO("Implement this to handle requests to insert a new row.")
|
||||
}
|
||||
|
||||
override fun update(
|
||||
uri: Uri,
|
||||
values: ContentValues?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<String>?
|
||||
): Int {
|
||||
TODO("Implement this to handle requests to update one or more rows.")
|
||||
}
|
||||
|
||||
override fun onCreate(): Boolean {
|
||||
Log.d(TAG, "onCreate")
|
||||
return true
|
||||
}
|
||||
|
||||
override fun attachInfo(context: Context?, info: ProviderInfo?) {
|
||||
if (info != null) {
|
||||
QueryEnum.PAGE_DEBUG_QUERY.addUri(uriMatcher, info.authority)
|
||||
QueryEnum.ENTRY_DEBUG_QUERY.addUri(uriMatcher, info.authority)
|
||||
QueryEnum.PAGE_INFO_QUERY.addUri(uriMatcher, info.authority)
|
||||
QueryEnum.ENTRY_INFO_QUERY.addUri(uriMatcher, info.authority)
|
||||
}
|
||||
super.attachInfo(context, info)
|
||||
}
|
||||
|
||||
override fun query(
|
||||
uri: Uri,
|
||||
projection: Array<String>?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<String>?,
|
||||
sortOrder: String?
|
||||
): Cursor? {
|
||||
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()
|
||||
else -> throw UnsupportedOperationException("Unknown Uri $uri")
|
||||
}
|
||||
} catch (e: UnsupportedOperationException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Provider querying exception:", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun queryPageDebug(): Cursor {
|
||||
val entryRepository by spaEnvironment.entryRepository
|
||||
val cursor = MatrixCursor(QueryEnum.PAGE_DEBUG_QUERY.getColumns())
|
||||
for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
|
||||
val command = pageWithEntry.page.createBrowseAdbCommand(
|
||||
context,
|
||||
spaEnvironment.browseActivityClass
|
||||
)
|
||||
if (command != null) {
|
||||
cursor.newRow().add(ColumnEnum.PAGE_START_ADB.id, command)
|
||||
}
|
||||
}
|
||||
return cursor
|
||||
}
|
||||
|
||||
private fun queryEntryDebug(): Cursor {
|
||||
val entryRepository by spaEnvironment.entryRepository
|
||||
val cursor = MatrixCursor(QueryEnum.ENTRY_DEBUG_QUERY.getColumns())
|
||||
for (entry in entryRepository.getAllEntries()) {
|
||||
val command = entry.containerPage()
|
||||
.createBrowseAdbCommand(context, spaEnvironment.browseActivityClass, entry.id)
|
||||
if (command != null) {
|
||||
cursor.newRow().add(ColumnEnum.ENTRY_START_ADB.id, command)
|
||||
}
|
||||
}
|
||||
return cursor
|
||||
}
|
||||
|
||||
private fun queryPageInfo(): Cursor {
|
||||
val entryRepository by spaEnvironment.entryRepository
|
||||
val cursor = MatrixCursor(QueryEnum.PAGE_INFO_QUERY.getColumns())
|
||||
for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
|
||||
val page = pageWithEntry.page
|
||||
val intent =
|
||||
page.createBrowseIntent(context, spaEnvironment.browseActivityClass) ?: Intent()
|
||||
cursor.newRow()
|
||||
.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)
|
||||
.add(ColumnEnum.HAS_RUNTIME_PARAM.id, if (page.hasRuntimeParam()) 1 else 0)
|
||||
.add(ColumnEnum.PAGE_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME))
|
||||
}
|
||||
return cursor
|
||||
}
|
||||
|
||||
private fun queryEntryInfo(): Cursor {
|
||||
val entryRepository by spaEnvironment.entryRepository
|
||||
val cursor = MatrixCursor(QueryEnum.ENTRY_INFO_QUERY.getColumns())
|
||||
for (entry in entryRepository.getAllEntries()) {
|
||||
val intent = entry.containerPage()
|
||||
.createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id)
|
||||
?: Intent()
|
||||
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, intent.toUri(URI_INTENT_SCHEME))
|
||||
}
|
||||
return cursor
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user