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 71d4d6fc040e1ee3206b7e67e95a5a52efd6a2ff..f3906ab6abca857bd9378670943699c059a417bc 100644 --- a/app/core/src/main/java/com/fsck/k9/Account.kt +++ b/app/core/src/main/java/com/fsck/k9/Account.kt @@ -360,6 +360,10 @@ 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 e827460425df7812d20e08dc42929e8148fee139..4851915118773e86eeb2c0bf9d3515c7d3a2965b 100644 --- a/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt +++ b/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt @@ -54,6 +54,7 @@ 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) @@ -259,6 +260,7 @@ 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) @@ -549,6 +551,7 @@ 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/controller/push/PushController.kt b/app/core/src/main/java/com/fsck/k9/controller/push/PushController.kt index 9edc8b295cb760b942413cf2b3ce39cece3d19d3..a47dd70189094b6c4eec27046c71674a7f7a0d73 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 @@ -211,7 +211,7 @@ class PushController internal constructor( private fun getPushAccounts(): List { return preferences.accounts.filter { account -> - account.folderPushMode != FolderMode.NONE && backendManager.getBackend(account)?.isPushCapable ?: false + account.folderPushMode != FolderMode.NONE && account.backgroundSync && backendManager.getBackend(account)?.isPushCapable ?: false } } private fun setPushNotificationState(notificationState: PushNotificationState) { 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 3b317628df7a188a241afee45a561566bcffcc2f..057fa690927ed26d082aca6f24ebacd53e6404af 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 @@ -41,6 +41,11 @@ class MailSyncWorker( return Result.success() } + if (!account.backgroundSync) { + Timber.d("Mail sync is disable for this account. Skipping mail sync.") + return Result.success() + } + if (account.incomingServerSettings.isMissingCredentials) { Timber.d("Password for this account is missing. 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 77ea8abbc13369a502ae64c5a8f12d85499f5fdf..87df71d0c14d93c4b47599d0d02142620b5c679b 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 @@ -24,6 +24,10 @@ class MailSyncWorkerManager(private val workManager: WorkManager, val clock: Clo fun scheduleMailSync(account: Account) { if (isNeverSyncInBackground()) return + if (!account.backgroundSync) { + return + } + getSyncIntervalIfEnabled(account)?.let { syncIntervalMinutes -> Timber.v("Scheduling mail sync worker for %s", account) Timber.v(" sync interval: %d minutes", syncIntervalMinutes) diff --git a/app/core/src/main/java/com/fsck/k9/setup/AccountManagerConstants.kt b/app/core/src/main/java/com/fsck/k9/setup/AccountManagerConstants.kt index 368a5a2abb0a51a22b48397fa5a07ca8bd2b5ea6..b70aad6478f429b13042a57ab6a054e5d46a2f52 100644 --- a/app/core/src/main/java/com/fsck/k9/setup/AccountManagerConstants.kt +++ b/app/core/src/main/java/com/fsck/k9/setup/AccountManagerConstants.kt @@ -26,4 +26,6 @@ object AccountManagerConstants { const val OPEN_APP_PACKAGE_AFTER_AUTH = "open_app_package_after_auth" const val OPEN_APP_ACTIVITY_AFTER_AUTH = "open_app_activity_after_auth" + + const val IGNORE_ACCOUNT_SETUP = "ignore_account_setup" } diff --git a/app/k9mail/src/main/AndroidManifest.xml b/app/k9mail/src/main/AndroidManifest.xml index 5ab09c4ff1a6ed827933c070468ccf08b3659d95..ccb5349bc302c3b686a21f606a3aee4184461e32 100644 --- a/app/k9mail/src/main/AndroidManifest.xml +++ b/app/k9mail/src/main/AndroidManifest.xml @@ -344,6 +344,7 @@ + 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 ce18077553c243cf0bd1c72bb1963de692eeafcd..6a79dce9091c8e9c409684029979d11cfebd0c80 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 @@ -19,9 +19,11 @@ package com.fsck.k9.account import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import com.fsck.k9.Account 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 java.util.concurrent.Executors import org.koin.core.component.KoinComponent import org.koin.core.component.inject @@ -29,13 +31,19 @@ import org.koin.core.component.inject class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { companion object { - private const val ACCOUNT_CREATION_ACTION = "foundation.e.accountmanager.account.create" - private const val ACCOUNT_REMOVAL_ACTION = "foundation.e.accountmanager.account.remove" + 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_DISABLE_SYNC_ACTION = "$ACTION_PREFIX.disablesync" + + private const val ACCOUNT = "account" } private val pushController: PushController by inject() private val preferences: Preferences by inject() private val accountRemover: BackgroundAccountRemover by inject() + private val jobManager: K9JobManager by inject() override fun onReceive(context: Context?, intent: Intent?) { if (intent == null) { @@ -45,6 +53,7 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { when (intent.action) { ACCOUNT_CREATION_ACTION -> createNewAccount(context) ACCOUNT_REMOVAL_ACTION -> removeAccount(intent) + ACCOUNT_DISABLE_SYNC_ACTION -> disableSync(intent) } } @@ -56,6 +65,7 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { it.applicationContext, preferences, accountRemover, + jobManager, null ) } @@ -63,12 +73,27 @@ class AccountSyncReceiver : BroadcastReceiver(), KoinComponent { } private fun removeAccount(intent: Intent) { - val account = intent.extras?.getString("account") ?: return + val account = getAccount(intent) ?: return + 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 account = intent.extras?.getString(ACCOUNT) ?: return null + preferences.accounts.forEach { if (it.email == account) { - accountRemover.removeAccountAsync(it.uuid) - return@forEach + return it } } + + return null } } \ No newline at end of file diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt index e0fed2a76663c280220fde61d84aef0eaf8d9f07..83695f9addf957ba2d65828a08e719015f8e4bc2 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt @@ -61,6 +61,7 @@ import com.fsck.k9.fragment.MessageListFragment import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener import com.fsck.k9.helper.Contacts import com.fsck.k9.helper.ParcelableUtil +import com.fsck.k9.job.K9JobManager import com.fsck.k9.mailstore.SearchStatusManager import com.fsck.k9.preferences.GeneralSettingsManager import com.fsck.k9.search.LocalSearch @@ -69,6 +70,7 @@ import com.fsck.k9.search.SearchSpecification import com.fsck.k9.search.SearchSpecification.SearchCondition import com.fsck.k9.search.SearchSpecification.SearchField import com.fsck.k9.search.isUnifiedInbox +import com.fsck.k9.setup.AccountManagerConstants import com.fsck.k9.ui.BuildConfig import com.fsck.k9.ui.K9Drawer import com.fsck.k9.ui.R @@ -119,6 +121,7 @@ open class MessageList : private val accountRemover: BackgroundAccountRemover by inject() private val generalSettingsManager: GeneralSettingsManager by inject() private val messagingController: MessagingController by inject() + private val jobManager: K9JobManager by inject() private val permissionUiHelper: PermissionUiHelper = K9PermissionUiHelper(this) @@ -166,6 +169,12 @@ open class MessageList : super.onCreate(savedInstanceState) setLayout(R.layout.message_list_loading) + if (intent.getBooleanExtra(AccountManagerConstants.IGNORE_ACCOUNT_SETUP, false)) { + // no need to setup mail accounts for accountManager accounts + onAccountConfigurationFinish(savedInstanceState) + return + } + addNewAccountsAutomatically(savedInstanceState) } @@ -1446,7 +1455,7 @@ open class MessageList : private fun addNewAccountsAutomatically(savedInstanceState: Bundle?) { lifecycleScope.launch(Dispatchers.IO) { - EeloAccountCreator.loadAccountsFromAccountManager(applicationContext, preferences, accountRemover) { + EeloAccountCreator.loadAccountsFromAccountManager(applicationContext, preferences, accountRemover, jobManager) { lifecycleScope.launch(Dispatchers.Main) { onAccountConfigurationFinish(savedInstanceState) } 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 bcfe1ec6d6784d9a859a5b4e38ef4b0e3c3bfbeb..56cde0a6b7acdc574c964b4782f41bfa2eaa3822 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 @@ -20,6 +20,7 @@ package com.fsck.k9.activity.setup.accountmanager; import java.util.List; import android.accounts.AccountManager; +import android.content.ContentResolver; import android.content.Context; import android.os.Build.VERSION_CODES; @@ -38,6 +39,7 @@ import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings; import com.fsck.k9.autodiscovery.api.DiscoveryResults; import com.fsck.k9.autodiscovery.api.DiscoveryTarget; import com.fsck.k9.autodiscovery.providersxml.ProvidersXmlDiscovery; +import com.fsck.k9.job.K9JobManager; import com.fsck.k9.mail.AuthType; import com.fsck.k9.mail.ConnectionSecurity; import com.fsck.k9.mail.ServerSettings; @@ -56,15 +58,15 @@ public class EeloAccountCreator { @RequiresApi(api = VERSION_CODES.N) @WorkerThread public static void loadAccountsFromAccountManager(@NonNull Context context, @NonNull Preferences preferences, - @NonNull BackgroundAccountRemover accountRemover, @Nullable OnAccountLoadCompleteCallBack callBack) { + @NonNull BackgroundAccountRemover accountRemover, @NonNull K9JobManager jobManager, @Nullable OnAccountLoadCompleteCallBack callBack) { try { AccountManager accountManager = AccountManager.get(context); List accounts = preferences.getAccounts(); deleteIncompleteAccounts(accounts, accountRemover); - loadEeloAccounts(context, accounts, accountManager); - loadGoogleAccounts(context, accounts, accountManager); + loadEeloAccounts(context, accounts, accountManager, jobManager); + loadGoogleAccounts(context, accounts, accountManager, jobManager); } catch (SecurityException e) { Timber.e(e, "Failed to load accounts from accountManager because of security violation"); } @@ -73,9 +75,23 @@ public class EeloAccountCreator { } } + // check the account sync for mail authority is enable or not + private static boolean isSyncable(@Nullable android.accounts.Account account) { + if (account == null) { + return false; + } + + // if master sync disable, then account sync is disable + if (!ContentResolver.getMasterSyncAutomatically()) { + return false; + } + + return ContentResolver.getSyncAutomatically(account, AccountManagerConstants.MAIL_CONTENT_AUTHORITY); + } + @RequiresApi(api = VERSION_CODES.N) private static void loadGoogleAccounts(@NonNull Context context, List accounts, - @NonNull AccountManager accountManager) { + @NonNull AccountManager accountManager, @NonNull K9JobManager jobManager) { android.accounts.Account[] googleAccounts = accountManager.getAccountsByType(AccountManagerConstants.GOOGLE_ACCOUNT_TYPE); for (android.accounts.Account googleAccount : googleAccounts) { @@ -85,14 +101,22 @@ public class EeloAccountCreator { continue; } - boolean accountAlreadyPresent = accounts.stream() + if (!isSyncable(googleAccount)) { + continue; + } + + var existenceAccount = accounts.stream() .filter(account -> emailId.equalsIgnoreCase(account.getEmail())) .peek(account -> updateAccountNameIfMissing(context, emailId, account)) - .findAny().isPresent(); - if (!accountAlreadyPresent) { + .findAny(); + + if (!existenceAccount.isPresent()) { String authState = accountManager.getUserData(googleAccount, AccountManagerConstants.KEY_AUTH_STATE); createAccount(context, emailId, "", authState); + continue; } + + enableSync(jobManager, existenceAccount.get()); } } @@ -109,23 +133,43 @@ public class EeloAccountCreator { @RequiresApi(api = VERSION_CODES.N) private static void loadEeloAccounts(@NonNull Context context, List accounts, - @NonNull AccountManager accountManager) { + @NonNull AccountManager accountManager, @NonNull K9JobManager jobManager) { android.accounts.Account[] eeloAccounts = accountManager.getAccountsByType(AccountManagerConstants.EELO_ACCOUNT_TYPE); for (android.accounts.Account eeloAccount : eeloAccounts) { - String emailId = - accountManager.getUserData(eeloAccount, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY); + String emailId = accountManager.getUserData(eeloAccount, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY); if (isInvalidEmail(emailId)) { continue; } - boolean isNewAccount = accounts.stream() - .noneMatch(account -> emailId.equalsIgnoreCase(account.getEmail())); - if (isNewAccount) { + if (!isSyncable(eeloAccount)) { + continue; + } + + var existenceAccount = accounts.stream() + .filter(account -> emailId.equalsIgnoreCase(account.getEmail())) + .findAny(); + + if (!existenceAccount.isPresent()) { String password = accountManager.getPassword(eeloAccount); createAccount(context, emailId, password, null); + continue; } + + enableSync(jobManager, existenceAccount.get()); + } + } + + // 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)