diff options
| author | 2024-06-14 13:06:03 -0400 | |
|---|---|---|
| committer | 2024-06-19 01:08:23 +0000 | |
| commit | 3aaaa6923faa6876e78063b6c922b4a063819f56 (patch) | |
| tree | 480a162c5512b242e6921bd8d8f2e1305f82b9f5 | |
| parent | 29c3e4f3cb3fefdc5089337ee0544dbc0330a0e4 (diff) | |
[Sat] Change the satellite provisioned check to eager; query when start
SatelliteManager does not fire the current state for registered
callbacks at the time of registration. This change adds an
initialization step to `registerForProvisionStateChanged` such that we
always query the current status of the provisioned state and send it
through the Flow before continuing with the callback registration.
Also, we change the sharing strategy to `Eagerly` since we don't want to
generate unnecessary IPC if the device goes in and out of OOS.
Bug: 347083255
Test: DeviceBasedSatelliteRepositoryImplTest
Flag: NONE bugfix
Change-Id: Ic7025223ae803abd1b772e72fab3ccd11b175929
Merged-In: Ic7025223ae803abd1b772e72fab3ccd11b175929
2 files changed, 197 insertions, 20 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt index 86c6b18c62e1..80fbabe3a24f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt @@ -345,32 +345,67 @@ constructor( orElse = flowOf(false), retrySignal = telephonyProcessCrashedEvent, ) - .stateIn(scope, SharingStarted.WhileSubscribed(), false) + .stateIn(scope, SharingStarted.Eagerly, false) private fun satelliteProvisioned(sm: SupportedSatelliteManager): Flow<Boolean> = conflatedCallbackFlow { - val callback = SatelliteProvisionStateCallback { provisioned -> - logBuffer.i { - "onSatelliteProvisionStateChanged: " + - if (provisioned) "provisioned" else "not provisioned" + // TODO(b/347992038): SatelliteManager should be sending the current provisioned + // status when we register a callback. Until then, we have to manually query here. + + // First, check to see what the current status is, and send the result to the output + trySend(queryIsSatelliteProvisioned(sm)) + + val callback = SatelliteProvisionStateCallback { provisioned -> + logBuffer.i { + "onSatelliteProvisionStateChanged: " + + if (provisioned) "provisioned" else "not provisioned" + } + trySend(provisioned) } - trySend(provisioned) - } - var registered = false - try { - sm.registerForProvisionStateChanged( - bgDispatcher.asExecutor(), - callback, - ) - registered = true - } catch (e: Exception) { - logBuffer.e("error registering for provisioning state callback", e) + var registered = false + try { + logBuffer.i { "registerForProvisionStateChanged" } + sm.registerForProvisionStateChanged( + bgDispatcher.asExecutor(), + callback, + ) + registered = true + } catch (e: Exception) { + logBuffer.e("error registering for provisioning state callback", e) + } + + awaitClose { + if (registered) { + sm.unregisterForProvisionStateChanged(callback) + } + } } + .flowOn(bgDispatcher) + + /** Check the current satellite provisioning status. */ + private suspend fun queryIsSatelliteProvisioned(sm: SupportedSatelliteManager): Boolean = + withContext(bgDispatcher) { + suspendCancellableCoroutine { continuation -> + val receiver = + object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> { + override fun onResult(result: Boolean) { + logBuffer.i { "requestIsProvisioned.onResult: $result" } + continuation.resume(result) + } - awaitClose { - if (registered) { - sm.unregisterForProvisionStateChanged(callback) + override fun onError(exception: SatelliteManager.SatelliteException) { + logBuffer.e("requestIsProvisioned.onError:", exception) + continuation.resume(false) + } + } + + logBuffer.i { "Query for current satellite provisioned state." } + try { + sm.requestIsProvisioned(bgDispatcher.asExecutor(), receiver) + } catch (e: Exception) { + logBuffer.e("Exception while calling SatelliteManager.requestIsProvisioned:", e) + continuation.resume(false) } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt index d491d75955c8..ec8e92111d83 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt @@ -32,6 +32,7 @@ import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_NOT_CO import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN +import android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ERROR import android.telephony.satellite.SatelliteManager.SatelliteException import android.telephony.satellite.SatelliteModemStateCallback import android.telephony.satellite.SatelliteProvisionStateCallback @@ -62,6 +63,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.mockito.Mock import org.mockito.Mockito +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.doAnswer import org.mockito.Mockito.never import org.mockito.Mockito.times @@ -354,13 +356,142 @@ class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { } @Test - fun satelliteProvisioned_supported_tracksCallback() = + fun satelliteProvisioned_returnsException_defaultsToFalse() = + testScope.runTest { + // GIVEN satellite is supported on device + doAnswer { + val callback: OutcomeReceiver<Boolean, SatelliteException> = + it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException> + callback.onResult(true) + } + .whenever(satelliteManager) + .requestIsSupported(any(), any()) + + // GIVEN satellite returns an error when asked if provisioned + doAnswer { + val receiver = it.arguments[1] as OutcomeReceiver<Boolean, SatelliteException> + receiver.onError(SatelliteException(SATELLITE_RESULT_ERROR)) + null + } + .whenever(satelliteManager) + .requestIsProvisioned( + any(), + any<OutcomeReceiver<Boolean, SatelliteException>>() + ) + + // GIVEN we've been up long enough to start querying + systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME) + + underTest = + DeviceBasedSatelliteRepositoryImpl( + Optional.of(satelliteManager), + telephonyManager, + dispatcher, + testScope.backgroundScope, + logBuffer = FakeLogBuffer.Factory.create(), + verboseLogBuffer = FakeLogBuffer.Factory.create(), + systemClock, + ) + + // WHEN we try to check for provisioned status + val provisioned by collectLastValue(underTest.isSatelliteProvisioned) + + // THEN well, first we don't throw... + // AND THEN we assume that it's not provisioned + assertThat(provisioned).isFalse() + } + + @Test + fun satelliteProvisioned_throwsWhenQuerying_defaultsToFalse() = + testScope.runTest { + // GIVEN satellite is supported on device + doAnswer { + val callback: OutcomeReceiver<Boolean, SatelliteException> = + it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException> + callback.onResult(true) + } + .whenever(satelliteManager) + .requestIsSupported(any(), any()) + + // GIVEN satellite throws when asked if provisioned + whenever(satelliteManager.requestIsProvisioned(any(), any())) + .thenThrow(SecurityException()) + + // GIVEN we've been up long enough to start querying + systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME) + + underTest = + DeviceBasedSatelliteRepositoryImpl( + Optional.of(satelliteManager), + telephonyManager, + dispatcher, + testScope.backgroundScope, + logBuffer = FakeLogBuffer.Factory.create(), + verboseLogBuffer = FakeLogBuffer.Factory.create(), + systemClock, + ) + + // WHEN we try to check for provisioned status + val provisioned by collectLastValue(underTest.isSatelliteProvisioned) + + // THEN well, first we don't throw... + // AND THEN we assume that it's not provisioned + assertThat(provisioned).isFalse() + } + + @Test + fun satelliteProvisioned_supported_provisioned_queriesInitialStateBeforeCallbacks() = + testScope.runTest { + // GIVEN satellite is supported, and provisioned + setUpRepo( + uptime = MIN_UPTIME, + satMan = satelliteManager, + satelliteSupported = true, + initialSatelliteIsProvisioned = true, + ) + + val provisioned by collectLastValue(underTest.isSatelliteProvisioned) + + runCurrent() + + // THEN the current state is requested + verify(satelliteManager, atLeastOnce()).requestIsProvisioned(any(), any()) + + // AND the state is correct + assertThat(provisioned).isTrue() + } + + @Test + fun satelliteProvisioned_supported_notProvisioned_queriesInitialStateBeforeCallbacks() = + testScope.runTest { + // GIVEN satellite is supported, and provisioned + setUpRepo( + uptime = MIN_UPTIME, + satMan = satelliteManager, + satelliteSupported = true, + initialSatelliteIsProvisioned = false, + ) + + val provisioned by collectLastValue(underTest.isSatelliteProvisioned) + + runCurrent() + + // THEN the current state is requested + verify(satelliteManager, atLeastOnce()).requestIsProvisioned(any(), any()) + + // AND the state is correct + assertThat(provisioned).isFalse() + } + + @Test + fun satelliteProvisioned_supported_notInitiallyProvisioned_tracksCallback() = testScope.runTest { // GIVEN satellite is not supported setUpRepo( uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = true, + initialSatelliteIsProvisioned = false, ) val provisioned by collectLastValue(underTest.isSatelliteProvisioned) @@ -416,6 +547,8 @@ class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { // THEN listeners are re-registered verify(satelliteManager, times(2)).registerForProvisionStateChanged(any(), any()) + // AND the state is queried again + verify(satelliteManager, times(2)).requestIsProvisioned(any(), any()) } @Test @@ -632,6 +765,7 @@ class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { uptime: Long = MIN_UPTIME, satMan: SatelliteManager? = satelliteManager, satelliteSupported: Boolean = true, + initialSatelliteIsProvisioned: Boolean = true, ) { doAnswer { val callback: OutcomeReceiver<Boolean, SatelliteException> = @@ -641,6 +775,14 @@ class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { .whenever(satelliteManager) .requestIsSupported(any(), any()) + doAnswer { + val callback: OutcomeReceiver<Boolean, SatelliteException> = + it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException> + callback.onResult(initialSatelliteIsProvisioned) + } + .whenever(satelliteManager) + .requestIsProvisioned(any(), any()) + systemClock.setUptimeMillis(Process.getStartUptimeMillis() + uptime) underTest = |