Merge "Fix Wi-Fi calling option does not appear" into main
This commit is contained in:
@@ -27,6 +27,8 @@ import android.util.Log;
|
|||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import com.android.settings.network.telephony.wificalling.WifiCallingRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for querying Wifi calling status
|
* Controller class for querying Wifi calling status
|
||||||
*/
|
*/
|
||||||
@@ -92,7 +94,9 @@ public class WifiCallingQueryImsState extends ImsQueryController {
|
|||||||
* Check whether Wifi Calling can be perform or not on this subscription
|
* Check whether Wifi Calling can be perform or not on this subscription
|
||||||
*
|
*
|
||||||
* @return true when Wifi Calling can be performed, otherwise false
|
* @return true when Wifi Calling can be performed, otherwise false
|
||||||
|
* @deprecated Use {@link WifiCallingRepository#wifiCallingReadyFlow()} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public boolean isReadyToWifiCalling() {
|
public boolean isReadyToWifiCalling() {
|
||||||
if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
|
if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
|
||||||
return false;
|
return false;
|
||||||
|
@@ -80,6 +80,7 @@ import com.android.settings.network.CarrierConfigCache;
|
|||||||
import com.android.settings.network.SubscriptionUtil;
|
import com.android.settings.network.SubscriptionUtil;
|
||||||
import com.android.settings.network.ims.WifiCallingQueryImsState;
|
import com.android.settings.network.ims.WifiCallingQueryImsState;
|
||||||
import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants;
|
import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants;
|
||||||
|
import com.android.settings.network.telephony.wificalling.WifiCallingRepository;
|
||||||
import com.android.settingslib.core.instrumentation.Instrumentable;
|
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||||
import com.android.settingslib.development.DevelopmentSettingsEnabler;
|
import com.android.settingslib.development.DevelopmentSettingsEnabler;
|
||||||
import com.android.settingslib.graph.SignalDrawable;
|
import com.android.settingslib.graph.SignalDrawable;
|
||||||
@@ -928,7 +929,10 @@ public class MobileNetworkUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Copied from WifiCallingPreferenceController#isWifiCallingEnabled()
|
* Copied from WifiCallingPreferenceController#isWifiCallingEnabled()
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link WifiCallingRepository#wifiCallingReadyFlow()} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static boolean isWifiCallingEnabled(Context context, int subId,
|
public static boolean isWifiCallingEnabled(Context context, int subId,
|
||||||
@Nullable WifiCallingQueryImsState queryImsState) {
|
@Nullable WifiCallingQueryImsState queryImsState) {
|
||||||
if (queryImsState == null) {
|
if (queryImsState == null) {
|
||||||
|
@@ -18,12 +18,16 @@ package com.android.settings.network.telephony
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.telephony.SubscriptionManager
|
import android.telephony.SubscriptionManager
|
||||||
|
import android.util.Log
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.asExecutor
|
import kotlinx.coroutines.asExecutor
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.conflate
|
import kotlinx.coroutines.flow.conflate
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
|
private const val TAG = "SubscriptionRepository"
|
||||||
|
|
||||||
fun Context.subscriptionsChangedFlow() = callbackFlow {
|
fun Context.subscriptionsChangedFlow() = callbackFlow {
|
||||||
val subscriptionManager = getSystemService(SubscriptionManager::class.java)!!
|
val subscriptionManager = getSystemService(SubscriptionManager::class.java)!!
|
||||||
@@ -40,4 +44,4 @@ fun Context.subscriptionsChangedFlow() = callbackFlow {
|
|||||||
)
|
)
|
||||||
|
|
||||||
awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(listener) }
|
awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(listener) }
|
||||||
}.conflate().flowOn(Dispatchers.Default)
|
}.conflate().onEach { Log.d(TAG, "subscriptions changed") }.flowOn(Dispatchers.Default)
|
||||||
|
@@ -45,7 +45,7 @@ open class WifiCallingPreferenceController @JvmOverloads constructor(
|
|||||||
context: Context,
|
context: Context,
|
||||||
key: String,
|
key: String,
|
||||||
private val callStateFlowFactory: (subId: Int) -> Flow<Int> = context::callStateFlow,
|
private val callStateFlowFactory: (subId: Int) -> Flow<Int> = context::callStateFlow,
|
||||||
private val wifiCallingRepository: (subId: Int) -> WifiCallingRepository = { subId ->
|
private val wifiCallingRepositoryFactory: (subId: Int) -> WifiCallingRepository = { subId ->
|
||||||
WifiCallingRepository(context, subId)
|
WifiCallingRepository(context, subId)
|
||||||
},
|
},
|
||||||
) : TelephonyBasePreferenceController(context, key) {
|
) : TelephonyBasePreferenceController(context, key) {
|
||||||
@@ -80,15 +80,11 @@ open class WifiCallingPreferenceController @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
|
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
wifiCallingRepositoryFactory(mSubId).wifiCallingReadyFlow()
|
||||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
.collectLatestWithLifecycle(viewLifecycleOwner) {
|
||||||
val isVisible = withContext(Dispatchers.Default) {
|
preference.isVisible = it
|
||||||
MobileNetworkUtils.isWifiCallingEnabled(mContext, mSubId, null)
|
callingPreferenceCategoryController.updateChildVisible(preferenceKey, it)
|
||||||
}
|
|
||||||
preference.isVisible = isVisible
|
|
||||||
callingPreferenceCategoryController.updateChildVisible(preferenceKey, isVisible)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
@@ -122,7 +118,7 @@ open class WifiCallingPreferenceController @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getSummaryForWfcMode(): String {
|
private fun getSummaryForWfcMode(): String {
|
||||||
val resId = when (wifiCallingRepository(mSubId).getWiFiCallingMode()) {
|
val resId = when (wifiCallingRepositoryFactory(mSubId).getWiFiCallingMode()) {
|
||||||
ImsMmTelManager.WIFI_MODE_WIFI_ONLY ->
|
ImsMmTelManager.WIFI_MODE_WIFI_ONLY ->
|
||||||
com.android.internal.R.string.wfc_mode_wifi_only_summary
|
com.android.internal.R.string.wfc_mode_wifi_only_summary
|
||||||
|
|
||||||
|
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* 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.telephony.ims.ProvisioningManager
|
||||||
|
import android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback
|
||||||
|
import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability
|
||||||
|
import android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.asExecutor
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
|
import kotlinx.coroutines.flow.conflate
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
|
private const val TAG = "ImsFeatureProvisioned"
|
||||||
|
|
||||||
|
fun imsFeatureProvisionedFlow(
|
||||||
|
subId: Int,
|
||||||
|
@MmTelCapability capability: Int,
|
||||||
|
@ImsRegistrationTech tech: Int,
|
||||||
|
): Flow<Boolean> = imsFeatureProvisionedFlow(
|
||||||
|
subId = subId,
|
||||||
|
capability = capability,
|
||||||
|
tech = tech,
|
||||||
|
provisioningManager = ProvisioningManager.createForSubscriptionId(subId),
|
||||||
|
)
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
fun imsFeatureProvisionedFlow(
|
||||||
|
subId: Int,
|
||||||
|
@MmTelCapability capability: Int,
|
||||||
|
@ImsRegistrationTech tech: Int,
|
||||||
|
provisioningManager : ProvisioningManager,
|
||||||
|
): Flow<Boolean> = callbackFlow {
|
||||||
|
val callback = object : FeatureProvisioningCallback() {
|
||||||
|
override fun onFeatureProvisioningChanged(
|
||||||
|
receivedCapability: Int,
|
||||||
|
receivedTech: Int,
|
||||||
|
isProvisioned: Boolean,
|
||||||
|
) {
|
||||||
|
if (capability == receivedCapability && tech == receivedTech) trySend(isProvisioned)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRcsFeatureProvisioningChanged(
|
||||||
|
capability: Int,
|
||||||
|
tech: Int,
|
||||||
|
isProvisioned: Boolean,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioningManager.registerFeatureProvisioningChangedCallback(
|
||||||
|
Dispatchers.Default.asExecutor(),
|
||||||
|
callback,
|
||||||
|
)
|
||||||
|
trySend(provisioningManager.getProvisioningStatusForCapability(capability, tech))
|
||||||
|
|
||||||
|
awaitClose { provisioningManager.unregisterFeatureProvisioningChangedCallback(callback) }
|
||||||
|
}.catch { e ->
|
||||||
|
Log.w(TAG, "[$subId] error while imsFeatureProvisionedFlow", e)
|
||||||
|
}.conflate().onEach {
|
||||||
|
Log.d(TAG, "[$subId] changed: capability=$capability tech=$tech isProvisioned=$it")
|
||||||
|
}.flowOn(Dispatchers.Default)
|
@@ -17,14 +17,33 @@
|
|||||||
package com.android.settings.network.telephony.ims
|
package com.android.settings.network.telephony.ims
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.telephony.AccessNetworkConstants
|
||||||
import android.telephony.ims.ImsManager
|
import android.telephony.ims.ImsManager
|
||||||
import android.telephony.ims.ImsMmTelManager
|
import android.telephony.ims.ImsMmTelManager
|
||||||
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
|
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
|
||||||
|
import android.telephony.ims.ImsStateCallback
|
||||||
|
import android.telephony.ims.feature.MmTelFeature
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.asExecutor
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
|
import kotlinx.coroutines.flow.conflate
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
interface ImsMmTelRepository {
|
interface ImsMmTelRepository {
|
||||||
@WiFiCallingMode
|
@WiFiCallingMode
|
||||||
fun getWiFiCallingMode(useRoamingMode: Boolean): Int
|
fun getWiFiCallingMode(useRoamingMode: Boolean): Int
|
||||||
|
fun imsReadyFlow(): Flow<Boolean>
|
||||||
|
suspend fun isSupported(
|
||||||
|
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
||||||
|
@AccessNetworkConstants.TransportType transportType: Int,
|
||||||
|
): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImsMmTelRepositoryImpl(
|
class ImsMmTelRepositoryImpl(
|
||||||
@@ -45,6 +64,50 @@ class ImsMmTelRepositoryImpl(
|
|||||||
ImsMmTelManager.WIFI_MODE_UNKNOWN
|
ImsMmTelManager.WIFI_MODE_UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun imsReadyFlow(): Flow<Boolean> = callbackFlow {
|
||||||
|
val callback = object : ImsStateCallback() {
|
||||||
|
override fun onAvailable() {
|
||||||
|
Log.d(TAG, "[$subId] IMS onAvailable")
|
||||||
|
trySend(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError() {
|
||||||
|
Log.d(TAG, "[$subId] IMS onError")
|
||||||
|
trySend(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUnavailable(reason: Int) {
|
||||||
|
Log.d(TAG, "[$subId] IMS onUnavailable")
|
||||||
|
trySend(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imsMmTelManager.registerImsStateCallback(Dispatchers.Default.asExecutor(), callback)
|
||||||
|
|
||||||
|
awaitClose { imsMmTelManager.unregisterImsStateCallback(callback) }
|
||||||
|
}.catch { e ->
|
||||||
|
Log.w(TAG, "[$subId] error while imsReadyFlow", e)
|
||||||
|
}.conflate().flowOn(Dispatchers.Default)
|
||||||
|
|
||||||
|
override suspend fun isSupported(
|
||||||
|
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
||||||
|
@AccessNetworkConstants.TransportType transportType: Int,
|
||||||
|
): Boolean = withContext(Dispatchers.Default) {
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
try {
|
||||||
|
imsMmTelManager.isSupported(
|
||||||
|
capability,
|
||||||
|
transportType,
|
||||||
|
Dispatchers.Default.asExecutor(),
|
||||||
|
continuation::resume,
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
continuation.resume(false)
|
||||||
|
Log.w(TAG, "[$subId] isSupported failed", e)
|
||||||
|
}
|
||||||
|
}.also { Log.d(TAG, "[$subId] isSupported = $it") }
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private const val TAG = "ImsMmTelRepository"
|
private const val TAG = "ImsMmTelRepository"
|
||||||
}
|
}
|
||||||
|
@@ -17,12 +17,24 @@
|
|||||||
package com.android.settings.network.telephony.wificalling
|
package com.android.settings.network.telephony.wificalling
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.telephony.AccessNetworkConstants
|
||||||
import android.telephony.CarrierConfigManager
|
import android.telephony.CarrierConfigManager
|
||||||
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
|
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
|
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
|
||||||
|
import android.telephony.ims.feature.MmTelFeature
|
||||||
|
import android.telephony.ims.stub.ImsRegistrationImplBase
|
||||||
import com.android.settings.network.telephony.ims.ImsMmTelRepository
|
import com.android.settings.network.telephony.ims.ImsMmTelRepository
|
||||||
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
|
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
|
||||||
|
import com.android.settings.network.telephony.ims.imsFeatureProvisionedFlow
|
||||||
|
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
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
class WifiCallingRepository(
|
class WifiCallingRepository(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@@ -44,4 +56,30 @@ class WifiCallingRepository(
|
|||||||
carrierConfigManager
|
carrierConfigManager
|
||||||
.getConfigForSubId(subId, KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
|
.getConfigForSubId(subId, KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
|
||||||
.getBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
|
.getBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
fun wifiCallingReadyFlow(): Flow<Boolean> {
|
||||||
|
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
|
||||||
|
return context.subscriptionsChangedFlow().flatMapLatest {
|
||||||
|
combine(
|
||||||
|
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 && imsMmTelRepository.isSupported(
|
||||||
|
capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
|
||||||
|
transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,6 +62,7 @@ class WifiCallingPreferenceControllerTest {
|
|||||||
|
|
||||||
private val mockWifiCallingRepository = mock<WifiCallingRepository> {
|
private val mockWifiCallingRepository = mock<WifiCallingRepository> {
|
||||||
on { getWiFiCallingMode() } doReturn ImsMmTelManager.WIFI_MODE_UNKNOWN
|
on { getWiFiCallingMode() } doReturn ImsMmTelManager.WIFI_MODE_UNKNOWN
|
||||||
|
on { wifiCallingReadyFlow() } doReturn flowOf(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val callingPreferenceCategoryController =
|
private val callingPreferenceCategoryController =
|
||||||
@@ -71,7 +72,7 @@ class WifiCallingPreferenceControllerTest {
|
|||||||
context = context,
|
context = context,
|
||||||
key = TEST_KEY,
|
key = TEST_KEY,
|
||||||
callStateFlowFactory = { flowOf(callState) },
|
callStateFlowFactory = { flowOf(callState) },
|
||||||
wifiCallingRepository = { mockWifiCallingRepository },
|
wifiCallingRepositoryFactory = { mockWifiCallingRepository },
|
||||||
).init(subId = SUB_ID, callingPreferenceCategoryController)
|
).init(subId = SUB_ID, callingPreferenceCategoryController)
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.telephony.ims.ProvisioningManager
|
||||||
|
import android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback
|
||||||
|
import android.telephony.ims.feature.MmTelFeature
|
||||||
|
import android.telephony.ims.stub.ImsRegistrationImplBase
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
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.first
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.kotlin.any
|
||||||
|
import org.mockito.kotlin.doAnswer
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ImsFeatureProvisionedFlowTest {
|
||||||
|
|
||||||
|
private var callback: FeatureProvisioningCallback? = null
|
||||||
|
|
||||||
|
private val mockProvisioningManager = mock<ProvisioningManager> {
|
||||||
|
on { registerFeatureProvisioningChangedCallback(any(), any()) } doAnswer {
|
||||||
|
callback = it.arguments[1] as FeatureProvisioningCallback
|
||||||
|
callback?.onFeatureProvisioningChanged(CAPABILITY, TECH, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun imsFeatureProvisionedFlow_sendInitialValue() = runBlocking {
|
||||||
|
val flow = imsFeatureProvisionedFlow(SUB_ID, CAPABILITY, TECH, mockProvisioningManager)
|
||||||
|
|
||||||
|
val state = flow.first()
|
||||||
|
|
||||||
|
assertThat(state).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun imsFeatureProvisionedFlow_changed(): Unit = runBlocking {
|
||||||
|
val listDeferred = async {
|
||||||
|
imsFeatureProvisionedFlow(SUB_ID, CAPABILITY, TECH, mockProvisioningManager)
|
||||||
|
.toListWithTimeout()
|
||||||
|
}
|
||||||
|
delay(100)
|
||||||
|
|
||||||
|
callback?.onFeatureProvisioningChanged(CAPABILITY, TECH, false)
|
||||||
|
|
||||||
|
assertThat(listDeferred.await().last()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val SUB_ID = 1
|
||||||
|
const val CAPABILITY = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE
|
||||||
|
const val TECH = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
|
||||||
|
}
|
||||||
|
}
|
@@ -17,14 +17,26 @@
|
|||||||
package com.android.settings.network.telephony.ims
|
package com.android.settings.network.telephony.ims
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.telephony.AccessNetworkConstants
|
||||||
import android.telephony.ims.ImsMmTelManager
|
import android.telephony.ims.ImsMmTelManager
|
||||||
|
import android.telephony.ims.ImsStateCallback
|
||||||
|
import android.telephony.ims.feature.MmTelFeature
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.android.settingslib.spa.testutils.toListWithTimeout
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import java.util.function.Consumer
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.kotlin.any
|
||||||
|
import org.mockito.kotlin.doAnswer
|
||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.doThrow
|
import org.mockito.kotlin.doThrow
|
||||||
|
import org.mockito.kotlin.eq
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.stub
|
import org.mockito.kotlin.stub
|
||||||
|
|
||||||
@@ -32,10 +44,21 @@ import org.mockito.kotlin.stub
|
|||||||
class ImsMmTelRepositoryTest {
|
class ImsMmTelRepositoryTest {
|
||||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
|
|
||||||
|
private var stateCallback: ImsStateCallback? = null
|
||||||
|
|
||||||
private val mockImsMmTelManager = mock<ImsMmTelManager> {
|
private val mockImsMmTelManager = mock<ImsMmTelManager> {
|
||||||
on { isVoWiFiSettingEnabled } doReturn true
|
on { isVoWiFiSettingEnabled } doReturn true
|
||||||
on { getVoWiFiRoamingModeSetting() } doReturn ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED
|
on { getVoWiFiRoamingModeSetting() } doReturn ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED
|
||||||
on { getVoWiFiModeSetting() } doReturn ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED
|
on { getVoWiFiModeSetting() } doReturn ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED
|
||||||
|
on { registerImsStateCallback(any(), any()) } doAnswer {
|
||||||
|
stateCallback = it.arguments[1] as ImsStateCallback
|
||||||
|
stateCallback?.onAvailable()
|
||||||
|
}
|
||||||
|
on { isSupported(eq(CAPABILITY), eq(TRANSPORT), any(), any()) } doAnswer {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val consumer = it.arguments[3] as Consumer<Boolean>
|
||||||
|
consumer.accept(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val repository = ImsMmTelRepositoryImpl(context, SUB_ID, mockImsMmTelManager)
|
private val repository = ImsMmTelRepositoryImpl(context, SUB_ID, mockImsMmTelManager)
|
||||||
@@ -76,7 +99,37 @@ class ImsMmTelRepositoryTest {
|
|||||||
assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_UNKNOWN)
|
assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_UNKNOWN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun imsReadyFlow_sendInitialValue() = runBlocking {
|
||||||
|
val flow = repository.imsReadyFlow()
|
||||||
|
|
||||||
|
val state = flow.first()
|
||||||
|
|
||||||
|
assertThat(state).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun imsReadyFlow_changed(): Unit = runBlocking {
|
||||||
|
val listDeferred = async {
|
||||||
|
repository.imsReadyFlow().toListWithTimeout()
|
||||||
|
}
|
||||||
|
delay(100)
|
||||||
|
|
||||||
|
stateCallback?.onUnavailable(ImsStateCallback.REASON_IMS_SERVICE_NOT_READY)
|
||||||
|
|
||||||
|
assertThat(listDeferred.await().last()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isSupported() = runBlocking {
|
||||||
|
val isSupported = repository.isSupported(CAPABILITY, TRANSPORT)
|
||||||
|
|
||||||
|
assertThat(isSupported).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val SUB_ID = 1
|
const val SUB_ID = 1
|
||||||
|
const val CAPABILITY = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE
|
||||||
|
const val TRANSPORT = AccessNetworkConstants.TRANSPORT_TYPE_WLAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user