summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Caitlin Shkuratov <caitlinshk@google.com> 2024-05-08 14:18:22 +0000
committer Cherrypicker Worker <android-build-cherrypicker-worker@google.com> 2024-05-10 13:10:24 +0000
commitcc949afe44896788fd48e3bbb91674d78f1e9bb7 (patch)
treecb86941c1a7deb24045cd198bf884a06cc163a1b
parentaa34b3497b83ddade5d12b4c7f7249e78403f7ac (diff)
[SB][Sat] Never show icons for NTN-only subscriptions.
Fixes: 336881301 Test: all tests in statusbar/pipeline/mobile Flag: ACONFIG com.android.internal.telephony.flags.oem_enabled_satellite_flag NEXTFOOD (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:dbdaae6db9afb2aa5254ada5749b482dceb60bb2) Merged-In: I7a6e6994bc26b004a9b1e166e55655d7c00ee460 Change-Id: I7a6e6994bc26b004a9b1e166e55655d7c00ee460
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt101
6 files changed, 192 insertions, 15 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
index d9d909a49781..fc54f140dec5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
@@ -33,6 +33,18 @@ data class SubscriptionModel(
*/
val isOpportunistic: Boolean = false,
+ /**
+ * True if this subscription **only** supports non-terrestrial networks (NTN) and false
+ * otherwise. (non-terrestrial == satellite)
+ *
+ * Note that we intend to filter these subscriptions out, because these connections are actually
+ * supported by
+ * [com.android.systemui.statusbar.pipeline.satellite.data.DeviceBasedSatelliteRepository]. See
+ * [com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor] for
+ * the filtering.
+ */
+ val isExclusivelyNonTerrestrial: Boolean = false,
+
/** Subscriptions in the same group may be filtered or treated as a single subscription */
val groupUuid: ParcelUuid? = null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index 22785979f3ae..425c58b0074b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -23,6 +23,7 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import kotlinx.coroutines.flow.StateFlow
@@ -76,7 +77,17 @@ interface MobileConnectionRepository {
*/
val isInService: StateFlow<Boolean>
- /** Reflects [android.telephony.ServiceState.isUsingNonTerrestrialNetwork] */
+ /**
+ * True if this subscription is actively connected to a non-terrestrial network and false
+ * otherwise. Reflects [android.telephony.ServiceState.isUsingNonTerrestrialNetwork].
+ *
+ * Notably: This value reflects that this subscription is **currently** using a non-terrestrial
+ * network, because some subscriptions can switch between terrestrial and non-terrestrial
+ * networks. [SubscriptionModel.isExclusivelyNonTerrestrial] reflects whether a subscription is
+ * configured to exclusively connect to non-terrestrial networks. [isNonTerrestrial] can change
+ * during the lifetime of a subscription but [SubscriptionModel.isExclusivelyNonTerrestrial]
+ * will stay constant.
+ */
val isNonTerrestrial: StateFlow<Boolean>
/** True if [android.telephony.SignalStrength] told us that this connection is using GSM */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index a455db2e67ce..962b2229daa9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -417,6 +417,7 @@ constructor(
SubscriptionModel(
subscriptionId = subscriptionId,
isOpportunistic = isOpportunistic,
+ isExclusivelyNonTerrestrial = isOnlyNonTerrestrialNetwork,
groupUuid = groupUuid,
carrierName = carrierName.toString(),
profileClass = profileClass,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index d555c47f4da2..91d7ca65b30d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -172,21 +172,33 @@ constructor(
private val unfilteredSubscriptions: Flow<List<SubscriptionModel>> =
mobileConnectionsRepo.subscriptions
- /**
- * Any filtering that we can do based purely on the info of each subscription. Currently this
- * only applies the ProfileClass-based filter, but if we need other they can go here
- */
+ /** Any filtering that we can do based purely on the info of each subscription individually. */
private val subscriptionsBasedFilteredSubs =
- unfilteredSubscriptions.map { subs -> applyProvisioningFilter(subs) }.distinctUntilChanged()
+ unfilteredSubscriptions
+ .map { it.filterBasedOnProvisioning().filterBasedOnNtn() }
+ .distinctUntilChanged()
- private fun applyProvisioningFilter(subs: List<SubscriptionModel>): List<SubscriptionModel> =
+ private fun List<SubscriptionModel>.filterBasedOnProvisioning(): List<SubscriptionModel> =
if (!featureFlagsClassic.isEnabled(FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS)) {
- subs
+ this
} else {
- subs.filter { it.profileClass != PROFILE_CLASS_PROVISIONING }
+ this.filter { it.profileClass != PROFILE_CLASS_PROVISIONING }
}
/**
+ * Subscriptions that exclusively support non-terrestrial networks should **never** directly
+ * show any iconography in the status bar. These subscriptions only exist to provide a backing
+ * for the device-based satellite connections, and the iconography for those connections are
+ * already being handled in
+ * [com.android.systemui.statusbar.pipeline.satellite.data.DeviceBasedSatelliteRepository]. We
+ * need to filter out those subscriptions here so we guarantee the subscription never turns into
+ * an icon. See b/336881301.
+ */
+ private fun List<SubscriptionModel>.filterBasedOnNtn(): List<SubscriptionModel> {
+ return this.filter { !it.isExclusivelyNonTerrestrial }
+ }
+
+ /**
* Generally, SystemUI wants to show iconography for each subscription that is listed by
* [SubscriptionManager]. However, in the case of opportunistic subscriptions, we want to only
* show a single representation of the pair of subscriptions. The docs define opportunistic as:
@@ -204,12 +216,8 @@ constructor(
subscriptionsBasedFilteredSubs,
mobileConnectionsRepo.activeMobileDataSubscriptionId,
connectivityRepository.vcnSubId,
- ) { unfilteredSubs, activeId, vcnSubId ->
- filterSubsBasedOnOpportunistic(
- unfilteredSubs,
- activeId,
- vcnSubId,
- )
+ ) { preFilteredSubs, activeId, vcnSubId ->
+ filterSubsBasedOnOpportunistic(preFilteredSubs, activeId, vcnSubId)
}
.distinctUntilChanged()
.logDiffsForTable(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 07abd275d1ce..5152d6b1f8a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -272,6 +272,50 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
}
@Test
+ fun subscriptions_subIsOnlyNtn_modelHasExclusivelyNtnTrue() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.subscriptions)
+
+ val onlyNtnSub =
+ mock<SubscriptionInfo>().also {
+ whenever(it.isOnlyNonTerrestrialNetwork).thenReturn(true)
+ whenever(it.subscriptionId).thenReturn(45)
+ whenever(it.groupUuid).thenReturn(GROUP_1)
+ whenever(it.carrierName).thenReturn("NTN only")
+ whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+ }
+
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(onlyNtnSub))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isExclusivelyNonTerrestrial).isTrue()
+ }
+
+ @Test
+ fun subscriptions_subIsNotOnlyNtn_modelHasExclusivelyNtnFalse() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.subscriptions)
+
+ val notOnlyNtnSub =
+ mock<SubscriptionInfo>().also {
+ whenever(it.isOnlyNonTerrestrialNetwork).thenReturn(false)
+ whenever(it.subscriptionId).thenReturn(45)
+ whenever(it.groupUuid).thenReturn(GROUP_1)
+ whenever(it.carrierName).thenReturn("NTN only")
+ whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+ }
+
+ whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+ .thenReturn(listOf(notOnlyNtnSub))
+ getSubscriptionCallback().onSubscriptionsChanged()
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0].isExclusivelyNonTerrestrial).isFalse()
+ }
+
+ @Test
fun testSubscriptions_carrierMergedOnly_listHasCarrierMerged() =
testScope.runTest {
val latest by collectLastValue(underTest.subscriptions)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 925b2e574962..0f9cbfa66b5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -408,6 +408,107 @@ class MobileIconsInteractorTest : SysuiTestCase() {
}
@Test
+ fun filteredSubscriptions_subNotExclusivelyNonTerrestrial_hasSub() =
+ testScope.runTest {
+ val notExclusivelyNonTerrestrialSub =
+ SubscriptionModel(
+ isExclusivelyNonTerrestrial = false,
+ subscriptionId = 5,
+ carrierName = "Carrier 5",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
+
+ connectionsRepository.setSubscriptions(listOf(notExclusivelyNonTerrestrialSub))
+
+ val latest by collectLastValue(underTest.filteredSubscriptions)
+
+ assertThat(latest).isEqualTo(listOf(notExclusivelyNonTerrestrialSub))
+ }
+
+ @Test
+ fun filteredSubscriptions_subExclusivelyNonTerrestrial_doesNotHaveSub() =
+ testScope.runTest {
+ val exclusivelyNonTerrestrialSub =
+ SubscriptionModel(
+ isExclusivelyNonTerrestrial = true,
+ subscriptionId = 5,
+ carrierName = "Carrier 5",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
+
+ connectionsRepository.setSubscriptions(listOf(exclusivelyNonTerrestrialSub))
+
+ val latest by collectLastValue(underTest.filteredSubscriptions)
+
+ assertThat(latest).isEmpty()
+ }
+
+ @Test
+ fun filteredSubscription_mixOfExclusivelyNonTerrestrialAndOther_hasOtherSubsOnly() =
+ testScope.runTest {
+ val exclusivelyNonTerrestrialSub =
+ SubscriptionModel(
+ isExclusivelyNonTerrestrial = true,
+ subscriptionId = 5,
+ carrierName = "Carrier 5",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
+ val otherSub1 =
+ SubscriptionModel(
+ isExclusivelyNonTerrestrial = false,
+ subscriptionId = 1,
+ carrierName = "Carrier 1",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
+ val otherSub2 =
+ SubscriptionModel(
+ isExclusivelyNonTerrestrial = false,
+ subscriptionId = 2,
+ carrierName = "Carrier 2",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
+
+ connectionsRepository.setSubscriptions(
+ listOf(otherSub1, exclusivelyNonTerrestrialSub, otherSub2)
+ )
+
+ val latest by collectLastValue(underTest.filteredSubscriptions)
+
+ assertThat(latest).isEqualTo(listOf(otherSub1, otherSub2))
+ }
+
+ @Test
+ fun filteredSubscriptions_exclusivelyNonTerrestrialSub_andOpportunistic_bothFiltersHappen() =
+ testScope.runTest {
+ // Exclusively non-terrestrial sub
+ val exclusivelyNonTerrestrialSub =
+ SubscriptionModel(
+ isExclusivelyNonTerrestrial = true,
+ subscriptionId = 5,
+ carrierName = "Carrier 5",
+ profileClass = PROFILE_CLASS_UNSET,
+ )
+
+ // Opportunistic subs
+ val (sub3, sub4) =
+ createSubscriptionPair(
+ subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+ opportunistic = Pair(true, true),
+ grouped = true,
+ )
+
+ // WHEN both an exclusively non-terrestrial sub and opportunistic sub pair is included
+ connectionsRepository.setSubscriptions(listOf(sub3, sub4, exclusivelyNonTerrestrialSub))
+ connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+
+ val latest by collectLastValue(underTest.filteredSubscriptions)
+
+ // THEN both the only-non-terrestrial sub and the non-active sub are filtered out,
+ // leaving only sub3.
+ assertThat(latest).isEqualTo(listOf(sub3))
+ }
+
+ @Test
fun activeDataConnection_turnedOn() =
testScope.runTest {
CONNECTION_1.setDataEnabled(true)