diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt index 1aa954ff48cf5..012b9ec09e7a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectionModel.kt @@ -51,6 +51,16 @@ data class MobileConnectionModel( */ val operatorAlphaShort: String? = null, + /** + * TODO (b/263167683): Clarify this field + * + * This check comes from [com.android.settingslib.Utils.isInService]. It is intended to be a + * mapping from a ServiceState to a notion of connectivity. Notably, it will consider a + * connection to be in-service if either the voice registration state is IN_SERVICE or the data + * registration state is IN_SERVICE and NOT IWLAN. + */ + val isInService: Boolean = false, + /** Fields below from [SignalStrengthsListener.onSignalStrengthsChanged] */ val isGsm: Boolean = false, @IntRange(from = 0, to = 4) @@ -99,6 +109,10 @@ data class MobileConnectionModel( row.logChange(COL_OPERATOR, operatorAlphaShort) } + if (prevVal.isInService != isInService) { + row.logChange(COL_IS_IN_SERVICE, isInService) + } + if (prevVal.isGsm != isGsm) { row.logChange(COL_IS_GSM, isGsm) } @@ -129,6 +143,7 @@ data class MobileConnectionModel( row.logChange(COL_EMERGENCY, isEmergencyOnly) row.logChange(COL_ROAMING, isRoaming) row.logChange(COL_OPERATOR, operatorAlphaShort) + row.logChange(COL_IS_IN_SERVICE, isInService) row.logChange(COL_IS_GSM, isGsm) row.logChange(COL_CDMA_LEVEL, cdmaLevel) row.logChange(COL_PRIMARY_LEVEL, primaryLevel) @@ -141,6 +156,7 @@ data class MobileConnectionModel( const val COL_EMERGENCY = "EmergencyOnly" const val COL_ROAMING = "Roaming" const val COL_OPERATOR = "OperatorName" + const val COL_IS_IN_SERVICE = "IsInService" const val COL_IS_GSM = "IsGsm" const val COL_CDMA_LEVEL = "CdmaLevel" const val COL_PRIMARY_LEVEL = "PrimaryLevel" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt index b252de8dd3890..0b5f9d5ae59e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt @@ -247,6 +247,7 @@ constructor( return MobileConnectionModel( isEmergencyOnly = false, // TODO(b/261029387): not yet supported isRoaming = roaming, + isInService = (level ?: 0) > 0, isGsm = false, // TODO(b/261029387): not yet supported cdmaLevel = level ?: 0, primaryLevel = level ?: 0, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index 0b9e1583898e5..5cfff82253c5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -32,6 +32,7 @@ import android.telephony.TelephonyManager import android.telephony.TelephonyManager.ERI_OFF import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN +import com.android.settingslib.Utils import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Application @@ -117,6 +118,7 @@ class MobileConnectionRepositoryImpl( isEmergencyOnly = serviceState.isEmergencyOnly, isRoaming = serviceState.roaming, operatorAlphaShort = serviceState.operatorAlphaShort, + isInService = Utils.isInService(serviceState), ) trySend(state) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index 7970443f69b1b..c63dd2a2318c8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -20,7 +20,10 @@ import android.content.Intent import android.os.UserHandle import android.provider.Settings import android.telephony.CellSignalStrengthCdma +import android.telephony.NetworkRegistrationInfo import android.telephony.ServiceState +import android.telephony.ServiceState.STATE_IN_SERVICE +import android.telephony.ServiceState.STATE_OUT_OF_SERVICE import android.telephony.SignalStrength import android.telephony.SubscriptionInfo import android.telephony.TelephonyCallback @@ -47,7 +50,6 @@ import android.telephony.TelephonyManager.EXTRA_SHOW_SPN import android.telephony.TelephonyManager.EXTRA_SPN import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID import android.telephony.TelephonyManager.NETWORK_TYPE_LTE -import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.log.table.TableLogBuffer @@ -302,7 +304,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { var latest: MobileConnectionModel? = null val job = underTest.connectionInfo.onEach { latest = it }.launchIn(this) - val type = NETWORK_TYPE_UNKNOWN val expected = UnknownNetworkType assertThat(latest?.resolvedNetworkType).isEqualTo(expected) @@ -590,6 +591,56 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { job.cancel() } + @Test + fun `connection model - isInService - not iwlan`() = + runBlocking(IMMEDIATE) { + var latest: Boolean? = null + val job = underTest.connectionInfo.onEach { latest = it.isInService }.launchIn(this) + + val serviceState = ServiceState() + serviceState.voiceRegState = STATE_IN_SERVICE + serviceState.dataRegState = STATE_IN_SERVICE + + getTelephonyCallbackForType().onServiceStateChanged(serviceState) + + assertThat(latest).isTrue() + + serviceState.voiceRegState = STATE_OUT_OF_SERVICE + getTelephonyCallbackForType().onServiceStateChanged(serviceState) + assertThat(latest).isTrue() + + serviceState.dataRegState = STATE_OUT_OF_SERVICE + getTelephonyCallbackForType().onServiceStateChanged(serviceState) + assertThat(latest).isFalse() + + job.cancel() + } + + @Test + fun `connection model - isInService - is iwlan - voice out of service - data in service`() = + runBlocking(IMMEDIATE) { + var latest: Boolean? = null + val job = underTest.connectionInfo.onEach { latest = it.isInService }.launchIn(this) + + // Mock the service state here so we can make it specifically IWLAN + val serviceState: ServiceState = mock() + whenever(serviceState.state).thenReturn(STATE_OUT_OF_SERVICE) + whenever(serviceState.dataRegistrationState).thenReturn(STATE_IN_SERVICE) + + // See [com.android.settingslib.Utils.isInService] for more info. This is one way to + // make the network look like IWLAN + val networkRegWlan: NetworkRegistrationInfo = mock() + whenever(serviceState.getNetworkRegistrationInfo(any(), any())) + .thenReturn(networkRegWlan) + whenever(networkRegWlan.registrationState) + .thenReturn(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + + getTelephonyCallbackForType().onServiceStateChanged(serviceState) + assertThat(latest).isFalse() + + job.cancel() + } + private fun getTelephonyCallbacks(): List { val callbackCaptor = argumentCaptor() Mockito.verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())