[Sb refactor] Ensure we fetch default data subId on flow start

The old pipeline aggressively polls SubscriptionManager for the
`defaultDataSubId`. We don't want to do that since it's going to cause
IPC on the main thread, and it's not necessary.

This change enforces that we poll
SubscriptionManager.getDefaultDataSubscrpitionId() when the flow is
started, so that we always know the current value when collectors show
up. Further updates are still expected to come in through the broadcast.

Test: MobileConnectionsRepositoryTest
Bug: 270315194

Change-Id: I74aa6b9b456ca497b02de48d4c932a2b4814c97a
This commit is contained in:
Evan Laird
2023-03-30 12:17:26 -04:00
parent db1dbe4d89
commit 1861485237
6 changed files with 117 additions and 9 deletions

View File

@@ -37,6 +37,8 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIc
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxyImpl
import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy
import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxyImpl
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository
@@ -65,8 +67,7 @@ abstract class StatusBarPipelineModule {
@Binds abstract fun wifiRepository(impl: WifiRepositorySwitcher): WifiRepository
@Binds
abstract fun wifiInteractor(impl: WifiInteractorImpl): WifiInteractor
@Binds abstract fun wifiInteractor(impl: WifiInteractorImpl): WifiInteractor
@Binds
abstract fun mobileConnectionsRepository(
@@ -77,6 +78,11 @@ abstract class StatusBarPipelineModule {
@Binds abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy
@Binds
abstract fun subscriptionManagerProxy(
impl: SubscriptionManagerProxyImpl
): SubscriptionManagerProxy
@Binds
abstract fun mobileIconsInteractor(impl: MobileIconsInteractorImpl): MobileIconsInteractor

View File

@@ -44,6 +44,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
@@ -65,6 +66,7 @@ import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
@@ -76,6 +78,7 @@ class MobileConnectionsRepositoryImpl
constructor(
connectivityRepository: ConnectivityRepository,
private val subscriptionManager: SubscriptionManager,
private val subscriptionManagerProxy: SubscriptionManagerProxy,
private val telephonyManager: TelephonyManager,
private val logger: MobileInputLogger,
@MobileSummaryLog private val tableLogger: TableLogBuffer,
@@ -195,7 +198,7 @@ constructor(
override val defaultDataSubId: StateFlow<Int> =
broadcastDispatcher
.broadcastFlow(
IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED),
) { intent, _ ->
intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
}
@@ -204,14 +207,11 @@ constructor(
tableLogger,
LOGGING_PREFIX,
columnName = "defaultSubId",
initialValue = SubscriptionManager.getDefaultDataSubscriptionId(),
initialValue = INVALID_SUBSCRIPTION_ID,
)
.onStart { emit(subscriptionManagerProxy.getDefaultDataSubscriptionId()) }
.onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
SubscriptionManager.getDefaultDataSubscriptionId()
)
.stateIn(scope, SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
private val carrierConfigChangedEvent =
broadcastDispatcher

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 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.systemui.statusbar.pipeline.mobile.util
import android.telephony.SubscriptionManager
import javax.inject.Inject
interface SubscriptionManagerProxy {
fun getDefaultDataSubscriptionId(): Int
}
/** Injectable proxy class for [SubscriptionManager]'s static methods */
class SubscriptionManagerProxyImpl @Inject constructor() : SubscriptionManagerProxy {
/** The system default data subscription id, or INVALID_SUBSCRIPTION_ID on error */
override fun getDefaultDataSubscriptionId() = SubscriptionManager.getDefaultDataSubscriptionId()
}

View File

@@ -34,6 +34,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
@@ -89,6 +90,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
private val fakeNetworkEventsFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
private val mobileMappings = FakeMobileMappingsProxy()
private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
private val scope = CoroutineScope(IMMEDIATE)
@@ -117,6 +119,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
MobileConnectionsRepositoryImpl(
connectivityRepository,
subscriptionManager,
subscriptionManagerProxy,
telephonyManager,
logger,
summaryLogger,

View File

@@ -47,6 +47,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierCon
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
@@ -98,6 +99,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
@Mock private lateinit var logBufferFactory: TableLogBufferFactory
private val mobileMappings = FakeMobileMappingsProxy()
private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
private val scope = CoroutineScope(IMMEDIATE)
@@ -179,6 +181,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
MobileConnectionsRepositoryImpl(
connectivityRepository,
subscriptionManager,
subscriptionManagerProxy,
telephonyManager,
logger,
summaryLogger,
@@ -662,6 +665,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
var latest: Int? = null
val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
assertThat(latest).isEqualTo(INVALID_SUBSCRIPTION_ID)
fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
receiver.onReceive(
context,
@@ -685,6 +690,42 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
job.cancel()
}
@Test
fun defaultDataSubId_fetchesInitialValueOnStart() =
runBlocking(IMMEDIATE) {
subscriptionManagerProxy.defaultDataSubId = 2
var latest: Int? = null
val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
assertThat(latest).isEqualTo(2)
job.cancel()
}
@Test
fun defaultDataSubId_fetchesCurrentOnRestart() =
runBlocking(IMMEDIATE) {
subscriptionManagerProxy.defaultDataSubId = 2
var latest: Int? = null
var job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
assertThat(latest).isEqualTo(2)
job.cancel()
// Collectors go away but come back later
latest = null
subscriptionManagerProxy.defaultDataSubId = 1
job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
assertThat(latest).isEqualTo(1)
job.cancel()
}
@Test
fun mobileIsDefault_startsAsFalse() {
assertThat(underTest.mobileIsDefault.value).isFalse()
@@ -902,6 +943,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
MobileConnectionsRepositoryImpl(
connectivityRepository,
subscriptionManager,
subscriptionManagerProxy,
telephonyManager,
logger,
summaryLogger,

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2023 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.systemui.statusbar.pipeline.mobile.util
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
/** Fake of [SubscriptionManagerProxy] for easy testing */
class FakeSubscriptionManagerProxy(
/** Set the default data subId to be returned in [getDefaultDataSubscriptionId] */
var defaultDataSubId: Int = INVALID_SUBSCRIPTION_ID
) : SubscriptionManagerProxy {
override fun getDefaultDataSubscriptionId(): Int = defaultDataSubId
}