Loading src/com/android/settings/network/AirplaneModePreference.kt +5 −4 Original line number Diff line number Diff line Loading @@ -28,8 +28,7 @@ import com.android.settingslib.metadata.SwitchPreference // LINT.IfChange class AirplaneModePreference : SwitchPreference(KEY, R.string.airplane_mode), PreferenceAvailabilityProvider { SwitchPreference(KEY, R.string.airplane_mode), PreferenceAvailabilityProvider { override val icon: Int @DrawableRes get() = R.drawable.ic_airplanemode_active Loading @@ -40,11 +39,13 @@ class AirplaneModePreference : get() = SensitivityLevel.HIGH_SENSITIVITY override fun isAvailable(context: Context) = (context.resources.getBoolean(R.bool.config_show_toggle_airplane) && !context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) (context.resources.getBoolean(R.bool.config_show_toggle_airplane) && !context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) companion object { const val KEY = Settings.Global.AIRPLANE_MODE_ON fun Context.isAirplaneModeOn() = SettingsGlobalStore.get(this).getBoolean(KEY) == true } } // LINT.ThenChange(AirplaneModePreferenceController.java) src/com/android/settings/network/MobileDataPreference.kt 0 → 100644 +78 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.telephony.SubscriptionManager import com.android.settings.R import com.android.settings.network.telephony.MobileDataRepository import com.android.settings.network.telephony.SubscriptionRepository import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.NoOpKeyedObservable import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.ReadWritePermit import com.android.settingslib.metadata.SensitivityLevel import com.android.settingslib.metadata.SwitchPreference import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking class MobileDataPreference : SwitchPreference( KEY, R.string.mobile_data_settings_title, R.string.mobile_data_settings_summary, ), PreferenceAvailabilityProvider { override fun isAvailable(context: Context) = SubscriptionRepository(context).getSelectableSubscriptionInfoList().any { it.simSlotIndex > -1 } override fun storage(context: Context): KeyValueStore = MobileDataStorage(context) override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) = ReadWritePermit.ALLOW override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) = ReadWritePermit.ALLOW override val sensitivityLevel get() = SensitivityLevel.LOW_SENSITIVITY @Suppress("UNCHECKED_CAST") private class MobileDataStorage(private val context: Context) : NoOpKeyedObservable<String>(), KeyValueStore { override fun contains(key: String) = key == KEY override fun <T : Any> getValue(key: String, valueType: Class<T>): T { val subId = SubscriptionManager.getDefaultDataSubscriptionId() val flow = MobileDataRepository(context).isMobileDataEnabledFlow(subId) return runBlocking { flow.first() } as T } override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) { val subId = SubscriptionManager.getDefaultDataSubscriptionId() MobileDataRepository(context).setMobileDataEnabled(subId, value as Boolean) } } companion object { const val KEY = "mobile_data" } } src/com/android/settings/network/MobileNetworkListScreen.kt +114 −3 Original line number Diff line number Diff line Loading @@ -17,15 +17,49 @@ package com.android.settings.network import android.content.Context import android.os.UserManager import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener import androidx.preference.Preference import androidx.preference.Preference.OnPreferenceClickListener import com.android.settings.PreferenceRestrictionMixin import com.android.settings.R import com.android.settings.flags.Flags import com.android.settings.network.AirplaneModePreference.Companion.isAirplaneModeOn import com.android.settings.network.SubscriptionUtil.getUniqueSubscriptionDisplayName import com.android.settings.network.telephony.SimRepository import com.android.settings.network.telephony.SubscriptionRepository import com.android.settings.network.telephony.euicc.EuiccRepository import com.android.settings.spa.network.getAddSimIntent import com.android.settings.spa.network.startAddSimFlow import com.android.settingslib.RestrictedPreference import com.android.settingslib.datastore.HandlerExecutor import com.android.settingslib.datastore.KeyedObserver import com.android.settingslib.datastore.SettingsGlobalStore import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.PreferenceLifecycleContext import com.android.settingslib.metadata.PreferenceLifecycleProvider import com.android.settingslib.metadata.PreferenceMetadata import com.android.settingslib.metadata.PreferenceSummaryProvider import com.android.settingslib.metadata.ProvidePreferenceScreen import com.android.settingslib.metadata.preferenceHierarchy import com.android.settingslib.preference.PreferenceScreenBinding import com.android.settingslib.preference.PreferenceScreenCreator @ProvidePreferenceScreen class MobileNetworkListScreen : PreferenceScreenCreator, PreferenceRestrictionMixin { class MobileNetworkListScreen : PreferenceScreenCreator, PreferenceScreenBinding, PreferenceAvailabilityProvider, PreferenceSummaryProvider, PreferenceLifecycleProvider, PreferenceRestrictionMixin, OnPreferenceClickListener { private var airplaneModeObserver: KeyedObserver<String>? = null private var subscriptionInfoList: List<SubscriptionInfo>? = null private var onSubscriptionsChangedListener: OnSubscriptionsChangedListener? = null override val key: String get() = KEY Loading @@ -38,18 +72,95 @@ class MobileNetworkListScreen : PreferenceScreenCreator, PreferenceRestrictionMi override val keywords: Int get() = R.string.keywords_more_mobile_networks override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context) override fun intent(context: Context) = getAddSimIntent() override fun getSummary(context: Context): CharSequence? { val list = getSelectableSubscriptionInfoList(context) return when { list.isNotEmpty() -> list .map { getUniqueSubscriptionDisplayName(it, context).toString() } .distinct() .joinToString(", ") EuiccRepository(context).showEuiccSettings() -> context.getString(R.string.mobile_network_summary_add_a_network) else -> null } } override fun isAvailable(context: Context) = SimRepository(context).showMobileNetworkPageEntrance() override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context) && !context.isAirplaneModeOn() && (getSelectableSubscriptionInfoList(context).isNotEmpty() || EuiccRepository(context).showEuiccSettings()) private fun getSelectableSubscriptionInfoList(context: Context): List<SubscriptionInfo> = subscriptionInfoList ?: SubscriptionRepository(context).getSelectableSubscriptionInfoList().also { subscriptionInfoList = it } override val restrictionKeys get() = arrayOf(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS) override val useAdminDisabledSummary get() = true override fun createWidget(context: Context) = RestrictedPreference(context) override fun bind(preference: Preference, metadata: PreferenceMetadata) { super.bind(preference, metadata) preference.onPreferenceClickListener = this } override fun onPreferenceClick(preference: Preference): Boolean { val summary = preference.summary ?: return true // no-op val context = preference.context if (summary == context.getString(R.string.mobile_network_summary_add_a_network)) { startAddSimFlow(context) // start intent return true } return false // start fragment } override fun onCreate(context: PreferenceLifecycleContext) { val executor = HandlerExecutor.main val observer = KeyedObserver<String> { _, _ -> context.notifyPreferenceChange(KEY) } airplaneModeObserver = observer SettingsGlobalStore.get(context).addObserver(AirplaneModePreference.KEY, observer, executor) context.getSystemService(SubscriptionManager::class.java)?.let { val listener = object : OnSubscriptionsChangedListener() { override fun onSubscriptionsChanged() { subscriptionInfoList = null // invalid cache context.notifyPreferenceChange(KEY) } } it.addOnSubscriptionsChangedListener(executor, listener) onSubscriptionsChangedListener = listener } } override fun onDestroy(context: PreferenceLifecycleContext) { airplaneModeObserver?.let { SettingsGlobalStore.get(context).removeObserver(AirplaneModePreference.KEY, it) } context.getSystemService(SubscriptionManager::class.java)?.apply { onSubscriptionsChangedListener?.let { removeOnSubscriptionsChangedListener(it) } } } override fun isFlagEnabled(context: Context) = Flags.catalystMobileNetworkList() override fun hasCompleteHierarchy() = false override fun fragmentClass() = MobileNetworkListFragment::class.java override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {} override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) { +MobileDataPreference() } companion object { const val KEY = "mobile_network_list" Loading src/com/android/settings/network/MobileNetworkSummaryController.kt +2 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import kotlinx.coroutines.flow.Flow * - Has subscriptions: click action takes you to a page listing the subscriptions, and the summary * text gives the count of SIMs */ // LINT.IfChange class MobileNetworkSummaryController @JvmOverloads constructor( Loading Loading @@ -119,3 +120,4 @@ constructor( ) } } // LINT.ThenChange(MobileNetworkListScreen.kt) src/com/android/settings/network/NetworkDashboardScreen.kt +1 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ class NetworkDashboardScreen : PreferenceScreenCreator, PreferenceIconProvider { override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) { +MobileNetworkListScreen.KEY order -15 +DataSaverScreen.KEY order 10 } Loading Loading
src/com/android/settings/network/AirplaneModePreference.kt +5 −4 Original line number Diff line number Diff line Loading @@ -28,8 +28,7 @@ import com.android.settingslib.metadata.SwitchPreference // LINT.IfChange class AirplaneModePreference : SwitchPreference(KEY, R.string.airplane_mode), PreferenceAvailabilityProvider { SwitchPreference(KEY, R.string.airplane_mode), PreferenceAvailabilityProvider { override val icon: Int @DrawableRes get() = R.drawable.ic_airplanemode_active Loading @@ -40,11 +39,13 @@ class AirplaneModePreference : get() = SensitivityLevel.HIGH_SENSITIVITY override fun isAvailable(context: Context) = (context.resources.getBoolean(R.bool.config_show_toggle_airplane) && !context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) (context.resources.getBoolean(R.bool.config_show_toggle_airplane) && !context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) companion object { const val KEY = Settings.Global.AIRPLANE_MODE_ON fun Context.isAirplaneModeOn() = SettingsGlobalStore.get(this).getBoolean(KEY) == true } } // LINT.ThenChange(AirplaneModePreferenceController.java)
src/com/android/settings/network/MobileDataPreference.kt 0 → 100644 +78 −0 Original line number Diff line number Diff line /* * 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 import android.content.Context import android.telephony.SubscriptionManager import com.android.settings.R import com.android.settings.network.telephony.MobileDataRepository import com.android.settings.network.telephony.SubscriptionRepository import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.NoOpKeyedObservable import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.ReadWritePermit import com.android.settingslib.metadata.SensitivityLevel import com.android.settingslib.metadata.SwitchPreference import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking class MobileDataPreference : SwitchPreference( KEY, R.string.mobile_data_settings_title, R.string.mobile_data_settings_summary, ), PreferenceAvailabilityProvider { override fun isAvailable(context: Context) = SubscriptionRepository(context).getSelectableSubscriptionInfoList().any { it.simSlotIndex > -1 } override fun storage(context: Context): KeyValueStore = MobileDataStorage(context) override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) = ReadWritePermit.ALLOW override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) = ReadWritePermit.ALLOW override val sensitivityLevel get() = SensitivityLevel.LOW_SENSITIVITY @Suppress("UNCHECKED_CAST") private class MobileDataStorage(private val context: Context) : NoOpKeyedObservable<String>(), KeyValueStore { override fun contains(key: String) = key == KEY override fun <T : Any> getValue(key: String, valueType: Class<T>): T { val subId = SubscriptionManager.getDefaultDataSubscriptionId() val flow = MobileDataRepository(context).isMobileDataEnabledFlow(subId) return runBlocking { flow.first() } as T } override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) { val subId = SubscriptionManager.getDefaultDataSubscriptionId() MobileDataRepository(context).setMobileDataEnabled(subId, value as Boolean) } } companion object { const val KEY = "mobile_data" } }
src/com/android/settings/network/MobileNetworkListScreen.kt +114 −3 Original line number Diff line number Diff line Loading @@ -17,15 +17,49 @@ package com.android.settings.network import android.content.Context import android.os.UserManager import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener import androidx.preference.Preference import androidx.preference.Preference.OnPreferenceClickListener import com.android.settings.PreferenceRestrictionMixin import com.android.settings.R import com.android.settings.flags.Flags import com.android.settings.network.AirplaneModePreference.Companion.isAirplaneModeOn import com.android.settings.network.SubscriptionUtil.getUniqueSubscriptionDisplayName import com.android.settings.network.telephony.SimRepository import com.android.settings.network.telephony.SubscriptionRepository import com.android.settings.network.telephony.euicc.EuiccRepository import com.android.settings.spa.network.getAddSimIntent import com.android.settings.spa.network.startAddSimFlow import com.android.settingslib.RestrictedPreference import com.android.settingslib.datastore.HandlerExecutor import com.android.settingslib.datastore.KeyedObserver import com.android.settingslib.datastore.SettingsGlobalStore import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.PreferenceLifecycleContext import com.android.settingslib.metadata.PreferenceLifecycleProvider import com.android.settingslib.metadata.PreferenceMetadata import com.android.settingslib.metadata.PreferenceSummaryProvider import com.android.settingslib.metadata.ProvidePreferenceScreen import com.android.settingslib.metadata.preferenceHierarchy import com.android.settingslib.preference.PreferenceScreenBinding import com.android.settingslib.preference.PreferenceScreenCreator @ProvidePreferenceScreen class MobileNetworkListScreen : PreferenceScreenCreator, PreferenceRestrictionMixin { class MobileNetworkListScreen : PreferenceScreenCreator, PreferenceScreenBinding, PreferenceAvailabilityProvider, PreferenceSummaryProvider, PreferenceLifecycleProvider, PreferenceRestrictionMixin, OnPreferenceClickListener { private var airplaneModeObserver: KeyedObserver<String>? = null private var subscriptionInfoList: List<SubscriptionInfo>? = null private var onSubscriptionsChangedListener: OnSubscriptionsChangedListener? = null override val key: String get() = KEY Loading @@ -38,18 +72,95 @@ class MobileNetworkListScreen : PreferenceScreenCreator, PreferenceRestrictionMi override val keywords: Int get() = R.string.keywords_more_mobile_networks override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context) override fun intent(context: Context) = getAddSimIntent() override fun getSummary(context: Context): CharSequence? { val list = getSelectableSubscriptionInfoList(context) return when { list.isNotEmpty() -> list .map { getUniqueSubscriptionDisplayName(it, context).toString() } .distinct() .joinToString(", ") EuiccRepository(context).showEuiccSettings() -> context.getString(R.string.mobile_network_summary_add_a_network) else -> null } } override fun isAvailable(context: Context) = SimRepository(context).showMobileNetworkPageEntrance() override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context) && !context.isAirplaneModeOn() && (getSelectableSubscriptionInfoList(context).isNotEmpty() || EuiccRepository(context).showEuiccSettings()) private fun getSelectableSubscriptionInfoList(context: Context): List<SubscriptionInfo> = subscriptionInfoList ?: SubscriptionRepository(context).getSelectableSubscriptionInfoList().also { subscriptionInfoList = it } override val restrictionKeys get() = arrayOf(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS) override val useAdminDisabledSummary get() = true override fun createWidget(context: Context) = RestrictedPreference(context) override fun bind(preference: Preference, metadata: PreferenceMetadata) { super.bind(preference, metadata) preference.onPreferenceClickListener = this } override fun onPreferenceClick(preference: Preference): Boolean { val summary = preference.summary ?: return true // no-op val context = preference.context if (summary == context.getString(R.string.mobile_network_summary_add_a_network)) { startAddSimFlow(context) // start intent return true } return false // start fragment } override fun onCreate(context: PreferenceLifecycleContext) { val executor = HandlerExecutor.main val observer = KeyedObserver<String> { _, _ -> context.notifyPreferenceChange(KEY) } airplaneModeObserver = observer SettingsGlobalStore.get(context).addObserver(AirplaneModePreference.KEY, observer, executor) context.getSystemService(SubscriptionManager::class.java)?.let { val listener = object : OnSubscriptionsChangedListener() { override fun onSubscriptionsChanged() { subscriptionInfoList = null // invalid cache context.notifyPreferenceChange(KEY) } } it.addOnSubscriptionsChangedListener(executor, listener) onSubscriptionsChangedListener = listener } } override fun onDestroy(context: PreferenceLifecycleContext) { airplaneModeObserver?.let { SettingsGlobalStore.get(context).removeObserver(AirplaneModePreference.KEY, it) } context.getSystemService(SubscriptionManager::class.java)?.apply { onSubscriptionsChangedListener?.let { removeOnSubscriptionsChangedListener(it) } } } override fun isFlagEnabled(context: Context) = Flags.catalystMobileNetworkList() override fun hasCompleteHierarchy() = false override fun fragmentClass() = MobileNetworkListFragment::class.java override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {} override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) { +MobileDataPreference() } companion object { const val KEY = "mobile_network_list" Loading
src/com/android/settings/network/MobileNetworkSummaryController.kt +2 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import kotlinx.coroutines.flow.Flow * - Has subscriptions: click action takes you to a page listing the subscriptions, and the summary * text gives the count of SIMs */ // LINT.IfChange class MobileNetworkSummaryController @JvmOverloads constructor( Loading Loading @@ -119,3 +120,4 @@ constructor( ) } } // LINT.ThenChange(MobileNetworkListScreen.kt)
src/com/android/settings/network/NetworkDashboardScreen.kt +1 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ class NetworkDashboardScreen : PreferenceScreenCreator, PreferenceIconProvider { override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) { +MobileNetworkListScreen.KEY order -15 +DataSaverScreen.KEY order 10 } Loading