From ce18c81da698354e84ae2d9c6f5cb664cba1e8d9 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Wed, 20 Dec 2023 17:03:59 +0800 Subject: [PATCH] Show "MMS messages" when mobile data is off For some corner case, - Single SIM, data off, auto switch on (although hidden) - Dual SIM, default data off, auto switch on Bug: 303759893 Test: manual - on Mobile Settings Test: unit test Change-Id: I70dd792ecff590f34100efaaf6ee4efcc2b759fd --- .../MmsMessagePreferenceController.kt | 23 +++- .../MmsMessagePreferenceControllerTest.kt | 101 +++++++++++++----- 2 files changed, 94 insertions(+), 30 deletions(-) diff --git a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt index 4e41038f068..bf954753922 100644 --- a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt +++ b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt @@ -29,8 +29,13 @@ import kotlinx.coroutines.flow.combine /** * Preference controller for "MMS messages" */ -class MmsMessagePreferenceController(context: Context, key: String) : - TelephonyTogglePreferenceController(context, key) { +class MmsMessagePreferenceController @JvmOverloads constructor( + context: Context, + key: String, + private val getDefaultDataSubId: () -> Int = { + SubscriptionManager.getDefaultDataSubscriptionId() + }, +) : TelephonyTogglePreferenceController(context, key) { private lateinit var telephonyManager: TelephonyManager @@ -46,10 +51,17 @@ class MmsMessagePreferenceController(context: Context, key: String) : if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && !telephonyManager.isDataEnabled && telephonyManager.isApnMetered(ApnSetting.TYPE_MMS) && - !telephonyManager.isMobileDataPolicyEnabled( + !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 ) - ) AVAILABLE else CONDITIONALLY_UNAVAILABLE + } override fun displayPreference(screen: PreferenceScreen) { super.displayPreference(screen) @@ -61,7 +73,8 @@ class MmsMessagePreferenceController(context: Context, key: String) : mContext.mobileDataEnabledFlow(mSubId), mContext.subscriptionsChangedFlow(), // Capture isMobileDataPolicyEnabled() changes ) { _, _ -> }.collectLatestWithLifecycle(viewLifecycleOwner) { - preferenceScreen?.let { super.displayPreference(it) } } + preferenceScreen?.let { super.displayPreference(it) } + } } override fun isChecked(): Boolean = telephonyManager.isMobileDataPolicyEnabled( diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.kt index 588881941b9..a2f635d0b2a 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.kt @@ -27,7 +27,6 @@ import com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILA 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.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.spy @@ -36,20 +35,35 @@ import org.mockito.kotlin.verify @RunWith(AndroidJUnit4::class) class MmsMessagePreferenceControllerTest { + private val mockTelephonyManager1: TelephonyManager = mock { + on { isApnMetered(ApnSetting.TYPE_MMS) } doReturn true + } + + private val mockTelephonyManager2: TelephonyManager = mock { + on { createForSubscriptionId(SUB_1_ID) } doReturn mockTelephonyManager1 + on { isApnMetered(ApnSetting.TYPE_MMS) } doReturn true + } + private val mockTelephonyManager: TelephonyManager = mock { - on { createForSubscriptionId(any()) } doReturn mock + on { createForSubscriptionId(SUB_1_ID) } doReturn mockTelephonyManager1 + on { createForSubscriptionId(SUB_2_ID) } doReturn mockTelephonyManager2 + on { createForSubscriptionId(INVALID_SUBSCRIPTION_ID) } doReturn mock } private var context: Context = spy(ApplicationProvider.getApplicationContext()) { on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager } - private val controller = MmsMessagePreferenceController(context, KEY).apply { - init(SUB_ID) - } + private var defaultDataSubId = SUB_1_ID + + private val controller = MmsMessagePreferenceController( + context = context, + key = KEY, + getDefaultDataSubId = { defaultDataSubId }, + ).apply { init(SUB_2_ID) } @Test - fun getAvailabilityStatus_invalidSubscription_returnUnavailable() { + fun getAvailabilityStatus_invalidSubscription_unavailable() { controller.init(INVALID_SUBSCRIPTION_ID) val availabilityStatus = controller.getAvailabilityStatus(INVALID_SUBSCRIPTION_ID) @@ -58,56 +72,92 @@ class MmsMessagePreferenceControllerTest { } @Test - fun getAvailabilityStatus_mobileDataOn_returnUnavailable() { - mockTelephonyManager.stub { + fun getAvailabilityStatus_mobileDataOn_unavailable() { + mockTelephonyManager2.stub { on { isDataEnabled } doReturn true } - val availabilityStatus = controller.getAvailabilityStatus(SUB_ID) + val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID) assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE) } @Test - fun getAvailabilityStatus_meteredOff_returnUnavailable() { - mockTelephonyManager.stub { + fun getAvailabilityStatus_meteredOff_unavailable() { + mockTelephonyManager2.stub { on { isApnMetered(ApnSetting.TYPE_MMS) } doReturn false } - val availabilityStatus = controller.getAvailabilityStatus(SUB_ID) + val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID) assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE) } @Test - fun getAvailabilityStatus_autoDataSwitch_returnUnavailable() { - mockTelephonyManager.stub { - on { isApnMetered(ApnSetting.TYPE_MMS) } doReturn true + fun getAvailabilityStatus_isDefaultDataAndDataOnAndAutoDataSwitchOn_unavailable() { + defaultDataSubId = SUB_2_ID + mockTelephonyManager2.stub { + on { isDataEnabled } doReturn true on { isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH) } doReturn true } - val availabilityStatus = controller.getAvailabilityStatus(SUB_ID) + val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID) assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE) } @Test - fun getAvailabilityStatus_mobileDataOffWithValidSubId_returnAvailable() { - mockTelephonyManager.stub { + fun getAvailabilityStatus_isDefaultDataAndDataOffAndAutoDataSwitchOn_available() { + defaultDataSubId = SUB_2_ID + mockTelephonyManager2.stub { on { isDataEnabled } doReturn false - on { isApnMetered(ApnSetting.TYPE_MMS) } doReturn true + on { + isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH) + } doReturn true } - val availabilityStatus = controller.getAvailabilityStatus(SUB_ID) + val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID) + + assertThat(availabilityStatus).isEqualTo(AVAILABLE) + } + + @Test + fun getAvailabilityStatus_defaultDataOnAndAutoDataSwitchOn_unavailable() { + mockTelephonyManager1.stub { + on { isDataEnabled } doReturn true + } + mockTelephonyManager2.stub { + on { + isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH) + } doReturn true + } + + val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID) + + assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE) + } + + @Test + fun getAvailabilityStatus_defaultDataOffAndAutoDataSwitchOn_available() { + mockTelephonyManager1.stub { + on { isDataEnabled } doReturn false + } + mockTelephonyManager2.stub { + on { + isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH) + } doReturn true + } + + val availabilityStatus = controller.getAvailabilityStatus(SUB_2_ID) assertThat(availabilityStatus).isEqualTo(AVAILABLE) } @Test fun isChecked_whenMmsNotAlwaysAllowed_returnFalse() { - mockTelephonyManager.stub { + mockTelephonyManager2.stub { on { isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED) } doReturn false @@ -120,7 +170,7 @@ class MmsMessagePreferenceControllerTest { @Test fun isChecked_whenMmsAlwaysAllowed_returnTrue() { - mockTelephonyManager.stub { + mockTelephonyManager2.stub { on { isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED) } doReturn true @@ -135,7 +185,7 @@ class MmsMessagePreferenceControllerTest { fun setChecked_setTrue_setDataIntoSubscriptionManager() { controller.setChecked(true) - verify(mockTelephonyManager).setMobileDataPolicyEnabled( + verify(mockTelephonyManager2).setMobileDataPolicyEnabled( TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, true ) } @@ -144,13 +194,14 @@ class MmsMessagePreferenceControllerTest { fun setChecked_setFalse_setDataIntoSubscriptionManager() { controller.setChecked(false) - verify(mockTelephonyManager).setMobileDataPolicyEnabled( + verify(mockTelephonyManager2).setMobileDataPolicyEnabled( TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, false ) } private companion object { const val KEY = "mms_message" - const val SUB_ID = 2 + const val SUB_1_ID = 1 + const val SUB_2_ID = 2 } }