Create ImsFeatureRepository

To be shared with video calling and VoLTE features.

Bug: 233327342
Flag: EXEMPT bug fix
Test: manual - on Mobile Settings
Test: atest ImsFeatureRepositoryTest
Change-Id: Ic7bcb532c4bd32c6f7ac4af1eebdd8a70a86ff29
This commit is contained in:
Chaohui Wang
2024-08-16 12:56:36 +08:00
parent 6b25f15fe6
commit 37693f29f1
5 changed files with 195 additions and 33 deletions

View File

@@ -0,0 +1,61 @@
/*
* 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.telephony.ims
import android.content.Context
import android.telephony.AccessNetworkConstants.TransportType
import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability
import android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech
import com.android.settings.network.telephony.subscriptionsChangedFlow
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
/**
* A repository for the IMS feature.
*
* @throws IllegalArgumentException if the [subId] is invalid.
*/
@OptIn(ExperimentalCoroutinesApi::class)
class ImsFeatureRepository(
private val context: Context,
private val subId: Int,
private val provisioningRepository: ProvisioningRepository = ProvisioningRepository(context),
private val imsMmTelRepository: ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId)
) {
/**
* A cold flow that determines the provisioning status for the specified IMS MmTel capability,
* and whether or not the requested MmTel capability is supported by the carrier on the
* specified network transport.
*
* @return true if the feature is provisioned and supported, false otherwise.
*/
fun isReadyFlow(
@MmTelCapability capability: Int,
@ImsRegistrationTech tech: Int,
@TransportType transportType: Int,
): Flow<Boolean> =
context.subscriptionsChangedFlow().flatMapLatest {
combine(
provisioningRepository.imsFeatureProvisionedFlow(subId, capability, tech),
imsMmTelRepository.isSupportedFlow(capability, transportType),
) { imsFeatureProvisioned, isSupported ->
imsFeatureProvisioned && isSupported
}
}
}

View File

@@ -36,6 +36,7 @@ import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
@@ -47,6 +48,11 @@ interface ImsMmTelRepository {
fun imsReadyFlow(): Flow<Boolean>
fun isSupportedFlow(
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
@AccessNetworkConstants.TransportType transportType: Int,
): Flow<Boolean>
suspend fun isSupported(
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
@AccessNetworkConstants.TransportType transportType: Int,
@@ -55,6 +61,11 @@ interface ImsMmTelRepository {
suspend fun setCrossSimCallingEnabled(enabled: Boolean)
}
/**
* A repository for the IMS MMTel.
*
* @throws IllegalArgumentException if the [subId] is invalid.
*/
class ImsMmTelRepositoryImpl(
context: Context,
private val subId: Int,
@@ -126,8 +137,12 @@ class ImsMmTelRepositoryImpl(
awaitClose { imsMmTelManager.unregisterImsStateCallback(callback) }
}.catch { e ->
Log.w(TAG, "[$subId] error while imsReadyFlow", e)
emit(false)
}.conflate().flowOn(Dispatchers.Default)
override fun isSupportedFlow(capability: Int, transportType: Int): Flow<Boolean> =
imsReadyFlow().map { imsReady -> imsReady && isSupported(capability, transportType) }
override suspend fun isSupported(
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
@AccessNetworkConstants.TransportType transportType: Int,

View File

@@ -20,24 +20,17 @@ import android.content.Context
import android.telephony.AccessNetworkConstants
import android.telephony.CarrierConfigManager
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
import android.telephony.SubscriptionManager
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
import android.telephony.ims.feature.MmTelFeature
import android.telephony.ims.stub.ImsRegistrationImplBase
import androidx.lifecycle.LifecycleOwner
import com.android.settings.network.telephony.ims.ImsFeatureRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
import com.android.settings.network.telephony.ims.ProvisioningRepository
import com.android.settings.network.telephony.subscriptionsChangedFlow
import com.android.settings.network.telephony.telephonyManager
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
interface IWifiCallingRepository {
@@ -50,11 +43,11 @@ class WifiCallingRepository
constructor(
private val context: Context,
private val subId: Int,
private val imsMmTelRepository: ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId)
private val imsFeatureRepository: ImsFeatureRepository = ImsFeatureRepository(context, subId),
private val imsMmTelRepository: ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId),
) : IWifiCallingRepository {
private val telephonyManager = context.telephonyManager(subId)
private val provisioningRepository = ProvisioningRepository(context)
private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!!
@WiFiCallingMode
@@ -76,28 +69,12 @@ constructor(
wifiCallingReadyFlow().collectLatestWithLifecycle(lifecycleOwner, action = action)
}
@OptIn(ExperimentalCoroutinesApi::class)
fun wifiCallingReadyFlow(): Flow<Boolean> {
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
return context.subscriptionsChangedFlow().flatMapLatest {
combine(
provisioningRepository.imsFeatureProvisionedFlow(
subId = subId,
capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
),
isWifiCallingSupportedFlow(),
) { imsFeatureProvisioned, isWifiCallingSupported ->
imsFeatureProvisioned && isWifiCallingSupported
}
}
}
private fun isWifiCallingSupportedFlow(): Flow<Boolean> {
return imsMmTelRepository.imsReadyFlow().map { imsReady ->
imsReady && isWifiCallingSupported()
}
}
fun wifiCallingReadyFlow(): Flow<Boolean> =
imsFeatureRepository.isReadyFlow(
capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
)
suspend fun isWifiCallingSupported(): Boolean = withContext(Dispatchers.Default) {
imsMmTelRepository.isSupported(