Merge "Support search "Mobile data"" into main
This commit is contained in:
@@ -5187,6 +5187,15 @@
|
|||||||
<activity android:name=".spa.SpaBridgeActivity" android:exported="false"/>
|
<activity android:name=".spa.SpaBridgeActivity" android:exported="false"/>
|
||||||
<activity android:name=".spa.SpaAppBridgeActivity" android:exported="false"/>
|
<activity android:name=".spa.SpaAppBridgeActivity" android:exported="false"/>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".spa.search.SpaSearchLandingActivity"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter android:priority="1">
|
||||||
|
<action android:name="android.settings.SPA_SEARCH_LANDING" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".Settings$FingerprintSettingsActivityV2"
|
<activity android:name=".Settings$FingerprintSettingsActivityV2"
|
||||||
android:label="@string/security_settings_fingerprint_preference_title"
|
android:label="@string/security_settings_fingerprint_preference_title"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
@@ -22,11 +22,18 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import com.android.settings.search.SearchIndexableResourcesFactory.createSearchIndexableResources
|
import com.android.settings.search.SearchIndexableResourcesFactory.createSearchIndexableResources
|
||||||
|
import com.android.settings.spa.search.SpaSearchRepository
|
||||||
import com.android.settingslib.search.SearchIndexableResources
|
import com.android.settingslib.search.SearchIndexableResources
|
||||||
|
|
||||||
/** FeatureProvider for the refactored search code. */
|
/** FeatureProvider for the refactored search code. */
|
||||||
open class SearchFeatureProviderImpl : SearchFeatureProvider {
|
open class SearchFeatureProviderImpl : SearchFeatureProvider {
|
||||||
private val lazySearchIndexableResources by lazy { createSearchIndexableResources() }
|
private val lazySearchIndexableResources by lazy {
|
||||||
|
createSearchIndexableResources().apply {
|
||||||
|
for (searchIndexableData in SpaSearchRepository().getSearchIndexableDataList()) {
|
||||||
|
addIndex(searchIndexableData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun verifyLaunchSearchResultPageCaller(context: Context, callerPackage: String) {
|
override fun verifyLaunchSearchResultPageCaller(context: Context, callerPackage: String) {
|
||||||
require(callerPackage.isNotEmpty()) {
|
require(callerPackage.isNotEmpty()) {
|
||||||
|
@@ -46,10 +46,14 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
|
import com.android.settings.flags.Flags
|
||||||
import com.android.settings.network.SubscriptionInfoListViewModel
|
import com.android.settings.network.SubscriptionInfoListViewModel
|
||||||
|
import com.android.settings.network.SubscriptionUtil
|
||||||
import com.android.settings.network.telephony.DataSubscriptionRepository
|
import com.android.settings.network.telephony.DataSubscriptionRepository
|
||||||
import com.android.settings.network.telephony.MobileDataRepository
|
import com.android.settings.network.telephony.MobileDataRepository
|
||||||
|
import com.android.settings.network.telephony.requireSubscriptionManager
|
||||||
import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo
|
import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo
|
||||||
|
import com.android.settings.spa.search.SearchablePage
|
||||||
import com.android.settings.wifi.WifiPickerTrackerHelper
|
import com.android.settings.wifi.WifiPickerTrackerHelper
|
||||||
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
|
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
|
||||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||||
@@ -62,6 +66,7 @@ import com.android.settingslib.spa.widget.preference.PreferenceModel
|
|||||||
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
|
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
|
||||||
import com.android.settingslib.spa.widget.ui.Category
|
import com.android.settingslib.spa.widget.ui.Category
|
||||||
import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverFlow
|
import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverFlow
|
||||||
|
import com.android.settingslib.spaprivileged.framework.common.userManager
|
||||||
import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow
|
import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -78,7 +83,7 @@ import kotlinx.coroutines.withContext
|
|||||||
/**
|
/**
|
||||||
* Showing the sim onboarding which is the process flow of sim switching on.
|
* Showing the sim onboarding which is the process flow of sim switching on.
|
||||||
*/
|
*/
|
||||||
open class NetworkCellularGroupProvider : SettingsPageProvider {
|
open class NetworkCellularGroupProvider : SettingsPageProvider, SearchablePage {
|
||||||
override val name = fileName
|
override val name = fileName
|
||||||
override val metricsCategory = SettingsEnums.MOBILE_NETWORK_LIST
|
override val metricsCategory = SettingsEnums.MOBILE_NETWORK_LIST
|
||||||
private val owner = createSettingsPage()
|
private val owner = createSettingsPage()
|
||||||
@@ -191,8 +196,24 @@ open class NetworkCellularGroupProvider : SettingsPageProvider {
|
|||||||
open fun OtherSection(){
|
open fun OtherSection(){
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getSearchableTitles(context: Context): List<String> {
|
||||||
|
if (!isPageSearchable(context)) return emptyList()
|
||||||
|
return buildList {
|
||||||
|
if (context.requireSubscriptionManager().activeSubscriptionInfoCount > 0) {
|
||||||
|
add(context.getString(R.string.mobile_data_settings_title))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val fileName = "NetworkCellularGroupProvider"
|
const val fileName = "NetworkCellularGroupProvider"
|
||||||
|
|
||||||
|
private fun isPageSearchable(context: Context) =
|
||||||
|
Flags.isDualSimOnboardingEnabled() &&
|
||||||
|
SubscriptionUtil.isSimHardwareVisible(context) &&
|
||||||
|
!com.android.settingslib.Utils.isWifiOnly(context) &&
|
||||||
|
context.userManager.isAdminUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
25
src/com/android/settings/spa/search/SearchablePage.kt
Normal file
25
src/com/android/settings/spa/search/SearchablePage.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 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.settings.spa.search
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
interface SearchablePage {
|
||||||
|
|
||||||
|
/** Gets the searchable titles at the current moment. */
|
||||||
|
fun getSearchableTitles(context: Context): List<String>
|
||||||
|
}
|
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 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.settings.spa.search
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY
|
||||||
|
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
|
||||||
|
import com.android.settings.password.PasswordUtils
|
||||||
|
import com.android.settings.spa.SpaDestination
|
||||||
|
|
||||||
|
class SpaSearchLandingActivity : Activity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
if (!isValidCall()) return
|
||||||
|
|
||||||
|
val destination = intent.getStringExtra(EXTRA_FRAGMENT_ARG_KEY)
|
||||||
|
if (destination.isNullOrBlank()) return
|
||||||
|
|
||||||
|
SpaDestination(destination = destination, highlightMenuKey = null)
|
||||||
|
.startFromExportedActivity(this)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isValidCall() =
|
||||||
|
PasswordUtils.getCallingAppPackageName(activityToken) ==
|
||||||
|
featureFactory.searchFeatureProvider.getSettingsIntelligencePkgName(this)
|
||||||
|
}
|
85
src/com/android/settings/spa/search/SpaSearchRepository.kt
Normal file
85
src/com/android/settings/spa/search/SpaSearchRepository.kt
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 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.settings.spa.search
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.provider.SearchIndexableResource
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import com.android.settingslib.search.Indexable
|
||||||
|
import com.android.settingslib.search.SearchIndexableData
|
||||||
|
import com.android.settingslib.search.SearchIndexableRaw
|
||||||
|
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||||
|
import com.android.settingslib.spa.framework.common.SpaEnvironment
|
||||||
|
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
|
||||||
|
|
||||||
|
class SpaSearchRepository(
|
||||||
|
private val spaEnvironment: SpaEnvironment = SpaEnvironmentFactory.instance,
|
||||||
|
) {
|
||||||
|
fun getSearchIndexableDataList(): List<SearchIndexableData> {
|
||||||
|
Log.d(TAG, "getSearchIndexableDataList")
|
||||||
|
return spaEnvironment.pageProviderRepository.value.getAllProviders().mapNotNull { page ->
|
||||||
|
if (page is SearchablePage) {
|
||||||
|
page.createSearchIndexableData(page::getSearchableTitles)
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "SpaSearchRepository"
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
fun SettingsPageProvider.createSearchIndexableData(
|
||||||
|
titlesProvider: (context: Context) -> List<String>,
|
||||||
|
): SearchIndexableData {
|
||||||
|
val searchIndexProvider =
|
||||||
|
object : Indexable.SearchIndexProvider {
|
||||||
|
override fun getXmlResourcesToIndex(
|
||||||
|
context: Context,
|
||||||
|
enabled: Boolean,
|
||||||
|
): List<SearchIndexableResource> = emptyList()
|
||||||
|
|
||||||
|
override fun getRawDataToIndex(
|
||||||
|
context: Context,
|
||||||
|
enabled: Boolean,
|
||||||
|
): List<SearchIndexableRaw> = emptyList()
|
||||||
|
|
||||||
|
override fun getDynamicRawDataToIndex(
|
||||||
|
context: Context,
|
||||||
|
enabled: Boolean,
|
||||||
|
): List<SearchIndexableRaw> =
|
||||||
|
titlesProvider(context).map { title ->
|
||||||
|
createSearchIndexableRaw(context, title)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNonIndexableKeys(context: Context): List<String> = emptyList()
|
||||||
|
}
|
||||||
|
return SearchIndexableData(this::class.java, searchIndexProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SettingsPageProvider.createSearchIndexableRaw(context: Context, title: String) =
|
||||||
|
SearchIndexableRaw(context).apply {
|
||||||
|
key = name
|
||||||
|
this.title = title
|
||||||
|
intentAction = SEARCH_LANDING_ACTION
|
||||||
|
packageName = context.packageName
|
||||||
|
className = SpaSearchLandingActivity::class.qualifiedName
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val SEARCH_LANDING_ACTION = "android.settings.SPA_SEARCH_LANDING"
|
||||||
|
}
|
||||||
|
}
|
@@ -29,6 +29,7 @@ import android.database.Cursor;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.android.settings.network.NetworkProviderSettings;
|
import com.android.settings.network.NetworkProviderSettings;
|
||||||
|
import com.android.settings.spa.search.SearchablePage;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.testutils.FakeIndexProvider;
|
import com.android.settings.testutils.FakeIndexProvider;
|
||||||
import com.android.settingslib.search.SearchIndexableData;
|
import com.android.settingslib.search.SearchIndexableData;
|
||||||
@@ -117,8 +118,10 @@ public class SearchIndexableResourcesTest {
|
|||||||
public void testAllClassNamesHaveProviders() {
|
public void testAllClassNamesHaveProviders() {
|
||||||
for (SearchIndexableData data :
|
for (SearchIndexableData data :
|
||||||
mSearchProvider.getSearchIndexableResources().getProviderValues()) {
|
mSearchProvider.getSearchIndexableResources().getProviderValues()) {
|
||||||
if (DatabaseIndexingUtils.getSearchIndexProvider(data.getTargetClass()) == null) {
|
Class<?> targetClass = data.getTargetClass();
|
||||||
fail(data.getTargetClass().getName() + "is not an index provider");
|
if (DatabaseIndexingUtils.getSearchIndexProvider(targetClass) == null
|
||||||
|
&& !SearchablePage.class.isAssignableFrom(targetClass)) {
|
||||||
|
fail(targetClass.getName() + " is not an index provider");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 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.settings.spa.search
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.android.settings.spa.search.SpaSearchRepository.Companion.createSearchIndexableData
|
||||||
|
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class SpaSearchRepositoryTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createSearchIndexableData() {
|
||||||
|
val pageProvider =
|
||||||
|
object : SettingsPageProvider {
|
||||||
|
override val name = PAGE_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
val searchIndexableData = pageProvider.createSearchIndexableData { listOf(TITLE) }
|
||||||
|
val dynamicRawDataToIndex =
|
||||||
|
searchIndexableData.searchIndexProvider.getDynamicRawDataToIndex(mock<Context>(), true)
|
||||||
|
|
||||||
|
assertThat(searchIndexableData.targetClass).isEqualTo(pageProvider::class.java)
|
||||||
|
assertThat(dynamicRawDataToIndex).hasSize(1)
|
||||||
|
assertThat(dynamicRawDataToIndex[0].title).isEqualTo(TITLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val PAGE_NAME = "PageName"
|
||||||
|
const val TITLE = "Title"
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user