diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index 8fc4f9c04efd7600cd4d35c76fcd629da4ab6e11..94a9678f1ef66977be44dbdd25a9fbcbe2f46e98 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -28,6 +28,7 @@ import android.os.SystemClock;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import androidx.work.ListenableWorker.Result;
import com.fsck.k9.Account;
import com.fsck.k9.Account.DeletePolicy;
import com.fsck.k9.Account.Expunge;
@@ -2243,7 +2244,7 @@ public class MessagingController {
return !backend.getSupportsTrashFolder();
}
- public boolean performPeriodicMailSync(Account account) {
+ public Result performPeriodicMailSync(Account account) {
final CountDownLatch latch = new CountDownLatch(1);
MutableBoolean syncError = new MutableBoolean(false);
checkMail(account, false, false, true, new SimpleMessagingListener() {
@@ -2269,13 +2270,17 @@ public class MessagingController {
boolean success = !syncError.getValue();
if (success) {
+ if (preferences.getAccount(account.getUuid()) == null) {
+ Timber.e("Account %s not present. Can't perform mail sync.", account.getUuid());
+ return Result.failure();
+ }
long now = System.currentTimeMillis();
Timber.v("Account %s successfully synced @ %tc", account, now);
account.setLastSyncTime(now);
preferences.saveAccount(account);
}
- return success;
+ return success ? Result.success() : Result.retry();
}
/**
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 193c24a5ccc6c2eb8d86b8ba6a47dd43bcd551a2..d24ee920f3137770d7117aa341890dc58dcbeaac 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
@@ -44,9 +44,7 @@ class MailSyncWorker(
return Result.success()
}
- val success = messagingController.performPeriodicMailSync(account)
-
- return if (success) Result.success() else Result.retry()
+ return messagingController.performPeriodicMailSync(account)
}
private fun isBackgroundSyncDisabled(): Boolean {
diff --git a/app/k9mail/src/main/AndroidManifest.xml b/app/k9mail/src/main/AndroidManifest.xml
index 575306f922f42d9c7c7989c82b9d2a75223af114..58f4db6613fbcb3a2129a686a6d601d14e41cb55 100644
--- a/app/k9mail/src/main/AndroidManifest.xml
+++ b/app/k9mail/src/main/AndroidManifest.xml
@@ -343,6 +343,15 @@
+
+
+
+
+
+
+
.
+ */
+
+package com.fsck.k9.account
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import com.fsck.k9.Preferences
+import com.fsck.k9.activity.setup.accountmanager.EeloAccountCreator
+import com.fsck.k9.controller.push.PushController
+import java.util.concurrent.Executors
+import org.koin.core.component.KoinComponent
+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 val pushController: PushController by inject()
+ private val preferences: Preferences by inject()
+ private val accountRemover: BackgroundAccountRemover by inject()
+
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (intent == null) {
+ return
+ }
+
+ when (intent.action) {
+ ACCOUNT_CREATION_ACTION -> createNewAccount(context)
+ ACCOUNT_REMOVAL_ACTION -> removeAccount(intent)
+ }
+ }
+
+ private fun createNewAccount(context: Context?) {
+ pushController.init()
+ context?.let {
+ Executors.newSingleThreadExecutor().execute {
+ EeloAccountCreator.loadAccountsFromAccountManager(
+ it.applicationContext,
+ preferences,
+ accountRemover,
+ null
+ )
+ }
+ }
+ }
+
+ private fun removeAccount(intent: Intent) {
+ val account = intent.extras?.getString("account") ?: return
+ preferences.accounts.forEach {
+ if (it.email == account) {
+ accountRemover.removeAccountAsync(it.uuid)
+ return@forEach
+ }
+ }
+ }
+}
\ 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 19c1aecf2e373e9df275a34ccca7aa6dc8defe55..ee593e734433c1569ea99066a3a8cb5b0eb3d4b7 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
@@ -16,7 +16,6 @@
package com.fsck.k9.activity
-import android.accounts.AccountManager
import android.annotation.SuppressLint
import android.app.SearchManager
import android.content.Context
@@ -53,9 +52,6 @@ import com.fsck.k9.Preferences
import com.fsck.k9.account.BackgroundAccountRemover
import com.fsck.k9.activity.compose.MessageActions
import com.fsck.k9.activity.setup.AccountSetupBasics
-import com.fsck.k9.activity.setup.accountmanager.AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY
-import com.fsck.k9.activity.setup.accountmanager.AccountManagerConstants.EELO_ACCOUNT_TYPE
-import com.fsck.k9.activity.setup.accountmanager.AccountManagerConstants.GOOGLE_ACCOUNT_TYPE
import com.fsck.k9.activity.setup.accountmanager.EeloAccountCreator
import com.fsck.k9.controller.MessageReference
import com.fsck.k9.controller.MessagingController
@@ -157,17 +153,11 @@ open class MessageList :
private var viewSwitcher: ViewSwitcher? = null
private lateinit var recentChangesSnackbar: Snackbar
- private lateinit var accountManager: AccountManager
-
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setLayout(R.layout.message_list_loading)
- val accounts = preferences.accounts
- deleteIncompleteAccounts(accounts)
-
- accountManager = AccountManager.get(this)
- addNewAccountsAutomatically(accounts, savedInstanceState)
+ addNewAccountsAutomatically(savedInstanceState)
}
private fun onAccountConfigurationFinish(savedInstanceState: Bundle?) {
@@ -276,12 +266,6 @@ open class MessageList :
displayViews()
}
- private fun deleteIncompleteAccounts(accounts: List) {
- accounts.filter { !it.isFinishedSetup }.forEach {
- accountRemover.removeAccountAsync(it.uuid)
- }
- }
-
private fun findFragments() {
val fragmentManager = supportFragmentManager
messageListFragment = fragmentManager.findFragmentById(R.id.message_list_container) as MessageListFragment?
@@ -1704,61 +1688,16 @@ open class MessageList :
val messageViewOnly: Boolean = false
)
- private fun addNewAccountsAutomatically(accounts: List, savedInstanceState: Bundle?) {
+ private fun addNewAccountsAutomatically(savedInstanceState: Bundle?) {
lifecycleScope.launch(Dispatchers.IO) {
- try {
- val eeloAccounts: Array = getEeloAccountsOnDevice()
- val googleAccounts: Array = getGoogleAccountsOnDevice()
- for (eeloAccount in eeloAccounts) {
- val emailId: String = accountManager.getUserData(eeloAccount, ACCOUNT_EMAIL_ADDRESS_KEY)
- if (!emailId.contains("@")) continue
- var accountIsSignedIn = false
- for (account in accounts) {
- if (emailId == account.email) {
- accountIsSignedIn = true
- break
- }
- }
- if (!accountIsSignedIn) {
- val password: String = accountManager.getPassword(eeloAccount)
- EeloAccountCreator.createAccount(applicationContext, emailId, password, false)
- }
+ EeloAccountCreator.loadAccountsFromAccountManager(applicationContext, preferences, accountRemover) {
+ lifecycleScope.launch(Dispatchers.Main) {
+ onAccountConfigurationFinish(savedInstanceState)
}
-
- for (googleAccount in googleAccounts) {
- val emailId: String = accountManager.getUserData(googleAccount, ACCOUNT_EMAIL_ADDRESS_KEY)
-
- var accountIsSignedIn = false
- for (account in accounts) {
- if (emailId == account.email) {
- if (account.name == null) { // we need to fix an old bug
- account.name = emailId
- Preferences.getPreferences(applicationContext).saveAccount(account)
- }
- accountIsSignedIn = true
- break
- }
- }
- if (!accountIsSignedIn) {
- EeloAccountCreator.createAccount(applicationContext, emailId, "", true)
- }
- }
- } catch (e: SecurityException) {
- Timber.e(e)
- }
- lifecycleScope.launch(Dispatchers.Main) {
- onAccountConfigurationFinish(savedInstanceState)
}
}
}
- private fun getEeloAccountsOnDevice(): Array {
- return accountManager.getAccountsByType(EELO_ACCOUNT_TYPE)
- }
-
- private fun getGoogleAccountsOnDevice(): Array {
- return accountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE)
- }
companion object : KoinComponent {
private const val EXTRA_SEARCH = "search_bytes"
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt
index d1d3946c0f4d9c7ed0e6e02a84220fa607d6f0da..cbfb08b70e9e788a0b6235be0143f34ec71ff991 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt
@@ -331,7 +331,9 @@ class AccountSetupBasics : K9Activity() {
account.senderName = getOwnerName()
account.email = email
- account.name = email
+ if (account.name == null) {
+ account.name = email
+ }
return account
}
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 16627d6565934300a69e0b2d7ef98f7189e09281..07571c3ef35df359b3591c33beb86c9ec712bbf4 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
@@ -16,14 +16,24 @@
package com.fsck.k9.activity.setup.accountmanager;
+
+import java.util.List;
+
+import android.accounts.AccountManager;
import android.content.Context;
+import android.os.Build.VERSION_CODES;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.WorkerThread;
import com.fsck.k9.Account;
import com.fsck.k9.Account.DeletePolicy;
import com.fsck.k9.Core;
import com.fsck.k9.DI;
import com.fsck.k9.Preferences;
import com.fsck.k9.account.AccountCreator;
+import com.fsck.k9.account.BackgroundAccountRemover;
import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings;
import com.fsck.k9.autodiscovery.api.DiscoveryResults;
import com.fsck.k9.autodiscovery.api.DiscoveryTarget;
@@ -42,7 +52,87 @@ public class EeloAccountCreator {
private static final AccountCreator accountCreator = DI.get(AccountCreator.class);
private static final SpecialLocalFoldersCreator localFoldersCreator = DI.get(SpecialLocalFoldersCreator.class);
- public static void createAccount(Context context, String emailId, String password, boolean isGoogleAccount) {
+ @RequiresApi(api = VERSION_CODES.N)
+ @WorkerThread
+ public static void loadAccountsFromAccountManager(@NonNull Context context, @NonNull Preferences preferences,
+ @NonNull BackgroundAccountRemover accountRemover, @Nullable OnAccountLoadCompleteCallBack callBack) {
+ try {
+ AccountManager accountManager = AccountManager.get(context);
+
+ List accounts = preferences.getAccounts();
+ deleteIncompleteAccounts(accounts, accountRemover);
+
+ loadEeloAccounts(context, accounts, accountManager);
+ loadGoogleAccounts(context, accounts, accountManager);
+ } catch (SecurityException e) {
+ Timber.e(e, "Failed to load accounts from accountManager because of security violation");
+ }
+ if (callBack != null) {
+ callBack.onAccountLoadComplete();
+ }
+ }
+
+ @RequiresApi(api = VERSION_CODES.N)
+ private static void loadGoogleAccounts(@NonNull Context context, List accounts,
+ @NonNull AccountManager accountManager) {
+ android.accounts.Account[] googleAccounts =
+ accountManager.getAccountsByType(AccountManagerConstants.GOOGLE_ACCOUNT_TYPE);
+ for (android.accounts.Account googleAccount : googleAccounts) {
+ String emailId =
+ accountManager.getUserData(googleAccount, AccountManagerConstants.ACCOUNT_EMAIL_ADDRESS_KEY);
+ if (isInvalidEmail(emailId)) {
+ continue;
+ }
+
+ boolean accountAlreadyPresent = accounts.stream()
+ .filter(account -> emailId.equalsIgnoreCase(account.getEmail()))
+ .peek(account -> updateAccountNameIfMissing(context, emailId, account))
+ .findAny().isPresent();
+ if (!accountAlreadyPresent) {
+ createAccount(context, emailId, "", true);
+ }
+ }
+ }
+
+ private static void updateAccountNameIfMissing(@NonNull Context context, String emailId, Account account) {
+ if (account.getName() == null) { // we need to fix an old bug
+ account.setName(emailId);
+ Preferences.getPreferences(context).saveAccount(account);
+ }
+ }
+
+ private static boolean isInvalidEmail(String emailId) {
+ return emailId == null || !emailId.contains("@");
+ }
+
+ @RequiresApi(api = VERSION_CODES.N)
+ private static void loadEeloAccounts(@NonNull Context context, List accounts,
+ @NonNull AccountManager accountManager) {
+ 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);
+ if (isInvalidEmail(emailId)) {
+ continue;
+ }
+
+ boolean isNewAccount = accounts.stream()
+ .noneMatch(account -> emailId.equalsIgnoreCase(account.getEmail()));
+ if (isNewAccount) {
+ String password = accountManager.getPassword(eeloAccount);
+ createAccount(context, emailId, password, false);
+ }
+ }
+ }
+
+ @RequiresApi(api = VERSION_CODES.N)
+ private static void deleteIncompleteAccounts(List accounts, BackgroundAccountRemover accountRemover) {
+ accounts.stream().filter(account -> !account.isFinishedSetup())
+ .forEach(account -> accountRemover.removeAccountAsync(account.getUuid()));
+ }
+
+ private static void createAccount(Context context, String emailId, String password, boolean isGoogleAccount) {
Preferences preferences = Preferences.getPreferences(context);
Account account = preferences.newAccount();
@@ -137,5 +227,9 @@ public class EeloAccountCreator {
)
);
}
+
+ public interface OnAccountLoadCompleteCallBack {
+ void onAccountLoadComplete();
+ }
}