diff --git a/src/com/android/settings/deviceinfo/simstatus/ImsRegistrationStateController.kt b/src/com/android/settings/deviceinfo/simstatus/ImsRegistrationStateController.kt deleted file mode 100644 index 3d17ec0d9ce..00000000000 --- a/src/com/android/settings/deviceinfo/simstatus/ImsRegistrationStateController.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.deviceinfo.simstatus - -import android.content.Context -import android.telephony.SubscriptionManager -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import com.android.settings.network.telephony.SimSlotRepository -import com.android.settings.network.telephony.ims.ImsMmTelRepository -import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.conflate -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.launch - -@OptIn(ExperimentalCoroutinesApi::class) -class ImsRegistrationStateController @JvmOverloads constructor( - private val context: Context, - private val simSlotRepository: SimSlotRepository = SimSlotRepository(context), - private val imsMmTelRepositoryFactory: (subId: Int) -> ImsMmTelRepository = { subId -> - ImsMmTelRepositoryImpl(context, subId) - }, -) { - fun collectImsRegistered( - lifecycleOwner: LifecycleOwner, - simSlotIndex: Int, - action: (imsRegistered: Boolean) -> Unit, - ) { - lifecycleOwner.lifecycleScope.launch { - lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { - imsRegisteredFlow(simSlotIndex).collect(action) - } - } - } - - private fun imsRegisteredFlow(simSlotIndex: Int): Flow = - simSlotRepository.subIdInSimSlotFlow(simSlotIndex) - .flatMapLatest { subId -> - if (SubscriptionManager.isValidSubscriptionId(subId)) { - imsMmTelRepositoryFactory(subId).imsRegisteredFlow() - } else { - flowOf(false) - } - } - .conflate() - .flowOn(Dispatchers.Default) -} diff --git a/src/com/android/settings/deviceinfo/simstatus/SignalStrengthRepository.kt b/src/com/android/settings/deviceinfo/simstatus/SignalStrengthRepository.kt new file mode 100644 index 00000000000..8b062e70e03 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SignalStrengthRepository.kt @@ -0,0 +1,78 @@ +/* + * 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.deviceinfo.simstatus + +import android.content.Context +import android.telephony.ServiceState +import android.telephony.SignalStrength +import android.telephony.TelephonyCallback +import android.util.Log +import com.android.settings.R +import com.android.settings.network.telephony.serviceStateFlow +import com.android.settings.network.telephony.telephonyCallbackFlow +import com.android.settingslib.Utils +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +@OptIn(ExperimentalCoroutinesApi::class) +class SignalStrengthRepository( + private val context: Context, + private val serviceStateFlowFactory: (subId: Int) -> Flow = { + context.serviceStateFlow(it) + }, +) { + fun signalStrengthDisplayFlow(subId: Int): Flow = + serviceStateFlowFactory(subId).flatMapLatest { serviceState -> + if (Utils.isInService(serviceState)) { + signalStrengthFlow(subId).map { it.displayString() } + } else { + flowOf("0") + } + }.conflate().flowOn(Dispatchers.Default) + + /** Creates an instance of a cold Flow for [SignalStrength] of given [subId]. */ + private fun signalStrengthFlow(subId: Int): Flow = + context.telephonyCallbackFlow(subId) { + object : TelephonyCallback(), TelephonyCallback.SignalStrengthsListener { + override fun onSignalStrengthsChanged(signalStrength: SignalStrength) { + trySend(signalStrength) + val cellSignalStrengths = signalStrength.cellSignalStrengths + Log.d(TAG, "[$subId] onSignalStrengthsChanged: $cellSignalStrengths") + } + } + } + + private fun SignalStrength.displayString() = + context.getString(R.string.sim_signal_strength, signalDbm(), signalAsu()) + + private companion object { + private const val TAG = "SignalStrengthRepo" + + + private fun SignalStrength.signalDbm(): Int = + cellSignalStrengths.firstOrNull { it.dbm != -1 }?.dbm ?: 0 + + private fun SignalStrength.signalAsu(): Int = + cellSignalStrengths.firstOrNull { it.asuLevel != -1 }?.asuLevel ?: 0 + } +} diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java index e5882dd9759..b5ee1d88108 100644 --- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java @@ -32,10 +32,8 @@ import android.telephony.Annotation; import android.telephony.CarrierConfigManager; import android.telephony.CellBroadcastIntents; import android.telephony.CellBroadcastService; -import android.telephony.CellSignalStrength; import android.telephony.ICellBroadcastService; import android.telephony.ServiceState; -import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; @@ -113,7 +111,6 @@ public class SimStatusDialogController implements DefaultLifecycleObserver { private SubscriptionInfo mSubscriptionInfo; private TelephonyDisplayInfo mTelephonyDisplayInfo; - private ServiceState mPreviousServiceState; private final int mSlotIndex; private TelephonyManager mTelephonyManager; @@ -219,15 +216,12 @@ public class SimStatusDialogController implements DefaultLifecycleObserver { // getServiceState() may return null when the subscription is inactive // or when there was an error communicating with the phone process. final ServiceState serviceState = getTelephonyManager().getServiceState(); - final SignalStrength signalStrength = getTelephonyManager().getSignalStrength(); updatePhoneNumber(); updateServiceState(serviceState); - updateSignalStrength(signalStrength); updateNetworkType(); updateRoamingStatus(serviceState); updateIccidNumber(); - updateImsRegistrationState(); } /** @@ -257,7 +251,7 @@ public class SimStatusDialogController implements DefaultLifecycleObserver { .registerTelephonyCallback(mContext.getMainExecutor(), mTelephonyCallback); mSubscriptionManager.addOnSubscriptionsChangedListener( mContext.getMainExecutor(), mOnSubscriptionsChangedListener); - collectImsRegistered(owner); + collectSimStatusDialogInfo(owner); if (mShowLatestAreaInfo) { updateAreaInfoText(); @@ -420,12 +414,6 @@ public class SimStatusDialogController implements DefaultLifecycleObserver { private void updateServiceState(ServiceState serviceState) { final int state = Utils.getCombinedServiceState(serviceState); - if (!Utils.isInService(serviceState)) { - resetSignalStrength(); - } else if (!Utils.isInService(mPreviousServiceState)) { - // If ServiceState changed from out of service -> in service, update signal strength. - updateSignalStrength(getTelephonyManager().getSignalStrength()); - } String serviceStateValue; @@ -450,49 +438,11 @@ public class SimStatusDialogController implements DefaultLifecycleObserver { mDialog.setText(SERVICE_STATE_VALUE_ID, serviceStateValue); } - private void updateSignalStrength(SignalStrength signalStrength) { - if (signalStrength == null) { - return; - } - // by default we show the signal strength - boolean showSignalStrength = true; - if (mSubscriptionInfo != null) { - final int subscriptionId = mSubscriptionInfo.getSubscriptionId(); - final PersistableBundle carrierConfig = - mCarrierConfigManager.getConfigForSubId(subscriptionId); - if (carrierConfig != null) { - showSignalStrength = carrierConfig.getBoolean( - CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL); - } - } - if (!showSignalStrength) { - mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_LABEL_ID); - mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_VALUE_ID); - return; - } - - ServiceState serviceState = getTelephonyManager().getServiceState(); - if (!Utils.isInService(serviceState)) { - return; - } - - int signalDbm = getDbm(signalStrength); - int signalAsu = getAsuLevel(signalStrength); - - if (signalDbm == -1) { - signalDbm = 0; - } - - if (signalAsu == -1) { - signalAsu = 0; - } - - mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, mRes.getString(R.string.sim_signal_strength, - signalDbm, signalAsu)); - } - - private void resetSignalStrength() { - mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, "0"); + private void updateSignalStrength(@Nullable String signalStrength) { + boolean isVisible = signalStrength != null; + mDialog.setSettingVisibility(SIGNAL_STRENGTH_LABEL_ID, isVisible); + mDialog.setSettingVisibility(SIGNAL_STRENGTH_VALUE_ID, isVisible); + mDialog.setText(SIGNAL_STRENGTH_VALUE_ID, signalStrength); } private void updateNetworkType() { @@ -581,39 +531,21 @@ public class SimStatusDialogController implements DefaultLifecycleObserver { } } - private boolean isImsRegistrationStateShowUp() { - if (mSubscriptionInfo == null) { - return false; - } - final int subscriptionId = mSubscriptionInfo.getSubscriptionId(); - final PersistableBundle carrierConfig = - mCarrierConfigManager.getConfigForSubId(subscriptionId); - return carrierConfig == null ? false : - carrierConfig.getBoolean( - CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL); + private void updateImsRegistrationState(@Nullable Boolean imsRegistered) { + boolean isVisible = imsRegistered != null; + mDialog.setSettingVisibility(IMS_REGISTRATION_STATE_LABEL_ID, isVisible); + mDialog.setSettingVisibility(IMS_REGISTRATION_STATE_VALUE_ID, isVisible); + int stringId = Boolean.TRUE.equals(imsRegistered) + ? com.android.settingslib.R.string.ims_reg_status_registered + : com.android.settingslib.R.string.ims_reg_status_not_registered; + mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString(stringId)); } - private void updateImsRegistrationState() { - if (isImsRegistrationStateShowUp()) { - return; - } - mDialog.removeSettingFromScreen(IMS_REGISTRATION_STATE_LABEL_ID); - mDialog.removeSettingFromScreen(IMS_REGISTRATION_STATE_VALUE_ID); - } - - private void collectImsRegistered(@NonNull LifecycleOwner owner) { - if (!isImsRegistrationStateShowUp()) { - return; - } - new ImsRegistrationStateController(mContext).collectImsRegistered( - owner, mSlotIndex, (Boolean imsRegistered) -> { - if (imsRegistered) { - mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString( - com.android.settingslib.R.string.ims_reg_status_registered)); - } else { - mDialog.setText(IMS_REGISTRATION_STATE_VALUE_ID, mRes.getString( - com.android.settingslib.R.string.ims_reg_status_not_registered)); - } + private void collectSimStatusDialogInfo(@NonNull LifecycleOwner owner) { + new SimStatusDialogRepository(mContext).collectSimStatusDialogInfo( + owner, mSlotIndex, (simStatusDialogInfo) -> { + updateSignalStrength(simStatusDialogInfo.getSignalStrength()); + updateImsRegistrationState(simStatusDialogInfo.getImsRegistered()); return Unit.INSTANCE; } ); @@ -623,44 +555,9 @@ public class SimStatusDialogController implements DefaultLifecycleObserver { return SubscriptionManager.from(mContext).getActiveSubscriptionInfoForSimSlotIndex(slotId); } - private int getDbm(SignalStrength signalStrength) { - List cellSignalStrengthList = signalStrength.getCellSignalStrengths(); - int dbm = -1; - if (cellSignalStrengthList == null) { - return dbm; - } - - for (CellSignalStrength cell : cellSignalStrengthList) { - if (cell.getDbm() != -1) { - dbm = cell.getDbm(); - break; - } - } - - return dbm; - } - - private int getAsuLevel(SignalStrength signalStrength) { - List cellSignalStrengthList = signalStrength.getCellSignalStrengths(); - int asu = -1; - if (cellSignalStrengthList == null) { - return asu; - } - - for (CellSignalStrength cell : cellSignalStrengthList) { - if (cell.getAsuLevel() != -1) { - asu = cell.getAsuLevel(); - break; - } - } - - return asu; - } - @VisibleForTesting class SimStatusDialogTelephonyCallback extends TelephonyCallback implements TelephonyCallback.DataConnectionStateListener, - TelephonyCallback.SignalStrengthsListener, TelephonyCallback.ServiceStateListener, TelephonyCallback.DisplayInfoListener { @Override @@ -669,17 +566,11 @@ public class SimStatusDialogController implements DefaultLifecycleObserver { updateNetworkType(); } - @Override - public void onSignalStrengthsChanged(SignalStrength signalStrength) { - updateSignalStrength(signalStrength); - } - @Override public void onServiceStateChanged(ServiceState serviceState) { updateNetworkProvider(); updateServiceState(serviceState); updateRoamingStatus(serviceState); - mPreviousServiceState = serviceState; } @Override diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java index f212eea0d2e..c51417cfcb6 100644 --- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java @@ -26,6 +26,7 @@ import android.view.View; import android.view.WindowManager; import android.widget.TextView; +import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -91,6 +92,13 @@ public class SimStatusDialogFragment extends InstrumentedDialogFragment { super.onDestroy(); } + public void setSettingVisibility(int viewId, boolean isVisible) { + final View view = mRootView.findViewById(viewId); + if (view != null) { + view.setVisibility(isVisible ? View.VISIBLE : View.GONE); + } + } + public void removeSettingFromScreen(int viewId) { final View view = mRootView.findViewById(viewId); if (view != null) { @@ -106,7 +114,7 @@ public class SimStatusDialogFragment extends InstrumentedDialogFragment { SimStatusDialogController.PHONE_NUMBER_VALUE_ID) .sorted().toArray(); - public void setText(int viewId, CharSequence text) { + public void setText(int viewId, @Nullable CharSequence text) { if (!isAdded()) { Log.d(TAG, "Fragment not attached yet."); return; diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepository.kt b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepository.kt new file mode 100644 index 00000000000..5ed6993cc98 --- /dev/null +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepository.kt @@ -0,0 +1,120 @@ +/* + * 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.deviceinfo.simstatus + +import android.content.Context +import android.telephony.CarrierConfigManager +import android.telephony.SubscriptionManager +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.android.settings.network.telephony.SimSlotRepository +import com.android.settings.network.telephony.ims.ImsMmTelRepository +import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl +import com.android.settings.network.telephony.safeGetConfig +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.launch + +@OptIn(ExperimentalCoroutinesApi::class) +class SimStatusDialogRepository @JvmOverloads constructor( + private val context: Context, + private val simSlotRepository: SimSlotRepository = SimSlotRepository(context), + private val signalStrengthRepository: SignalStrengthRepository = + SignalStrengthRepository(context), + private val imsMmTelRepositoryFactory: (subId: Int) -> ImsMmTelRepository = { subId -> + ImsMmTelRepositoryImpl(context, subId) + }, +) { + private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!! + + data class SimStatusDialogInfo( + val signalStrength: String? = null, + val imsRegistered: Boolean? = null, + ) + + private data class SimStatusDialogVisibility( + val signalStrengthShowUp: Boolean, + val imsRegisteredShowUp: Boolean, + ) + + fun collectSimStatusDialogInfo( + lifecycleOwner: LifecycleOwner, + simSlotIndex: Int, + action: (info: SimStatusDialogInfo) -> Unit, + ) { + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + simStatusDialogInfoBySlotFlow(simSlotIndex).collect(action) + } + } + } + + private fun simStatusDialogInfoBySlotFlow(simSlotIndex: Int): Flow = + simSlotRepository.subIdInSimSlotFlow(simSlotIndex) + .flatMapLatest { subId -> + if (SubscriptionManager.isValidSubscriptionId(subId)) { + simStatusDialogInfoFlow(subId) + } else { + flowOf(SimStatusDialogInfo()) + } + } + .conflate() + .flowOn(Dispatchers.Default) + + private fun simStatusDialogInfoFlow(subId: Int): Flow = + showUpFlow(subId).flatMapLatest { visibility -> + combine( + if (visibility.signalStrengthShowUp) { + signalStrengthRepository.signalStrengthDisplayFlow(subId) + } else flowOf(null), + if (visibility.imsRegisteredShowUp) { + imsMmTelRepositoryFactory(subId).imsRegisteredFlow() + } else flowOf(null), + ) { signalStrength, imsRegistered -> + SimStatusDialogInfo(signalStrength = signalStrength, imsRegistered = imsRegistered) + } + } + + private fun showUpFlow(subId: Int) = flow { + val config = carrierConfigManager.safeGetConfig( + keys = listOf( + CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, + CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, + ), + subId = subId, + ) + val visibility = SimStatusDialogVisibility( + signalStrengthShowUp = config.getBoolean( + CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, + true, // by default we show the signal strength in sim status + ), + imsRegisteredShowUp = config.getBoolean( + CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL + ), + ) + emit(visibility) + } +} diff --git a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/ImsRegistrationStateControllerTest.kt b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/ImsRegistrationStateControllerTest.kt deleted file mode 100644 index 5e486dd733e..00000000000 --- a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/ImsRegistrationStateControllerTest.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.deviceinfo.simstatus - -import android.content.Context -import androidx.lifecycle.testing.TestLifecycleOwner -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.android.settings.network.telephony.SimSlotRepository -import com.android.settings.network.telephony.ims.ImsMmTelRepository -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.runBlocking -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.mock - -@RunWith(AndroidJUnit4::class) -class ImsRegistrationStateControllerTest { - - private val context: Context = ApplicationProvider.getApplicationContext() - - private val mockSimSlotRepository = mock { - on { subIdInSimSlotFlow(SIM_SLOT_INDEX) } doReturn flowOf(SUB_ID) - } - - private val mockImsMmTelRepository = mock { - on { imsRegisteredFlow() } doReturn flowOf(true) - } - - private val controller = ImsRegistrationStateController( - context = context, - simSlotRepository = mockSimSlotRepository, - imsMmTelRepositoryFactory = { subId -> - assertThat(subId).isEqualTo(SUB_ID) - mockImsMmTelRepository - }, - ) - - @Test - fun collectImsRegistered() = runBlocking { - var imsRegistered = false - - controller.collectImsRegistered(TestLifecycleOwner(), SIM_SLOT_INDEX) { - imsRegistered = it - } - delay(100) - - assertThat(imsRegistered).isTrue() - } - - private companion object { - const val SIM_SLOT_INDEX = 0 - const val SUB_ID = 1 - } -} diff --git a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SignalStrengthRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SignalStrengthRepositoryTest.kt new file mode 100644 index 00000000000..d7486604f10 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SignalStrengthRepositoryTest.kt @@ -0,0 +1,148 @@ +/* + * 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.deviceinfo.simstatus + +import android.content.Context +import android.telephony.CellSignalStrengthCdma +import android.telephony.CellSignalStrengthGsm +import android.telephony.CellSignalStrengthLte +import android.telephony.CellSignalStrengthNr +import android.telephony.CellSignalStrengthTdscdma +import android.telephony.CellSignalStrengthWcdma +import android.telephony.ServiceState +import android.telephony.SignalStrength +import android.telephony.TelephonyCallback +import android.telephony.TelephonyManager +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.flowOf +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.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy + +@RunWith(AndroidJUnit4::class) +class SignalStrengthRepositoryTest { + + private var signalStrength = SignalStrength() + + private val mockTelephonyManager = mock { + on { createForSubscriptionId(SUB_ID) } doReturn mock + on { registerTelephonyCallback(any(), any()) } doAnswer { + val listener = it.getArgument(1) + listener.onSignalStrengthsChanged(signalStrength) + } + } + + private val context: Context = spy(ApplicationProvider.getApplicationContext()) { + on { getSystemService(TelephonyManager::class.java) } doAnswer { mockTelephonyManager } + } + + private val serviceState = ServiceState() + + private val repository = SignalStrengthRepository(context) { flowOf(serviceState) } + + @Test + fun signalStrengthDisplayFlow_serviceStatePowerOff() = runBlocking { + serviceState.state = ServiceState.STATE_POWER_OFF + + val signalStrength = repository.signalStrengthDisplayFlow(SUB_ID).firstWithTimeoutOrNull() + + assertThat(signalStrength).isEqualTo("0") + } + + @Test + fun signalStrengthDisplayFlow_lteWcdma() = runBlocking { + serviceState.state = ServiceState.STATE_IN_SERVICE + signalStrength = SignalStrength( + CellSignalStrengthCdma(), + CellSignalStrengthGsm(), + mock { + on { isValid } doReturn true + on { dbm } doReturn 40 + on { asuLevel } doReturn 41 + }, + CellSignalStrengthTdscdma(), + mock { + on { isValid } doReturn true + on { dbm } doReturn 50 + on { asuLevel } doReturn 51 + }, + CellSignalStrengthNr(), + ) + + val signalStrength = repository.signalStrengthDisplayFlow(SUB_ID).firstWithTimeoutOrNull() + + assertThat(signalStrength).isEqualTo("50 dBm 51 asu") + } + + @Test + fun signalStrengthDisplayFlow_lteCdma() = runBlocking { + serviceState.state = ServiceState.STATE_IN_SERVICE + signalStrength = SignalStrength( + mock { + on { isValid } doReturn true + on { dbm } doReturn 30 + on { asuLevel } doReturn 31 + }, + CellSignalStrengthGsm(), + CellSignalStrengthWcdma(), + CellSignalStrengthTdscdma(), + mock { + on { isValid } doReturn true + on { dbm } doReturn 50 + on { asuLevel } doReturn 51 + }, + CellSignalStrengthNr(), + ) + + val signalStrength = repository.signalStrengthDisplayFlow(SUB_ID).firstWithTimeoutOrNull() + + assertThat(signalStrength).isEqualTo("50 dBm 51 asu") + } + + @Test + fun signalStrengthDisplayFlow_lteOnly() = runBlocking { + serviceState.state = ServiceState.STATE_IN_SERVICE + signalStrength = SignalStrength( + CellSignalStrengthCdma(), + CellSignalStrengthGsm(), + CellSignalStrengthWcdma(), + CellSignalStrengthTdscdma(), + mock { + on { isValid } doReturn true + on { dbm } doReturn 50 + on { asuLevel } doReturn 51 + }, + CellSignalStrengthNr(), + ) + + val signalStrength = repository.signalStrengthDisplayFlow(SUB_ID).firstWithTimeoutOrNull() + + assertThat(signalStrength).isEqualTo("50 dBm 51 asu") + } + + private companion object { + const val SUB_ID = 1 + } +} diff --git a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepositoryTest.kt new file mode 100644 index 00000000000..01f32bfccf0 --- /dev/null +++ b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepositoryTest.kt @@ -0,0 +1,129 @@ +/* + * 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.deviceinfo.simstatus + +import android.content.Context +import android.os.PersistableBundle +import android.telephony.CarrierConfigManager +import androidx.lifecycle.testing.TestLifecycleOwner +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.deviceinfo.simstatus.SimStatusDialogRepository.SimStatusDialogInfo +import com.android.settings.network.telephony.SimSlotRepository +import com.android.settings.network.telephony.ims.ImsMmTelRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.runBlocking +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.anyVararg +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.spy + +@RunWith(AndroidJUnit4::class) +class SimStatusDialogRepositoryTest { + + private val carrierConfig = PersistableBundle().apply { + putBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, true) + } + + private val mockCarrierConfigManager = mock { + on { getConfigForSubId(eq(SUB_ID), anyVararg()) } doReturn carrierConfig + } + + private val context: Context = spy(ApplicationProvider.getApplicationContext()) { + on { getSystemService(CarrierConfigManager::class.java) } doReturn mockCarrierConfigManager + } + + private val mockSimSlotRepository = mock { + on { subIdInSimSlotFlow(SIM_SLOT_INDEX) } doReturn flowOf(SUB_ID) + } + + private val mockSignalStrengthRepository = mock { + on { signalStrengthDisplayFlow(SUB_ID) } doReturn flowOf(SIGNAL_STRENGTH) + } + + private val mockImsMmTelRepository = mock { + on { imsRegisteredFlow() } doReturn flowOf(true) + } + + private val controller = SimStatusDialogRepository( + context = context, + simSlotRepository = mockSimSlotRepository, + signalStrengthRepository = mockSignalStrengthRepository, + imsMmTelRepositoryFactory = { subId -> + assertThat(subId).isEqualTo(SUB_ID) + mockImsMmTelRepository + }, + ) + + @Test + fun collectSimStatusDialogInfo() = runBlocking { + var simStatusDialogInfo = SimStatusDialogInfo() + + controller.collectSimStatusDialogInfo(TestLifecycleOwner(), SIM_SLOT_INDEX) { + simStatusDialogInfo = it + } + delay(100) + + assertThat(simStatusDialogInfo).isEqualTo( + SimStatusDialogInfo( + signalStrength = SIGNAL_STRENGTH, + imsRegistered = true, + ) + ) + } + + @Test + fun collectSimStatusDialogInfo_doNotShowSignalStrength() = runBlocking { + carrierConfig.putBoolean( + CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, + false + ) + var simStatusDialogInfo = SimStatusDialogInfo() + + controller.collectSimStatusDialogInfo(TestLifecycleOwner(), SIM_SLOT_INDEX) { + simStatusDialogInfo = it + } + delay(100) + + assertThat(simStatusDialogInfo.signalStrength).isNull() + } + + @Test + fun collectSimStatusDialogInfo_doNotShowImsRegistration() = runBlocking { + carrierConfig.putBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false) + var simStatusDialogInfo = SimStatusDialogInfo() + + controller.collectSimStatusDialogInfo(TestLifecycleOwner(), SIM_SLOT_INDEX) { + simStatusDialogInfo = it + } + delay(100) + + assertThat(simStatusDialogInfo.imsRegistered).isNull() + } + + private companion object { + const val SIM_SLOT_INDEX = 0 + const val SUB_ID = 1 + + const val SIGNAL_STRENGTH = "-82 dBm 58 asu" + } +} diff --git a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java index f65480d3911..3fa380828b9 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java @@ -28,26 +28,18 @@ import static com.android.settings.deviceinfo.simstatus.SimStatusDialogControlle import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.OPERATOR_INFO_VALUE_ID; import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.ROAMING_INFO_VALUE_ID; import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.SERVICE_STATE_VALUE_ID; -import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.SIGNAL_STRENGTH_LABEL_ID; -import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.SIGNAL_STRENGTH_VALUE_ID; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; -import android.telephony.CellSignalStrength; import android.telephony.ServiceState; -import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -71,7 +63,6 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -87,14 +78,6 @@ public class SimStatusDialogControllerTest { @Mock private ServiceState mServiceState; @Mock - private SignalStrength mSignalStrength; - @Mock - private CellSignalStrength mCellSignalStrengthCdma; - @Mock - private CellSignalStrength mCellSignalStrengthLte; - @Mock - private CellSignalStrength mCellSignalStrengthWcdma; - @Mock private CarrierConfigManager mCarrierConfigManager; private PersistableBundle mPersistableBundle; @Mock @@ -149,15 +132,6 @@ public class SimStatusDialogControllerTest { mUpdatePhoneNumberCount.incrementAndGet(); } }; - // CellSignalStrength setup - doReturn(0).when(mCellSignalStrengthCdma).getDbm(); - doReturn(0).when(mCellSignalStrengthCdma).getAsuLevel(); - doReturn(0).when(mCellSignalStrengthLte).getDbm(); - doReturn(0).when(mCellSignalStrengthLte).getAsuLevel(); - doReturn(0).when(mCellSignalStrengthWcdma).getDbm(); - doReturn(0).when(mCellSignalStrengthWcdma).getAsuLevel(); - - doReturn(null).when(mSignalStrength).getCellSignalStrengths(); doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt()); when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_SINGLE_SIM); @@ -172,10 +146,7 @@ public class SimStatusDialogControllerTest { mPersistableBundle = new PersistableBundle(); when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mPersistableBundle); - mPersistableBundle.putBoolean( - CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, true); doReturn(mServiceState).when(mTelephonyManager).getServiceState(); - doReturn(mSignalStrength).when(mTelephonyManager).getSignalStrength(); } @Test @@ -218,7 +189,7 @@ public class SimStatusDialogControllerTest { @Test @Ignore("b/337417520") - public void initialize_updateServiceStateWithPowerOff_shouldUpdateTextAndResetSignalStrength() { + public void initialize_updateServiceStateWithPowerOff_shouldUpdateText() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF); mController.initialize(); @@ -226,12 +197,11 @@ public class SimStatusDialogControllerTest { final String offServiceText = ResourcesUtils.getResourcesString( mContext, "radioInfo_service_off"); verify(mDialog).setText(SERVICE_STATE_VALUE_ID, offServiceText); - verify(mDialog).setText(SIGNAL_STRENGTH_VALUE_ID, "0"); } @Test @Ignore("b/337417520") - public void initialize_updateVoiceDataOutOfService_shouldUpdateSettingAndResetSignalStrength() { + public void initialize_updateVoiceDataOutOfService_shouldUpdateSetting() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); when(mServiceState.getDataRegistrationState()).thenReturn( ServiceState.STATE_OUT_OF_SERVICE); @@ -241,7 +211,6 @@ public class SimStatusDialogControllerTest { final String offServiceText = ResourcesUtils.getResourcesString( mContext, "radioInfo_service_out"); verify(mDialog).setText(SERVICE_STATE_VALUE_ID, offServiceText); - verify(mDialog).setText(SIGNAL_STRENGTH_VALUE_ID, "0"); } @Test @@ -256,52 +225,6 @@ public class SimStatusDialogControllerTest { verify(mDialog).setText(SERVICE_STATE_VALUE_ID, inServiceText); } - @Test - public void initialize_updateSignalStrengthWithLte50Wcdma40_shouldUpdateSignalStrengthTo50() { - final int lteDbm = 50; - final int lteAsu = 50; - final int wcdmaDbm = 40; - final int wcdmaAsu = 40; - setupCellSignalStrength_lteWcdma(lteDbm, lteAsu, wcdmaDbm, wcdmaAsu); - - mController.initialize(); - - final String signalStrengthString = ResourcesUtils.getResourcesString( - mContext, "sim_signal_strength", lteDbm, lteAsu); - verify(mDialog, times(2)).setText(SIGNAL_STRENGTH_VALUE_ID, signalStrengthString); - } - - @Test - public void initialize_updateSignalStrengthWithLte50Cdma30_shouldUpdateSignalStrengthTo50() { - final int lteDbm = 50; - final int lteAsu = 50; - final int cdmaDbm = 30; - final int cdmaAsu = 30; - setupCellSignalStrength_lteCdma(lteDbm, lteAsu, cdmaDbm, cdmaAsu); - - mController.initialize(); - - final String signalStrengthString = ResourcesUtils.getResourcesString( - mContext, "sim_signal_strength", lteDbm, lteAsu); - verify(mDialog, times(2)).setText(SIGNAL_STRENGTH_VALUE_ID, signalStrengthString); - } - - @Test - public void initialize_updateVoiceOutOfServiceDataInService_shouldUpdateSignalStrengthTo50() { - when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); - when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); - - final int lteDbm = 50; - final int lteAsu = 50; - setupCellSignalStrength_lteOnly(lteDbm, lteAsu); - - mController.initialize(); - - final String signalStrengthString = ResourcesUtils.getResourcesString( - mContext, "sim_signal_strength", lteDbm, lteAsu); - verify(mDialog, times(2)).setText(SIGNAL_STRENGTH_VALUE_ID, signalStrengthString); - } - @Test public void initialize_updateVoiceNetworkTypeWithEdge_shouldUpdateSettingToEdge() { when(mTelephonyManager.getVoiceNetworkType()).thenReturn( @@ -357,17 +280,6 @@ public class SimStatusDialogControllerTest { verify(mDialog).removeSettingFromScreen(ICCID_INFO_VALUE_ID); } - @Test - public void initialize_doNotShowSignalStrength_shouldRemoveSignalStrengthSetting() { - mPersistableBundle.putBoolean( - CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, false); - - mController.initialize(); - - verify(mDialog, times(2)).removeSettingFromScreen(SIGNAL_STRENGTH_LABEL_ID); - verify(mDialog, times(2)).removeSettingFromScreen(SIGNAL_STRENGTH_VALUE_ID); - } - @Test public void initialize_showSignalStrengthAndIccId_shouldShowSignalStrengthAndIccIdSetting() { // getConfigForSubId is nullable, so make sure the default behavior is correct @@ -375,7 +287,6 @@ public class SimStatusDialogControllerTest { mController.initialize(); - verify(mDialog, times(2)).setText(eq(SIGNAL_STRENGTH_VALUE_ID), any()); verify(mDialog).removeSettingFromScreen(ICCID_INFO_LABEL_ID); verify(mDialog).removeSettingFromScreen(ICCID_INFO_VALUE_ID); } @@ -394,8 +305,6 @@ public class SimStatusDialogControllerTest { @Test @Ignore public void initialize_imsRegistered_shouldSetImsRegistrationStateSummaryToRegisterd() { - mPersistableBundle.putBoolean( - CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, true); when(mTelephonyManager.isImsRegistered(anyInt())).thenReturn(true); mController.initialize(); @@ -407,8 +316,6 @@ public class SimStatusDialogControllerTest { @Test @Ignore public void initialize_imsNotRegistered_shouldSetImsRegistrationStateSummaryToNotRegisterd() { - mPersistableBundle.putBoolean( - CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, true); when(mTelephonyManager.isImsRegistered(anyInt())).thenReturn(false); mController.initialize(); @@ -418,67 +325,19 @@ public class SimStatusDialogControllerTest { } @Test - public void initialize_showImsRegistration_shouldNotRemoveImsRegistrationStateSetting() { - mPersistableBundle.putBoolean( - CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, true); - + @Ignore("b/337417520") + public void initialize_showImsRegistration_shouldShowImsRegistrationStateSetting() { mController.initialize(); - verify(mDialog, never()).removeSettingFromScreen(IMS_REGISTRATION_STATE_VALUE_ID); + verify(mDialog).setSettingVisibility(IMS_REGISTRATION_STATE_VALUE_ID, true); } @Test - public void initialize_doNotShowImsRegistration_shouldRemoveImsRegistrationStateSetting() { - mPersistableBundle.putBoolean( - CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false); - + @Ignore("b/337417520") + public void initialize_doNotShowImsRegistration_shouldHideImsRegistrationStateSetting() { mController.initialize(); - verify(mDialog).removeSettingFromScreen(IMS_REGISTRATION_STATE_LABEL_ID); - verify(mDialog).removeSettingFromScreen(IMS_REGISTRATION_STATE_VALUE_ID); - } - - @Test - public void initialize_nullSignalStrength_noCrash() { - doReturn(null).when(mTelephonyManager).getSignalStrength(); - // we should not crash when running the following line - mController.initialize(); - } - - private void setupCellSignalStrength_lteWcdma(int lteDbm, int lteAsu, int wcdmaDbm, - int wcdmaAsu) { - doReturn(lteDbm).when(mCellSignalStrengthLte).getDbm(); - doReturn(lteAsu).when(mCellSignalStrengthLte).getAsuLevel(); - doReturn(wcdmaDbm).when(mCellSignalStrengthWcdma).getDbm(); - doReturn(wcdmaAsu).when(mCellSignalStrengthWcdma).getAsuLevel(); - - List cellSignalStrengthList = new ArrayList<>(2); - cellSignalStrengthList.add(mCellSignalStrengthLte); - cellSignalStrengthList.add(mCellSignalStrengthWcdma); - - doReturn(cellSignalStrengthList).when(mSignalStrength).getCellSignalStrengths(); - } - - private void setupCellSignalStrength_lteCdma(int lteDbm, int lteAsu, int cdmaDbm, int cdmaAsu) { - doReturn(lteDbm).when(mCellSignalStrengthLte).getDbm(); - doReturn(lteAsu).when(mCellSignalStrengthLte).getAsuLevel(); - doReturn(cdmaDbm).when(mCellSignalStrengthCdma).getDbm(); - doReturn(cdmaAsu).when(mCellSignalStrengthCdma).getAsuLevel(); - - List cellSignalStrengthList = new ArrayList<>(2); - cellSignalStrengthList.add(mCellSignalStrengthLte); - cellSignalStrengthList.add(mCellSignalStrengthCdma); - - doReturn(cellSignalStrengthList).when(mSignalStrength).getCellSignalStrengths(); - } - - private void setupCellSignalStrength_lteOnly(int lteDbm, int lteAsu) { - doReturn(lteDbm).when(mCellSignalStrengthLte).getDbm(); - doReturn(lteAsu).when(mCellSignalStrengthLte).getAsuLevel(); - - List cellSignalStrengthList = new ArrayList<>(2); - cellSignalStrengthList.add(mCellSignalStrengthLte); - - doReturn(cellSignalStrengthList).when(mSignalStrength).getCellSignalStrengths(); + verify(mDialog).setSettingVisibility(IMS_REGISTRATION_STATE_LABEL_ID, false); + verify(mDialog).setSettingVisibility(IMS_REGISTRATION_STATE_VALUE_ID, false); } }