diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/network/NetworkStateProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/network/NetworkStateProvider.kt index 6a550115de27fbb85d6d041c16a9793219323d80..e74c06d654b8431e4692e9e214b37f8c91a297e2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/network/NetworkStateProvider.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/network/NetworkStateProvider.kt @@ -40,23 +40,26 @@ class NetworkStateProvider @Inject constructor( val networkState: Flow<State> = callbackFlow { send(currentState) - val callback = object : ConnectivityManager.NetworkCallback() { - override fun onAvailable(network: Network) { - Timber.tag(TAG).v("onAvailable(network=%s)", network) - appScope.launch { send(currentState) } - } - - override fun onUnavailable() { - Timber.tag(TAG).v("onUnavailable()") - appScope.launch { send(currentState) } - } - } val request = networkRequestBuilderProvider.get() .addCapability(NET_CAPABILITY_INTERNET) .build() + var registeredCallback: ConnectivityManager.NetworkCallback? = null + try { + val callback = object : ConnectivityManager.NetworkCallback() { + override fun onAvailable(network: Network) { + Timber.tag(TAG).v("onAvailable(network=%s)", network) + appScope.launch { send(currentState) } + } + + override fun onUnavailable() { + Timber.tag(TAG).v("onUnavailable()") + appScope.launch { send(currentState) } + } + } + /** * This may throw java.lang.SecurityException on Samsung devices * java.lang.SecurityException: @@ -64,6 +67,7 @@ class NetworkStateProvider @Inject constructor( * at android.net.ConnectivityManager.registerNetworkCallback (ConnectivityManager.java:4564) */ manager.registerNetworkCallback(request, callback) + registeredCallback = callback } catch (e: SecurityException) { Timber.e(e, "registerNetworkCallback() threw an undocumented SecurityException, Just Samsung Thingsâ„¢ï¸") State( @@ -82,8 +86,8 @@ class NetworkStateProvider @Inject constructor( } awaitClose { - Timber.tag(TAG).v("unregisterNetworkCallback()") - manager.unregisterNetworkCallback(callback) + Timber.tag(TAG).v("unregisterNetworkCallback(%s)", registeredCallback) + registeredCallback?.let { manager.unregisterNetworkCallback(it) } fakeConnectionSubscriber.cancel() } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/network/NetworkStateProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/network/NetworkStateProviderTest.kt index 76c94e5083dd30a0c300bc1732680bd34d53842d..104e1d6e9b5ead4e8201798cccf725b94fdd3499 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/network/NetworkStateProviderTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/network/NetworkStateProviderTest.kt @@ -237,4 +237,33 @@ class NetworkStateProviderTest : BaseTest() { linkProperties = null ).isMeteredConnection shouldBe true } + + @Test + fun `if we fail to register the callback, we do not attempt to unregister it`() = + runBlockingTest2(ignoreActive = true) { + every { + conMan.registerNetworkCallback( + any(), + any<ConnectivityManager.NetworkCallback>() + ) + } throws SecurityException() + + val instance = createInstance(this) + + instance.networkState.first() shouldBe NetworkStateProvider.State( + activeNetwork = null, + capabilities = null, + linkProperties = null + ) + + advanceUntilIdle() + + verifySequence { + conMan.activeNetwork + conMan.getNetworkCapabilities(network) + conMan.getLinkProperties(network) + conMan.registerNetworkCallback(networkRequest, any<ConnectivityManager.NetworkCallback>()) + } + verify(exactly = 0) { conMan.unregisterNetworkCallback(any<ConnectivityManager.NetworkCallback>()) } + } }