Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit edc72a9b authored by Chaohui Wang's avatar Chaohui Wang
Browse files

SubscriptionRepository.activeSubscriptionIdListFlow

Bug: 328293508
Flag: EXEMPT refactor
Test: manual - on Mobile Settings
Test: unit test
Change-Id: I63a86569f4fa3a27bd38d9853f6141890d26b881
parent 69f68682
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -25,14 +25,17 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onEach

@OptIn(ExperimentalCoroutinesApi::class)
class CallStateRepository(private val context: Context) {
    private val subscriptionManager = context.requireSubscriptionManager()
class CallStateRepository(
    private val context: Context,
    private val subscriptionRepository: SubscriptionRepository = SubscriptionRepository(context),
) {

    /** Flow for call state of given [subId]. */
    fun callStateFlow(subId: Int): Flow<Int> = context.telephonyCallbackFlow(subId) {
@@ -48,9 +51,8 @@ class CallStateRepository(private val context: Context) {
     *
     * @return true if any active subscription's call state is not idle.
     */
    fun isInCallFlow(): Flow<Boolean> = context.subscriptionsChangedFlow()
        .flatMapLatest {
            val subIds = subscriptionManager.activeSubscriptionIdList
    fun isInCallFlow(): Flow<Boolean> = subscriptionRepository.activeSubscriptionIdListFlow()
        .flatMapLatest { subIds ->
            if (subIds.isEmpty()) {
                flowOf(false)
            } else {
@@ -59,9 +61,10 @@ class CallStateRepository(private val context: Context) {
                }
            }
        }
        .distinctUntilChanged()
        .conflate()
        .flowOn(Dispatchers.Default)
        .onEach { Log.d(TAG, "isInCallFlow: $it") }
        .flowOn(Dispatchers.Default)

    private companion object {
        private const val TAG = "CallStateRepository"
+27 −16
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
@@ -68,20 +69,9 @@ class SubscriptionRepository(private val context: Context) {
    }

    fun canDisablePhysicalSubscription() = subscriptionManager.canDisablePhysicalSubscription()
}

val Context.subscriptionManager: SubscriptionManager?
    get() = getSystemService(SubscriptionManager::class.java)

fun Context.requireSubscriptionManager(): SubscriptionManager = subscriptionManager!!

fun Context.phoneNumberFlow(subscriptionInfo: SubscriptionInfo) = subscriptionsChangedFlow().map {
    SubscriptionUtil.getBidiFormattedPhoneNumber(this, subscriptionInfo)
}.filterNot { it.isNullOrEmpty() }.flowOn(Dispatchers.Default)

fun Context.subscriptionsChangedFlow() = callbackFlow {
    val subscriptionManager = requireSubscriptionManager()

    /** Flow for subscriptions changes. */
    fun subscriptionsChangedFlow() = callbackFlow {
        val listener = object : SubscriptionManager.OnSubscriptionsChangedListener() {
            override fun onSubscriptionsChanged() {
                trySend(Unit)
@@ -96,6 +86,27 @@ fun Context.subscriptionsChangedFlow() = callbackFlow {
        awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(listener) }
    }.conflate().onEach { Log.d(TAG, "subscriptions changed") }.flowOn(Dispatchers.Default)

    /** Flow of active subscription ids. */
    fun activeSubscriptionIdListFlow(): Flow<List<Int>> = context.subscriptionsChangedFlow()
        .map { subscriptionManager.activeSubscriptionIdList.sorted() }
        .distinctUntilChanged()
        .conflate()
        .onEach { Log.d(TAG, "activeSubscriptionIdList: $it") }
        .flowOn(Dispatchers.Default)
}

val Context.subscriptionManager: SubscriptionManager?
    get() = getSystemService(SubscriptionManager::class.java)

fun Context.requireSubscriptionManager(): SubscriptionManager = subscriptionManager!!

fun Context.phoneNumberFlow(subscriptionInfo: SubscriptionInfo) = subscriptionsChangedFlow().map {
    SubscriptionUtil.getBidiFormattedPhoneNumber(this, subscriptionInfo)
}.filterNot { it.isNullOrEmpty() }.flowOn(Dispatchers.Default)

fun Context.subscriptionsChangedFlow(): Flow<Unit> =
    SubscriptionRepository(this).subscriptionsChangedFlow()

/**
 * Return a list of subscriptions that are available and visible to the user.
 *
+4 −6
Original line number Diff line number Diff line
@@ -25,10 +25,9 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.android.settings.R
import com.android.settings.network.telephony.MobileDataRepository
import com.android.settings.network.telephony.SubscriptionRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
import com.android.settings.network.telephony.requireSubscriptionManager
import com.android.settings.network.telephony.safeGetConfig
import com.android.settings.network.telephony.subscriptionsChangedFlow
import com.android.settings.network.telephony.telephonyManager
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import kotlinx.coroutines.Dispatchers
@@ -48,7 +47,7 @@ class CrossSimCallingViewModel(
    private val application: Application,
) : AndroidViewModel(application) {

    private val subscriptionManager = application.requireSubscriptionManager()
    private val subscriptionRepository = SubscriptionRepository(application)
    private val carrierConfigManager =
        application.getSystemService(CarrierConfigManager::class.java)!!
    private val scope = viewModelScope + Dispatchers.Default
@@ -59,9 +58,8 @@ class CrossSimCallingViewModel(
    init {
        val resources = application.resources
        if (resources.getBoolean(R.bool.config_auto_data_switch_enables_cross_sim_calling)) {
            application.subscriptionsChangedFlow()
                .flatMapLatest {
                    val activeSubIds = subscriptionManager.activeSubscriptionIdList.toList()
            subscriptionRepository.activeSubscriptionIdListFlow()
                .flatMapLatest { activeSubIds ->
                    merge(
                        activeSubIds.anyMobileDataEnableChangedFlow(),
                        updateChannel.receiveAsFlow(),
+6 −11
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.settings.network.telephony

import android.content.Context
import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import androidx.test.core.app.ApplicationProvider
@@ -27,6 +26,7 @@ import com.android.settingslib.spa.testutils.toListWithTimeout
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,20 +49,15 @@ class CallStateRepositoryTest {
        }
    }

    private val mockSubscriptionManager = mock<SubscriptionManager> {
        on { activeSubscriptionIdList } doReturn intArrayOf(SUB_ID)
        on { addOnSubscriptionsChangedListener(any(), any()) } doAnswer {
            val listener = it.arguments[1] as SubscriptionManager.OnSubscriptionsChangedListener
            listener.onSubscriptionsChanged()
        }
    private val mockSubscriptionRepository = mock<SubscriptionRepository> {
        on { activeSubscriptionIdListFlow() } doReturn flowOf(listOf(SUB_ID))
    }

    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
        on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
        on { subscriptionManager } doReturn mockSubscriptionManager
    }

    private val repository = CallStateRepository(context)
    private val repository = CallStateRepository(context, mockSubscriptionRepository)

    @Test
    fun callStateFlow_initial_sendInitialState() = runBlocking {
@@ -89,8 +84,8 @@ class CallStateRepositoryTest {

    @Test
    fun isInCallFlow_noActiveSubscription() = runBlocking {
        mockSubscriptionManager.stub {
            on { activeSubscriptionIdList } doReturn intArrayOf()
        mockSubscriptionRepository.stub {
            on { activeSubscriptionIdListFlow() } doReturn flowOf(emptyList())
        }

        val isInCall = repository.isInCallFlow().firstWithTimeoutOrNull()
+13 −2
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ class SubscriptionRepositoryTest {

    @Test
    fun subscriptionsChangedFlow_hasInitialValue() = runBlocking {
        val initialValue = context.subscriptionsChangedFlow().firstWithTimeoutOrNull()
        val initialValue = repository.subscriptionsChangedFlow().firstWithTimeoutOrNull()

        assertThat(initialValue).isSameInstanceAs(Unit)
    }
@@ -85,7 +85,7 @@ class SubscriptionRepositoryTest {
    @Test
    fun subscriptionsChangedFlow_changed() = runBlocking {
        val listDeferred = async {
            context.subscriptionsChangedFlow().toListWithTimeout()
            repository.subscriptionsChangedFlow().toListWithTimeout()
        }
        delay(100)

@@ -94,6 +94,17 @@ class SubscriptionRepositoryTest {
        assertThat(listDeferred.await()).hasSize(2)
    }

    @Test
    fun activeSubscriptionIdListFlow(): Unit = runBlocking {
        mockSubscriptionManager.stub {
            on { activeSubscriptionIdList } doReturn intArrayOf(SUB_ID_IN_SLOT_0)
        }

        val activeSubIds = repository.activeSubscriptionIdListFlow().firstWithTimeoutOrNull()

        assertThat(activeSubIds).containsExactly(SUB_ID_IN_SLOT_0)
    }

    @Test
    fun getSelectableSubscriptionInfoList_sortedBySimSlotIndex() {
        mockSubscriptionManager.stub {