From 3410b5fac10f6f23fd77e2b1bc0860d277822551 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Tue, 20 Dec 2022 15:03:01 +0600 Subject: [PATCH 1/3] Replace onAccountRemove broadcast action issue: https://gitlab.e.foundation/e/os/backlog/-/issues/922 use os broadcast action for account remove so little modification in Settings & AccountManager app is needed. --- app/k9mail/src/main/AndroidManifest.xml | 2 +- .../com/fsck/k9/account/AccountSyncReceiver.kt | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/k9mail/src/main/AndroidManifest.xml b/app/k9mail/src/main/AndroidManifest.xml index c6fccb39d3..84e3466bcd 100644 --- a/app/k9mail/src/main/AndroidManifest.xml +++ b/app/k9mail/src/main/AndroidManifest.xml @@ -329,7 +329,7 @@ android:exported="true"> - + diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt index 6a79dce909..1874018a37 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt @@ -16,6 +16,7 @@ package com.fsck.k9.account +import android.accounts.AccountManager import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -24,9 +25,11 @@ import com.fsck.k9.Preferences import com.fsck.k9.activity.setup.accountmanager.EeloAccountCreator import com.fsck.k9.controller.push.PushController import com.fsck.k9.job.K9JobManager +import com.fsck.k9.setup.AccountManagerConstants import java.util.concurrent.Executors import org.koin.core.component.KoinComponent import org.koin.core.component.inject +import timber.log.Timber class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { @@ -34,10 +37,10 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { private const val ACTION_PREFIX = "foundation.e.accountmanager.account" private const val ACCOUNT_CREATION_ACTION = "$ACTION_PREFIX.create" - private const val ACCOUNT_REMOVAL_ACTION = "$ACTION_PREFIX.remove" + private const val ACCOUNT_REMOVAL_ACTION = "android.accounts.action.ACCOUNT_REMOVED" private const val ACCOUNT_DISABLE_SYNC_ACTION = "$ACTION_PREFIX.disablesync" - private const val ACCOUNT = "account" + private val ACCOUNT_TYPES = listOf(AccountManagerConstants.EELO_ACCOUNT_TYPE, AccountManagerConstants.GOOGLE_ACCOUNT_TYPE) } private val pushController: PushController by inject() @@ -86,7 +89,13 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { private fun getAccount(intent: Intent) : Account? { - val account = intent.extras?.getString(ACCOUNT) ?: return null + val accountType = intent.extras?.getString(AccountManager.KEY_ACCOUNT_TYPE) + + if (!ACCOUNT_TYPES.contains(accountType)) { + return null + } + + val account = intent.extras?.getString(AccountManager.KEY_ACCOUNT_NAME) ?: return null preferences.accounts.forEach { if (it.email == account) { -- GitLab From 664a9594312e38a7f40708eb29d3c23c19a7e51c Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Tue, 20 Dec 2022 20:15:44 +0600 Subject: [PATCH 2/3] Update disable/enable sync logic for osAccontManagaer accounts issue: https://gitlab.e.foundation/e/os/backlog/-/issues/922 --- app/core/src/main/java/com/fsck/k9/Account.kt | 4 -- .../fsck/k9/AccountPreferenceSerializer.kt | 3 - .../java/com/fsck/k9/OsAccountManagerUtil.kt | 67 +++++++++++++++++++ .../com/fsck/k9/controller/push/KoinModule.kt | 3 +- .../fsck/k9/controller/push/PushController.kt | 7 +- .../main/java/com/fsck/k9/job/KoinModule.kt | 2 +- .../java/com/fsck/k9/job/MailSyncWorker.kt | 3 +- .../com/fsck/k9/job/MailSyncWorkerManager.kt | 6 +- app/k9mail/src/main/AndroidManifest.xml | 1 - .../fsck/k9/account/AccountSyncReceiver.kt | 10 --- .../accountmanager/EeloAccountCreator.java | 16 +---- 11 files changed, 83 insertions(+), 39 deletions(-) create mode 100644 app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt diff --git a/app/core/src/main/java/com/fsck/k9/Account.kt b/app/core/src/main/java/com/fsck/k9/Account.kt index f3906ab6ab..71d4d6fc04 100644 --- a/app/core/src/main/java/com/fsck/k9/Account.kt +++ b/app/core/src/main/java/com/fsck/k9/Account.kt @@ -360,10 +360,6 @@ class Account(override val uuid: String) : BaseAccount { @set:Synchronized var messagesNotificationChannelVersion = 0 - @get:Synchronized - @set:Synchronized - var backgroundSync = true - @get:Synchronized @set:Synchronized var isChangedVisibleLimits = false diff --git a/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt b/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt index 4851915118..e827460425 100644 --- a/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt +++ b/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt @@ -54,7 +54,6 @@ class AccountPreferenceSerializer( isIgnoreChatMessages = storage.getBoolean("$accountUuid.ignoreChatMessages", false) isNotifySync = storage.getBoolean("$accountUuid.notifyMailCheck", false) messagesNotificationChannelVersion = storage.getInt("$accountUuid.messagesNotificationChannelVersion", 0) - backgroundSync = storage.getBoolean("$accountUuid.backgroundSync", true) deletePolicy = DeletePolicy.fromInt(storage.getInt("$accountUuid.deletePolicy", DeletePolicy.NEVER.setting)) legacyInboxFolder = storage.getString("$accountUuid.inboxFolderName", null) importedDraftsFolder = storage.getString("$accountUuid.draftsFolderName", null) @@ -260,7 +259,6 @@ class AccountPreferenceSerializer( editor.putBoolean("$accountUuid.ignoreChatMessages", isIgnoreChatMessages) editor.putBoolean("$accountUuid.notifyMailCheck", isNotifySync) editor.putInt("$accountUuid.messagesNotificationChannelVersion", messagesNotificationChannelVersion) - editor.putBoolean("$accountUuid.backgroundSync", backgroundSync) editor.putInt("$accountUuid.deletePolicy", deletePolicy.setting) editor.putString("$accountUuid.inboxFolderName", legacyInboxFolder) editor.putString("$accountUuid.draftsFolderName", importedDraftsFolder) @@ -551,7 +549,6 @@ class AccountPreferenceSerializer( isNotifyContactsMailOnly = false isIgnoreChatMessages = false messagesNotificationChannelVersion = 0 - backgroundSync = true folderDisplayMode = FolderMode.NOT_SECOND_CLASS folderSyncMode = FolderMode.FIRST_CLASS folderPushMode = FolderMode.ALL diff --git a/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt b/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt new file mode 100644 index 0000000000..f8b3b105fe --- /dev/null +++ b/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt @@ -0,0 +1,67 @@ +/* + * Copyright MURENA SAS 2022 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.fsck.k9 + +import android.accounts.Account +import android.accounts.AccountManager +import android.content.ContentResolver +import android.content.Context +import com.fsck.k9.setup.AccountManagerConstants +import timber.log.Timber + +object OsAccountManagerUtil { + + /** + * @return syncEnable or not. If account not found in accountManager accounts, + * means account is setup by user... so return true by default + */ + fun isSyncEnable(context: Context, email: String): Boolean { + val accountManager = AccountManager.get(context) + val murenaAccounts = accountManager.getAccountsByType(AccountManagerConstants.EELO_ACCOUNT_TYPE) + + val syncEnable = isSyncEnable(accountManager, murenaAccounts, email) + + if (syncEnable != null) { + return syncEnable + } + + val googleAccounts = accountManager.getAccountsByType(AccountManagerConstants.GOOGLE_ACCOUNT_TYPE) + + return isSyncEnable(accountManager, googleAccounts, email) ?: true + } + + /** + * @return Boolean if sync is enable/disable. null if no account found + */ + private fun isSyncEnable(accountManager: AccountManager, accounts: Array, email: String): Boolean? { + accounts.forEach { + try { + val accountEmail: String = accountManager.getUserData(it, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY) + if (accountEmail == email) { + // if master sync disable, then account sync is disable + return if (!ContentResolver.getMasterSyncAutomatically()) { + false + } else ContentResolver.getSyncAutomatically(it, AccountManagerConstants.MAIL_CONTENT_AUTHORITY) + } + } catch (e: Throwable) { + Timber.e(e) + } + } + + return null + } +} \ No newline at end of file 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 b8046a970d..86b0ae1227 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 @@ -24,7 +24,8 @@ internal val controllerPushModule = module { autoSyncManager = get(), pushNotificationManager = get(), connectivityManager = get(), - accountPushControllerFactory = get() + accountPushControllerFactory = get(), + context = get() ) } } diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/PushController.kt b/app/core/src/main/java/com/fsck/k9/controller/push/PushController.kt index a47dd70189..206ae84221 100644 --- a/app/core/src/main/java/com/fsck/k9/controller/push/PushController.kt +++ b/app/core/src/main/java/com/fsck/k9/controller/push/PushController.kt @@ -1,7 +1,9 @@ package com.fsck.k9.controller.push +import android.content.Context import com.fsck.k9.Account import com.fsck.k9.Account.FolderMode +import com.fsck.k9.OsAccountManagerUtil import com.fsck.k9.Preferences import com.fsck.k9.backend.BackendManager import com.fsck.k9.network.ConnectivityChangeListener @@ -39,7 +41,8 @@ class PushController internal constructor( private val connectivityManager: ConnectivityManager, private val accountPushControllerFactory: AccountPushControllerFactory, private val coroutineScope: CoroutineScope = GlobalScope, - private val coroutineDispatcher: CoroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher() + private val coroutineDispatcher: CoroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher(), + private val context: Context ) { private val lock = Any() private var initializationStarted = false @@ -211,7 +214,7 @@ class PushController internal constructor( private fun getPushAccounts(): List { return preferences.accounts.filter { account -> - account.folderPushMode != FolderMode.NONE && account.backgroundSync && backendManager.getBackend(account)?.isPushCapable ?: false + account.folderPushMode != FolderMode.NONE && OsAccountManagerUtil.isSyncEnable(context, account.email) && backendManager.getBackend(account)?.isPushCapable ?: false } } private fun setPushNotificationState(notificationState: PushNotificationState) { diff --git a/app/core/src/main/java/com/fsck/k9/job/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/job/KoinModule.kt index 4dd6f0e8fa..40df51b649 100644 --- a/app/core/src/main/java/com/fsck/k9/job/KoinModule.kt +++ b/app/core/src/main/java/com/fsck/k9/job/KoinModule.kt @@ -8,5 +8,5 @@ val jobModule = module { single { K9WorkerFactory(get(), get()) } single { get().getWorkManager() } single { K9JobManager(get(), get(), get()) } - factory { MailSyncWorkerManager(workManager = get(), clock = get()) } + factory { MailSyncWorkerManager(workManager = get(), clock = get(), context = get()) } } diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt index 057fa69092..e39d6404d3 100644 --- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt +++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt @@ -6,6 +6,7 @@ import androidx.work.Worker import androidx.work.WorkerParameters import com.fsck.k9.Account import com.fsck.k9.K9 +import com.fsck.k9.OsAccountManagerUtil import com.fsck.k9.Preferences import com.fsck.k9.controller.MessagingController import com.fsck.k9.mail.AuthType @@ -41,7 +42,7 @@ class MailSyncWorker( return Result.success() } - if (!account.backgroundSync) { + if (!OsAccountManagerUtil.isSyncEnable(context, account.email)) { Timber.d("Mail sync is disable for this account. Skipping mail sync.") return Result.success() } diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt index 87df71d0c1..81e655fa0a 100644 --- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt +++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorkerManager.kt @@ -1,5 +1,6 @@ package com.fsck.k9.job +import android.content.Context import androidx.work.BackoffPolicy import androidx.work.Constraints import androidx.work.ExistingPeriodicWorkPolicy @@ -10,10 +11,11 @@ import androidx.work.workDataOf import com.fsck.k9.Account import com.fsck.k9.Clock import com.fsck.k9.K9 +import com.fsck.k9.OsAccountManagerUtil import java.util.concurrent.TimeUnit import timber.log.Timber -class MailSyncWorkerManager(private val workManager: WorkManager, val clock: Clock) { +class MailSyncWorkerManager(private val workManager: WorkManager, val clock: Clock, private val context: Context) { fun cancelMailSync(account: Account) { Timber.v("Canceling mail sync worker for %s", account) @@ -24,7 +26,7 @@ class MailSyncWorkerManager(private val workManager: WorkManager, val clock: Clo fun scheduleMailSync(account: Account) { if (isNeverSyncInBackground()) return - if (!account.backgroundSync) { + if (!OsAccountManagerUtil.isSyncEnable(context, account.email)) { return } diff --git a/app/k9mail/src/main/AndroidManifest.xml b/app/k9mail/src/main/AndroidManifest.xml index 84e3466bcd..4100e6b82d 100644 --- a/app/k9mail/src/main/AndroidManifest.xml +++ b/app/k9mail/src/main/AndroidManifest.xml @@ -330,7 +330,6 @@ - diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt index 1874018a37..a1f9617c80 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountSyncReceiver.kt @@ -38,7 +38,6 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { private const val ACCOUNT_CREATION_ACTION = "$ACTION_PREFIX.create" private const val ACCOUNT_REMOVAL_ACTION = "android.accounts.action.ACCOUNT_REMOVED" - private const val ACCOUNT_DISABLE_SYNC_ACTION = "$ACTION_PREFIX.disablesync" private val ACCOUNT_TYPES = listOf(AccountManagerConstants.EELO_ACCOUNT_TYPE, AccountManagerConstants.GOOGLE_ACCOUNT_TYPE) } @@ -56,7 +55,6 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { when (intent.action) { ACCOUNT_CREATION_ACTION -> createNewAccount(context) ACCOUNT_REMOVAL_ACTION -> removeAccount(intent) - ACCOUNT_DISABLE_SYNC_ACTION -> disableSync(intent) } } @@ -80,14 +78,6 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { accountRemover.removeAccountAsync(account.uuid) } - private fun disableSync(intent: Intent) { - val account = getAccount(intent) ?: return - account.backgroundSync = false - preferences.saveAccount(account) - jobManager.scheduleAllMailJobs() - } - - private fun getAccount(intent: Intent) : Account? { val accountType = intent.extras?.getString(AccountManager.KEY_ACCOUNT_TYPE) diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloAccountCreator.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloAccountCreator.java index da1d29a030..897b21dd3d 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloAccountCreator.java +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/accountmanager/EeloAccountCreator.java @@ -115,7 +115,7 @@ public class EeloAccountCreator { continue; } - enableSync(jobManager, existenceAccount.get()); + jobManager.scheduleAllMailJobs(); } } @@ -155,22 +155,10 @@ public class EeloAccountCreator { continue; } - enableSync(jobManager, existenceAccount.get()); + jobManager.scheduleAllMailJobs(); } } - // enable account sync if not already enabled - private static void enableSync(@NonNull K9JobManager jobManager, @NonNull Account account) { - // sync is already enabled, ignore - if (account.getBackgroundSync()) { - return; - } - - account.setBackgroundSync(true); - Preferences.getPreferences().saveAccount(account); - jobManager.scheduleAllMailJobs(); - } - @RequiresApi(api = VERSION_CODES.N) private static void deleteIncompleteAccounts(List accounts, BackgroundAccountRemover accountRemover) { accounts.stream().filter(account -> !account.isFinishedSetup()) -- GitLab From 6ed672a6da88a46db803b99587863de680bf2a4c Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Wed, 21 Dec 2022 15:17:27 +0600 Subject: [PATCH 3/3] Add enum return type for OSAccountManagerUtil.isSyncEnable method for better understanding --- .../java/com/fsck/k9/OsAccountManagerUtil.kt | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt b/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt index f8b3b105fe..9229ca2565 100644 --- a/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt +++ b/app/core/src/main/java/com/fsck/k9/OsAccountManagerUtil.kt @@ -31,37 +31,51 @@ object OsAccountManagerUtil { */ fun isSyncEnable(context: Context, email: String): Boolean { val accountManager = AccountManager.get(context) - val murenaAccounts = accountManager.getAccountsByType(AccountManagerConstants.EELO_ACCOUNT_TYPE) - - val syncEnable = isSyncEnable(accountManager, murenaAccounts, email) - if (syncEnable != null) { - return syncEnable + val murenaAccounts = accountManager.getAccountsByType(AccountManagerConstants.EELO_ACCOUNT_TYPE) + var syncEnable = isSyncEnable(accountManager, murenaAccounts, email) + if (syncEnable.isAccountFound()) { + return syncEnable.getStatus() } val googleAccounts = accountManager.getAccountsByType(AccountManagerConstants.GOOGLE_ACCOUNT_TYPE) + syncEnable = isSyncEnable(accountManager, googleAccounts, email) + if (syncEnable.isAccountFound()) { + return syncEnable.getStatus() + } - return isSyncEnable(accountManager, googleAccounts, email) ?: true + return true } - /** - * @return Boolean if sync is enable/disable. null if no account found - */ - private fun isSyncEnable(accountManager: AccountManager, accounts: Array, email: String): Boolean? { + private fun isSyncEnable(accountManager: AccountManager, accounts: Array, email: String): Syncable { accounts.forEach { try { val accountEmail: String = accountManager.getUserData(it, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY) if (accountEmail == email) { // if master sync disable, then account sync is disable return if (!ContentResolver.getMasterSyncAutomatically()) { - false - } else ContentResolver.getSyncAutomatically(it, AccountManagerConstants.MAIL_CONTENT_AUTHORITY) + Syncable.NOT_SYNCABLE + } else Syncable.getSyncable(ContentResolver.getSyncAutomatically(it, AccountManagerConstants.MAIL_CONTENT_AUTHORITY)) } } catch (e: Throwable) { Timber.e(e) } } - return null + return Syncable.ACCOUNT_NOT_FOUND + } + + private enum class Syncable { + SYNCABLE, + NOT_SYNCABLE, + ACCOUNT_NOT_FOUND; + + companion object { + fun getSyncable(status: Boolean) = if (status) SYNCABLE else NOT_SYNCABLE + } + + fun getStatus() = this == SYNCABLE + + fun isAccountFound() = this != ACCOUNT_NOT_FOUND } } \ No newline at end of file -- GitLab