Repository: thundernest/k-9
Issue: K-9 Mail draining battery after latest update

There's been a significant increase in battery usage after the latest update. K-9 Mail is now #1 in the battery usage list on my device

Changed files:
backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapFolderPusher.kt
app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapPusherCallback.kt
app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackendPusher.kt
app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
backend/api/src/main/java/com/fsck/k9/backend/api/BackendPusherCallback.kt

diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
index a3df472ca..862770084 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
@@ -1,6 +1,8 @@
 package com.fsck.k9.controller.push
 
 import com.fsck.k9.Account
+import com.fsck.k9.Account.FolderMode
+import com.fsck.k9.Preferences
 import com.fsck.k9.backend.BackendManager
 import com.fsck.k9.backend.api.BackendPusher
 import com.fsck.k9.backend.api.BackendPusherCallback
@@ -17,6 +19,7 @@ import timber.log.Timber
 internal class AccountPushController(
     private val backendManager: BackendManager,
     private val messagingController: MessagingController,
+    private val preferences: Preferences,
     folderRepositoryManager: FolderRepositoryManager,
     backgroundDispatcher: CoroutineDispatcher = Dispatchers.IO,
     private val account: Account
@@ -35,6 +38,11 @@ internal class AccountPushController(
         override fun onPushError(exception: Exception) {
             messagingController.handleException(account, exception)
         }
+
+        override fun onPushNotSupported() {
+            Timber.v("AccountPushController(%s) - Push not supported. Disabling Push for account.", account.uuid)
+            disablePush()
+        }
     }
 
     fun start() {
@@ -88,4 +96,9 @@ internal class AccountPushController(
     private fun syncFolders(folderServerId: String) {
         messagingController.synchronizeMailboxBlocking(account, folderServerId)
     }
+
+    private fun disablePush() {
+        account.folderPushMode = FolderMode.NONE
+        preferences.saveAccount(account)
+    }
 }
diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
index 9a083a45e..89ae3bef1 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
@@ -1,6 +1,7 @@
 package com.fsck.k9.controller.push
 
 import com.fsck.k9.Account
+import com.fsck.k9.Preferences
 import com.fsck.k9.backend.BackendManager
 import com.fsck.k9.controller.MessagingController
 import com.fsck.k9.mailstore.FolderRepositoryManager
@@ -8,9 +9,16 @@ import com.fsck.k9.mailstore.FolderRepositoryManager
 internal class AccountPushControllerFactory(
     private val backendManager: BackendManager,
     private val messagingController: MessagingController,
-    private val folderRepositoryManager: FolderRepositoryManager
+    private val folderRepositoryManager: FolderRepositoryManager,
+    private val preferences: Preferences
 ) {
     fun create(account: Account): AccountPushController {
-        return AccountPushController(backendManager, messagingController, folderRepositoryManager, account = account)
+        return AccountPushController(
+            backendManager,
+            messagingController,
+            preferences,
+            folderRepositoryManager,
+            account = account
+        )
     }
 }
diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
index 146eec236..7a7a6441c 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
@@ -10,7 +10,8 @@ internal val controllerPushModule = module {
         AccountPushControllerFactory(
             backendManager = get(),
             messagingController = get(),
-            folderRepositoryManager = get()
+            folderRepositoryManager = get(),
+            preferences = get()
         )
     }
     single {
diff --git a/backend/api/src/main/java/com/fsck/k9/backend/api/BackendPusherCallback.kt b/backend/api/src/main/java/com/fsck/k9/backend/api/BackendPusherCallback.kt
index bf159bf9d..d503bb701 100644
--- a/backend/api/src/main/java/com/fsck/k9/backend/api/BackendPusherCallback.kt
+++ b/backend/api/src/main/java/com/fsck/k9/backend/api/BackendPusherCallback.kt
@@ -3,4 +3,5 @@ package com.fsck.k9.backend.api
 interface BackendPusherCallback {
     fun onPushEvent(folderServerId: String)
     fun onPushError(exception: Exception)
+    fun onPushNotSupported()
 }
diff --git a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackendPusher.kt b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackendPusher.kt
index 76e1650d0..96c68da54 100644
--- a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackendPusher.kt
+++ b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackendPusher.kt
@@ -226,6 +226,10 @@ internal class ImapBackendPusher(
         }
     }
 
+    override fun onPushNotSupported() {
+        callback.onPushNotSupported()
+    }
+
     private fun startRetryTimer(folderServerId: String, timeout: Long) {
         Timber.v("ImapBackendPusher for folder %s sleeping for %d ms", folderServerId, timeout)
         pushFolderSleeping[folderServerId] = idleRefreshManager.startTimer(timeout, ::restartFolderPushers)
diff --git a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapFolderPusher.kt b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapFolderPusher.kt
index be83bb60a..f9c4c4516 100644
--- a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapFolderPusher.kt
+++ b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapFolderPusher.kt
@@ -70,10 +70,19 @@ class ImapFolderPusher(
 
         try {
             while (!stopPushing) {
-                val idleResult = folderIdler.idle()
-
-                if (idleResult == IdleResult.SYNC) {
-                    callback.onPushEvent(folderServerId)
+                when (folderIdler.idle()) {
+                    IdleResult.SYNC -> {
+                        callback.onPushEvent(folderServerId)
+                    }
+                    IdleResult.STOPPED -> {
+                        // ImapFolderIdler only stops when we ask it to.
+                        // But it can't hurt to make extra sure we exit the loop.
+                        stopPushing = true
+                    }
+                    IdleResult.NOT_SUPPORTED -> {
+                        stopPushing = true
+                        callback.onPushNotSupported()
+                    }
                 }
             }
         } catch (e: Exception) {
diff --git a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapPusherCallback.kt b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapPusherCallback.kt
index ebbc084d8..642668e62 100644
--- a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapPusherCallback.kt
+++ b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapPusherCallback.kt
@@ -3,4 +3,5 @@ package com.fsck.k9.backend.imap
 interface ImapPusherCallback {
     fun onPushEvent(folderServerId: String)
     fun onPushError(folderServerId: String, exception: Exception)
+    fun onPushNotSupported()
 }