Merge changes from topic "MobileNetworkSettingsSearchIndex" into main
* changes: Fix search for MMS Message Show category when search "Mobile data"
This commit is contained in:
@@ -82,12 +82,10 @@ android_library {
|
||||
"android.hardware.dumpstate-V1-java",
|
||||
"android.hardware.dumpstate-V1.0-java",
|
||||
"android.hardware.dumpstate-V1.1-java",
|
||||
"android.view.accessibility.flags-aconfig-java",
|
||||
"com_android_server_accessibility_flags_lib",
|
||||
"net-utils-framework-common",
|
||||
"notification_flags_lib",
|
||||
"securebox",
|
||||
"android.os.flags-aconfig-java",
|
||||
"//frameworks/libs/systemui:com_android_systemui_shared_flags_lib",
|
||||
"WindowManager-Shell-shared-desktopMode",
|
||||
|
||||
@@ -103,12 +101,9 @@ android_library {
|
||||
"contextualcards",
|
||||
"development_settings_flag_lib",
|
||||
"factory_reset_flags_lib",
|
||||
"fuelgauge-log-protos-lite",
|
||||
"settings-protos-lite",
|
||||
"fuelgauge-protos-lite",
|
||||
"settings-contextual-card-protos-lite",
|
||||
"settings-log-bridge-protos-lite",
|
||||
"settings-logtags",
|
||||
"settings-telephony-protos-lite",
|
||||
"statslog-settings",
|
||||
"telephony_flags_core_java_lib",
|
||||
"setupdesign-lottie-loading-layout",
|
||||
|
@@ -1,44 +1,12 @@
|
||||
package {
|
||||
default_team: "trendy_team_android_settings_app",
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "packages_apps_Settings_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["packages_apps_Settings_license"],
|
||||
}
|
||||
|
||||
java_library_static {
|
||||
name: "settings-contextual-card-protos-lite",
|
||||
host_supported: true,
|
||||
proto: {
|
||||
type: "lite",
|
||||
},
|
||||
srcs: ["contextual_card_list.proto"],
|
||||
}
|
||||
|
||||
java_library_static {
|
||||
name: "settings-log-bridge-protos-lite",
|
||||
host_supported: true,
|
||||
proto: {
|
||||
type: "lite",
|
||||
},
|
||||
srcs: ["settings_log_bridge.proto"],
|
||||
}
|
||||
|
||||
java_library_static {
|
||||
name: "settings-telephony-protos-lite",
|
||||
host_supported: true,
|
||||
proto: {
|
||||
type: "lite",
|
||||
},
|
||||
srcs: ["network_mode_choices.proto"],
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "fuelgauge-log-protos-lite",
|
||||
name: "settings-protos-lite",
|
||||
proto: {
|
||||
type: "lite",
|
||||
},
|
||||
srcs: ["fuelgauge_log.proto"],
|
||||
srcs: ["*.proto"],
|
||||
}
|
||||
|
34
protos/spa_search_landing.proto
Normal file
34
protos/spa_search_landing.proto
Normal file
@@ -0,0 +1,34 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package com.android.settings.spa;
|
||||
|
||||
message SpaSearchLandingKey {
|
||||
oneof page {
|
||||
SpaSearchLandingSpaPage spa_page = 1;
|
||||
SpaSearchLandingFragment fragment = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message SpaSearchLandingSpaPage {
|
||||
/** The destination of SPA page. */
|
||||
optional string destination = 1;
|
||||
}
|
||||
|
||||
message SpaSearchLandingFragment {
|
||||
/** The fragment class name. */
|
||||
optional string fragment_name = 1;
|
||||
|
||||
/** The key of the preference to highlight the item. */
|
||||
optional string preference_key = 2;
|
||||
|
||||
/** The arguments passed to the page. */
|
||||
map<string, BundleValue> arguments = 3;
|
||||
}
|
||||
|
||||
/** A value in an Android Bundle. */
|
||||
message BundleValue {
|
||||
oneof value {
|
||||
/** A 32-bit signed integer value. */
|
||||
int32 int_value = 1;
|
||||
}
|
||||
}
|
@@ -112,10 +112,12 @@
|
||||
android:selectable="false"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<!-- Settings search is handled by MmsMessageSearchItem. -->
|
||||
<SwitchPreferenceCompat
|
||||
android:key="mms_message"
|
||||
android:title="@string/mms_message_title"
|
||||
android:summary="@string/mms_message_summary"
|
||||
settings:searchable="false"
|
||||
settings:controller="com.android.settings.network.telephony.MmsMessagePreferenceController"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
|
@@ -34,7 +34,7 @@ object EmbeddedDeepLinkUtils {
|
||||
private const val TAG = "EmbeddedDeepLinkUtils"
|
||||
|
||||
@JvmStatic
|
||||
fun Activity.tryStartMultiPaneDeepLink(
|
||||
fun Context.tryStartMultiPaneDeepLink(
|
||||
intent: Intent,
|
||||
highlightMenuKey: String? = null,
|
||||
): Boolean {
|
||||
|
@@ -22,46 +22,38 @@ import android.telephony.TelephonyManager
|
||||
import android.telephony.data.ApnSetting
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.android.settings.R
|
||||
import com.android.settings.Settings.MobileNetworkActivity.EXTRA_MMS_MESSAGE
|
||||
import com.android.settings.core.TogglePreferenceController
|
||||
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
|
||||
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
||||
/**
|
||||
* Preference controller for "MMS messages"
|
||||
*/
|
||||
class MmsMessagePreferenceController @JvmOverloads constructor(
|
||||
/** Preference controller for "MMS messages" */
|
||||
class MmsMessagePreferenceController
|
||||
@JvmOverloads
|
||||
constructor(
|
||||
context: Context,
|
||||
key: String,
|
||||
private val getDefaultDataSubId: () -> Int = {
|
||||
SubscriptionManager.getDefaultDataSubscriptionId()
|
||||
},
|
||||
) : TelephonyTogglePreferenceController(context, key) {
|
||||
) : TogglePreferenceController(context, key) {
|
||||
|
||||
private lateinit var telephonyManager: TelephonyManager
|
||||
private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||
private var telephonyManager: TelephonyManager =
|
||||
context.getSystemService(TelephonyManager::class.java)!!
|
||||
|
||||
private var preferenceScreen: PreferenceScreen? = null
|
||||
|
||||
fun init(subId: Int) {
|
||||
mSubId = subId
|
||||
telephonyManager = mContext.getSystemService(TelephonyManager::class.java)!!
|
||||
.createForSubscriptionId(subId)
|
||||
this.subId = subId
|
||||
telephonyManager = telephonyManager.createForSubscriptionId(subId)
|
||||
}
|
||||
|
||||
override fun getAvailabilityStatus(subId: Int) =
|
||||
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID &&
|
||||
this::telephonyManager.isInitialized &&
|
||||
!telephonyManager.isDataEnabled &&
|
||||
telephonyManager.isApnMetered(ApnSetting.TYPE_MMS) &&
|
||||
!isFallbackDataEnabled()
|
||||
) AVAILABLE else CONDITIONALLY_UNAVAILABLE
|
||||
|
||||
private fun isFallbackDataEnabled(): Boolean {
|
||||
val defaultDataSubId = getDefaultDataSubId()
|
||||
return defaultDataSubId != mSubId &&
|
||||
telephonyManager.createForSubscriptionId(defaultDataSubId).isDataEnabled &&
|
||||
telephonyManager.isMobileDataPolicyEnabled(
|
||||
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
|
||||
)
|
||||
}
|
||||
override fun getAvailabilityStatus() =
|
||||
if (getAvailabilityStatus(telephonyManager, subId, getDefaultDataSubId)) AVAILABLE
|
||||
else CONDITIONALLY_UNAVAILABLE
|
||||
|
||||
override fun displayPreference(screen: PreferenceScreen) {
|
||||
super.displayPreference(screen)
|
||||
@@ -70,16 +62,20 @@ class MmsMessagePreferenceController @JvmOverloads constructor(
|
||||
|
||||
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
|
||||
combine(
|
||||
MobileDataRepository(mContext).mobileDataEnabledChangedFlow(mSubId),
|
||||
mContext.subscriptionsChangedFlow(), // Capture isMobileDataPolicyEnabled() changes
|
||||
) { _, _ -> }.collectLatestWithLifecycle(viewLifecycleOwner) {
|
||||
preferenceScreen?.let { super.displayPreference(it) }
|
||||
}
|
||||
MobileDataRepository(mContext).mobileDataEnabledChangedFlow(subId),
|
||||
mContext.subscriptionsChangedFlow(), // Capture isMobileDataPolicyEnabled() changes
|
||||
) { _, _ ->
|
||||
}
|
||||
.collectLatestWithLifecycle(viewLifecycleOwner) {
|
||||
preferenceScreen?.let { super.displayPreference(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun isChecked(): Boolean = telephonyManager.isMobileDataPolicyEnabled(
|
||||
TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED
|
||||
)
|
||||
override fun getSliceHighlightMenuRes() = NO_RES
|
||||
|
||||
override fun isChecked(): Boolean =
|
||||
telephonyManager.isMobileDataPolicyEnabled(
|
||||
TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED)
|
||||
|
||||
override fun setChecked(isChecked: Boolean): Boolean {
|
||||
telephonyManager.setMobileDataPolicyEnabled(
|
||||
@@ -88,4 +84,45 @@ class MmsMessagePreferenceController @JvmOverloads constructor(
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun getAvailabilityStatus(
|
||||
telephonyManager: TelephonyManager,
|
||||
subId: Int,
|
||||
getDefaultDataSubId: () -> Int,
|
||||
): Boolean {
|
||||
return SubscriptionManager.isValidSubscriptionId(subId) &&
|
||||
!telephonyManager.isDataEnabled &&
|
||||
telephonyManager.isApnMetered(ApnSetting.TYPE_MMS) &&
|
||||
!isFallbackDataEnabled(telephonyManager, subId, getDefaultDataSubId())
|
||||
}
|
||||
|
||||
private fun isFallbackDataEnabled(
|
||||
telephonyManager: TelephonyManager,
|
||||
subId: Int,
|
||||
defaultDataSubId: Int,
|
||||
): Boolean {
|
||||
return defaultDataSubId != subId &&
|
||||
telephonyManager.createForSubscriptionId(defaultDataSubId).isDataEnabled &&
|
||||
telephonyManager.isMobileDataPolicyEnabled(
|
||||
TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
|
||||
}
|
||||
|
||||
class MmsMessageSearchItem(
|
||||
context: Context,
|
||||
private val getDefaultDataSubId: () -> Int = {
|
||||
SubscriptionManager.getDefaultDataSubscriptionId()
|
||||
},
|
||||
) : MobileNetworkSettingsSearchItem {
|
||||
private var telephonyManager: TelephonyManager =
|
||||
context.getSystemService(TelephonyManager::class.java)!!
|
||||
|
||||
override val key: String = EXTRA_MMS_MESSAGE
|
||||
override val title: String = context.getString(R.string.mms_message_title)
|
||||
|
||||
override fun isAvailable(subId: Int): Boolean =
|
||||
getAvailabilityStatus(
|
||||
telephonyManager.createForSubscriptionId(subId), subId, getDefaultDataSubId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -467,14 +467,10 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.mobile_network_settings) {
|
||||
|
||||
/** suppress full page if user is not admin */
|
||||
@Override
|
||||
protected boolean isPageSearchEnabled(Context context) {
|
||||
boolean isAirplaneOff = Settings.Global.getInt(context.getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, 0) == 0;
|
||||
return isAirplaneOff && SubscriptionUtil.isSimHardwareVisible(context)
|
||||
&& context.getSystemService(UserManager.class).isAdminUser();
|
||||
return MobileNetworkSettingsSearchIndex
|
||||
.isMobileNetworkSettingsSearchable(context);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.network.telephony
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import android.telephony.SubscriptionInfo
|
||||
import com.android.settings.R
|
||||
import com.android.settings.network.SubscriptionUtil
|
||||
import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem
|
||||
import com.android.settings.spa.SpaSearchLanding.BundleValue
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey
|
||||
import com.android.settings.spa.search.SpaSearchRepository.Companion.createSearchIndexableRaw
|
||||
import com.android.settings.spa.search.SpaSearchRepository.Companion.searchIndexProviderOf
|
||||
import com.android.settingslib.search.SearchIndexableData
|
||||
import com.android.settingslib.search.SearchIndexableRaw
|
||||
import com.android.settingslib.spaprivileged.framework.common.userManager
|
||||
import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBoolean
|
||||
|
||||
class MobileNetworkSettingsSearchIndex(
|
||||
private val searchItemsFactory: (context: Context) -> List<MobileNetworkSettingsSearchItem> =
|
||||
::createSearchItems,
|
||||
) {
|
||||
interface MobileNetworkSettingsSearchItem {
|
||||
val key: String
|
||||
|
||||
val title: String
|
||||
|
||||
fun isAvailable(subId: Int): Boolean
|
||||
}
|
||||
|
||||
fun createSearchIndexableData(): SearchIndexableData {
|
||||
val searchIndexProvider = searchIndexProviderOf { context ->
|
||||
if (!isMobileNetworkSettingsSearchable(context)) {
|
||||
return@searchIndexProviderOf emptyList()
|
||||
}
|
||||
val subInfos = context.requireSubscriptionManager().activeSubscriptionInfoList
|
||||
if (subInfos.isNullOrEmpty()) {
|
||||
return@searchIndexProviderOf emptyList()
|
||||
}
|
||||
searchItemsFactory(context).flatMap { searchItem ->
|
||||
searchIndexableRawList(context, searchItem, subInfos)
|
||||
}
|
||||
}
|
||||
return SearchIndexableData(MobileNetworkSettings::class.java, searchIndexProvider)
|
||||
}
|
||||
|
||||
private fun searchIndexableRawList(
|
||||
context: Context,
|
||||
searchItem: MobileNetworkSettingsSearchItem,
|
||||
subInfos: List<SubscriptionInfo>
|
||||
): List<SearchIndexableRaw> =
|
||||
subInfos
|
||||
.filter { searchItem.isAvailable(it.subscriptionId) }
|
||||
.map { subInfo -> searchIndexableRaw(context, searchItem, subInfo) }
|
||||
|
||||
private fun searchIndexableRaw(
|
||||
context: Context,
|
||||
searchItem: MobileNetworkSettingsSearchItem,
|
||||
subInfo: SubscriptionInfo,
|
||||
): SearchIndexableRaw {
|
||||
val key =
|
||||
SpaSearchLandingKey.newBuilder()
|
||||
.setFragment(
|
||||
SpaSearchLandingFragment.newBuilder()
|
||||
.setFragmentName(MobileNetworkSettings::class.java.name)
|
||||
.setPreferenceKey(searchItem.key)
|
||||
.putArguments(
|
||||
Settings.EXTRA_SUB_ID,
|
||||
BundleValue.newBuilder().setIntValue(subInfo.subscriptionId).build()))
|
||||
.build()
|
||||
val simsTitle = context.getString(R.string.provider_network_settings_title)
|
||||
return createSearchIndexableRaw(
|
||||
context = context,
|
||||
spaSearchLandingKey = key,
|
||||
itemTitle = searchItem.title,
|
||||
indexableClass = MobileNetworkSettings::class.java,
|
||||
pageTitle = "$simsTitle > ${subInfo.displayName}",
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/** suppress full page if user is not admin */
|
||||
@JvmStatic
|
||||
fun isMobileNetworkSettingsSearchable(context: Context): Boolean {
|
||||
val isAirplaneMode by context.settingsGlobalBoolean(Settings.Global.AIRPLANE_MODE_ON)
|
||||
return SubscriptionUtil.isSimHardwareVisible(context) &&
|
||||
!isAirplaneMode &&
|
||||
context.userManager.isAdminUser
|
||||
}
|
||||
|
||||
fun createSearchItems(context: Context): List<MobileNetworkSettingsSearchItem> =
|
||||
listOf(
|
||||
MmsMessageSearchItem(context),
|
||||
)
|
||||
}
|
||||
}
|
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.settings.spa
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.android.settings.activityembedding.ActivityEmbeddingUtils
|
||||
import com.android.settings.activityembedding.EmbeddedDeepLinkUtils.tryStartMultiPaneDeepLink
|
||||
@@ -27,16 +27,16 @@ data class SpaDestination(
|
||||
val destination: String,
|
||||
val highlightMenuKey: String?,
|
||||
) {
|
||||
fun startFromExportedActivity(activity: Activity) {
|
||||
val intent = Intent(activity, SpaActivity::class.java)
|
||||
fun startFromExportedActivity(context: Context) {
|
||||
val intent = Intent(context, SpaActivity::class.java)
|
||||
.appendSpaParams(
|
||||
destination = destination,
|
||||
sessionName = SESSION_EXTERNAL,
|
||||
)
|
||||
if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(activity) ||
|
||||
!activity.tryStartMultiPaneDeepLink(intent, highlightMenuKey)
|
||||
if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context) ||
|
||||
!context.tryStartMultiPaneDeepLink(intent, highlightMenuKey)
|
||||
) {
|
||||
activity.startActivity(intent)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -197,6 +197,9 @@ open class NetworkCellularGroupProvider : SettingsPageProvider, SearchablePage {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun getPageTitleForSearch(context: Context): String =
|
||||
context.getString(R.string.provider_network_settings_title)
|
||||
|
||||
override fun getSearchableTitles(context: Context): List<String> {
|
||||
if (!isPageSearchable(context)) return emptyList()
|
||||
return buildList {
|
||||
|
@@ -20,6 +20,9 @@ import android.content.Context
|
||||
|
||||
interface SearchablePage {
|
||||
|
||||
/** Gets the searchable titles at the current moment. */
|
||||
/** Gets the title of the page. */
|
||||
fun getPageTitleForSearch(context: Context): String = ""
|
||||
|
||||
/** Gets the titles of the searchable items at the current moment. */
|
||||
fun getSearchableTitles(context: Context): List<String>
|
||||
}
|
||||
|
@@ -17,26 +17,68 @@
|
||||
package com.android.settings.spa.search
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.settings.SettingsEnums
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY
|
||||
import com.android.settings.core.SubSettingLauncher
|
||||
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
|
||||
import com.android.settings.password.PasswordUtils
|
||||
import com.android.settings.spa.SpaDestination
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey
|
||||
import com.google.protobuf.ByteString
|
||||
import com.google.protobuf.InvalidProtocolBufferException
|
||||
|
||||
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)
|
||||
val keyString = intent.getStringExtra(EXTRA_FRAGMENT_ARG_KEY)
|
||||
if (!keyString.isNullOrEmpty() && isValidCall()) {
|
||||
tryLaunch(this, keyString)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun isValidCall() =
|
||||
PasswordUtils.getCallingAppPackageName(activityToken) ==
|
||||
featureFactory.searchFeatureProvider.getSettingsIntelligencePkgName(this)
|
||||
|
||||
companion object {
|
||||
@VisibleForTesting
|
||||
fun tryLaunch(context: Context, keyString: String) {
|
||||
val key =
|
||||
try {
|
||||
SpaSearchLandingKey.parseFrom(ByteString.copyFromUtf8(keyString))
|
||||
} catch (e: InvalidProtocolBufferException) {
|
||||
Log.w(TAG, "arg key ($keyString) invalid", e)
|
||||
return
|
||||
}
|
||||
|
||||
if (key.hasSpaPage()) {
|
||||
val destination = key.spaPage.destination
|
||||
if (destination.isNotEmpty()) {
|
||||
SpaDestination(destination = destination, highlightMenuKey = null)
|
||||
.startFromExportedActivity(context)
|
||||
}
|
||||
}
|
||||
if (key.hasFragment()) {
|
||||
val arguments =
|
||||
Bundle().apply {
|
||||
key.fragment.argumentsMap.forEach { (k, v) ->
|
||||
if (v.hasIntValue()) putInt(k, v.intValue)
|
||||
}
|
||||
putString(EXTRA_FRAGMENT_ARG_KEY, key.fragment.preferenceKey)
|
||||
}
|
||||
SubSettingLauncher(context)
|
||||
.setDestination(key.fragment.fragmentName)
|
||||
.setArguments(arguments)
|
||||
.setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
|
||||
.launch()
|
||||
}
|
||||
}
|
||||
|
||||
private const val TAG = "SpaSearchLandingActivity"
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,9 @@ import android.content.Context
|
||||
import android.provider.SearchIndexableResource
|
||||
import android.util.Log
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingSpaPage
|
||||
import com.android.settingslib.search.Indexable
|
||||
import com.android.settingslib.search.SearchIndexableData
|
||||
import com.android.settingslib.search.SearchIndexableRaw
|
||||
@@ -34,9 +37,10 @@ class SpaSearchRepository(
|
||||
Log.d(TAG, "getSearchIndexableDataList")
|
||||
return spaEnvironment.pageProviderRepository.value.getAllProviders().mapNotNull { page ->
|
||||
if (page is SearchablePage) {
|
||||
page.createSearchIndexableData(page::getSearchableTitles)
|
||||
page.createSearchIndexableData(
|
||||
page::getPageTitleForSearch, page::getSearchableTitles)
|
||||
} else null
|
||||
}
|
||||
} + MobileNetworkSettingsSearchIndex().createSearchIndexableData()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -44,40 +48,60 @@ class SpaSearchRepository(
|
||||
|
||||
@VisibleForTesting
|
||||
fun SettingsPageProvider.createSearchIndexableData(
|
||||
getPageTitleForSearch: (context: Context) -> String,
|
||||
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()
|
||||
val key =
|
||||
SpaSearchLandingKey.newBuilder()
|
||||
.setSpaPage(SpaSearchLandingSpaPage.newBuilder().setDestination(name))
|
||||
.build()
|
||||
val indexableClass = this::class.java
|
||||
val searchIndexProvider = searchIndexProviderOf { context ->
|
||||
val pageTitle = getPageTitleForSearch(context)
|
||||
titlesProvider(context).map { itemTitle ->
|
||||
createSearchIndexableRaw(context, key, itemTitle, indexableClass, pageTitle)
|
||||
}
|
||||
return SearchIndexableData(this::class.java, searchIndexProvider)
|
||||
}
|
||||
return SearchIndexableData(indexableClass, searchIndexProvider)
|
||||
}
|
||||
|
||||
private fun SettingsPageProvider.createSearchIndexableRaw(context: Context, title: String) =
|
||||
fun searchIndexProviderOf(
|
||||
getDynamicRawDataToIndex: (context: Context) -> List<SearchIndexableRaw>,
|
||||
) =
|
||||
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> = getDynamicRawDataToIndex(context)
|
||||
|
||||
override fun getNonIndexableKeys(context: Context): List<String> = emptyList()
|
||||
}
|
||||
|
||||
fun createSearchIndexableRaw(
|
||||
context: Context,
|
||||
spaSearchLandingKey: SpaSearchLandingKey,
|
||||
itemTitle: String,
|
||||
indexableClass: Class<*>,
|
||||
pageTitle: String,
|
||||
) =
|
||||
SearchIndexableRaw(context).apply {
|
||||
key = name
|
||||
this.title = title
|
||||
key = spaSearchLandingKey.toByteString().toStringUtf8()
|
||||
title = itemTitle
|
||||
intentAction = SEARCH_LANDING_ACTION
|
||||
intentTargetClass = SpaSearchLandingActivity::class.qualifiedName
|
||||
packageName = context.packageName
|
||||
className = SpaSearchLandingActivity::class.qualifiedName
|
||||
className = indexableClass.name
|
||||
screenTitle = pageTitle
|
||||
}
|
||||
|
||||
private const val SEARCH_LANDING_ACTION = "android.settings.SPA_SEARCH_LANDING"
|
||||
|
@@ -29,18 +29,14 @@ import static org.mockito.Mockito.when;
|
||||
import android.app.Activity;
|
||||
import android.app.usage.NetworkStatsManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.datausage.DataUsageSummaryPreferenceController;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
|
||||
import com.android.settings.widget.EntityHeaderController;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
@@ -53,7 +49,6 @@ import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -73,7 +68,6 @@ public class MobileNetworkSettingsTest {
|
||||
private FragmentActivity mActivity;
|
||||
|
||||
private Context mContext;
|
||||
private Resources mResources;
|
||||
private MobileNetworkSettings mFragment;
|
||||
|
||||
@Before
|
||||
@@ -81,10 +75,6 @@ public class MobileNetworkSettingsTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
|
||||
mResources = spy(mContext.getResources());
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mResources.getBoolean(R.bool.config_show_sim_info)).thenReturn(true);
|
||||
|
||||
when(mActivity.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
|
||||
when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
|
||||
when(mContext.getSystemService(NetworkStatsManager.class)).thenReturn(mNetworkStatsManager);
|
||||
@@ -123,34 +113,4 @@ public class MobileNetworkSettingsTest {
|
||||
mFragment.onActivityResult(REQUEST_CODE_DELETE_SUBSCRIPTION, Activity.RESULT_OK, null);
|
||||
verify(mActivity).finish();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPageSearchEnabled_adminUser_shouldReturnTrue() {
|
||||
final UserManager userManager = mock(UserManager.class);
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(userManager);
|
||||
when(userManager.isAdminUser()).thenReturn(true);
|
||||
final BaseSearchIndexProvider provider =
|
||||
(BaseSearchIndexProvider) mFragment.SEARCH_INDEX_DATA_PROVIDER;
|
||||
|
||||
final Object obj = ReflectionHelpers.callInstanceMethod(provider, "isPageSearchEnabled",
|
||||
ReflectionHelpers.ClassParameter.from(Context.class, mContext));
|
||||
final boolean isEnabled = (Boolean) obj;
|
||||
|
||||
assertThat(isEnabled).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPageSearchEnabled_nonAdminUser_shouldReturnFalse() {
|
||||
final UserManager userManager = mock(UserManager.class);
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(userManager);
|
||||
when(userManager.isAdminUser()).thenReturn(false);
|
||||
final BaseSearchIndexProvider provider =
|
||||
(BaseSearchIndexProvider) mFragment.SEARCH_INDEX_DATA_PROVIDER;
|
||||
|
||||
final Object obj = ReflectionHelpers.callInstanceMethod(provider, "isPageSearchEnabled",
|
||||
ReflectionHelpers.ClassParameter.from(Context.class, mContext));
|
||||
final boolean isEnabled = (Boolean) obj;
|
||||
|
||||
assertThat(isEnabled).isFalse();
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settings.core.BasePreferenceController.AVAILABLE
|
||||
import com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE
|
||||
import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -60,13 +61,13 @@ class MmsMessagePreferenceControllerTest {
|
||||
context = context,
|
||||
key = KEY,
|
||||
getDefaultDataSubId = { defaultDataSubId },
|
||||
).apply { init(SUB_2_ID) }
|
||||
)
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_invalidSubscription_unavailable() {
|
||||
controller.init(INVALID_SUBSCRIPTION_ID)
|
||||
|
||||
val availabilityStatus = controller.getAvailabilityStatus(INVALID_SUBSCRIPTION_ID)
|
||||
val availabilityStatus = controller.getAvailabilityStatus()
|
||||
|
||||
assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
|
||||
}
|
||||
@@ -76,8 +77,9 @@ class MmsMessagePreferenceControllerTest {
|
||||
mockTelephonyManager2.stub {
|
||||
on { isDataEnabled } doReturn true
|
||||
}
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID)
|
||||
val availabilityStatus = controller.getAvailabilityStatus()
|
||||
|
||||
assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
|
||||
}
|
||||
@@ -87,8 +89,9 @@ class MmsMessagePreferenceControllerTest {
|
||||
mockTelephonyManager2.stub {
|
||||
on { isApnMetered(ApnSetting.TYPE_MMS) } doReturn false
|
||||
}
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID)
|
||||
val availabilityStatus = controller.getAvailabilityStatus()
|
||||
|
||||
assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
|
||||
}
|
||||
@@ -102,8 +105,9 @@ class MmsMessagePreferenceControllerTest {
|
||||
isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
|
||||
} doReturn true
|
||||
}
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID)
|
||||
val availabilityStatus = controller.getAvailabilityStatus()
|
||||
|
||||
assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
|
||||
}
|
||||
@@ -117,14 +121,16 @@ class MmsMessagePreferenceControllerTest {
|
||||
isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
|
||||
} doReturn true
|
||||
}
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID)
|
||||
val availabilityStatus = controller.getAvailabilityStatus()
|
||||
|
||||
assertThat(availabilityStatus).isEqualTo(AVAILABLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_defaultDataOnAndAutoDataSwitchOn_unavailable() {
|
||||
fun getAvailabilityStatus_notDefaultDataAndDataOnAndAutoDataSwitchOn_unavailable() {
|
||||
defaultDataSubId = SUB_1_ID
|
||||
mockTelephonyManager1.stub {
|
||||
on { isDataEnabled } doReturn true
|
||||
}
|
||||
@@ -133,14 +139,16 @@ class MmsMessagePreferenceControllerTest {
|
||||
isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
|
||||
} doReturn true
|
||||
}
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID)
|
||||
val availabilityStatus = controller.getAvailabilityStatus()
|
||||
|
||||
assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_defaultDataOffAndAutoDataSwitchOn_available() {
|
||||
fun getAvailabilityStatus_notDefaultDataAndDataOffAndAutoDataSwitchOn_available() {
|
||||
defaultDataSubId = SUB_1_ID
|
||||
mockTelephonyManager1.stub {
|
||||
on { isDataEnabled } doReturn false
|
||||
}
|
||||
@@ -149,12 +157,49 @@ class MmsMessagePreferenceControllerTest {
|
||||
isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
|
||||
} doReturn true
|
||||
}
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID)
|
||||
val availabilityStatus = controller.getAvailabilityStatus()
|
||||
|
||||
assertThat(availabilityStatus).isEqualTo(AVAILABLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchIsAvailable_notDefaultDataAndDataOnAndAutoDataSwitchOn_unavailable() {
|
||||
mockTelephonyManager1.stub {
|
||||
on { isDataEnabled } doReturn true
|
||||
}
|
||||
mockTelephonyManager2.stub {
|
||||
on { isApnMetered(ApnSetting.TYPE_MMS) } doReturn true
|
||||
on {
|
||||
isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
|
||||
} doReturn true
|
||||
}
|
||||
val mmsMessageSearchItem = MmsMessageSearchItem(context) { SUB_1_ID }
|
||||
|
||||
val isAvailable = mmsMessageSearchItem.isAvailable(SUB_2_ID)
|
||||
|
||||
assertThat(isAvailable).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchIsAvailable_notDefaultDataAndDataOffAndAutoDataSwitchOn_available() {
|
||||
mockTelephonyManager1.stub {
|
||||
on { isDataEnabled } doReturn false
|
||||
}
|
||||
mockTelephonyManager2.stub {
|
||||
on { isApnMetered(ApnSetting.TYPE_MMS) } doReturn true
|
||||
on {
|
||||
isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
|
||||
} doReturn true
|
||||
}
|
||||
val mmsMessageSearchItem = MmsMessageSearchItem(context) { SUB_1_ID }
|
||||
|
||||
val isAvailable = mmsMessageSearchItem.isAvailable(SUB_2_ID)
|
||||
|
||||
assertThat(isAvailable).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isChecked_whenMmsNotAlwaysAllowed_returnFalse() {
|
||||
mockTelephonyManager2.stub {
|
||||
@@ -162,6 +207,7 @@ class MmsMessagePreferenceControllerTest {
|
||||
isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED)
|
||||
} doReturn false
|
||||
}
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
val isChecked = controller.isChecked()
|
||||
|
||||
@@ -175,6 +221,7 @@ class MmsMessagePreferenceControllerTest {
|
||||
isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED)
|
||||
} doReturn true
|
||||
}
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
val isChecked = controller.isChecked()
|
||||
|
||||
@@ -183,6 +230,8 @@ class MmsMessagePreferenceControllerTest {
|
||||
|
||||
@Test
|
||||
fun setChecked_setTrue_setDataIntoSubscriptionManager() {
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
controller.setChecked(true)
|
||||
|
||||
verify(mockTelephonyManager2).setMobileDataPolicyEnabled(
|
||||
@@ -192,6 +241,8 @@ class MmsMessagePreferenceControllerTest {
|
||||
|
||||
@Test
|
||||
fun setChecked_setFalse_setDataIntoSubscriptionManager() {
|
||||
controller.init(SUB_2_ID)
|
||||
|
||||
controller.setChecked(false)
|
||||
|
||||
verify(mockTelephonyManager2).setMobileDataPolicyEnabled(
|
||||
|
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.network.telephony
|
||||
|
||||
import android.content.Context
|
||||
import android.os.UserManager
|
||||
import android.provider.Settings
|
||||
import android.telephony.SubscriptionInfo
|
||||
import android.telephony.SubscriptionManager
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settings.R
|
||||
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.Companion.isMobileNetworkSettingsSearchable
|
||||
import com.android.settings.spa.SpaSearchLanding.BundleValue
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey
|
||||
import com.android.settings.spa.search.SpaSearchLandingActivity
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.google.protobuf.ByteString
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.stub
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class MobileNetworkSettingsSearchIndexTest {
|
||||
|
||||
private val mockUserManager = mock<UserManager> { on { isAdminUser } doReturn true }
|
||||
|
||||
private val mockSubscriptionManager =
|
||||
mock<SubscriptionManager> {
|
||||
on { activeSubscriptionInfoList } doReturn listOf(SUB_INFO_1, SUB_INFO_2)
|
||||
}
|
||||
|
||||
private val context: Context =
|
||||
spy(ApplicationProvider.getApplicationContext()) {
|
||||
on { getSystemService(UserManager::class.java) } doReturn mockUserManager
|
||||
on { getSystemService(SubscriptionManager::class.java) } doReturn
|
||||
mockSubscriptionManager
|
||||
}
|
||||
|
||||
private val resources =
|
||||
spy(context.resources) { on { getBoolean(R.bool.config_show_sim_info) } doReturn true }
|
||||
|
||||
private val mobileNetworkSettingsSearchIndex = MobileNetworkSettingsSearchIndex {
|
||||
listOf(
|
||||
object : MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem {
|
||||
override val key = KEY
|
||||
override val title = TITLE
|
||||
|
||||
override fun isAvailable(subId: Int) = subId == SUB_ID_1
|
||||
})
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
context.stub { on { resources } doReturn resources }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isMobileNetworkSettingsSearchable_adminUser_returnTrue() {
|
||||
mockUserManager.stub { on { isAdminUser } doReturn true }
|
||||
|
||||
val isSearchable = isMobileNetworkSettingsSearchable(context)
|
||||
|
||||
assertThat(isSearchable).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isMobileNetworkSettingsSearchable_nonAdminUser_returnFalse() {
|
||||
mockUserManager.stub { on { isAdminUser } doReturn false }
|
||||
|
||||
val isSearchable = isMobileNetworkSettingsSearchable(context)
|
||||
|
||||
assertThat(isSearchable).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createSearchIndexableData() {
|
||||
val searchIndexableData = mobileNetworkSettingsSearchIndex.createSearchIndexableData()
|
||||
|
||||
assertThat(searchIndexableData.targetClass).isEqualTo(MobileNetworkSettings::class.java)
|
||||
val dynamicRawDataToIndex =
|
||||
searchIndexableData.searchIndexProvider.getDynamicRawDataToIndex(context, true)
|
||||
assertThat(dynamicRawDataToIndex).hasSize(1)
|
||||
val rawData = dynamicRawDataToIndex[0]
|
||||
val key = SpaSearchLandingKey.parseFrom(ByteString.copyFromUtf8(rawData.key))
|
||||
assertThat(key)
|
||||
.isEqualTo(
|
||||
SpaSearchLandingKey.newBuilder()
|
||||
.setFragment(
|
||||
SpaSearchLandingFragment.newBuilder()
|
||||
.setFragmentName(MobileNetworkSettings::class.java.name)
|
||||
.setPreferenceKey(KEY)
|
||||
.putArguments(
|
||||
Settings.EXTRA_SUB_ID,
|
||||
BundleValue.newBuilder().setIntValue(SUB_ID_1).build()))
|
||||
.build())
|
||||
assertThat(rawData.title).isEqualTo(TITLE)
|
||||
assertThat(rawData.intentAction).isEqualTo("android.settings.SPA_SEARCH_LANDING")
|
||||
assertThat(rawData.intentTargetClass)
|
||||
.isEqualTo(SpaSearchLandingActivity::class.qualifiedName)
|
||||
assertThat(rawData.className).isEqualTo(MobileNetworkSettings::class.java.name)
|
||||
assertThat(rawData.screenTitle).isEqualTo("SIMs > $SUB_DISPLAY_NAME_1")
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val KEY = "key"
|
||||
const val TITLE = "Title"
|
||||
const val SUB_ID_1 = 1
|
||||
const val SUB_ID_2 = 2
|
||||
const val SUB_DISPLAY_NAME_1 = "Sub 1"
|
||||
const val SUB_DISPLAY_NAME_2 = "Sub 2"
|
||||
|
||||
val SUB_INFO_1: SubscriptionInfo =
|
||||
SubscriptionInfo.Builder()
|
||||
.apply {
|
||||
setId(SUB_ID_1)
|
||||
setDisplayName(SUB_DISPLAY_NAME_1)
|
||||
}
|
||||
.build()
|
||||
|
||||
val SUB_INFO_2: SubscriptionInfo =
|
||||
SubscriptionInfo.Builder()
|
||||
.apply {
|
||||
setId(SUB_ID_2)
|
||||
setDisplayName(SUB_DISPLAY_NAME_2)
|
||||
}
|
||||
.build()
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.content.Intent
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settings.SettingsActivity
|
||||
import com.android.settings.spa.SpaSearchLanding.BundleValue
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingSpaPage
|
||||
import com.android.settingslib.spa.framework.util.KEY_DESTINATION
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.argThat
|
||||
import org.mockito.kotlin.argumentCaptor
|
||||
import org.mockito.kotlin.doNothing
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SpaSearchLandingActivityTest {
|
||||
|
||||
private val context: Context =
|
||||
spy(ApplicationProvider.getApplicationContext()) {
|
||||
doNothing().whenever(mock).startActivity(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tryLaunch_spaPage() {
|
||||
val key =
|
||||
SpaSearchLandingKey.newBuilder()
|
||||
.setSpaPage(SpaSearchLandingSpaPage.newBuilder().setDestination(DESTINATION))
|
||||
.build()
|
||||
|
||||
SpaSearchLandingActivity.tryLaunch(context, key.toByteString().toStringUtf8())
|
||||
|
||||
verify(context).startActivity(argThat { getStringExtra(KEY_DESTINATION) == DESTINATION })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tryLaunch_fragment() {
|
||||
val key =
|
||||
SpaSearchLandingKey.newBuilder()
|
||||
.setFragment(
|
||||
SpaSearchLandingFragment.newBuilder()
|
||||
.setFragmentName(DESTINATION)
|
||||
.setPreferenceKey(PREFERENCE_KEY)
|
||||
.putArguments(
|
||||
ARGUMENT_KEY,
|
||||
BundleValue.newBuilder().setIntValue(ARGUMENT_VALUE).build()))
|
||||
.build()
|
||||
|
||||
SpaSearchLandingActivity.tryLaunch(context, key.toByteString().toStringUtf8())
|
||||
|
||||
val intent = argumentCaptor<Intent> { verify(context).startActivity(capture()) }.firstValue
|
||||
assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
|
||||
.isEqualTo(DESTINATION)
|
||||
val fragmentArguments =
|
||||
intent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)!!
|
||||
assertThat(fragmentArguments.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY))
|
||||
.isEqualTo(PREFERENCE_KEY)
|
||||
assertThat(fragmentArguments.getInt(ARGUMENT_KEY)).isEqualTo(ARGUMENT_VALUE)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val DESTINATION = "Destination"
|
||||
const val PREFERENCE_KEY = "preference_key"
|
||||
const val ARGUMENT_KEY = "argument_key"
|
||||
const val ARGUMENT_VALUE = 123
|
||||
}
|
||||
}
|
@@ -18,9 +18,12 @@ package com.android.settings.spa.search
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingKey
|
||||
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingSpaPage
|
||||
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 com.google.protobuf.ByteString
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.mock
|
||||
@@ -35,17 +38,31 @@ class SpaSearchRepositoryTest {
|
||||
override val name = PAGE_NAME
|
||||
}
|
||||
|
||||
val searchIndexableData = pageProvider.createSearchIndexableData { listOf(TITLE) }
|
||||
val searchIndexableData =
|
||||
pageProvider.createSearchIndexableData({ PAGE_TITLE }) { listOf(ITEM_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)
|
||||
val rawData = dynamicRawDataToIndex[0]
|
||||
val key = SpaSearchLandingKey.parseFrom(ByteString.copyFromUtf8(rawData.key))
|
||||
assertThat(key)
|
||||
.isEqualTo(
|
||||
SpaSearchLandingKey.newBuilder()
|
||||
.setSpaPage(SpaSearchLandingSpaPage.newBuilder().setDestination(PAGE_NAME))
|
||||
.build())
|
||||
assertThat(rawData.title).isEqualTo(ITEM_TITLE)
|
||||
assertThat(rawData.intentAction).isEqualTo("android.settings.SPA_SEARCH_LANDING")
|
||||
assertThat(rawData.intentTargetClass)
|
||||
.isEqualTo(SpaSearchLandingActivity::class.qualifiedName)
|
||||
assertThat(rawData.className).isEqualTo(pageProvider::class.java.name)
|
||||
assertThat(rawData.screenTitle).isEqualTo(PAGE_TITLE)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PAGE_NAME = "PageName"
|
||||
const val TITLE = "Title"
|
||||
const val PAGE_TITLE = "Page Title"
|
||||
const val ITEM_TITLE = "Item Title"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user