diff options
| author | 2024-05-08 14:18:22 +0000 | |
|---|---|---|
| committer | 2024-05-10 13:10:24 +0000 | |
| commit | cc949afe44896788fd48e3bbb91674d78f1e9bb7 (patch) | |
| tree | cb86941c1a7deb24045cd198bf884a06cc163a1b | |
| parent | aa34b3497b83ddade5d12b4c7f7249e78403f7ac (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
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) |