Merge changes from topic "catalyst-sims" into main
* changes:
[Catalyst] Migrate "Mobile data"
[Catalyst] Migrate SIMs entry point
diff --git a/src/com/android/settings/network/AirplaneModePreference.kt b/src/com/android/settings/network/AirplaneModePreference.kt
index d9d1bd8..0899add 100644
--- a/src/com/android/settings/network/AirplaneModePreference.kt
+++ b/src/com/android/settings/network/AirplaneModePreference.kt
@@ -28,8 +28,7 @@
// 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
@@ -40,11 +39,13 @@
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)
diff --git a/src/com/android/settings/network/MobileDataPreference.kt b/src/com/android/settings/network/MobileDataPreference.kt
new file mode 100644
index 0000000..d285a8c
--- /dev/null
+++ b/src/com/android/settings/network/MobileDataPreference.kt
@@ -0,0 +1,78 @@
+/*
+ * 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"
+ }
+}
diff --git a/src/com/android/settings/network/MobileNetworkListScreen.kt b/src/com/android/settings/network/MobileNetworkListScreen.kt
index 2e05e3a..d7231cc 100644
--- a/src/com/android/settings/network/MobileNetworkListScreen.kt
+++ b/src/com/android/settings/network/MobileNetworkListScreen.kt
@@ -17,15 +17,49 @@
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
@@ -38,18 +72,95 @@
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"
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.kt b/src/com/android/settings/network/MobileNetworkSummaryController.kt
index 8cf9bec..62c5766 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.kt
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.kt
@@ -41,6 +41,7 @@
* - 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(
@@ -119,3 +120,4 @@
)
}
}
+// LINT.ThenChange(MobileNetworkListScreen.kt)
diff --git a/src/com/android/settings/network/NetworkDashboardScreen.kt b/src/com/android/settings/network/NetworkDashboardScreen.kt
index 3fb2cbe..5dadcaf 100644
--- a/src/com/android/settings/network/NetworkDashboardScreen.kt
+++ b/src/com/android/settings/network/NetworkDashboardScreen.kt
@@ -46,6 +46,7 @@
override fun getPreferenceHierarchy(context: Context) =
preferenceHierarchy(this) {
+ +MobileNetworkListScreen.KEY order -15
+DataSaverScreen.KEY order 10
}
diff --git a/src/com/android/settings/spa/network/SimsSection.kt b/src/com/android/settings/spa/network/SimsSection.kt
index 7d88748..fa7fa44 100644
--- a/src/com/android/settings/spa/network/SimsSection.kt
+++ b/src/com/android/settings/spa/network/SimsSection.kt
@@ -137,9 +137,9 @@
}
}
-fun startAddSimFlow(context: Context) {
- val intent = Intent(EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION)
- intent.setPackage(Utils.PHONE_PACKAGE_NAME)
- intent.putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true)
- context.startActivity(intent)
+fun startAddSimFlow(context: Context) = context.startActivity(getAddSimIntent())
+
+fun getAddSimIntent() = Intent(EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION).apply {
+ setPackage(Utils.PHONE_PACKAGE_NAME)
+ putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true)
}