Close all Push connections when Android connects to another network

When the default network changes Android usually kills connections established over the old network after a little while. K-9 Mail treats this as a regular network error and sleeps for 5 minutes before trying to re-establish the Push connection(s). Closing old connections and opening new ones when a network change is detected avoids this error.
This commit is contained in:
cketti 2021-07-04 21:27:38 +02:00
parent 830b358ff3
commit 95ecac8893
4 changed files with 40 additions and 3 deletions

View file

@ -49,6 +49,11 @@ internal class AccountPushController(
stopBackendPusher()
}
fun reconnect() {
Timber.v("AccountPushController(%s).reconnect()", account.uuid)
backendPusher?.reconnect()
}
private fun startBackendPusher() {
val backend = backendManager.getBackend(account)
backendPusher = backend.createPusher(backendPusherCallback).also { backendPusher ->

View file

@ -13,10 +13,11 @@ import com.fsck.k9.notification.PushNotificationState.WAIT_BACKGROUND_SYNC
import com.fsck.k9.notification.PushNotificationState.WAIT_NETWORK
import com.fsck.k9.preferences.BackgroundSync
import com.fsck.k9.preferences.GeneralSettingsManager
import java.util.concurrent.Executors
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
@ -38,7 +39,7 @@ class PushController internal constructor(
private val connectivityManager: ConnectivityManager,
private val accountPushControllerFactory: AccountPushControllerFactory,
private val coroutineScope: CoroutineScope = GlobalScope,
private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO
private val coroutineDispatcher: CoroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
) {
private val lock = Any()
private var initializationStarted = false
@ -47,7 +48,7 @@ class PushController internal constructor(
private val autoSyncListener = AutoSyncListener(::onAutoSyncChanged)
private val connectivityChangeListener = object : ConnectivityChangeListener {
override fun onConnectivityChanged() = this@PushController.onConnectivityChanged()
override fun onConnectivityLost() = this@PushController.onConnectivityChanged()
override fun onConnectivityLost() = this@PushController.onConnectivityLost()
}
/**
@ -98,6 +99,16 @@ class PushController internal constructor(
}
private fun onConnectivityChanged() {
coroutineScope.launch(coroutineDispatcher) {
synchronized(lock) {
for (accountPushController in pushers.values) {
accountPushController.reconnect()
}
}
}
}
private fun onConnectivityLost() {
launchUpdatePushers()
}

View file

@ -4,4 +4,5 @@ interface BackendPusher {
fun start()
fun updateFolders(folderServerIds: Collection<String>)
fun stop()
fun reconnect()
}

View file

@ -151,6 +151,26 @@ internal class ImapBackendPusher(
}
}
override fun reconnect() {
Timber.v("ImapBackendPusher.reconnect()")
synchronized(lock) {
for (pushFolder in pushFolders.values) {
pushFolder.stop()
}
pushFolders.clear()
for (retryTimer in pushFolderSleeping.values) {
retryTimer.cancel()
}
pushFolderSleeping.clear()
}
imapStore.closeAllConnections()
updateFolders()
}
private fun createImapFolderPusher(folderServerId: String): ImapFolderPusher {
return ImapFolderPusher(
imapStore,