From a5bd1cf34fb450af15a5e70117206d500f8169b9 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 29 Feb 2024 09:44:37 -0800 Subject: [PATCH 1/2] settings(dev): Remove NFC stack logging control We are now turning on verbose logging by default. Bug: 327517842 Test: Compiles Change-Id: I3c6026e230c7d35f04d9771442fadbf040a84b94 --- .../DevelopmentSettingsDashboardFragment.java | 1 - .../NfcStackDebugLogPreferenceController.java | 82 ------------- ...StackDebugLogPreferenceControllerTest.java | 112 ------------------ 3 files changed, 195 deletions(-) delete mode 100644 src/com/android/settings/development/NfcStackDebugLogPreferenceController.java delete mode 100644 tests/unit/src/com/android/settings/development/NfcStackDebugLogPreferenceControllerTest.java diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index 6b38b28adc9..cfa4a589cd0 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -686,7 +686,6 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment)); controllers.add(new BluetoothLeAudioHwOffloadPreferenceController(context, fragment)); controllers.add(new BluetoothMaxConnectedAudioDevicesPreferenceController(context)); - controllers.add(new NfcStackDebugLogPreferenceController(context)); controllers.add(new NfcSnoopLogPreferenceController(context, fragment)); controllers.add(new NfcVerboseVendorLogPreferenceController(context, fragment)); controllers.add(new ShowTapsPreferenceController(context)); diff --git a/src/com/android/settings/development/NfcStackDebugLogPreferenceController.java b/src/com/android/settings/development/NfcStackDebugLogPreferenceController.java deleted file mode 100644 index 4464923b958..00000000000 --- a/src/com/android/settings/development/NfcStackDebugLogPreferenceController.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2021 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.development; - -import android.content.Context; -import android.os.SystemProperties; -import android.util.Log; - -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.TwoStatePreference; - -import com.android.settings.core.PreferenceControllerMixin; -import com.android.settingslib.development.DeveloperOptionsPreferenceController; - -public class NfcStackDebugLogPreferenceController extends - DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, - PreferenceControllerMixin { - - private static final String NFC_STACK_DEBUGLOG_ENABLED_KEY = - "nfc_stack_debuglog_enabled"; - @VisibleForTesting - static final String NFC_STACK_DEBUGLOG_ENABLED_PROPERTY = - "persist.nfc.debug_enabled"; - - public NfcStackDebugLogPreferenceController(Context context) { - super(context); - } - - @Override - public String getPreferenceKey() { - return NFC_STACK_DEBUGLOG_ENABLED_KEY; - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - final boolean isEnabled = (Boolean) newValue; - try { - SystemProperties.set(NFC_STACK_DEBUGLOG_ENABLED_PROPERTY, - isEnabled ? "true" : "false"); - } catch (RuntimeException e) { - Log.e(TAG, "Fail to set nfc system property: " + e.getMessage()); - } - return true; - } - - @Override - public void updateState(Preference preference) { - try { - final boolean isEnabled = SystemProperties.getBoolean( - NFC_STACK_DEBUGLOG_ENABLED_PROPERTY, false /* default */); - ((TwoStatePreference) mPreference).setChecked(isEnabled); - } catch (RuntimeException e) { - Log.e(TAG, "Fail to get nfc system property: " + e.getMessage()); - } - } - - @Override - protected void onDeveloperOptionsSwitchDisabled() { - super.onDeveloperOptionsSwitchDisabled(); - try { - SystemProperties.set(NFC_STACK_DEBUGLOG_ENABLED_PROPERTY, "false"); - ((TwoStatePreference) mPreference).setChecked(false); - } catch (RuntimeException e) { - Log.e(TAG, "Fail to set nfc system property: " + e.getMessage()); - } - } -} diff --git a/tests/unit/src/com/android/settings/development/NfcStackDebugLogPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/NfcStackDebugLogPreferenceControllerTest.java deleted file mode 100644 index 914d01d9d23..00000000000 --- a/tests/unit/src/com/android/settings/development/NfcStackDebugLogPreferenceControllerTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2021 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.development; - -import static com.android.settings.development.NfcStackDebugLogPreferenceController - .NFC_STACK_DEBUGLOG_ENABLED_PROPERTY; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; -import android.os.Looper; -import android.os.SystemProperties; - -import androidx.preference.SwitchPreference; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceScreen; -import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class NfcStackDebugLogPreferenceControllerTest { - - private Context mContext; - private NfcStackDebugLogPreferenceController mController; - private SwitchPreference mPreference; - - @Before - public void setUp() { - mContext = ApplicationProvider.getApplicationContext(); - mController = new NfcStackDebugLogPreferenceController(mContext); - if (Looper.myLooper() == null) { - Looper.prepare(); - } - - final PreferenceManager preferenceManager = new PreferenceManager(mContext); - final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext); - mPreference = new SwitchPreference(mContext); - mPreference.setKey(mController.getPreferenceKey()); - screen.addPreference(mPreference); - mController.displayPreference(screen); - } - - @Test - public void onPreferenceChanged_settingDisabled_shouldTurnOffNfcStackDebugLog() { - mController.onPreferenceChange(mPreference, false /* new value */); - - final boolean mode = SystemProperties.getBoolean( - NFC_STACK_DEBUGLOG_ENABLED_PROPERTY, false /* default */); - - assertThat(mode).isFalse(); - } - - @Test - public void onPreferenceChanged_settingEnabled_shouldTurnOnNfcStackDebugLog() { - mController.onPreferenceChange(mPreference, true /* new value */); - - final boolean mode = SystemProperties.getBoolean( - NFC_STACK_DEBUGLOG_ENABLED_PROPERTY, false /* default */); - - assertThat(mode).isTrue(); - } - - @Test - public void updateState_settingEnabled_preferenceShouldBeChecked() { - SystemProperties.set(NFC_STACK_DEBUGLOG_ENABLED_PROPERTY, - Boolean.toString(true)); - - mController.updateState(mPreference); - assertThat(mPreference.isChecked()).isTrue(); - } - - @Test - public void updateState_settingDisabled_preferenceShouldNotBeChecked() { - SystemProperties.set(NFC_STACK_DEBUGLOG_ENABLED_PROPERTY, - Boolean.toString(false)); - - mController.updateState(mPreference); - assertThat(mPreference.isChecked()).isFalse(); - } - - @Test - public void onDeveloperOptionsDisabled_shouldDisablePreference() { - mController.onDeveloperOptionsSwitchDisabled(); - final boolean mode = SystemProperties.getBoolean( - NFC_STACK_DEBUGLOG_ENABLED_PROPERTY, - false /* default */); - - mController.updateState(mPreference); - - assertThat(mode).isFalse(); - assertThat(mPreference.isChecked()).isFalse(); - } -} From bec4c9573ef92c583e235f57e9f220e68572e39d Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Thu, 29 Feb 2024 14:52:36 +0800 Subject: [PATCH 2/2] Create isSubscriptionEnabledFlow To better display the isEnable checked state. Bug: 318310357 Test: manual - on Mobile Settings Test: unit test Change-Id: Ia595e7445650ad67883f1e7c1a0662cb826565ea --- .../telephony/SubscriptionRepository.kt | 7 + .../network/NetworkCellularGroupProvider.kt | 172 ++++-------------- .../settings/spa/network/SimsSection.kt | 98 ++++++++++ .../telephony/SubscriptionRepositoryTest.kt | 16 ++ 4 files changed, 161 insertions(+), 132 deletions(-) create mode 100644 src/com/android/settings/spa/network/SimsSection.kt diff --git a/src/com/android/settings/network/telephony/SubscriptionRepository.kt b/src/com/android/settings/network/telephony/SubscriptionRepository.kt index ee4ac1e8efb..9a462727bb6 100644 --- a/src/com/android/settings/network/telephony/SubscriptionRepository.kt +++ b/src/com/android/settings/network/telephony/SubscriptionRepository.kt @@ -25,10 +25,17 @@ import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach private const val TAG = "SubscriptionRepository" +fun Context.isSubscriptionEnabledFlow(subId: Int) = subscriptionsChangedFlow().map { + val subscriptionManager = getSystemService(SubscriptionManager::class.java) + + subscriptionManager?.isSubscriptionEnabled(subId) ?: false +}.flowOn(Dispatchers.Default) + fun Context.subscriptionsChangedFlow() = callbackFlow { val subscriptionManager = getSystemService(SubscriptionManager::class.java)!! diff --git a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt index 351ac777d8d..a0c363a206b 100644 --- a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt +++ b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt @@ -16,37 +16,33 @@ package com.android.settings.spa.network -import android.app.Application import android.content.Context -import android.content.Intent import android.content.IntentFilter import android.os.Bundle -import android.os.UserManager import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager import android.telephony.TelephonyManager -import android.telephony.euicc.EuiccManager import android.util.Log import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.Message -import androidx.compose.material.icons.outlined.Add import androidx.compose.material.icons.outlined.DataUsage import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableIntState +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.toMutableStateList import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel import com.android.settings.R import com.android.settings.network.SubscriptionInfoListViewModel -import com.android.settings.network.SubscriptionUtil import com.android.settings.network.telephony.MobileNetworkUtils import com.android.settings.wifi.WifiPickerTrackerHelper import com.android.settingslib.spa.framework.common.SettingsEntryBuilder @@ -59,17 +55,13 @@ import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel -import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference import com.android.settingslib.spa.widget.scaffold.RegularScaffold import com.android.settingslib.spa.widget.ui.Category -import com.android.settingslib.spa.widget.ui.SettingsIcon import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverFlow - -import com.android.settingslib.spaprivileged.model.enterprise.Restrictions -import com.android.settingslib.spaprivileged.template.preference.RestrictedPreference import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOf @@ -85,10 +77,8 @@ import kotlinx.coroutines.withContext object NetworkCellularGroupProvider : SettingsPageProvider { override val name = "NetworkCellularGroupProvider" - private lateinit var subscriptionViewModel: SubscriptionInfoListViewModel private val owner = createSettingsPage() - var selectableSubscriptionInfoList: List = listOf() var defaultVoiceSubId: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID var defaultSmsSubId: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID var defaultDataSubId: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID @@ -106,9 +96,6 @@ object NetworkCellularGroupProvider : SettingsPageProvider { @Composable override fun Page(arguments: Bundle?) { val context = LocalContext.current - var selectableSubscriptionInfoListRemember = remember { - mutableListOf().toMutableStateList() - } var callsSelectedId = rememberSaveable { mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID) } @@ -122,24 +109,24 @@ object NetworkCellularGroupProvider : SettingsPageProvider { mutableIntStateOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID) } - subscriptionViewModel = SubscriptionInfoListViewModel( - context.applicationContext as Application) + val subscriptionViewModel = viewModel() - allOfFlows(context, subscriptionViewModel.selectableSubscriptionInfoListFlow) - .collectLatestWithLifecycle(LocalLifecycleOwner.current) { - selectableSubscriptionInfoListRemember.clear() - selectableSubscriptionInfoListRemember.addAll(selectableSubscriptionInfoList) - callsSelectedId.intValue = defaultVoiceSubId - textsSelectedId.intValue = defaultSmsSubId - mobileDataSelectedId.intValue = defaultDataSubId - nonDdsRemember.intValue = nonDds - } + remember { + allOfFlows(context, subscriptionViewModel.selectableSubscriptionInfoListFlow) + }.collectLatestWithLifecycle(LocalLifecycleOwner.current) { + callsSelectedId.intValue = defaultVoiceSubId + textsSelectedId.intValue = defaultSmsSubId + mobileDataSelectedId.intValue = defaultDataSubId + nonDdsRemember.intValue = nonDds + } - PageImpl(selectableSubscriptionInfoListRemember, - callsSelectedId, - textsSelectedId, - mobileDataSelectedId, - nonDdsRemember) + PageImpl( + subscriptionViewModel.selectableSubscriptionInfoListFlow, + callsSelectedId, + textsSelectedId, + mobileDataSelectedId, + nonDdsRemember + ) } private fun allOfFlows(context: Context, @@ -152,13 +139,12 @@ object NetworkCellularGroupProvider : SettingsPageProvider { NetworkCellularGroupProvider::refreshUiStates, ).flowOn(Dispatchers.Default) - fun refreshUiStates( - inputSelectableSubscriptionInfoList: List, - inputDefaultVoiceSubId: Int, - inputDefaultSmsSubId: Int, - inputDefaultDateSubId: Int - ): Unit { - selectableSubscriptionInfoList = inputSelectableSubscriptionInfoList + private fun refreshUiStates( + selectableSubscriptionInfoList: List, + inputDefaultVoiceSubId: Int, + inputDefaultSmsSubId: Int, + inputDefaultDateSubId: Int + ) { defaultVoiceSubId = inputDefaultVoiceSubId defaultSmsSubId = inputDefaultSmsSubId defaultDataSubId = inputDefaultDateSubId @@ -178,25 +164,23 @@ object NetworkCellularGroupProvider : SettingsPageProvider { } @Composable -fun PageImpl(selectableSubscriptionInfoList: List, - defaultVoiceSubId: MutableIntState, - defaultSmsSubId: MutableIntState, - defaultDataSubId: MutableIntState, - nonDds: MutableIntState) { - val context = LocalContext.current - var activeSubscriptionInfoList: List = - selectableSubscriptionInfoList.filter { subscriptionInfo -> - subscriptionInfo.simSlotIndex != -1 - } - var subscriptionManager = context.getSystemService(SubscriptionManager::class.java) +fun PageImpl( + selectableSubscriptionInfoListFlow: StateFlow>, + defaultVoiceSubId: MutableIntState, + defaultSmsSubId: MutableIntState, + defaultDataSubId: MutableIntState, + nonDds: MutableIntState +) { + val selectableSubscriptionInfoList by selectableSubscriptionInfoListFlow + .collectAsStateWithLifecycle(initialValue = emptyList()) + val activeSubscriptionInfoList: List = + selectableSubscriptionInfoList.filter { subscriptionInfo -> + subscriptionInfo.simSlotIndex != -1 + } val stringSims = stringResource(R.string.provider_network_settings_title) RegularScaffold(title = stringSims) { - SimsSectionImpl( - context, - subscriptionManager, - selectableSubscriptionInfoList - ) + SimsSection(selectableSubscriptionInfoList) PrimarySimSectionImpl( activeSubscriptionInfoList, defaultVoiceSubId, @@ -207,56 +191,6 @@ fun PageImpl(selectableSubscriptionInfoList: List, } } -@Composable -fun SimsSectionImpl( - context: Context, - subscriptionManager: SubscriptionManager?, - subscriptionInfoList: List -) { - val coroutineScope = rememberCoroutineScope() - for (subInfo in subscriptionInfoList) { - val checked = rememberSaveable() { - mutableStateOf(false) - } - //TODO: Add the Restricted TwoTargetSwitchPreference in SPA - TwoTargetSwitchPreference( - object : SwitchPreferenceModel { - override val title = subInfo.displayName.toString() - override val summary = { subInfo.number } - override val checked = { - coroutineScope.launch { - withContext(Dispatchers.Default) { - checked.value = subscriptionManager?.isSubscriptionEnabled( - subInfo.subscriptionId)?:false - } - } - checked.value - } - override val onCheckedChange = { newChecked: Boolean -> - startToggleSubscriptionDialog(context, subInfo, newChecked) - } - } - ) { - startMobileNetworkSettings(context, subInfo) - } - } - - // + add sim - if (showEuiccSettings(context)) { - RestrictedPreference( - model = object : PreferenceModel { - override val title = stringResource(id = R.string.mobile_network_list_add_more) - override val icon = @Composable { SettingsIcon(Icons.Outlined.Add) } - override val onClick = { - startAddSimFlow(context) - } - }, - restrictions = Restrictions(keys = - listOf(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)), - ) - } -} - @Composable fun PrimarySimImpl( subscriptionInfoList: List, @@ -440,32 +374,6 @@ private fun Context.defaultDefaultDataSubscriptionFlow(): Flow = ).map { SubscriptionManager.getDefaultDataSubscriptionId() } .conflate().flowOn(Dispatchers.Default) -private fun startToggleSubscriptionDialog( - context: Context, - subInfo: SubscriptionInfo, - newStatus: Boolean -) { - SubscriptionUtil.startToggleSubscriptionDialogActivity( - context, - subInfo.subscriptionId, - newStatus - ) -} - -private fun startMobileNetworkSettings(context: Context, subInfo: SubscriptionInfo) { - MobileNetworkUtils.launchMobileNetworkSettings(context, subInfo) -} - -private fun startAddSimFlow(context: Context) { - val intent = Intent(EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION) - intent.putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true) - context.startActivity(intent) -} - -private fun showEuiccSettings(context: Context): Boolean { - return MobileNetworkUtils.showEuiccSettings(context) -} - suspend fun setDefaultVoice( subscriptionManager: SubscriptionManager?, subId: Int diff --git a/src/com/android/settings/spa/network/SimsSection.kt b/src/com/android/settings/spa/network/SimsSection.kt new file mode 100644 index 00000000000..cc8a5d1c527 --- /dev/null +++ b/src/com/android/settings/spa/network/SimsSection.kt @@ -0,0 +1,98 @@ +/* + * 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.network + +import android.content.Context +import android.content.Intent +import android.os.UserManager +import android.telephony.SubscriptionInfo +import android.telephony.euicc.EuiccManager +import androidx.compose.foundation.layout.Column +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Add +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.settings.R +import com.android.settings.network.SubscriptionUtil +import com.android.settings.network.telephony.MobileNetworkUtils +import com.android.settings.network.telephony.isSubscriptionEnabledFlow +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel +import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference +import com.android.settingslib.spa.widget.ui.SettingsIcon +import com.android.settingslib.spaprivileged.model.enterprise.Restrictions +import com.android.settingslib.spaprivileged.template.preference.RestrictedPreference + +@Composable +fun SimsSection(subscriptionInfoList: List) { + Column { + for (subInfo in subscriptionInfoList) { + SimPreference(subInfo) + } + + AddSim() + } +} + +@Composable +private fun SimPreference(subInfo: SubscriptionInfo) { + val context = LocalContext.current + val checked = remember(subInfo.subscriptionId) { + context.isSubscriptionEnabledFlow(subInfo.subscriptionId) + }.collectAsStateWithLifecycle(initialValue = false) + //TODO: Add the Restricted TwoTargetSwitchPreference in SPA + TwoTargetSwitchPreference( + object : SwitchPreferenceModel { + override val title = subInfo.displayName.toString() + override val summary = { subInfo.number } + override val checked = { checked.value } + override val onCheckedChange = { newChecked: Boolean -> + SubscriptionUtil.startToggleSubscriptionDialogActivity( + context, + subInfo.subscriptionId, + newChecked, + ) + } + } + ) { + MobileNetworkUtils.launchMobileNetworkSettings(context, subInfo) + } +} + +@Composable +private fun AddSim() { + val context = LocalContext.current + if (remember { MobileNetworkUtils.showEuiccSettings(context) }) { + RestrictedPreference( + model = object : PreferenceModel { + override val title = stringResource(id = R.string.mobile_network_list_add_more) + override val icon = @Composable { SettingsIcon(Icons.Outlined.Add) } + override val onClick = { startAddSimFlow(context) } + }, + restrictions = Restrictions(keys = listOf(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)), + ) + } +} + +private fun startAddSimFlow(context: Context) { + val intent = Intent(EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION) + intent.putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true) + context.startActivity(intent) +} diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt index 28871340888..a59bf932508 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt @@ -33,6 +33,7 @@ import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.spy +import org.mockito.kotlin.stub @RunWith(AndroidJUnit4::class) class SubscriptionRepositoryTest { @@ -49,6 +50,17 @@ class SubscriptionRepositoryTest { on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager } + @Test + fun isSubscriptionEnabledFlow() = runBlocking { + mockSubscriptionManager.stub { + on { isSubscriptionEnabled(SUB_ID) } doReturn true + } + + val isEnabled = context.isSubscriptionEnabledFlow(SUB_ID).firstWithTimeoutOrNull() + + assertThat(isEnabled).isTrue() + } + @Test fun subscriptionsChangedFlow_hasInitialValue() = runBlocking { val initialValue = context.subscriptionsChangedFlow().firstWithTimeoutOrNull() @@ -67,4 +79,8 @@ class SubscriptionRepositoryTest { assertThat(listDeferred.await()).hasSize(2) } + + private companion object { + const val SUB_ID = 1 + } }