From edcfec0fe7569c14f2f0677245ea58f93d112a00 Mon Sep 17 00:00:00 2001 From: Zekan Qian Date: Wed, 30 Nov 2022 12:03:37 +0800 Subject: [PATCH] Add SpaIntent for all intent operator in Spa Support Session Name in SpaIntent Add tests for SpaIntent Set proper Session Name in DebugActivity, SpaSearchProvider & SliceUtil Bug: 244122804 Test: unit-test & local build gallery Change-Id: Ia9c21e2f56dcf7b4437e5bb417bdfe05b7c85b77 --- .../spa/gallery/preference/PreferencePage.kt | 5 +- .../settingslib/spa/debug/DebugActivity.kt | 36 +++----- .../settingslib/spa/debug/DebugProvider.kt | 55 +++++++++--- .../spa/framework/BrowseActivity.kt | 16 ++-- .../spa/framework/common/SettingsPage.kt | 46 +--------- .../spa/framework/util/SpaIntent.kt | 85 +++++++++++++++++++ .../spa/search/SpaSearchProvider.kt | 13 +-- .../spa/slice/SettingsSliceDataRepository.kt | 1 + .../settingslib/spa/slice/SliceUtil.kt | 50 ++++++----- .../common/SettingsEntryRepositoryTest.kt | 2 + .../spa/framework/common/SettingsEntryTest.kt | 2 + .../spa/framework/common/SettingsPageTest.kt | 22 ++--- .../spa/framework/util/SpaIntentTest.kt | 62 ++++++++++++++ .../slice/SettingsSliceDataRepositoryTest.kt | 8 +- .../settingslib/spa/slice/SliceUtilTest.kt | 8 +- .../testutils}/UniqueIdHelper.kt | 4 +- 16 files changed, 273 insertions(+), 142 deletions(-) create mode 100644 packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt create mode 100644 packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SpaIntentTest.kt rename packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/{framework/common => tests/testutils}/UniqueIdHelper.kt (89%) diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt index 0c9a0430bc1ed..238204a66bb4e 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt @@ -36,6 +36,7 @@ import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory import com.android.settingslib.spa.framework.common.createSettingsPage import com.android.settingslib.spa.framework.compose.toState import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.framework.util.createIntent import com.android.settingslib.spa.gallery.R import com.android.settingslib.spa.gallery.SettingsPageProviderEnum import com.android.settingslib.spa.gallery.preference.PreferencePageModel.Companion.ASYNC_PREFERENCE_SUMMARY @@ -91,6 +92,7 @@ object PreferencePageProvider : SettingsPageProvider { spaLogger.message(TAG, "create macro for ${EntryEnum.SIMPLE_PREFERENCE}") SimplePreferenceMacro(title = SIMPLE_PREFERENCE_TITLE) } + .setStatusDataFn { EntryStatusData(isDisabled = false) } .build() ) entryList.add( @@ -103,6 +105,7 @@ object PreferencePageProvider : SettingsPageProvider { searchKeywords = SIMPLE_PREFERENCE_KEYWORDS, ) } + .setStatusDataFn { EntryStatusData(isDisabled = true) } .build() ) entryList.add(singleLineSummaryEntry()) @@ -269,7 +272,7 @@ object PreferencePageProvider : SettingsPageProvider { ) } .setSliceDataFn { sliceUri, _ -> - val intent = owner.createBrowseIntent()?.createBrowsePendingIntent() + val intent = owner.createIntent()?.createBrowsePendingIntent() ?: return@setSliceDataFn null return@setSliceDataFn object : EntrySliceData() { init { diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt index 238268a9ee087..f7cbdae6909fa 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt @@ -39,7 +39,10 @@ import com.android.settingslib.spa.framework.compose.localNavController import com.android.settingslib.spa.framework.compose.navigator import com.android.settingslib.spa.framework.compose.toState import com.android.settingslib.spa.framework.theme.SettingsTheme -import com.android.settingslib.spa.slice.appendSliceParams +import com.android.settingslib.spa.framework.util.SESSION_BROWSE +import com.android.settingslib.spa.framework.util.SESSION_SEARCH +import com.android.settingslib.spa.framework.util.createIntent +import com.android.settingslib.spa.slice.fromEntry import com.android.settingslib.spa.slice.presenter.SliceDemo import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel @@ -158,14 +161,13 @@ class DebugActivity : ComponentActivity() { remember { entryRepository.getAllEntries().filter { it.hasSliceSupport } } RegularScaffold(title = "All Slices (${allSliceEntry.size})") { for (entry in allSliceEntry) { - SliceDemo(sliceUri = entry.createSliceUri(authority)) + SliceDemo(sliceUri = Uri.Builder().fromEntry(entry, authority).build()) } } } @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)!! @@ -176,8 +178,8 @@ class DebugActivity : ComponentActivity() { Text(text = "Entry size: ${pageWithEntry.entries.size}") Preference(model = object : PreferenceModel { override val title = "open page" - override val enabled = - page.isBrowsable(context, spaEnvironment.browseActivityClass).toState() + override val enabled = (spaEnvironment.browseActivityClass != null && + page.isBrowsable()).toState() override val onClick = openPage(page) }) EntryList(pageWithEntry.entries) @@ -186,7 +188,6 @@ 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)!! @@ -194,9 +195,9 @@ class DebugActivity : ComponentActivity() { RegularScaffold(title = "Entry - ${entry.debugBrief()}") { Preference(model = object : PreferenceModel { override val title = "open entry" - override val enabled = - entry.containerPage().isBrowsable(context, spaEnvironment.browseActivityClass) - .toState() + override val enabled = (spaEnvironment.browseActivityClass != null && + entry.containerPage().isBrowsable()) + .toState() override val onClick = openEntry(entry) }) Text(text = entryContent) @@ -219,7 +220,7 @@ class DebugActivity : ComponentActivity() { private fun openPage(page: SettingsPage): (() -> Unit)? { val context = LocalContext.current val intent = - page.createBrowseIntent(context, spaEnvironment.browseActivityClass) ?: return null + page.createIntent(SESSION_BROWSE) ?: return null val route = page.buildRoute() return { spaEnvironment.logger.message( @@ -232,8 +233,7 @@ class DebugActivity : ComponentActivity() { @Composable private fun openEntry(entry: SettingsEntry): (() -> Unit)? { val context = LocalContext.current - val intent = entry.containerPage() - .createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id) + val intent = entry.createIntent(SESSION_SEARCH) ?: return null val route = entry.containerPage().buildRoute() return { @@ -245,18 +245,6 @@ class DebugActivity : ComponentActivity() { } } -private fun SettingsEntry.createSliceUri( - authority: String?, - runtimeArguments: Bundle? = null -): Uri { - if (authority == null) return Uri.EMPTY - return Uri.Builder().scheme("content").authority(authority).appendSliceParams( - route = this.containerPage().buildRoute(), - entryId = this.id, - runtimeArguments = runtimeArguments, - ).build() -} - /** * A blank activity without any page. */ diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt index 3df77277c205c..59ec985ba2539 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt @@ -32,6 +32,12 @@ 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 +import com.android.settingslib.spa.framework.util.KEY_DESTINATION +import com.android.settingslib.spa.framework.util.KEY_HIGHLIGHT_ENTRY +import com.android.settingslib.spa.framework.util.KEY_SESSION_SOURCE_NAME +import com.android.settingslib.spa.framework.util.SESSION_BROWSE +import com.android.settingslib.spa.framework.util.SESSION_SEARCH +import com.android.settingslib.spa.framework.util.createIntent private const val TAG = "DebugProvider" @@ -116,9 +122,11 @@ class DebugProvider : ContentProvider() { 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 + val page = pageWithEntry.page + if (!page.isBrowsable()) continue + val command = createBrowseAdbCommand( + destination = page.buildRoute(), + sessionName = SESSION_BROWSE ) if (command != null) { cursor.newRow().add(ColumnEnum.PAGE_START_ADB.id, command) @@ -131,8 +139,13 @@ class DebugProvider : ContentProvider() { 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) + val page = entry.containerPage() + if (!page.isBrowsable()) continue + val command = createBrowseAdbCommand( + destination = page.buildRoute(), + entryId = entry.id, + sessionName = SESSION_SEARCH + ) if (command != null) { cursor.newRow().add(ColumnEnum.ENTRY_START_ADB.id, command) } @@ -145,8 +158,7 @@ class DebugProvider : ContentProvider() { 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() + val intent = page.createIntent(SESSION_BROWSE) ?: Intent() cursor.newRow() .add(ColumnEnum.PAGE_ID.id, page.id) .add(ColumnEnum.PAGE_NAME.id, page.displayName) @@ -162,17 +174,36 @@ class DebugProvider : ContentProvider() { 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() + val intent = entry.createIntent(SESSION_SEARCH) ?: 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)) - .add(ColumnEnum.ENTRY_HIERARCHY_PATH.id, - entryRepository.getEntryPathWithDisplayName(entry.id)) + .add( + ColumnEnum.ENTRY_HIERARCHY_PATH.id, + entryRepository.getEntryPathWithDisplayName(entry.id) + ) } return cursor } } + +private fun createBrowseAdbCommand( + destination: String? = null, + entryId: String? = null, + sessionName: String? = null, +): String? { + val context = SpaEnvironmentFactory.instance.appContext + val browseActivityClass = SpaEnvironmentFactory.instance.browseActivityClass ?: return null + val packageName = context.packageName + val activityName = browseActivityClass.name.replace(packageName, "") + val destinationParam = + if (destination != null) " -e $KEY_DESTINATION $destination" else "" + val highlightParam = + if (entryId != null) " -e $KEY_HIGHLIGHT_ENTRY $entryId" else "" + val sessionParam = + if (sessionName != null) " -e $KEY_SESSION_SOURCE_NAME $sessionName" else "" + return "adb shell am start -n $packageName/$activityName" + + "$destinationParam$highlightParam$sessionParam" +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt index cd3ec96cd78dd..aa10cc82a14e7 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt @@ -42,6 +42,9 @@ import com.android.settingslib.spa.framework.compose.NavControllerWrapperImpl import com.android.settingslib.spa.framework.compose.localNavController import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.framework.util.PageEvent +import com.android.settingslib.spa.framework.util.getDestination +import com.android.settingslib.spa.framework.util.getEntryId +import com.android.settingslib.spa.framework.util.getSessionName import com.android.settingslib.spa.framework.util.navRoute private const val TAG = "BrowseActivity" @@ -78,12 +81,6 @@ open class BrowseActivity : ComponentActivity() { } } } - - companion object { - const val KEY_DESTINATION = "spaActivityDestination" - const val KEY_HIGHLIGHT_ENTRY = "highlightEntry" - const val KEY_SESSION_SOURCE_NAME = "sessionSource" - } } @VisibleForTesting @@ -126,11 +123,10 @@ private fun NavControllerWrapperImpl.InitialDestination( if (destinationNavigated.value) return destinationNavigated.value = true - val initialDestination = initialIntent?.getStringExtra(BrowseActivity.KEY_DESTINATION) - ?: defaultDestination + val initialDestination = initialIntent?.getDestination() ?: defaultDestination if (initialDestination.isEmpty()) return - val initialEntryId = initialIntent?.getStringExtra(BrowseActivity.KEY_HIGHLIGHT_ENTRY) - val sessionSourceName = initialIntent?.getStringExtra(BrowseActivity.KEY_SESSION_SOURCE_NAME) + val initialEntryId = initialIntent?.getEntryId() + val sessionSourceName = initialIntent?.getSessionName() LaunchedEffect(Unit) { highlightId = initialEntryId diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt index bc5dca8778d8d..7a39b730342cb 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt @@ -16,13 +16,8 @@ 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 @@ -95,45 +90,8 @@ data class SettingsPage( return false } - fun createBrowseIntent(entryId: String? = null): Intent? { - val context = SpaEnvironmentFactory.instance.appContext - val browseActivityClass = SpaEnvironmentFactory.instance.browseActivityClass - return createBrowseIntent(context, browseActivityClass, entryId) - } - - fun createBrowseIntent( - context: Context?, - browseActivityClass: Class?, - 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?, - 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?): Boolean { - return context != null && - browseActivityClass != null && - !isCreateBy(NULL_PAGE_NAME) && + fun isBrowsable(): Boolean { + return !isCreateBy(NULL_PAGE_NAME) && !hasRuntimeParam() } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt new file mode 100644 index 0000000000000..2c3c2e003832c --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt @@ -0,0 +1,85 @@ +/* + * 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.util + +import android.content.ComponentName +import android.content.Intent +import com.android.settingslib.spa.framework.common.SettingsEntry +import com.android.settingslib.spa.framework.common.SettingsPage +import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory + +const val SESSION_BROWSE = "browse" +const val SESSION_SEARCH = "search" +const val SESSION_SLICE = "slice" + +const val KEY_DESTINATION = "spaActivityDestination" +const val KEY_HIGHLIGHT_ENTRY = "highlightEntry" +const val KEY_SESSION_SOURCE_NAME = "sessionSource" + +val SPA_INTENT_RESERVED_KEYS = listOf( + KEY_DESTINATION, + KEY_HIGHLIGHT_ENTRY, + KEY_SESSION_SOURCE_NAME +) + +private fun createBaseIntent(): Intent? { + val context = SpaEnvironmentFactory.instance.appContext + val browseActivityClass = SpaEnvironmentFactory.instance.browseActivityClass ?: return null + return Intent().setComponent(ComponentName(context, browseActivityClass)) +} + +fun SettingsPage.createIntent(sessionName: String? = null): Intent? { + if (!isBrowsable()) return null + return createBaseIntent()?.appendSpaParams( + destination = buildRoute(), + sessionName = sessionName + ) +} + +fun SettingsEntry.createIntent(sessionName: String? = null): Intent? { + val sp = containerPage() + if (!sp.isBrowsable()) return null + return createBaseIntent()?.appendSpaParams( + destination = sp.buildRoute(), + entryId = id, + sessionName = sessionName + ) +} + +fun Intent.appendSpaParams( + destination: String? = null, + entryId: String? = null, + sessionName: String? = null +): Intent { + return apply { + if (destination != null) putExtra(KEY_DESTINATION, destination) + if (entryId != null) putExtra(KEY_HIGHLIGHT_ENTRY, entryId) + if (sessionName != null) putExtra(KEY_SESSION_SOURCE_NAME, sessionName) + } +} + +fun Intent.getDestination(): String? { + return getStringExtra(KEY_DESTINATION) +} + +fun Intent.getEntryId(): String? { + return getStringExtra(KEY_HIGHLIGHT_ENTRY) +} + +fun Intent.getSessionName(): String? { + return getStringExtra(KEY_SESSION_SOURCE_NAME) +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt index 7f2f4fda44a98..02aed1ca33997 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt @@ -33,6 +33,8 @@ import com.android.settingslib.spa.framework.common.SettingsEntry import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory import com.android.settingslib.spa.framework.common.addUri import com.android.settingslib.spa.framework.common.getColumns +import com.android.settingslib.spa.framework.util.SESSION_SEARCH +import com.android.settingslib.spa.framework.util.createIntent private const val TAG = "SpaSearchProvider" @@ -162,20 +164,19 @@ class SpaSearchProvider : ContentProvider() { private fun fetchSearchData(entry: SettingsEntry, cursor: MatrixCursor) { val entryRepository by spaEnvironment.entryRepository - val browseActivityClass = spaEnvironment.browseActivityClass // Fetch search data. We can add runtime arguments later if necessary val searchData = entry.getSearchData() ?: return - val intent = entry.containerPage() - .createBrowseIntent(context, browseActivityClass, entry.id) - ?: Intent() + val intent = entry.createIntent(SESSION_SEARCH) ?: Intent() cursor.newRow() .add(ColumnEnum.ENTRY_ID.id, entry.id) .add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(Intent.URI_INTENT_SCHEME)) .add(ColumnEnum.SEARCH_TITLE.id, searchData.title) .add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword) - .add(ColumnEnum.SEARCH_PATH.id, - entryRepository.getEntryPathWithTitle(entry.id, searchData.title)) + .add( + ColumnEnum.SEARCH_PATH.id, + entryRepository.getEntryPathWithTitle(entry.id, searchData.title) + ) } private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) { diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SettingsSliceDataRepository.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SettingsSliceDataRepository.kt index 14855a8aed599..7a4750dfb1349 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SettingsSliceDataRepository.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SettingsSliceDataRepository.kt @@ -20,6 +20,7 @@ import android.net.Uri import android.util.Log import com.android.settingslib.spa.framework.common.EntrySliceData import com.android.settingslib.spa.framework.common.SettingsEntryRepository +import com.android.settingslib.spa.framework.util.getEntryId private const val TAG = "SliceDataRepository" diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SliceUtil.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SliceUtil.kt index ff143ed864c81..f3628903dc6d1 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SliceUtil.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SliceUtil.kt @@ -24,9 +24,15 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle -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.SettingsEntry import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory +import com.android.settingslib.spa.framework.util.KEY_DESTINATION +import com.android.settingslib.spa.framework.util.KEY_HIGHLIGHT_ENTRY +import com.android.settingslib.spa.framework.util.SESSION_SLICE +import com.android.settingslib.spa.framework.util.SPA_INTENT_RESERVED_KEYS +import com.android.settingslib.spa.framework.util.appendSpaParams +import com.android.settingslib.spa.framework.util.getDestination +import com.android.settingslib.spa.framework.util.getEntryId // Defines SliceUri, which contains special query parameters: // -- KEY_DESTINATION: The route that this slice is navigated to. @@ -35,11 +41,6 @@ import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory // Use {entryId, runtimeParams} as the unique Id of this Slice. typealias SliceUri = Uri -val RESERVED_KEYS = listOf( - KEY_DESTINATION, - KEY_HIGHLIGHT_ENTRY -) - fun SliceUri.getEntryId(): String? { return getQueryParameter(KEY_HIGHLIGHT_ENTRY) } @@ -51,7 +52,7 @@ fun SliceUri.getDestination(): String? { fun SliceUri.getRuntimeArguments(): Bundle { val params = Bundle() for (queryName in queryParameterNames) { - if (RESERVED_KEYS.contains(queryName)) continue + if (SPA_INTENT_RESERVED_KEYS.contains(queryName)) continue params.putString(queryName, getQueryParameter(queryName)) } return params @@ -63,12 +64,12 @@ fun SliceUri.getSliceId(): String? { return "${entryId}_$params" } -fun Uri.Builder.appendSliceParams( - route: String? = null, +fun Uri.Builder.appendSpaParams( + destination: String? = null, entryId: String? = null, runtimeArguments: Bundle? = null ): Uri.Builder { - if (route != null) appendQueryParameter(KEY_DESTINATION, route) + if (destination != null) appendQueryParameter(KEY_DESTINATION, destination) if (entryId != null) appendQueryParameter(KEY_HIGHLIGHT_ENTRY, entryId) if (runtimeArguments != null) { for (key in runtimeArguments.keySet()) { @@ -78,6 +79,20 @@ fun Uri.Builder.appendSliceParams( return this } +fun Uri.Builder.fromEntry( + entry: SettingsEntry, + authority: String?, + runtimeArguments: Bundle? = null +): Uri.Builder { + if (authority == null) return this + val sp = entry.containerPage() + return scheme("content").authority(authority).appendSpaParams( + destination = sp.buildRoute(), + entryId = entry.id, + runtimeArguments = runtimeArguments + ) +} + fun SliceUri.createBroadcastPendingIntent(): PendingIntent? { val context = SpaEnvironmentFactory.instance.appContext val sliceBroadcastClass = @@ -97,8 +112,8 @@ fun SliceUri.createBrowsePendingIntent(): PendingIntent? { fun Intent.createBrowsePendingIntent(): PendingIntent? { val context = SpaEnvironmentFactory.instance.appContext val browseActivityClass = SpaEnvironmentFactory.instance.browseActivityClass ?: return null - val destination = getStringExtra(KEY_DESTINATION) ?: return null - val entryId = getStringExtra(KEY_HIGHLIGHT_ENTRY) + val destination = getDestination() ?: return null + val entryId = getEntryId() return createBrowsePendingIntent(context, browseActivityClass, destination, entryId) } @@ -109,15 +124,12 @@ private fun createBrowsePendingIntent( entryId: String? ): PendingIntent { val intent = Intent().setComponent(ComponentName(context, browseActivityClass)) + .appendSpaParams(destination, entryId, SESSION_SLICE) .apply { // Set both extra and data (which is a Uri) in Slice Intent: // 1) extra is used in SPA navigation framework // 2) data is used in Slice framework - putExtra(KEY_DESTINATION, destination) - if (entryId != null) { - putExtra(KEY_HIGHLIGHT_ENTRY, entryId) - } - data = Uri.Builder().appendSliceParams(destination, entryId).build() + data = Uri.Builder().appendSpaParams(destination, entryId).build() flags = Intent.FLAG_ACTIVITY_NEW_TASK } @@ -130,7 +142,7 @@ private fun createBroadcastPendingIntent( entryId: String ): PendingIntent { val intent = Intent().setComponent(ComponentName(context, sliceBroadcastClass)) - .apply { data = Uri.Builder().appendSliceParams(entryId = entryId).build() } + .apply { data = Uri.Builder().appendSpaParams(entryId = entryId).build() } return PendingIntent.getBroadcast( context, 0 /* requestCode */, intent, PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt index 934b8f599be58..c0b7464e69e6e 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt @@ -23,6 +23,8 @@ import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest import com.android.settingslib.spa.tests.testutils.SppHome import com.android.settingslib.spa.tests.testutils.SppLayer1 import com.android.settingslib.spa.tests.testutils.SppLayer2 +import com.android.settingslib.spa.tests.testutils.getUniqueEntryId +import com.android.settingslib.spa.tests.testutils.getUniquePageId import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt index a343f6c30cdb9..f98963c869de0 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt @@ -20,6 +20,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.test.junit4.createComposeRule import androidx.core.os.bundleOf import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.spa.tests.testutils.getUniqueEntryId +import com.android.settingslib.spa.tests.testutils.getUniquePageId import com.google.common.truth.Truth.assertThat import org.junit.Rule import org.junit.Test diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsPageTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsPageTest.kt index 15c2db50c2343..1f5de2d972453 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsPageTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsPageTest.kt @@ -22,8 +22,8 @@ import androidx.navigation.NavType import androidx.navigation.navArgument import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.android.settingslib.spa.tests.testutils.BlankActivity import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest +import com.android.settingslib.spa.tests.testutils.getUniquePageId import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith @@ -43,9 +43,7 @@ class SettingsPageTest { assertThat(page.isCreateBy("NULL")).isTrue() assertThat(page.isCreateBy("Spp")).isFalse() assertThat(page.hasRuntimeParam()).isFalse() - assertThat(page.isBrowsable(context, BlankActivity::class.java)).isFalse() - assertThat(page.createBrowseIntent(context, BlankActivity::class.java)).isNull() - assertThat(page.createBrowseAdbCommand(context, BlankActivity::class.java)).isNull() + assertThat(page.isBrowsable()).isFalse() } @Test @@ -58,11 +56,7 @@ class SettingsPageTest { assertThat(page.isCreateBy("NULL")).isFalse() assertThat(page.isCreateBy("mySpp")).isTrue() assertThat(page.hasRuntimeParam()).isFalse() - assertThat(page.isBrowsable(context, BlankActivity::class.java)).isTrue() - assertThat(page.createBrowseIntent(context, BlankActivity::class.java)).isNotNull() - assertThat(page.createBrowseAdbCommand(context, BlankActivity::class.java)).contains( - "-e spaActivityDestination mySpp" - ) + assertThat(page.isBrowsable()).isTrue() } @Test @@ -85,11 +79,7 @@ class SettingsPageTest { assertThat(page.buildRoute()).isEqualTo("SppWithParam/myStr/10") assertThat(page.isCreateBy("SppWithParam")).isTrue() assertThat(page.hasRuntimeParam()).isFalse() - assertThat(page.isBrowsable(context, BlankActivity::class.java)).isTrue() - assertThat(page.createBrowseIntent(context, BlankActivity::class.java)).isNotNull() - assertThat(page.createBrowseAdbCommand(context, BlankActivity::class.java)).contains( - "-e spaActivityDestination SppWithParam/myStr/10" - ) + assertThat(page.isBrowsable()).isTrue() } @Test @@ -114,8 +104,6 @@ class SettingsPageTest { assertThat(page.buildRoute()).isEqualTo("SppWithRtParam/myStr/10/rtStr") assertThat(page.isCreateBy("SppWithRtParam")).isTrue() assertThat(page.hasRuntimeParam()).isTrue() - assertThat(page.isBrowsable(context, BlankActivity::class.java)).isFalse() - assertThat(page.createBrowseIntent(context, BlankActivity::class.java)).isNull() - assertThat(page.createBrowseAdbCommand(context, BlankActivity::class.java)).isNull() + assertThat(page.isBrowsable()).isFalse() } } diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SpaIntentTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SpaIntentTest.kt new file mode 100644 index 0000000000000..18547286eee03 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SpaIntentTest.kt @@ -0,0 +1,62 @@ +/* + * 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.util + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPage +import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory +import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest +import com.google.common.truth.Truth +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SpaIntentTest { + private val context: Context = ApplicationProvider.getApplicationContext() + private val spaEnvironment = SpaEnvironmentForTest(context) + + @Before + fun setEnvironment() { + SpaEnvironmentFactory.reset(spaEnvironment) + } + + @Test + fun testCreateIntent() { + val nullPage = SettingsPage.createNull() + Truth.assertThat(nullPage.createIntent()).isNull() + Truth.assertThat(SettingsEntryBuilder.createInject(nullPage).build().createIntent()) + .isNull() + + val page = spaEnvironment.createPage("SppHome") + val pageIntent = page.createIntent() + Truth.assertThat(pageIntent).isNotNull() + Truth.assertThat(pageIntent!!.getDestination()).isEqualTo(page.buildRoute()) + Truth.assertThat(pageIntent.getEntryId()).isNull() + Truth.assertThat(pageIntent.getSessionName()).isNull() + + val entry = SettingsEntryBuilder.createInject(page).build() + val entryIntent = entry.createIntent(SESSION_SEARCH) + Truth.assertThat(entryIntent).isNotNull() + Truth.assertThat(entryIntent!!.getDestination()).isEqualTo(page.buildRoute()) + Truth.assertThat(entryIntent.getEntryId()).isEqualTo(entry.id) + Truth.assertThat(entryIntent.getSessionName()).isEqualTo(SESSION_SEARCH) + } +} \ No newline at end of file diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt index 7fc09ff254afb..90e25f9a3b708 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt @@ -23,11 +23,11 @@ import androidx.slice.Slice import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spa.framework.common.createSettingsPage -import com.android.settingslib.spa.framework.common.getUniqueEntryId import com.android.settingslib.spa.testutils.InstantTaskExecutorRule import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest import com.android.settingslib.spa.tests.testutils.SppHome import com.android.settingslib.spa.tests.testutils.SppLayer2 +import com.android.settingslib.spa.tests.testutils.getUniqueEntryId import com.google.common.truth.Truth.assertThat import org.junit.Rule import org.junit.Test @@ -50,7 +50,7 @@ class SettingsSliceDataRepositoryTest { // Slice supported val page = SppLayer2.createSettingsPage() val entryId = getUniqueEntryId("Layer2Entry1", page) - val sliceUri = Uri.Builder().appendSliceParams(page.buildRoute(), entryId).build() + val sliceUri = Uri.Builder().appendSpaParams(page.buildRoute(), entryId).build() assertThat(sliceUri.getDestination()).isEqualTo("SppLayer2") assertThat(sliceUri.getSliceId()).isEqualTo("${entryId}_Bundle[{}]") val sliceData = sliceDataRepository.getOrBuildSliceData(sliceUri) @@ -59,7 +59,7 @@ class SettingsSliceDataRepositoryTest { // Slice unsupported val entryId2 = getUniqueEntryId("Layer2Entry2", page) - val sliceUri2 = Uri.Builder().appendSliceParams(page.buildRoute(), entryId2).build() + val sliceUri2 = Uri.Builder().appendSpaParams(page.buildRoute(), entryId2).build() assertThat(sliceUri2.getDestination()).isEqualTo("SppLayer2") assertThat(sliceUri2.getSliceId()).isEqualTo("${entryId2}_Bundle[{}]") assertThat(sliceDataRepository.getOrBuildSliceData(sliceUri2)).isNull() @@ -69,7 +69,7 @@ class SettingsSliceDataRepositoryTest { fun getActiveSliceDataTest() { val page = SppLayer2.createSettingsPage() val entryId = getUniqueEntryId("Layer2Entry1", page) - val sliceUri = Uri.Builder().appendSliceParams(page.buildRoute(), entryId).build() + val sliceUri = Uri.Builder().appendSpaParams(page.buildRoute(), entryId).build() // build slice data first val sliceData = sliceDataRepository.getOrBuildSliceData(sliceUri) diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SliceUtilTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SliceUtilTest.kt index 16a87f6034479..d1c4e5110f603 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SliceUtilTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SliceUtilTest.kt @@ -43,14 +43,14 @@ class SliceUtilTest { // valid slice uri val dest = "myRoute" val entryId = "myEntry" - val sliceUriWithoutParams = Uri.Builder().appendSliceParams(dest, entryId).build() + val sliceUriWithoutParams = Uri.Builder().appendSpaParams(dest, entryId).build() assertThat(sliceUriWithoutParams.getEntryId()).isEqualTo(entryId) assertThat(sliceUriWithoutParams.getDestination()).isEqualTo(dest) assertThat(sliceUriWithoutParams.getRuntimeArguments().size()).isEqualTo(0) assertThat(sliceUriWithoutParams.getSliceId()).isEqualTo("${entryId}_Bundle[{}]") val sliceUriWithParams = - Uri.Builder().appendSliceParams(dest, entryId, bundleOf("p1" to "v1")).build() + Uri.Builder().appendSpaParams(dest, entryId, bundleOf("p1" to "v1")).build() assertThat(sliceUriWithParams.getEntryId()).isEqualTo(entryId) assertThat(sliceUriWithParams.getDestination()).isEqualTo(dest) assertThat(sliceUriWithParams.getRuntimeArguments().size()).isEqualTo(1) @@ -67,7 +67,7 @@ class SliceUtilTest { // Valid Slice Uri val dest = "myRoute" val entryId = "myEntry" - val sliceUriWithoutParams = Uri.Builder().appendSliceParams(dest, entryId).build() + val sliceUriWithoutParams = Uri.Builder().appendSpaParams(dest, entryId).build() val pendingIntent = sliceUriWithoutParams.createBroadcastPendingIntent() assertThat(pendingIntent).isNotNull() assertThat(pendingIntent!!.isBroadcast).isTrue() @@ -87,7 +87,7 @@ class SliceUtilTest { // Valid Slice Uri val dest = "myRoute" val entryId = "myEntry" - val sliceUri = Uri.Builder().appendSliceParams(dest, entryId).build() + val sliceUri = Uri.Builder().appendSpaParams(dest, entryId).build() val pendingIntent = sliceUri.createBrowsePendingIntent() assertThat(pendingIntent).isNotNull() assertThat(pendingIntent!!.isActivity).isTrue() diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/UniqueIdHelper.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/UniqueIdHelper.kt similarity index 89% rename from packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/UniqueIdHelper.kt rename to packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/UniqueIdHelper.kt index 93f9afe16fb63..7e51fea69041c 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/UniqueIdHelper.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/UniqueIdHelper.kt @@ -14,10 +14,12 @@ * limitations under the License. */ -package com.android.settingslib.spa.framework.common +package com.android.settingslib.spa.tests.testutils import android.os.Bundle import androidx.navigation.NamedNavArgument +import com.android.settingslib.spa.framework.common.SettingsPage +import com.android.settingslib.spa.framework.common.toHashId import com.android.settingslib.spa.framework.util.normalize fun getUniquePageId(