From 9ee874625525a85bb3adf31c57f30f0669be253e Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 24 Mar 2021 15:48:30 +0100 Subject: [PATCH 1/5] Move some code from 'Preferences' to 'AccountRemover' --- .../src/main/java/com/fsck/k9/KoinModule.kt | 1 - .../src/main/java/com/fsck/k9/Preferences.kt | 19 +-------- .../com/fsck/k9/mailstore/LocalStore.java | 12 ------ .../com/fsck/k9/account/AccountRemover.kt | 40 ++++++++++++++----- .../java/com/fsck/k9/account/KoinModule.kt | 10 ++++- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/KoinModule.kt index 7e2e9e508..254189959 100644 --- a/app/core/src/main/java/com/fsck/k9/KoinModule.kt +++ b/app/core/src/main/java/com/fsck/k9/KoinModule.kt @@ -18,7 +18,6 @@ val mainModule = module { context = get(), storagePersister = get(), localStoreProvider = get(), - localKeyStoreManager = get(), accountPreferenceSerializer = get() ) } diff --git a/app/core/src/main/java/com/fsck/k9/Preferences.kt b/app/core/src/main/java/com/fsck/k9/Preferences.kt index efbb599e4..0ca23cb66 100644 --- a/app/core/src/main/java/com/fsck/k9/Preferences.kt +++ b/app/core/src/main/java/com/fsck/k9/Preferences.kt @@ -3,9 +3,7 @@ package com.fsck.k9 import android.content.Context import androidx.annotation.GuardedBy import androidx.annotation.RestrictTo -import com.fsck.k9.backend.BackendManager import com.fsck.k9.mail.MessagingException -import com.fsck.k9.mailstore.LocalStore import com.fsck.k9.mailstore.LocalStoreProvider import com.fsck.k9.preferences.Storage import com.fsck.k9.preferences.StorageEditor @@ -14,19 +12,14 @@ import java.util.HashMap import java.util.LinkedList import java.util.UUID import java.util.concurrent.CopyOnWriteArrayList -import org.koin.core.KoinComponent -import org.koin.core.inject import timber.log.Timber class Preferences internal constructor( private val context: Context, private val storagePersister: StoragePersister, private val localStoreProvider: LocalStoreProvider, - private val localKeyStoreManager: LocalKeyStoreManager, private val accountPreferenceSerializer: AccountPreferenceSerializer -) : KoinComponent { - private val backendManager: BackendManager by inject() - +) { private val accountLock = Any() @GuardedBy("accountLock") @@ -138,20 +131,10 @@ class Preferences internal constructor( accountsMap?.remove(account.uuid) accountsInOrder.remove(account) - try { - backendManager.removeBackend(account) - } catch (e: Exception) { - Timber.e(e, "Failed to reset remote store for account %s", account.uuid) - } - - LocalStore.removeAccount(account) - val storageEditor = createStorageEditor() accountPreferenceSerializer.delete(storageEditor, storage, account) storageEditor.commit() - localKeyStoreManager.deleteCertificates(account) - if (account === newAccount) { newAccount = null } diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java index 5ca2755a2..ecaae3e17 100644 --- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java +++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java @@ -228,18 +228,6 @@ public class LocalStore { return schemaDefinitionFactory.getDatabaseVersion(); } - public static void removeAccount(Account account) { - try { - removeInstance(account); - } catch (Exception e) { - Timber.e(e, "Failed to reset local store for account %s", account.getUuid()); - } - } - - private static void removeInstance(Account account) { - DI.get(LocalStoreProvider.class).removeInstance(account); - } - public void switchLocalStorage(final String newStorageProviderId) throws MessagingException { database.switchProvider(newStorageProviderId); } diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountRemover.kt b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountRemover.kt index 8e79e0165..d700de7dd 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountRemover.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountRemover.kt @@ -1,7 +1,10 @@ package com.fsck.k9.account +import com.fsck.k9.Account import com.fsck.k9.Core +import com.fsck.k9.LocalKeyStoreManager import com.fsck.k9.Preferences +import com.fsck.k9.backend.BackendManager import com.fsck.k9.controller.MessagingController import com.fsck.k9.mailstore.LocalStoreProvider import timber.log.Timber @@ -12,6 +15,8 @@ import timber.log.Timber class AccountRemover( private val localStoreProvider: LocalStoreProvider, private val messagingController: MessagingController, + private val backendManager: BackendManager, + private val localKeyStoreManager: LocalKeyStoreManager, private val preferences: Preferences ) { @@ -25,19 +30,36 @@ class AccountRemover( val accountName = account.description Timber.v("Removing account '%s'…", accountName) - try { - val localStore = localStoreProvider.getInstance(account) - localStore.delete() - } catch (e: Exception) { - Timber.w(e, "Error removing message database for account '%s'", accountName) - - // Ignore, this may lead to localStores on sd-cards that are currently not inserted to be left - } - + removeLocalStore(account) messagingController.deleteAccount(account) + removeBackend(account) + preferences.deleteAccount(account) + + localKeyStoreManager.deleteCertificates(account) Core.setServicesEnabled() Timber.v("Finished removing account '%s'.", accountName) } + + private fun removeLocalStore(account: Account) { + try { + val localStore = localStoreProvider.getInstance(account) + localStore.delete() + } catch (e: Exception) { + Timber.w(e, "Error removing message database for account '%s'", account.description) + + // Ignore, this may lead to localStores on sd-cards that are currently not inserted to be left + } + + localStoreProvider.removeInstance(account) + } + + private fun removeBackend(account: Account) { + try { + backendManager.removeBackend(account) + } catch (e: Exception) { + Timber.e(e, "Failed to reset remote store for account %s", account.uuid) + } + } } diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/account/KoinModule.kt b/app/ui/legacy/src/main/java/com/fsck/k9/account/KoinModule.kt index c6f46d80b..69540f651 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/account/KoinModule.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/account/KoinModule.kt @@ -3,7 +3,15 @@ package com.fsck.k9.account import org.koin.dsl.module val accountModule = module { - factory { AccountRemover(get(), get(), get()) } + factory { + AccountRemover( + localStoreProvider = get(), + messagingController = get(), + backendManager = get(), + localKeyStoreManager = get(), + preferences = get() + ) + } factory { BackgroundAccountRemover(get()) } factory { AccountCreator(get(), get()) } } From fb426b40086e3b47f0702a7c469a559b96faa15e Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 24 Mar 2021 16:04:53 +0100 Subject: [PATCH 2/5] Remove migration code for really old K-9 Mail versions --- app/core/src/main/java/com/fsck/k9/Preferences.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/Preferences.kt b/app/core/src/main/java/com/fsck/k9/Preferences.kt index 0ca23cb66..af850ca60 100644 --- a/app/core/src/main/java/com/fsck/k9/Preferences.kt +++ b/app/core/src/main/java/com/fsck/k9/Preferences.kt @@ -37,14 +37,6 @@ class Preferences internal constructor( init { val persistedStorageValues = storagePersister.loadValues() storage.replaceAll(persistedStorageValues) - - if (storage.isEmpty) { - Timber.i("Preferences storage is zero-size, importing from Android-style preferences") - - val editor = createStorageEditor() - editor.copy(context.getSharedPreferences("AndroidMail.Main", Context.MODE_PRIVATE)) - editor.commit() - } } fun createStorageEditor(): StorageEditor { From dc9333510031ef9a4e13643d942dcb6c739bf67a Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 24 Mar 2021 16:28:07 +0100 Subject: [PATCH 3/5] Move old migration code from 'K9' to storage module --- app/core/src/main/java/com/fsck/k9/K9.kt | 24 ------------------- .../migrations/StorageMigrationTo6.kt | 21 ++++++++++++++++ 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/K9.kt b/app/core/src/main/java/com/fsck/k9/K9.kt index 9d5353053..f5dc86238 100644 --- a/app/core/src/main/java/com/fsck/k9/K9.kt +++ b/app/core/src/main/java/com/fsck/k9/K9.kt @@ -21,8 +21,6 @@ object K9 : EarlyInit { @JvmField val DEVELOPER_MODE = BuildConfig.DEBUG - private const val VERSION_MIGRATE_OPENPGP_TO_ACCOUNTS = 63 - /** * Name of the [SharedPreferences] file used to store the last known version of the * accounts' databases. @@ -105,28 +103,6 @@ object K9 : EarlyInit { if (cachedVersion >= LocalStore.getDbVersion()) { setDatabasesUpToDate(false) } - - if (cachedVersion < VERSION_MIGRATE_OPENPGP_TO_ACCOUNTS) { - migrateOpenPgpGlobalToAccountSettings() - } - } - - private fun migrateOpenPgpGlobalToAccountSettings() { - val storage = preferences.storage - - val openPgpProvider = storage.getString("openPgpProvider", null) - val openPgpSupportSignOnly = storage.getBoolean("openPgpSupportSignOnly", false) - - for (account in preferences.accounts) { - account.openPgpProvider = openPgpProvider - account.isOpenPgpHideSignOnly = !openPgpSupportSignOnly - preferences.saveAccount(account) - } - - preferences.createStorageEditor() - .remove("openPgpProvider") - .remove("openPgpSupportSignOnly") - .commit() } @JvmStatic diff --git a/app/storage/src/main/java/com/fsck/k9/preferences/migrations/StorageMigrationTo6.kt b/app/storage/src/main/java/com/fsck/k9/preferences/migrations/StorageMigrationTo6.kt index a3ab14596..0066dd9a4 100644 --- a/app/storage/src/main/java/com/fsck/k9/preferences/migrations/StorageMigrationTo6.kt +++ b/app/storage/src/main/java/com/fsck/k9/preferences/migrations/StorageMigrationTo6.kt @@ -12,6 +12,7 @@ class StorageMigrationTo6( fun performLegacyMigrations() { rewriteKeyguardPrivacy() rewriteTheme() + migrateOpenPgpGlobalToAccountSettings() } private fun rewriteKeyguardPrivacy() { @@ -39,6 +40,26 @@ class StorageMigrationTo6( migrationsHelper.writeValue(db, "theme", newTheme.toString()) } + private fun migrateOpenPgpGlobalToAccountSettings() { + val accountUuidsListValue = migrationsHelper.readValue(db, "accountUuids") + if (accountUuidsListValue == null || accountUuidsListValue.isEmpty()) { + return + } + + val openPgpProvider = migrationsHelper.readValue(db, "openPgpProvider") ?: "" + val openPgpSupportSignOnly = migrationsHelper.readValue(db, "openPgpSupportSignOnly")?.toBoolean() ?: false + val openPgpHideSignOnly = (!openPgpSupportSignOnly).toString() + + val accountUuids = accountUuidsListValue.split(",") + for (accountUuid in accountUuids) { + migrationsHelper.writeValue(db, "$accountUuid.openPgpProvider", openPgpProvider) + migrationsHelper.writeValue(db, "$accountUuid.openPgpHideSignOnly", openPgpHideSignOnly) + } + + migrationsHelper.writeValue(db, "openPgpProvider", null) + migrationsHelper.writeValue(db, "openPgpSupportSignOnly", null) + } + companion object { private const val THEME_ORDINAL_LIGHT = 0 private const val THEME_ORDINAL_DARK = 1 From 827ea0059d4ffaee7c326367e269301b20603408 Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 24 Mar 2021 17:07:25 +0100 Subject: [PATCH 4/5] Make everyone use Preferences.saveSettings() to save general settings --- app/core/src/main/java/com/fsck/k9/K9.kt | 19 +++++++------------ .../src/main/java/com/fsck/k9/Preferences.kt | 6 ++++++ .../fsck/k9/fragment/MessageListFragment.kt | 4 +--- .../com/fsck/k9/ui/settings/KoinModule.kt | 2 +- .../general/GeneralSettingsDataStore.kt | 11 +---------- 5 files changed, 16 insertions(+), 26 deletions(-) diff --git a/app/core/src/main/java/com/fsck/k9/K9.kt b/app/core/src/main/java/com/fsck/k9/K9.kt index f5dc86238..b457e0ed3 100644 --- a/app/core/src/main/java/com/fsck/k9/K9.kt +++ b/app/core/src/main/java/com/fsck/k9/K9.kt @@ -2,13 +2,15 @@ package com.fsck.k9 import android.content.Context import android.content.SharedPreferences -import android.os.AsyncTask import com.fsck.k9.Account.SortType import com.fsck.k9.core.BuildConfig import com.fsck.k9.mail.K9MailLib import com.fsck.k9.mailstore.LocalStore import com.fsck.k9.preferences.Storage import com.fsck.k9.preferences.StorageEditor +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import timber.log.Timber import timber.log.Timber.DebugTree @@ -385,8 +387,7 @@ object K9 : EarlyInit { isFixedMessageViewTheme = storage.getBoolean("fixedMessageViewTheme", true) } - @JvmStatic - fun save(editor: StorageEditor) { + internal fun save(editor: StorageEditor) { editor.putBoolean("enableDebugLogging", isDebugLoggingEnabled) editor.putBoolean("enableSensitiveLogging", isSensitiveDebugLoggingEnabled) editor.putEnum("backgroundOperations", backgroundOps) @@ -460,15 +461,9 @@ object K9 : EarlyInit { @JvmStatic fun saveSettingsAsync() { - object : AsyncTask() { - override fun doInBackground(vararg voids: Void): Void? { - val editor = preferences.createStorageEditor() - save(editor) - editor.commit() - - return null - } - }.execute() + GlobalScope.launch(Dispatchers.IO) { + preferences.saveSettings() + } } private inline fun > Storage.getEnum(key: String, defaultValue: T): T { diff --git a/app/core/src/main/java/com/fsck/k9/Preferences.kt b/app/core/src/main/java/com/fsck/k9/Preferences.kt index af850ca60..dc0450782 100644 --- a/app/core/src/main/java/com/fsck/k9/Preferences.kt +++ b/app/core/src/main/java/com/fsck/k9/Preferences.kt @@ -168,6 +168,12 @@ class Preferences internal constructor( notifyListeners() } + fun saveSettings() { + val editor = createStorageEditor() + K9.save(editor) + editor.commit() + } + private fun ensureAssignedAccountNumber(account: Account) { if (account.accountNumber != Account.UNASSIGNED_ACCOUNT_NUMBER) return diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt index c13384ce8..04407faf2 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt @@ -558,9 +558,7 @@ class MessageListFragment : K9.setSortAscending(this.sortType, this.sortAscending) sortDateAscending = K9.isSortAscending(SortType.SORT_DATE) - val editor = preferences.createStorageEditor() - K9.save(editor) - editor.commit() + K9.saveSettingsAsync() } reSort() diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/KoinModule.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/KoinModule.kt index 2a459f5e7..3fcd8b44a 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/KoinModule.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/KoinModule.kt @@ -18,7 +18,7 @@ val settingsUiModule = module { single { AccountsLiveData(get()) } viewModel { SettingsViewModel(get()) } - factory { GeneralSettingsDataStore(get(), get(), get(named("SaveSettingsExecutorService")), get()) } + factory { GeneralSettingsDataStore(jobManager = get(), themeManager = get()) } single(named("SaveSettingsExecutorService")) { Executors.newSingleThreadExecutor(NamedThreadFactory("SaveSettings")) } diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/general/GeneralSettingsDataStore.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/general/GeneralSettingsDataStore.kt index 1b3d01c30..d705a1779 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/general/GeneralSettingsDataStore.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/general/GeneralSettingsDataStore.kt @@ -5,15 +5,11 @@ import androidx.preference.PreferenceDataStore import com.fsck.k9.K9 import com.fsck.k9.K9.AppTheme import com.fsck.k9.K9.SubTheme -import com.fsck.k9.Preferences import com.fsck.k9.job.K9JobManager import com.fsck.k9.ui.base.ThemeManager -import java.util.concurrent.ExecutorService class GeneralSettingsDataStore( - private val preferences: Preferences, private val jobManager: K9JobManager, - private val executorService: ExecutorService, private val themeManager: ThemeManager ) : PreferenceDataStore() { var activity: FragmentActivity? = null @@ -230,12 +226,7 @@ class GeneralSettingsDataStore( } private fun saveSettings() { - val editor = preferences.createStorageEditor() - K9.save(editor) - - executorService.execute { - editor.commit() - } + K9.saveSettingsAsync() } private fun setTheme(value: String?) { From d3e2c6635cb3d9913dd59cba1bb984f55b40bee7 Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 24 Mar 2021 17:18:16 +0100 Subject: [PATCH 5/5] Add 'SettingsChangeListener' mechanism to 'Preferences' --- .../src/main/java/com/fsck/k9/Preferences.kt | 25 ++++++++++++++++--- .../com/fsck/k9/SettingsChangeListener.kt | 5 ++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 app/core/src/main/java/com/fsck/k9/SettingsChangeListener.kt diff --git a/app/core/src/main/java/com/fsck/k9/Preferences.kt b/app/core/src/main/java/com/fsck/k9/Preferences.kt index dc0450782..17a1dcf95 100644 --- a/app/core/src/main/java/com/fsck/k9/Preferences.kt +++ b/app/core/src/main/java/com/fsck/k9/Preferences.kt @@ -31,6 +31,7 @@ class Preferences internal constructor( @GuardedBy("accountLock") private var newAccount: Account? = null private val accountsChangeListeners = CopyOnWriteArrayList() + private val settingsChangeListeners = CopyOnWriteArrayList() val storage = Storage() @@ -132,7 +133,7 @@ class Preferences internal constructor( } } - notifyListeners() + notifyAccountsChangeListeners() } var defaultAccount: Account? @@ -165,13 +166,15 @@ class Preferences internal constructor( accountPreferenceSerializer.save(editor, storage, account) editor.commit() - notifyListeners() + notifyAccountsChangeListeners() } fun saveSettings() { val editor = createStorageEditor() K9.save(editor) editor.commit() + + notifySettingsChangeListeners() } private fun ensureAssignedAccountNumber(account: Account) { @@ -218,10 +221,10 @@ class Preferences internal constructor( loadAccounts() } - notifyListeners() + notifyAccountsChangeListeners() } - private fun notifyListeners() { + private fun notifyAccountsChangeListeners() { for (listener in accountsChangeListeners) { listener.onAccountsChanged() } @@ -235,6 +238,20 @@ class Preferences internal constructor( accountsChangeListeners.remove(accountsChangeListener) } + private fun notifySettingsChangeListeners() { + for (listener in settingsChangeListeners) { + listener.onSettingsChanged() + } + } + + fun addSettingsChangeListener(settingsChangeListener: SettingsChangeListener) { + settingsChangeListeners.add(settingsChangeListener) + } + + fun removeSettingsChangeListener(settingsChangeListener: SettingsChangeListener) { + settingsChangeListeners.remove(settingsChangeListener) + } + companion object { @JvmStatic fun getPreferences(context: Context): Preferences { diff --git a/app/core/src/main/java/com/fsck/k9/SettingsChangeListener.kt b/app/core/src/main/java/com/fsck/k9/SettingsChangeListener.kt new file mode 100644 index 000000000..bed18ebf2 --- /dev/null +++ b/app/core/src/main/java/com/fsck/k9/SettingsChangeListener.kt @@ -0,0 +1,5 @@ +package com.fsck.k9 + +interface SettingsChangeListener { + fun onSettingsChanged() +}