[Satelllite] Avoid using "add ESIM page"

- When user clicks preference UI, show a dialog to nofity user
   satellite session.

Flag: EXEMPT bug fix
Fix: b/402544816
Test: atest pass
Test: Manual test

Change-Id: Ifeff9368fed906bc56abcc8eb23748a71f79ee4d
This commit is contained in:
tom hsu
2025-03-21 11:08:19 +00:00
parent 14fe4f0f01
commit 8be6d98b1f
6 changed files with 146 additions and 17 deletions

View File

@@ -12768,6 +12768,10 @@ Data usage charges may apply.</string>
<string name="title_satellite_supported_app_list_entry">see all apps</string> <string name="title_satellite_supported_app_list_entry">see all apps</string>
<!-- Title for a page of apps list page with Satellite service supported. [CHAR LIMIT=60] --> <!-- Title for a page of apps list page with Satellite service supported. [CHAR LIMIT=60] -->
<string name="title_satellite_supported_app_list_page">Supported apps on your phone</string> <string name="title_satellite_supported_app_list_page">Supported apps on your phone</string>
<!-- Title for showing a dialog to notify user sim restriction. [CHAR LIMIT=60] -->
<string name="title_satellite_dialog_for_sim_restriction">Can\u2019t add a SIM</string>
<!-- Description for showing a dialog to notify user sim restriction. [CHAR LIMIT=NONE] -->
<string name="description_satellite_dialog_for_sim_restriction">End the satellite connection before you add a SIM</string>
<!-- Title for Apn settings in mobile network settings [CHAR LIMIT=60] --> <!-- Title for Apn settings in mobile network settings [CHAR LIMIT=60] -->
<string name="mobile_network_apn_title">Access Point Names</string> <string name="mobile_network_apn_title">Access Point Names</string>

View File

@@ -25,6 +25,7 @@ import androidx.preference.Preference.OnPreferenceClickListener
import com.android.settings.R import com.android.settings.R
import com.android.settings.flags.Flags import com.android.settings.flags.Flags
import com.android.settings.network.AirplaneModePreference.Companion.isAirplaneModeOn import com.android.settings.network.AirplaneModePreference.Companion.isAirplaneModeOn
import com.android.settings.network.SatelliteRepository.Companion.isSatelliteOn
import com.android.settings.network.SubscriptionUtil.getUniqueSubscriptionDisplayName import com.android.settings.network.SubscriptionUtil.getUniqueSubscriptionDisplayName
import com.android.settings.network.telephony.SimRepository import com.android.settings.network.telephony.SimRepository
import com.android.settings.network.telephony.SubscriptionRepository import com.android.settings.network.telephony.SubscriptionRepository
@@ -32,6 +33,7 @@ import com.android.settings.network.telephony.euicc.EuiccRepository
import com.android.settings.restriction.PreferenceRestrictionMixin import com.android.settings.restriction.PreferenceRestrictionMixin
import com.android.settings.spa.network.getAddSimIntent import com.android.settings.spa.network.getAddSimIntent
import com.android.settings.spa.network.startAddSimFlow import com.android.settings.spa.network.startAddSimFlow
import com.android.settings.spa.network.startSatelliteWarningDialogFlow
import com.android.settingslib.RestrictedPreference import com.android.settingslib.RestrictedPreference
import com.android.settingslib.datastore.HandlerExecutor import com.android.settingslib.datastore.HandlerExecutor
import com.android.settingslib.datastore.KeyedObserver import com.android.settingslib.datastore.KeyedObserver
@@ -120,7 +122,11 @@ class MobileNetworkListScreen :
val summary = preference.summary ?: return true // no-op val summary = preference.summary ?: return true // no-op
val context = preference.context val context = preference.context
if (summary == context.getString(R.string.mobile_network_summary_add_a_network)) { if (summary == context.getString(R.string.mobile_network_summary_add_a_network)) {
startAddSimFlow(context) // start intent if (isSatelliteOn(context, 3000)) {
startSatelliteWarningDialogFlow(context) // start intent
} else {
startAddSimFlow(context) // start intent
}
return true return true
} }
return false // start fragment return false // start fragment

View File

@@ -27,6 +27,7 @@ import com.android.settings.dashboard.DashboardFragment
import com.android.settings.network.telephony.SimRepository import com.android.settings.network.telephony.SimRepository
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settings.spa.network.startAddSimFlow import com.android.settings.spa.network.startAddSimFlow
import com.android.settings.spa.network.startSatelliteWarningDialogFlow
import com.android.settingslib.RestrictedPreference import com.android.settingslib.RestrictedPreference
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow
@@ -51,11 +52,13 @@ constructor(
MobileNetworkSummaryRepository(context), MobileNetworkSummaryRepository(context),
private val airplaneModeOnFlow: Flow<Boolean> = private val airplaneModeOnFlow: Flow<Boolean> =
context.settingsGlobalBooleanFlow(Settings.Global.AIRPLANE_MODE_ON), context.settingsGlobalBooleanFlow(Settings.Global.AIRPLANE_MODE_ON),
private val satelliteIsStartedFlow: Flow<Boolean> = SatelliteRepository(context).getIsSessionStartedFlow()
) : BasePreferenceController(context, preferenceKey) { ) : BasePreferenceController(context, preferenceKey) {
private val metricsFeatureProvider = featureFactory.metricsFeatureProvider private val metricsFeatureProvider = featureFactory.metricsFeatureProvider
private var preference: RestrictedPreference? = null private var preference: RestrictedPreference? = null
private var isAirplaneModeOn = false private var isAirplaneModeOn = false
private var isSatelliteOn = false
override fun getAvailabilityStatus() = override fun getAvailabilityStatus() =
if (SimRepository(mContext).showMobileNetworkPageEntrance()) AVAILABLE if (SimRepository(mContext).showMobileNetworkPageEntrance()) AVAILABLE
@@ -74,6 +77,9 @@ constructor(
isAirplaneModeOn = it isAirplaneModeOn = it
updateEnabled() updateEnabled()
} }
satelliteIsStartedFlow.collectLatestWithLifecycle(viewLifecycleOwner) {
isSatelliteOn = it
}
} }
private fun update(state: MobileNetworkSummaryRepository.SubscriptionsState) { private fun update(state: MobileNetworkSummaryRepository.SubscriptionsState) {
@@ -87,7 +93,10 @@ constructor(
preference.onPreferenceClickListener = preference.onPreferenceClickListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceClickListener {
logPreferenceClick() logPreferenceClick()
startAddSimFlow(context) if (isSatelliteOn)
startSatelliteWarningDialogFlow(context)
else
startAddSimFlow(context)
true true
} }
} }

View File

@@ -32,11 +32,20 @@ import com.android.settingslib.wifi.WifiUtils
/** A dialog to show the warning message when device is under satellite mode. */ /** A dialog to show the warning message when device is under satellite mode. */
class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() { class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() {
private var warningType = TYPE_IS_UNKNOWN private var warningType = TYPE_IS_UNKNOWN
private var customizedContent: HashMap<Int, String> = HashMap<Int, String>()
private var isCustomizedContent = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
warningType = intent.getIntExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, TYPE_IS_UNKNOWN) isCustomizedContent = intent.hasExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT)
if (warningType == TYPE_IS_UNKNOWN) { if (isCustomizedContent) {
finish() customizedContent =
intent.getSerializableExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT)
as HashMap<Int, String>
} else {
warningType =
intent.getIntExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, TYPE_IS_UNKNOWN)
if (warningType == TYPE_IS_UNKNOWN) {
finish()
}
} }
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
@@ -48,23 +57,52 @@ class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() {
) )
} }
fun getBodyString(): String {
if (isCustomizedContent) {
// For customized content
return customizedContent.get(CUSTOM_CONTENT_DESCRIPTION).toString()
} else {
// For wifi, bluetooth, airplane mode
return String.format(
getString(R.string.satellite_warning_dialog_content),
getTypeString(warningType)
)
}
}
fun getButtonString(): String {
if (isCustomizedContent)
// For customized content
return customizedContent.get(CUSTOM_CONTENT_BUTTON_NAME).toString()
else
// For wifi, bluetooth, airplane mode
return getString(com.android.settingslib.R.string.okay)
}
fun getTitleString(): String {
if (isCustomizedContent)
// For customized content
return customizedContent.get(CUSTOM_CONTENT_TITLE).toString()
else
// For wifi, bluetooth, airplane mode
return String.format(
getString(R.string.satellite_warning_dialog_title),
getTypeString(warningType)
)
}
@Composable @Composable
override fun Content() { override fun Content() {
SettingsAlertDialogContent( SettingsAlertDialogContent(
dismissButton = null, dismissButton = null,
confirmButton = AlertDialogButton( confirmButton = AlertDialogButton(
getString(com.android.settingslib.R.string.okay) getButtonString()
) { finish() }, ) { finish() },
title = String.format( title = getTitleString(),
getString(R.string.satellite_warning_dialog_title),
getTypeString(warningType)
),
text = { text = {
Text( Text(
String.format( getBodyString(),
getString(R.string.satellite_warning_dialog_content),
getTypeString(warningType)
),
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
@@ -83,9 +121,14 @@ class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() {
companion object { companion object {
const val EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG: String = const val EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG: String =
"extra_type_of_satellite_warning_dialog" "extra_type_of_satellite_warning_dialog"
const val EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT: String =
"extra_type_of_satellite_customized_content"
const val TYPE_IS_UNKNOWN = -1 const val TYPE_IS_UNKNOWN = -1
const val TYPE_IS_WIFI = 0 const val TYPE_IS_WIFI = 0
const val TYPE_IS_BLUETOOTH = 1 const val TYPE_IS_BLUETOOTH = 1
const val TYPE_IS_AIRPLANE_MODE = 2 const val TYPE_IS_AIRPLANE_MODE = 2
const val CUSTOM_CONTENT_TITLE = 0
const val CUSTOM_CONTENT_DESCRIPTION = 1
const val CUSTOM_CONTENT_BUTTON_NAME = 2
} }
} }

View File

@@ -35,6 +35,10 @@ import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R import com.android.settings.R
import com.android.settings.Utils import com.android.settings.Utils
import com.android.settings.network.SatelliteWarningDialogActivity
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_BUTTON_NAME
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_DESCRIPTION
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_TITLE
import com.android.settings.network.SubscriptionUtil import com.android.settings.network.SubscriptionUtil
import com.android.settings.network.telephony.MobileNetworkUtils import com.android.settings.network.telephony.MobileNetworkUtils
import com.android.settings.network.telephony.SubscriptionActivationRepository import com.android.settings.network.telephony.SubscriptionActivationRepository
@@ -143,3 +147,14 @@ fun getAddSimIntent() = Intent(EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTI
setPackage(Utils.PHONE_PACKAGE_NAME) setPackage(Utils.PHONE_PACKAGE_NAME)
putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true) putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true)
} }
fun startSatelliteWarningDialogFlow(context: Context) = context.startActivity(getSatelliteWarningDialogIntent(context))
fun getSatelliteWarningDialogIntent(context: Context) = Intent(context,
SatelliteWarningDialogActivity::class.java).apply {
val content = HashMap<Int, String>()
content.put(CUSTOM_CONTENT_TITLE, context.getString(R.string.title_satellite_dialog_for_sim_restriction))
content.put(CUSTOM_CONTENT_DESCRIPTION, context.getString(R.string.description_satellite_dialog_for_sim_restriction))
content.put(CUSTOM_CONTENT_BUTTON_NAME, context.getString(R.string.okay))
putExtra(SatelliteWarningDialogActivity.EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT, content)
}

View File

@@ -28,6 +28,10 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R import com.android.settings.R
import com.android.settings.network.SatelliteWarningDialogActivity import com.android.settings.network.SatelliteWarningDialogActivity
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_BUTTON_NAME
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_DESCRIPTION
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_TITLE
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG import com.android.settings.network.SatelliteWarningDialogActivity.Companion.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_AIRPLANE_MODE import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_AIRPLANE_MODE
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_BLUETOOTH import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_BLUETOOTH
@@ -74,6 +78,33 @@ class SatelliteWarningDialogActivityTest {
scenario.close() scenario.close()
} }
@Test
fun launchActivity_checkCustomizedContent_hasContentIntent() {
val scenario = launchCustomizedDialogActivity()
scenario.onActivity { activity ->
assert(activity.intent.hasExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT))
}
scenario.close()
}
@Test
fun testCustomizedDialogIsExisted() {
val scenario = launchCustomizedDialogActivity()
composeTestRule.onNodeWithText(
getSatelliteTestContent().get(CUSTOM_CONTENT_BUTTON_NAME).toString()
).assertIsDisplayed()
composeTestRule.onNodeWithText(
getSatelliteTestContent().get(CUSTOM_CONTENT_TITLE).toString()
).assertIsDisplayed()
composeTestRule.onNodeWithText(
getSatelliteTestContent().get(CUSTOM_CONTENT_DESCRIPTION).toString()
).assertIsDisplayed()
scenario.close()
}
@Test @Test
fun launchActivity_unknownType_destroyActivity() { fun launchActivity_unknownType_destroyActivity() {
val scenario = launchDialogActivity(TYPE_IS_UNKNOWN) val scenario = launchDialogActivity(TYPE_IS_UNKNOWN)
@@ -117,10 +148,31 @@ class SatelliteWarningDialogActivityTest {
scenario.close() scenario.close()
} }
private fun launchDialogActivity(type: Int): ActivityScenario<SatelliteWarningDialogActivity> = launch( private fun launchDialogActivity(type: Int): ActivityScenario<SatelliteWarningDialogActivity> =
Intent( launch(Intent(
context, context,
SatelliteWarningDialogActivity::class.java SatelliteWarningDialogActivity::class.java
).putExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, type) ).putExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, type)
) )
private fun launchCustomizedDialogActivity(): ActivityScenario<SatelliteWarningDialogActivity> =
launch(Intent(
context,
SatelliteWarningDialogActivity::class.java
).putExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT, getSatelliteTestContent())
)
private fun getSatelliteTestContent(): HashMap<Int, String> {
val content = HashMap<Int, String>()
content.put(CUSTOM_CONTENT_TITLE, TEST_TITLE)
content.put(CUSTOM_CONTENT_DESCRIPTION, TEST_DESCRIPTION)
content.put(CUSTOM_CONTENT_BUTTON_NAME, TEST_BUTTON_NAME)
return content
}
companion object {
const val TEST_TITLE = "TEST_TITLE"
const val TEST_DESCRIPTION = "TEST_DESCRIPTION"
const val TEST_BUTTON_NAME = "TEST_BUTTON_NAME"
}
} }