Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/bitfireAT/davx5-ose.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRicki Hirner <hirner@bitfire.at>2022-05-11 12:25:42 +0300
committerRicki Hirner <hirner@bitfire.at>2022-05-12 11:46:48 +0300
commit8ca3d857d317e609b759ddf75c3161fa7e6def29 (patch)
tree780804c11ec4e45214aea1fc5e33e27339175feb
parent12cc2cfcdec6bf232887af7f2e17c2071b258bb7 (diff)
Use Koin Dependency Injection for Singletons (#84)
-rw-r--r--app/build.gradle5
-rw-r--r--app/src/androidTest/java/at/bitfire/davdroid/settings/SettingsManagerTest.kt7
-rw-r--r--app/src/main/java/at/bitfire/davdroid/App.kt40
-rw-r--r--app/src/main/java/at/bitfire/davdroid/Constants.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/DavService.kt10
-rw-r--r--app/src/main/java/at/bitfire/davdroid/DavUtils.kt1
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ForegroundService.kt13
-rw-r--r--app/src/main/java/at/bitfire/davdroid/HttpClient.kt8
-rw-r--r--app/src/main/java/at/bitfire/davdroid/MemoryCookieStore.kt1
-rw-r--r--app/src/main/java/at/bitfire/davdroid/Singleton.kt88
-rw-r--r--app/src/main/java/at/bitfire/davdroid/StorageLowReceiver.kt11
-rw-r--r--app/src/main/java/at/bitfire/davdroid/TasksWatcher.kt10
-rw-r--r--app/src/main/java/at/bitfire/davdroid/db/AppDatabase.kt15
-rw-r--r--app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/resource/LocalJtxICalObject.kt4
-rw-r--r--app/src/main/java/at/bitfire/davdroid/resource/LocalTaskList.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/resource/TaskUtils.kt10
-rw-r--r--app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt15
-rw-r--r--app/src/main/java/at/bitfire/davdroid/settings/SettingsManager.kt10
-rw-r--r--app/src/main/java/at/bitfire/davdroid/settings/SharedPreferencesProvider.kt8
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/AccountUtils.kt71
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/AccountsUpdatedListener.kt88
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt5
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt5
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncAdapterService.kt5
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAdapterService.kt3
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt50
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt5
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/AboutActivity.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt6
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/AppSettingsActivity.kt7
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/BaseAccountsDrawerHandler.kt4
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt10
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/TasksFragment.kt7
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/UiUtils.kt8
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt10
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/CollectionInfoFragment.kt7
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt11
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/CreateAddressBookActivity.kt7
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/CreateCalendarActivity.kt6
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/CreateCollectionFragment.kt8
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/DeleteCollectionFragment.kt6
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/RenameAccountFragment.kt8
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/SettingsActivity.kt12
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/account/WebcalFragment.kt8
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/intro/BatteryOptimizationsFragment.kt6
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/intro/IntroActivity.kt8
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/intro/OpenSourceFragment.kt6
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt23
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.kt2
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/webdav/AddWebdavMountActivity.kt9
-rw-r--r--app/src/main/java/at/bitfire/davdroid/ui/webdav/WebdavMountsActivity.kt7
-rw-r--r--app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt15
-rw-r--r--app/src/main/java/at/bitfire/davdroid/webdav/RandomAccessCallback.kt28
-rw-r--r--app/src/main/java/at/bitfire/davdroid/webdav/ThumbnailCache.kt2
-rw-r--r--app/src/test/java/at/bitfire/davdroid/SingletonTest.kt57
61 files changed, 399 insertions, 395 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 60e23d26..9ba305a2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -138,6 +138,7 @@ dependencies {
implementation 'commons-io:commons-io:2.6'
//noinspection GradleDependency - dnsjava 3+ needs Java 8/Android 7
implementation 'dnsjava:dnsjava:2.1.9'
+ implementation "io.insert-koin:koin-android:3.2.0"
//noinspection GradleDependency
implementation "org.apache.commons:commons-collections4:${versions.commonsCollections}"
//noinspection GradleDependency
@@ -151,9 +152,9 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0'
- androidTestImplementation 'junit:junit:4.13.2'
androidTestImplementation "com.squareup.okhttp3:mockwebserver:${versions.okhttp}"
+ androidTestImplementation 'junit:junit:4.13.2'
- testImplementation 'junit:junit:4.13.2'
testImplementation "com.squareup.okhttp3:mockwebserver:${versions.okhttp}"
+ testImplementation 'junit:junit:4.13.2'
}
diff --git a/app/src/androidTest/java/at/bitfire/davdroid/settings/SettingsManagerTest.kt b/app/src/androidTest/java/at/bitfire/davdroid/settings/SettingsManagerTest.kt
index 1fd3171c..951d28fe 100644
--- a/app/src/androidTest/java/at/bitfire/davdroid/settings/SettingsManagerTest.kt
+++ b/app/src/androidTest/java/at/bitfire/davdroid/settings/SettingsManagerTest.kt
@@ -4,14 +4,15 @@
package at.bitfire.davdroid.settings
-import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Test
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
-class SettingsManagerTest {
+class SettingsManagerTest: KoinComponent {
- val settingsManager by lazy { SettingsManager.getInstance(InstrumentationRegistry.getInstrumentation().targetContext) }
+ val settingsManager by inject<SettingsManager>()
@Test
fun testContainsKey_NotExisting() {
diff --git a/app/src/main/java/at/bitfire/davdroid/App.kt b/app/src/main/java/at/bitfire/davdroid/App.kt
index e4ec204b..b72ffd4b 100644
--- a/app/src/main/java/at/bitfire/davdroid/App.kt
+++ b/app/src/main/java/at/bitfire/davdroid/App.kt
@@ -10,18 +10,25 @@ import android.net.Uri
import android.os.StrictMode
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.graphics.drawable.toBitmap
+import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
-import at.bitfire.davdroid.syncadapter.AccountUtils
+import at.bitfire.davdroid.settings.SettingsManager
+import at.bitfire.davdroid.syncadapter.AccountsUpdatedListener
import at.bitfire.davdroid.ui.DebugInfoActivity
import at.bitfire.davdroid.ui.NotificationUtils
import at.bitfire.davdroid.ui.UiUtils
+import org.koin.android.ext.koin.androidContext
+import org.koin.android.ext.koin.androidLogger
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
+import org.koin.core.context.startKoin
import java.util.logging.Level
import kotlin.concurrent.thread
import kotlin.system.exitProcess
@Suppress("unused")
-class App: Application(), Thread.UncaughtExceptionHandler {
+class App: Application(), KoinComponent, Thread.UncaughtExceptionHandler {
companion object {
@@ -38,6 +45,27 @@ class App: Application(), Thread.UncaughtExceptionHandler {
}
+ override fun attachBaseContext(base: Context) {
+ super.attachBaseContext(base)
+
+ startKoin {
+ androidLogger(
+ if (BuildConfig.DEBUG)
+ org.koin.core.logger.Level.DEBUG
+ else
+ org.koin.core.logger.Level.INFO
+ )
+ androidContext(base)
+
+ modules(
+ AccountsUpdatedListener.defaultModule,
+ AppDatabase.defaultModule,
+ SettingsManager.defaultModule,
+ StorageLowReceiver.defaultModule
+ )
+ }
+ }
+
override fun onCreate() {
super.onCreate()
Logger.initialize(this)
@@ -59,19 +87,19 @@ class App: Application(), Thread.UncaughtExceptionHandler {
NotificationUtils.createChannels(this)
// set light/dark mode
- UiUtils.setTheme(this) // when this is called in the asynchronous thread below, it recreates
- // some current activity and causes an IllegalStateException in rare cases
+ UiUtils.setTheme() // when this is called in the asynchronous thread below, it recreates
+ // some current activity and causes an IllegalStateException in rare cases
// don't block UI for some background checks
thread {
// watch for account changes/deletions
- AccountUtils.registerAccountsUpdateListener(this)
+ get<AccountsUpdatedListener>().listen()
// foreground service (possible workaround for devices which prevent DAVx5 from being started)
ForegroundService.startIfActive(this)
// watch storage because low storage means synchronization is stopped
- StorageLowReceiver.getInstance(this)
+ get<StorageLowReceiver>().listen()
// watch installed/removed apps
TasksWatcher.watch(this)
diff --git a/app/src/main/java/at/bitfire/davdroid/Constants.kt b/app/src/main/java/at/bitfire/davdroid/Constants.kt
index 3bdbb691..8e6c59bc 100644
--- a/app/src/main/java/at/bitfire/davdroid/Constants.kt
+++ b/app/src/main/java/at/bitfire/davdroid/Constants.kt
@@ -3,8 +3,6 @@
**************************************************************************************************/
package at.bitfire.davdroid
-import java.io.File
-
object Constants {
const val DAVDROID_GREEN_RGBA = 0xFF8bc34a.toInt()
diff --git a/app/src/main/java/at/bitfire/davdroid/DavService.kt b/app/src/main/java/at/bitfire/davdroid/DavService.kt
index 880185f8..c5d57f2e 100644
--- a/app/src/main/java/at/bitfire/davdroid/DavService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/DavService.kt
@@ -20,9 +20,9 @@ import at.bitfire.dav4jvm.Response
import at.bitfire.dav4jvm.UrlUtils
import at.bitfire.dav4jvm.exception.HttpException
import at.bitfire.dav4jvm.property.*
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.*
import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
@@ -30,13 +30,15 @@ import at.bitfire.davdroid.ui.DebugInfoActivity
import at.bitfire.davdroid.ui.NotificationUtils
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
+import org.koin.android.ext.android.get
+import org.koin.core.component.KoinComponent
import java.lang.ref.WeakReference
import java.util.*
import java.util.logging.Level
import kotlin.collections.*
@Suppress("DEPRECATION")
-class DavService: IntentService("DavService") {
+class DavService: IntentService("DavService"), KoinComponent {
companion object {
@@ -93,7 +95,7 @@ class DavService: IntentService("DavService") {
listener.get()?.onDavRefreshStatusChanged(id, true)
}
- val db = AppDatabase.getInstance(this@DavService)
+ val db = get<AppDatabase>()
refreshCollections(db, id)
}
@@ -160,7 +162,7 @@ class DavService: IntentService("DavService") {
}
private fun refreshCollections(db: AppDatabase, serviceId: Long) {
- val settings = SettingsManager.getInstance(this)
+ val settings = get<SettingsManager>()
val syncAllCollections = settings.getBoolean(Settings.SYNC_ALL_COLLECTIONS)
val homeSetDao = db.homeSetDao()
diff --git a/app/src/main/java/at/bitfire/davdroid/DavUtils.kt b/app/src/main/java/at/bitfire/davdroid/DavUtils.kt
index 55b58467..db9a195b 100644
--- a/app/src/main/java/at/bitfire/davdroid/DavUtils.kt
+++ b/app/src/main/java/at/bitfire/davdroid/DavUtils.kt
@@ -22,7 +22,6 @@ import okhttp3.MediaType.Companion.toMediaType
import org.xbill.DNS.*
import java.net.InetAddress
import java.util.*
-import kotlin.collections.LinkedHashSet
/**
* Some WebDAV and related network utility methods
diff --git a/app/src/main/java/at/bitfire/davdroid/ForegroundService.kt b/app/src/main/java/at/bitfire/davdroid/ForegroundService.kt
index 33bb8d85..9a069447 100644
--- a/app/src/main/java/at/bitfire/davdroid/ForegroundService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ForegroundService.kt
@@ -16,10 +16,12 @@ import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.AppSettingsActivity
import at.bitfire.davdroid.ui.NotificationUtils
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
class ForegroundService : Service() {
- companion object {
+ companion object: KoinComponent {
/**
* Starts/stops a foreground service, according to the app setting [Settings.FOREGROUND_SERVICE]
@@ -43,16 +45,15 @@ class ForegroundService : Service() {
* Whether the foreground service is enabled (checked) in the app settings.
* @return true: foreground service enabled; false: foreground service not enabled
*/
- fun foregroundServiceActivated(context: Context): Boolean {
- val settings = SettingsManager.getInstance(context)
- return settings.getBooleanOrNull(Settings.FOREGROUND_SERVICE) == true
+ fun foregroundServiceActivated(): Boolean {
+ return get<SettingsManager>().getBooleanOrNull(Settings.FOREGROUND_SERVICE) == true
}
/**
* Starts the foreground service when enabled in the app settings and applicable.
*/
fun startIfActive(context: Context) {
- if (foregroundServiceActivated(context)) {
+ if (foregroundServiceActivated()) {
if (batteryOptimizationWhitelisted(context)) {
val serviceIntent = Intent(ACTION_FOREGROUND, null, context, ForegroundService::class.java)
if (Build.VERSION.SDK_INT >= 26)
@@ -86,7 +87,7 @@ class ForegroundService : Service() {
override fun onBind(intent: Intent?): Nothing? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- if (foregroundServiceActivated(this)) {
+ if (foregroundServiceActivated()) {
val settingsIntent = Intent(this, AppSettingsActivity::class.java).apply {
putExtra(AppSettingsActivity.EXTRA_SCROLL_TO, Settings.FOREGROUND_SERVICE)
}
diff --git a/app/src/main/java/at/bitfire/davdroid/HttpClient.kt b/app/src/main/java/at/bitfire/davdroid/HttpClient.kt
index 3ef5e638..9038c6c0 100644
--- a/app/src/main/java/at/bitfire/davdroid/HttpClient.kt
+++ b/app/src/main/java/at/bitfire/davdroid/HttpClient.kt
@@ -10,8 +10,8 @@ import android.security.KeyChain
import at.bitfire.cert4android.CustomCertManager
import at.bitfire.dav4jvm.BasicDigestAuthHandler
import at.bitfire.dav4jvm.UrlUtils
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.Credentials
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
@@ -19,6 +19,8 @@ import okhttp3.*
import okhttp3.brotli.BrotliInterceptor
import okhttp3.internal.tls.OkHostnameVerifier
import okhttp3.logging.HttpLoggingInterceptor
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.io.File
import java.net.InetSocketAddress
import java.net.Proxy
@@ -80,7 +82,7 @@ class HttpClient private constructor(
accountSettings: AccountSettings? = null,
val logger: java.util.logging.Logger? = Logger.log,
val loggerLevel: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.BODY
- ) {
+ ): KoinComponent {
private var certManager: CustomCertManager? = null
private var certificateAlias: String? = null
private var offerCompression: Boolean = false
@@ -99,7 +101,7 @@ class HttpClient private constructor(
}
if (context != null) {
- val settings = SettingsManager.getInstance(context)
+ val settings = get<SettingsManager>()
// custom proxy support
try {
diff --git a/app/src/main/java/at/bitfire/davdroid/MemoryCookieStore.kt b/app/src/main/java/at/bitfire/davdroid/MemoryCookieStore.kt
index 648b8ad9..250913d0 100644
--- a/app/src/main/java/at/bitfire/davdroid/MemoryCookieStore.kt
+++ b/app/src/main/java/at/bitfire/davdroid/MemoryCookieStore.kt
@@ -4,7 +4,6 @@
package at.bitfire.davdroid
-import at.bitfire.davdroid.log.Logger
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
diff --git a/app/src/main/java/at/bitfire/davdroid/Singleton.kt b/app/src/main/java/at/bitfire/davdroid/Singleton.kt
deleted file mode 100644
index 5d48c9bb..00000000
--- a/app/src/main/java/at/bitfire/davdroid/Singleton.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-/***************************************************************************************************
- * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
- **************************************************************************************************/
-
-package at.bitfire.davdroid
-
-import android.content.Context
-import java.lang.ref.WeakReference
-
-/**
- * A singleton registry that guarantees that there is not more than one instance per class.
- *
- * It uses weak references so that as soon as the singletons are not used anymore, they can be
- * freed by GC.
- */
-object Singleton {
-
- private val currentlyCreating = HashSet<Any>()
-
- private val singletons = mutableMapOf<Any, WeakReference<Any>>()
-
-
- /**
- * Gets a singleton instance of the class, using the Class [T] as key.
- *
- * This method is thread-safe.
- */
- inline fun<reified T> getInstance(noinline createInstance: () -> T): T =
- getInstanceByKey(T::class.java, createInstance)
-
- /**
- * Gets a singleton instance of the class, using the Class [T] as key.
- *
- * Accepts an Android Context, which is used to determine the [Context.getApplicationContext].
- * The application Context is then passed to [createInstance].
- *
- * This method is thread-safe.
- */
- inline fun<reified T> getInstance(context: Context, noinline createInstance: (appContext: Context) -> T): T =
- getInstanceByKey(T::class.java) {
- createInstance(context.applicationContext)
- }
-
-
- @Synchronized
- fun dropAll() {
- singletons.clear()
- }
-
- /**
- * Gets a singleton instance of the class (using a given key).
- *
- * This method is thread-safe.
- *
- * @param key unique key (only one instance is created for this key)
- * @param createInstance creates the instance
- *
- * @throws IllegalStateException when called recursively with the same key
- */
- @Synchronized
- fun<T> getInstanceByKey(key: Any, createInstance: () -> T): T {
- var cached = singletons[key]
- if (cached != null && cached.get() == null) {
- singletons.remove(cached)
- cached = null
- }
-
- // found existing singleton
- if (cached != null)
- @Suppress("UNCHECKED_CAST")
- return cached.get() as T
-
- // CREATE NEW SINGLETON
- // prevent recursive creation
- if (currentlyCreating.contains(key))
- throw IllegalStateException("Singleton.getInstance must not be called recursively")
- currentlyCreating += key
- // actually create the instance
- try {
- val newInstance = createInstance()
- singletons[key] = WeakReference(newInstance)
- return newInstance
- } finally {
- currentlyCreating -= key
- }
- }
-
-} \ No newline at end of file
diff --git a/app/src/main/java/at/bitfire/davdroid/StorageLowReceiver.kt b/app/src/main/java/at/bitfire/davdroid/StorageLowReceiver.kt
index df9a4690..25c79495 100644
--- a/app/src/main/java/at/bitfire/davdroid/StorageLowReceiver.kt
+++ b/app/src/main/java/at/bitfire/davdroid/StorageLowReceiver.kt
@@ -15,19 +15,24 @@ import androidx.core.app.NotificationManagerCompat
import androidx.lifecycle.MutableLiveData
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.NotificationUtils
+import org.koin.android.ext.koin.androidContext
+import org.koin.dsl.module
class StorageLowReceiver private constructor(
val context: Context
): BroadcastReceiver(), AutoCloseable {
companion object {
- fun getInstance(context: Context) =
- Singleton.getInstance(context) { StorageLowReceiver(context) }
+ val defaultModule = module {
+ single {
+ StorageLowReceiver(androidContext())
+ }
+ }
}
val storageLow = MutableLiveData<Boolean>(false)
- init {
+ fun listen() {
Logger.log.fine("Listening for device storage low/OK broadcasts")
val filter = IntentFilter().apply {
addAction(Intent.ACTION_DEVICE_STORAGE_LOW)
diff --git a/app/src/main/java/at/bitfire/davdroid/TasksWatcher.kt b/app/src/main/java/at/bitfire/davdroid/TasksWatcher.kt
index 565ed518..faf8be5e 100644
--- a/app/src/main/java/at/bitfire/davdroid/TasksWatcher.kt
+++ b/app/src/main/java/at/bitfire/davdroid/TasksWatcher.kt
@@ -10,9 +10,9 @@ import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import androidx.annotation.WorkerThread
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.TaskUtils
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.Settings
@@ -21,12 +21,14 @@ import at.bitfire.ical4android.TaskProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
class TasksWatcher protected constructor(
context: Context
): PackageChangedReceiver(context) {
- companion object {
+ companion object: KoinComponent {
fun watch(context: Context) = TasksWatcher(context)
@@ -42,7 +44,7 @@ class TasksWatcher protected constructor(
}
// check all accounts and (de)activate task provider(s) if a CalDAV service is defined
- val db = AppDatabase.getInstance(context)
+ val db = get<AppDatabase>()
val accountManager = AccountManager.get(context)
for (account in accountManager.getAccountsByType(context.getString(R.string.account_type))) {
val hasCalDAV = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV) != null
@@ -73,7 +75,7 @@ class TasksWatcher protected constructor(
try {
val settings = AccountSettings(context, account)
val interval = settings.getSavedTasksSyncInterval() ?:
- SettingsManager.getInstance(context).getLong(Settings.DEFAULT_SYNC_INTERVAL)
+ get<SettingsManager>().getLong(Settings.DEFAULT_SYNC_INTERVAL)
settings.setSyncInterval(authority, interval)
} catch (e: InvalidAccountException) {
// account has already been removed
diff --git a/app/src/main/java/at/bitfire/davdroid/db/AppDatabase.kt b/app/src/main/java/at/bitfire/davdroid/db/AppDatabase.kt
index 5de0ab1a..201568b2 100644
--- a/app/src/main/java/at/bitfire/davdroid/db/AppDatabase.kt
+++ b/app/src/main/java/at/bitfire/davdroid/db/AppDatabase.kt
@@ -16,11 +16,13 @@ import androidx.room.*
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import at.bitfire.davdroid.R
-import at.bitfire.davdroid.Singleton
import at.bitfire.davdroid.TextTable
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.AccountsActivity
import at.bitfire.davdroid.ui.NotificationUtils
+import org.koin.android.ext.koin.androidContext
+import org.koin.core.component.KoinComponent
+import org.koin.dsl.module
import java.io.Writer
@Suppress("ClassName")
@@ -45,9 +47,15 @@ abstract class AppDatabase: RoomDatabase() {
abstract fun webDavDocumentDao(): WebDavDocumentDao
abstract fun webDavMountDao(): WebDavMountDao
- companion object {
+ companion object: KoinComponent {
- fun getInstance(context: Context) = Singleton.getInstance<AppDatabase>(context) {
+ val defaultModule = module {
+ single {
+ AppDatabase.createInstance(androidContext())
+ }
+ }
+
+ fun createInstance(context: Context) =
Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "services.db")
.addMigrations(*migrations)
.fallbackToDestructiveMigration() // as a last fallback, recreate database instead of crashing
@@ -72,7 +80,6 @@ abstract class AppDatabase: RoomDatabase() {
}
})
.build()
- }
// migrations
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt
index d6101cca..54ab2145 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt
+++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt
@@ -16,9 +16,9 @@ import android.provider.ContactsContract.RawContacts
import android.util.Base64
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.R
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.SyncState
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.syncadapter.AccountUtils
import at.bitfire.vcard4android.*
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.kt b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.kt
index 0af67147..90240734 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.kt
+++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.kt
@@ -13,9 +13,9 @@ import android.provider.CalendarContract.Calendars
import android.provider.CalendarContract.Events
import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.DavUtils
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.SyncState
+import at.bitfire.davdroid.log.Logger
import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.AndroidCalendarFactory
import at.bitfire.ical4android.BatchOperation
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalJtxICalObject.kt b/app/src/main/java/at/bitfire/davdroid/resource/LocalJtxICalObject.kt
index 9c262d13..1627fc57 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/LocalJtxICalObject.kt
+++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalJtxICalObject.kt
@@ -5,7 +5,9 @@
package at.bitfire.davdroid.resource
import android.content.ContentValues
-import at.bitfire.ical4android.*
+import at.bitfire.ical4android.JtxCollection
+import at.bitfire.ical4android.JtxICalObject
+import at.bitfire.ical4android.JtxICalObjectFactory
import at.techbee.jtx.JtxContract
class LocalJtxICalObject(
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalTaskList.kt b/app/src/main/java/at/bitfire/davdroid/resource/LocalTaskList.kt
index 6a4c1f7c..20ea115a 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/LocalTaskList.kt
+++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalTaskList.kt
@@ -11,9 +11,9 @@ import android.content.Context
import android.net.Uri
import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.DavUtils
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.SyncState
+import at.bitfire.davdroid.log.Logger
import at.bitfire.ical4android.AndroidTaskList
import at.bitfire.ical4android.AndroidTaskListFactory
import at.bitfire.ical4android.TaskProvider
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/TaskUtils.kt b/app/src/main/java/at/bitfire/davdroid/resource/TaskUtils.kt
index 89298720..a0c525ee 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/TaskUtils.kt
+++ b/app/src/main/java/at/bitfire/davdroid/resource/TaskUtils.kt
@@ -12,11 +12,15 @@ import at.bitfire.ical4android.TaskProvider.ProviderName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
-object TaskUtils {
+object TaskUtils: KoinComponent {
+
+ val settingsManager by inject<SettingsManager>()
fun currentProvider(context: Context): ProviderName? {
- val preferredAuthority = SettingsManager.getInstance(context).getString(Settings.PREFERRED_TASKS_PROVIDER)
+ val preferredAuthority = settingsManager.getString(Settings.PREFERRED_TASKS_PROVIDER)
ProviderName.values()
.sortedByDescending { it.authority == preferredAuthority }
.forEach { providerName ->
@@ -29,7 +33,7 @@ object TaskUtils {
fun isAvailable(context: Context) = currentProvider(context) != null
fun setPreferredProvider(context: Context, providerName: ProviderName) {
- SettingsManager.getInstance(context).putString(Settings.PREFERRED_TASKS_PROVIDER, providerName.authority)
+ settingsManager.putString(Settings.PREFERRED_TASKS_PROVIDER, providerName.authority)
CoroutineScope(Dispatchers.Default).launch {
TasksWatcher.updateTaskSync(context)
}
diff --git a/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt b/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt
index 4088492c..0cc92a85 100644
--- a/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt
+++ b/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt
@@ -25,11 +25,11 @@ import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.R
import at.bitfire.davdroid.TasksWatcher
import at.bitfire.davdroid.closeCompat
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Credentials
import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.resource.LocalTask
import at.bitfire.davdroid.resource.TaskUtils
@@ -46,6 +46,9 @@ import net.fortuna.ical4j.model.property.Url
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.apache.commons.lang3.StringUtils
import org.dmfs.tasks.contract.TaskContract
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
+import org.koin.core.component.inject
import java.io.ByteArrayInputStream
import java.io.ObjectInputStream
import java.util.logging.Level
@@ -59,7 +62,7 @@ import java.util.logging.Level
class AccountSettings(
val context: Context,
val account: Account
-) {
+): KoinComponent {
companion object {
@@ -174,10 +177,10 @@ class AccountSettings(
}
}
-
-
+
+
val accountManager: AccountManager = AccountManager.get(context)
- val settings = SettingsManager.getInstance(context)
+ val settings by inject<SettingsManager>()
init {
synchronized(AccountSettings::class.java) {
@@ -581,7 +584,7 @@ class AccountSettings(
* Disable it on those accounts for the future.
*/
private fun update_8_9() {
- val db = AppDatabase.getInstance(context)
+ val db = get<AppDatabase>()
val hasCalDAV = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV) != null
if (!hasCalDAV && ContentResolver.getIsSyncable(account, OpenTasks.authority) != 0) {
Logger.log.info("Disabling OpenTasks sync for $account")
diff --git a/app/src/main/java/at/bitfire/davdroid/settings/SettingsManager.kt b/app/src/main/java/at/bitfire/davdroid/settings/SettingsManager.kt
index 7ea85342..80b7e535 100644
--- a/app/src/main/java/at/bitfire/davdroid/settings/SettingsManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/settings/SettingsManager.kt
@@ -7,8 +7,9 @@ package at.bitfire.davdroid.settings
import android.content.Context
import android.util.NoSuchPropertyException
import androidx.annotation.AnyThread
-import at.bitfire.davdroid.Singleton
import at.bitfire.davdroid.log.Logger
+import org.koin.android.ext.koin.androidContext
+import org.koin.dsl.module
import java.io.Writer
import java.lang.ref.WeakReference
import java.util.*
@@ -23,8 +24,11 @@ class SettingsManager private constructor(
) {
companion object {
- fun getInstance(context: Context) =
- Singleton.getInstance(context) { SettingsManager(context) }
+ val defaultModule = module {
+ single {
+ SettingsManager(androidContext())
+ }
+ }
}
private val providers = LinkedList<SettingsProvider>()
diff --git a/app/src/main/java/at/bitfire/davdroid/settings/SharedPreferencesProvider.kt b/app/src/main/java/at/bitfire/davdroid/settings/SharedPreferencesProvider.kt
index 65c43ae0..664a79e4 100644
--- a/app/src/main/java/at/bitfire/davdroid/settings/SharedPreferencesProvider.kt
+++ b/app/src/main/java/at/bitfire/davdroid/settings/SharedPreferencesProvider.kt
@@ -9,14 +9,16 @@ import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import at.bitfire.davdroid.TextTable
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.log.Logger
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.io.Writer
class SharedPreferencesProvider(
val context: Context,
val settingsManager: SettingsManager
-): SettingsProvider, SharedPreferences.OnSharedPreferenceChangeListener {
+): KoinComponent, SettingsProvider, SharedPreferences.OnSharedPreferenceChangeListener {
companion object {
private const val META_VERSION = "version"
@@ -124,7 +126,7 @@ class SharedPreferencesProvider(
edit.apply()
// open ServiceDB to upgrade it and possibly migrate settings
- AppDatabase.getInstance(context)
+ get<AppDatabase>()
}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountUtils.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountUtils.kt
index e5960285..add388be 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountUtils.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountUtils.kt
@@ -6,19 +6,9 @@ package at.bitfire.davdroid.syncadapter
import android.accounts.Account
import android.accounts.AccountManager
-import android.accounts.OnAccountsUpdateListener
import android.content.Context
import android.os.Bundle
-import androidx.annotation.AnyThread
-import at.bitfire.davdroid.R
-import at.bitfire.davdroid.Singleton
import at.bitfire.davdroid.log.Logger
-import at.bitfire.davdroid.db.AppDatabase
-import at.bitfire.davdroid.resource.LocalAddressBook
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import java.util.logging.Level
object AccountUtils {
@@ -60,15 +50,6 @@ object AccountUtils {
return true
}
- fun registerAccountsUpdateListener(context: Context) {
- val listener = Singleton.getInstance(context) {
- AccountsUpdatedListener(it)
- }
-
- val accountManager = AccountManager.get(context)
- accountManager.addOnAccountsUpdatedListener(listener, null, true)
- }
-
private fun verifyUserData(context: Context, account: Account, userData: Bundle): Boolean {
val accountManager = AccountManager.get(context)
userData.keySet().forEach { key ->
@@ -83,56 +64,4 @@ object AccountUtils {
}
- class AccountsUpdatedListener(val context: Context): OnAccountsUpdateListener {
-
- /**
- * Called when the main accounts have been updated, including when a main account has been
- * removed. In the latter case, this method fulfills two tasks:
- *
- * 1. Remove related address book accounts.
- * 2. Remove related service entries from the [AppDatabase].
- */
- @AnyThread
- override fun onAccountsUpdated(accounts: Array<out Account>) {
- /* onAccountsUpdated may be called from the main thread, but cleanupAccounts
- requires disk (database) access. So we launch it in a separate thread. */
- CoroutineScope(Dispatchers.Default).launch {
- cleanupAccounts(context, accounts)
- }
- }
-
- @Synchronized
- private fun cleanupAccounts(context: Context, accounts: Array<out Account>) {
- Logger.log.log(Level.INFO, "Cleaning up accounts. Current accounts:", accounts)
-
- val mainAccountType = context.getString(R.string.account_type)
- val mainAccountNames = accounts
- .filter { account -> account.type == mainAccountType }
- .map { it.name }
-
- val addressBookAccountType = context.getString(R.string.account_type_address_book)
- val addressBooks = accounts
- .filter { account -> account.type == addressBookAccountType }
- .map { addressBookAccount -> LocalAddressBook(context, addressBookAccount, null) }
- for (addressBook in addressBooks) {
- try {
- if (!mainAccountNames.contains(addressBook.mainAccount.name))
- // the main account for this address book doesn't exist anymore
- addressBook.delete()
- } catch(e: Exception) {
- Logger.log.log(Level.SEVERE, "Couldn't delete address book account", e)
- }
- }
-
- // delete orphaned services in DB
- val db = AppDatabase.getInstance(context)
- val serviceDao = db.serviceDao()
- if (mainAccountNames.isEmpty())
- serviceDao.deleteAll()
- else
- serviceDao.deleteExceptAccounts(mainAccountNames.toTypedArray())
- }
-
- }
-
} \ No newline at end of file
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountsUpdatedListener.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountsUpdatedListener.kt
new file mode 100644
index 00000000..654488cb
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountsUpdatedListener.kt
@@ -0,0 +1,88 @@
+/***************************************************************************************************
+ * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
+ **************************************************************************************************/
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.accounts.AccountManager
+import android.accounts.OnAccountsUpdateListener
+import android.content.Context
+import androidx.annotation.AnyThread
+import at.bitfire.davdroid.R
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalAddressBook
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import org.koin.android.ext.koin.androidContext
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
+import org.koin.dsl.module
+import java.util.logging.Level
+
+class AccountsUpdatedListener(val context: Context): KoinComponent, OnAccountsUpdateListener {
+
+ companion object {
+ val defaultModule = module {
+ single {
+ AccountsUpdatedListener(androidContext())
+ }
+ }
+ }
+
+
+ fun listen() {
+ val accountManager = AccountManager.get(context)
+ accountManager.addOnAccountsUpdatedListener(this, null, true)
+ }
+
+ /**
+ * Called when the main accounts have been updated, including when a main account has been
+ * removed. In the latter case, this method fulfills two tasks:
+ *
+ * 1. Remove related address book accounts.
+ * 2. Remove related service entries from the [AppDatabase].
+ */
+ @AnyThread
+ override fun onAccountsUpdated(accounts: Array<out Account>) {
+ /* onAccountsUpdated may be called from the main thread, but cleanupAccounts
+ requires disk (database) access. So we launch it in a separate thread. */
+ CoroutineScope(Dispatchers.Default).launch {
+ cleanupAccounts(context, accounts)
+ }
+ }
+
+ @Synchronized
+ private fun cleanupAccounts(context: Context, accounts: Array<out Account>) {
+ Logger.log.log(Level.INFO, "Cleaning up accounts. Current accounts:", accounts)
+
+ val mainAccountType = context.getString(R.string.account_type)
+ val mainAccountNames = accounts
+ .filter { account -> account.type == mainAccountType }
+ .map { it.name }
+
+ val addressBookAccountType = context.getString(R.string.account_type_address_book)
+ val addressBooks = accounts
+ .filter { account -> account.type == addressBookAccountType }
+ .map { addressBookAccount -> LocalAddressBook(context, addressBookAccount, null) }
+ for (addressBook in addressBooks) {
+ try {
+ if (!mainAccountNames.contains(addressBook.mainAccount.name))
+ // the main account for this address book doesn't exist anymore
+ addressBook.delete()
+ } catch(e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't delete address book account", e)
+ }
+ }
+
+ // delete orphaned services in DB
+ val serviceDao = get<AppDatabase>().serviceDao()
+ if (mainAccountNames.isEmpty())
+ serviceDao.deleteAll()
+ else
+ serviceDao.deleteExceptAccounts(mainAccountNames.toTypedArray())
+ }
+
+} \ No newline at end of file
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt
index 27880329..c52bfd4b 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt
@@ -14,14 +14,15 @@ import android.os.Bundle
import android.provider.ContactsContract
import androidx.core.content.ContextCompat
import at.bitfire.davdroid.closeCompat
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.settings.AccountSettings
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
+import org.koin.core.component.get
import java.util.logging.Level
class AddressBooksSyncAdapterService : SyncAdapterService() {
@@ -58,7 +59,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
}
private fun updateLocalAddressBooks(account: Account, syncResult: SyncResult): Boolean {
- val db = AppDatabase.getInstance(context)
+ val db = get<AppDatabase>()
val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CARDDAV)
val remoteAddressBooks = mutableMapOf<HttpUrl, Collection>()
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt
index 56ff7b99..2e2d2588 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt
@@ -15,8 +15,8 @@ import at.bitfire.dav4jvm.exception.DavException
import at.bitfire.dav4jvm.property.*
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.R
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.SyncState
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalCalendar
import at.bitfire.davdroid.resource.LocalEvent
import at.bitfire.davdroid.resource.LocalResource
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt
index 331c6f1e..4ac22118 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt
@@ -10,15 +10,16 @@ import android.content.Context
import android.content.SyncResult
import android.os.Bundle
import android.provider.CalendarContract
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalCalendar
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.ical4android.AndroidCalendar
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
+import org.koin.core.component.get
import java.util.logging.Level
class CalendarsSyncAdapterService: SyncAdapterService() {
@@ -63,7 +64,7 @@ class CalendarsSyncAdapterService: SyncAdapterService() {
}
private fun updateLocalCalendars(provider: ContentProviderClient, account: Account, settings: AccountSettings) {
- val db = AppDatabase.getInstance(context)
+ val db = get<AppDatabase>()
val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV)
val remoteCalendars = mutableMapOf<HttpUrl, Collection>()
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt
index 2603bc11..3f6e940a 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt
@@ -20,8 +20,8 @@ import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.DavUtils.sameTypeAs
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.SyncState
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.*
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.syncadapter.groups.CategoriesStrategy
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncAdapterService.kt
index 60264fd1..53ee9a3c 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncAdapterService.kt
@@ -12,16 +12,17 @@ import android.content.Context
import android.content.SyncResult
import android.os.Build
import android.os.Bundle
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalJtxCollection
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.ical4android.JtxCollection
import at.bitfire.ical4android.TaskProvider
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
+import org.koin.core.component.get
import java.util.logging.Level
class JtxSyncAdapterService: SyncAdapterService() {
@@ -69,7 +70,7 @@ class JtxSyncAdapterService: SyncAdapterService() {
}
private fun updateLocalCollections(account: Account, client: ContentProviderClient) {
- val db = AppDatabase.getInstance(context)
+ val db = get<AppDatabase>()
val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV)
val remoteCollections = mutableMapOf<HttpUrl, Collection>()
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt
index 00769178..638c36f5 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt
@@ -15,8 +15,8 @@ import at.bitfire.dav4jvm.exception.DavException
import at.bitfire.dav4jvm.property.*
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.R
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.SyncState
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalJtxCollection
import at.bitfire.davdroid.resource.LocalJtxICalObject
import at.bitfire.davdroid.resource.LocalResource
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAdapterService.kt
index 1b293202..17877a20 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAdapterService.kt
@@ -18,6 +18,7 @@ import at.bitfire.davdroid.PermissionUtils
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.ui.account.WifiPermissionsActivity
+import org.koin.core.component.KoinComponent
import java.util.*
import java.util.logging.Level
@@ -77,7 +78,7 @@ abstract class SyncAdapterService: Service() {
context,
true // isSyncable shouldn't be -1 because DAVx5 sets it to 0 or 1.
// However, if it is -1 by accident, set it to 1 to avoid endless sync loops.
- ) {
+ ), KoinComponent {
companion object {
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt
index 374377d8..5be1c897 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt
@@ -24,10 +24,10 @@ import at.bitfire.dav4jvm.property.GetETag
import at.bitfire.dav4jvm.property.ScheduleTag
import at.bitfire.dav4jvm.property.SyncToken
import at.bitfire.davdroid.*
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.db.SyncStats
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.*
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.ui.DebugInfoActivity
@@ -38,17 +38,17 @@ import at.bitfire.ical4android.Ical4Android
import at.bitfire.ical4android.TaskProvider
import at.bitfire.ical4android.UsesThreadContextClassLoader
import at.bitfire.vcard4android.ContactsStorageException
-import kotlinx.coroutines.asCoroutineDispatcher
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withContext
+import kotlinx.coroutines.*
import okhttp3.HttpUrl
import okhttp3.RequestBody
import org.apache.commons.io.FileUtils
import org.apache.commons.lang3.exception.ContextedException
import org.dmfs.tasks.contract.TaskContract
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.io.IOException
import java.io.InterruptedIOException
+import java.lang.ref.WeakReference
import java.net.HttpURLConnection
import java.security.cert.CertificateException
import java.util.*
@@ -68,7 +68,7 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
val authority: String,
val syncResult: SyncResult,
val localCollection: CollectionType
-): AutoCloseable {
+): AutoCloseable, KoinComponent {
enum class SyncAlgorithm {
PROPFIND_REPORT,
@@ -78,6 +78,27 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
companion object {
const val DEBUG_INFO_MAX_RESOURCE_DUMP_SIZE = 100*FileUtils.ONE_KB.toInt()
const val MAX_MULTIGET_RESOURCES = 10
+
+ var _workDispatcher: WeakReference<CoroutineDispatcher>? = null
+ /**
+ * We use our own dispatcher to
+ *
+ * - make sure that all threads have [Thread.getContextClassLoader] set, which is required for dav4jvm and ical4j (because they rely on [ServiceLoader]),
+ * - control the global number of sync worker threads.
+ *
+ * Threads created by a service automatically have a contextClassLoader.
+ */
+ fun getWorkDispatcher(): CoroutineDispatcher {
+ val cached = _workDispatcher?.get()
+ if (cached != null)
+ return cached
+
+ val newDispatcher = ThreadPoolExecutor(
+ 0, Integer.min(Runtime.getRuntime().availableProcessors(), 4),
+ 10, TimeUnit.SECONDS, LinkedBlockingQueue()
+ ).asCoroutineDispatcher()
+ return newDispatcher
+ }
}
init {
@@ -100,20 +121,7 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
protected var hasCollectionSync = false
- /**
- * We use our own dispatcher to
- *
- * - make sure that all threads have [Thread.getContextClassLoader] set, which is required for dav4jvm and ical4j (because they rely on [ServiceLoader]),
- * - control the global number of sync worker threads.
- *
- * Threads created by a service automatically have a contextClassLoader.
- */
- val workDispatcher = Singleton.getInstanceByKey("SyncManager.workDispatcher") {
- ThreadPoolExecutor(
- 0, Integer.min(Runtime.getRuntime().availableProcessors(), 4),
- 10, TimeUnit.SECONDS, LinkedBlockingQueue()
- ).asCoroutineDispatcher()
- }
+ val workDispatcher = getWorkDispatcher()
override fun close() {
@@ -133,7 +141,7 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
}
// log sync time
- val db = AppDatabase.getInstance(context)
+ val db = get<AppDatabase>()
db.runInTransaction {
db.collectionDao().getByUrl(collectionURL.toString())?.let { collection ->
db.syncStatsDao().insertOrReplace(
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt
index a7ad922b..8e33ec33 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt
@@ -11,10 +11,10 @@ import android.content.Context
import android.content.SyncResult
import android.os.Build
import android.os.Bundle
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalTaskList
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.ical4android.AndroidTaskList
@@ -22,6 +22,7 @@ import at.bitfire.ical4android.TaskProvider
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.dmfs.tasks.contract.TaskContract
+import org.koin.core.component.get
import java.util.logging.Level
/**
@@ -75,7 +76,7 @@ open class TasksSyncAdapterService: SyncAdapterService() {
}
private fun updateLocalTaskLists(provider: TaskProvider, account: Account, settings: AccountSettings) {
- val db = AppDatabase.getInstance(context)
+ val db = get<AppDatabase>()
val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV)
val remoteTaskLists = mutableMapOf<HttpUrl, Collection>()
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt
index 312e715e..3987c498 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt
@@ -15,8 +15,8 @@ import at.bitfire.dav4jvm.exception.DavException
import at.bitfire.dav4jvm.property.*
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.R
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.SyncState
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalResource
import at.bitfire.davdroid.resource.LocalTask
import at.bitfire.davdroid.resource.LocalTaskList
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AboutActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/AboutActivity.kt
index 9722c7e2..64f04a25 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/AboutActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/AboutActivity.kt
@@ -69,7 +69,7 @@ class AboutActivity: AppCompatActivity() {
binding.tabs.setupWithViewPager(binding.viewpager, false)
}
- override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.activity_about, menu)
return true
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt
index 980e7596..e34a08ac 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt
@@ -34,9 +34,11 @@ import at.bitfire.davdroid.StorageLowReceiver
import at.bitfire.davdroid.databinding.AccountListBinding
import at.bitfire.davdroid.databinding.AccountListItemBinding
import at.bitfire.davdroid.ui.account.AccountActivity
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.text.Collator
-class AccountListFragment: Fragment() {
+class AccountListFragment: Fragment(), KoinComponent {
private var _binding: AccountListBinding? = null
private val binding get() = _binding!!
@@ -61,7 +63,7 @@ class AccountListFragment: Fragment() {
startActivity(intent)
}
- StorageLowReceiver.getInstance(requireActivity()).storageLow.observe(viewLifecycleOwner) { storageLow ->
+ get<StorageLowReceiver>().storageLow.observe(viewLifecycleOwner) { storageLow ->
binding.lowStorageInfo.visibility = if (storageLow) View.VISIBLE else View.GONE
}
binding.manageStorage.setOnClickListener {
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AppSettingsActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/AppSettingsActivity.kt
index cc1719ff..062aa98c 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/AppSettingsActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/AppSettingsActivity.kt
@@ -29,6 +29,8 @@ import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
import java.net.URI
import java.net.URISyntaxException
import kotlin.math.roundToInt
@@ -53,9 +55,9 @@ class AppSettingsActivity: AppCompatActivity() {
}
- class SettingsFragment: PreferenceFragmentCompat(), SettingsManager.OnChangeListener {
+ class SettingsFragment: PreferenceFragmentCompat(), KoinComponent, SettingsManager.OnChangeListener {
- val settings by lazy { SettingsManager.getInstance(requireActivity()) }
+ val settings by inject<SettingsManager>()
val onBatteryOptimizationResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
loadSettings()
@@ -256,7 +258,6 @@ class AppSettingsActivity: AppCompatActivity() {
}
private fun resetHints() {
- val settings = SettingsManager.getInstance(requireActivity())
settings.remove(BatteryOptimizationsFragment.Model.HINT_BATTERY_OPTIMIZATIONS)
settings.remove(BatteryOptimizationsFragment.Model.HINT_AUTOSTART_PERMISSION)
settings.remove(TasksFragment.Model.HINT_OPENTASKS_NOT_INSTALLED)
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/BaseAccountsDrawerHandler.kt b/app/src/main/java/at/bitfire/davdroid/ui/BaseAccountsDrawerHandler.kt
index 5fd868b4..7e4e5252 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/BaseAccountsDrawerHandler.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/BaseAccountsDrawerHandler.kt
@@ -8,16 +8,12 @@ import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
-import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.annotation.CallSuper
-import at.bitfire.davdroid.App
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.R
-import at.bitfire.davdroid.log.Logger
-import at.bitfire.davdroid.ui.webdav.WebdavMountsActivity
/**
* Default menu items control
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt
index 753e7d70..0b1d249d 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt
@@ -39,8 +39,8 @@ import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.R
import at.bitfire.davdroid.TextTable
import at.bitfire.davdroid.databinding.ActivityDebugInfoBinding
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.SettingsManager
@@ -57,6 +57,8 @@ import org.apache.commons.io.IOUtils
import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.exception.ExceptionUtils
import org.dmfs.tasks.contract.TaskContract
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.io.*
import java.util.*
import java.util.logging.Level
@@ -171,7 +173,7 @@ class DebugInfoActivity: AppCompatActivity() {
class ReportModel(
val context: Application
- ): AndroidViewModel(context) {
+ ): AndroidViewModel(context), KoinComponent {
private var initialized = false
@@ -469,11 +471,11 @@ class DebugInfoActivity: AppCompatActivity() {
// database dump
writer.append("\nDATABASE DUMP\n\n")
- AppDatabase.getInstance(context).dump(writer, arrayOf("webdav_document"))
+ get<AppDatabase>().dump(writer, arrayOf("webdav_document"))
// app settings
writer.append("\nAPP SETTINGS\n\n")
- SettingsManager.getInstance(context).dump(writer)
+ get<SettingsManager>().dump(writer)
writer.append("--- END DEBUG INFO ---\n")
writer.toString()
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/TasksFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/TasksFragment.kt
index ce37b833..2f043f64 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/TasksFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/TasksFragment.kt
@@ -26,6 +26,8 @@ import at.bitfire.davdroid.resource.TaskUtils
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.ical4android.TaskProvider.ProviderName
import com.google.android.material.snackbar.Snackbar
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
class TasksFragment: Fragment() {
@@ -94,7 +96,7 @@ class TasksFragment: Fragment() {
}
- class Model(app: Application) : AndroidViewModel(app), SettingsManager.OnChangeListener {
+ class Model(app: Application) : AndroidViewModel(app), KoinComponent, SettingsManager.OnChangeListener {
companion object {
@@ -107,7 +109,7 @@ class TasksFragment: Fragment() {
}
- val settings = SettingsManager.getInstance(app)
+ val settings by inject<SettingsManager>()
val currentProvider = MutableLiveData<ProviderName>()
val openTasksInstalled = MutableLiveData<Boolean>()
@@ -126,7 +128,6 @@ class TasksFragment: Fragment() {
}
val dontShow = object: ObservableBoolean() {
- val settings = SettingsManager.getInstance(getApplication())
override fun get() = settings.getBooleanOrNull(HINT_OPENTASKS_NOT_INSTALLED) == false
override fun set(dontShowAgain: Boolean) {
if (dontShowAgain)
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/UiUtils.kt b/app/src/main/java/at/bitfire/davdroid/ui/UiUtils.kt
index 9f207add..d7aeabd8 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/UiUtils.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/UiUtils.kt
@@ -19,9 +19,11 @@ import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.util.logging.Level
-object UiUtils {
+object UiUtils: KoinComponent {
const val SHORTCUT_SYNC_ALL = "syncAllAccounts"
const val SNACKBAR_LENGTH_VERY_LONG = 5000 // 5s
@@ -52,8 +54,8 @@ object UiUtils {
return false
}
- fun setTheme(context: Context) {
- val settings = SettingsManager.getInstance(context)
+ fun setTheme() {
+ val settings = get<SettingsManager>()
val mode = settings.getIntOrNull(Settings.PREFERRED_THEME) ?: Settings.PREFERRED_THEME_DEFAULT
AppCompatDelegate.setDefaultNightMode(mode)
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt
index 2fb2d88a..59091f34 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt
@@ -23,16 +23,18 @@ import androidx.lifecycle.*
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.ActivityAccountBinding
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
import java.util.logging.Level
class AccountActivity: AppCompatActivity() {
@@ -80,7 +82,7 @@ class AccountActivity: AppCompatActivity() {
}
}
- override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.activity_account, menu)
return true
}
@@ -231,7 +233,7 @@ class AccountActivity: AppCompatActivity() {
class Model(
application: Application,
val account: Account
- ): AndroidViewModel(application), OnAccountsUpdateListener {
+ ): AndroidViewModel(application), KoinComponent, OnAccountsUpdateListener {
class Factory(
val application: Application,
@@ -242,7 +244,7 @@ class AccountActivity: AppCompatActivity() {
Model(application, account) as T
}
- private val db = AppDatabase.getInstance(application)
+ private val db by inject<AppDatabase>()
val accountManager = AccountManager.get(application)!!
val accountSettings by lazy { AccountSettings(getApplication(), account) }
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionInfoFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionInfoFragment.kt
index 31dfde73..96016f2d 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionInfoFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionInfoFragment.kt
@@ -20,6 +20,8 @@ import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
class CollectionInfoFragment: DialogFragment() {
@@ -54,20 +56,21 @@ class CollectionInfoFragment: DialogFragment() {
class Model(
application: Application
- ): AndroidViewModel(application) {
+ ): AndroidViewModel(application), KoinComponent {
+ val db by inject<AppDatabase>()
var collection = MutableLiveData<Collection>()
private var initialized = false
@UiThread
fun initialize(collectionId: Long) {
+ // TODO use constructor and model factory instead of custom initialize()
if (initialized)
return
initialized = true
viewModelScope.launch(Dispatchers.IO) {
- val db = AppDatabase.getInstance(getApplication())
collection.postValue(db.collectionDao().get(collectionId))
}
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt
index 28aa8bb5..7c4787d7 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt
@@ -32,14 +32,15 @@ import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.resource.TaskUtils
-import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.PermissionsActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
-abstract class CollectionsFragment: Fragment(), SwipeRefreshLayout.OnRefreshListener {
+abstract class CollectionsFragment: Fragment(), KoinComponent, SwipeRefreshLayout.OnRefreshListener {
companion object {
const val EXTRA_SERVICE_ID = "serviceId"
@@ -146,8 +147,6 @@ abstract class CollectionsFragment: Fragment(), SwipeRefreshLayout.OnRefreshList
}
override fun onPrepareOptionsMenu(menu: Menu) {
- val settings = SettingsManager.getInstance(requireActivity())
-
menu.findItem(R.id.showOnlyPersonal).let { showOnlyPersonal ->
accountModel.showOnlyPersonal.value?.let { value ->
showOnlyPersonal.isChecked = value
@@ -266,9 +265,9 @@ abstract class CollectionsFragment: Fragment(), SwipeRefreshLayout.OnRefreshList
class Model(
val context: Application,
val accountModel: AccountActivity.Model
- ): ViewModel(), DavService.RefreshingStatusListener, SyncStatusObserver {
+ ): ViewModel(), DavService.RefreshingStatusListener, KoinComponent, SyncStatusObserver {
- private val db = AppDatabase.getInstance(context)
+ private val db by inject<AppDatabase>()
val serviceId = MutableLiveData<Long>()
private lateinit var collectionType: String
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/CreateAddressBookActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/CreateAddressBookActivity.kt
index c18ee7fa..a3fdb297 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/CreateAddressBookActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/CreateAddressBookActivity.kt
@@ -29,6 +29,8 @@ import at.bitfire.davdroid.ui.HomeSetAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.apache.commons.lang3.StringUtils
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
import java.util.*
class CreateAddressBookActivity: AppCompatActivity() {
@@ -122,9 +124,10 @@ class CreateAddressBookActivity: AppCompatActivity() {
class Model(
application: Application
- ) : AndroidViewModel(application) {
+ ) : AndroidViewModel(application), KoinComponent {
var account: Account? = null
+ val db by inject<AppDatabase>()
val displayName = MutableLiveData<String>()
val displayNameError = MutableLiveData<String>()
@@ -140,13 +143,13 @@ class CreateAddressBookActivity: AppCompatActivity() {
@MainThread
fun initialize(account: Account) {
+ // TODO use constructor and model factory instead of custom initialize()
if (this.account != null)
return
this.account = account
viewModelScope.launch(Dispatchers.IO) {
// load account info
- val db = AppDatabase.getInstance(getApplication())
db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CARDDAV)?.let { service ->
homeSets.postValue(db.homeSetDao().getBindableByService(service.id))
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCalendarActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCalendarActivity.kt
index 4384cf69..a64c2e96 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCalendarActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCalendarActivity.kt
@@ -36,6 +36,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.fortuna.ical4j.model.Calendar
import org.apache.commons.lang3.StringUtils
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
import java.time.ZoneId
import java.time.format.TextStyle
import java.util.*
@@ -210,9 +212,10 @@ class CreateCalendarActivity: AppCompatActivity(), ColorPickerDialogListener {
class Model(
application: Application
- ): AndroidViewModel(application) {
+ ): AndroidViewModel(application), KoinComponent {
var account: Account? = null
+ val db by inject<AppDatabase>()
val displayName = MutableLiveData<String>()
val displayNameError = MutableLiveData<String>()
@@ -244,7 +247,6 @@ class CreateCalendarActivity: AppCompatActivity(), ColorPickerDialogListener {
viewModelScope.launch(Dispatchers.IO) {
// load account info
- val db = AppDatabase.getInstance(getApplication())
db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV)?.let { service ->
homeSets.postValue(db.homeSetDao().getBindableByService(service.id))
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCollectionFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCollectionFragment.kt
index 5a8cbd13..cca37bd1 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCollectionFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCollectionFragment.kt
@@ -19,15 +19,17 @@ import at.bitfire.davdroid.DavService
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.ui.ExceptionInfoFragment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import okhttp3.HttpUrl.Companion.toHttpUrl
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.io.IOException
import java.io.StringWriter
import java.util.logging.Level
@@ -103,7 +105,7 @@ class CreateCollectionFragment: DialogFragment() {
class Model(
app: Application
- ): AndroidViewModel(app) {
+ ): AndroidViewModel(app), KoinComponent {
lateinit var account: Account
lateinit var serviceType: String
@@ -123,7 +125,7 @@ class CreateCollectionFragment: DialogFragment() {
dav.mkCol(generateXml()) {}
// no HTTP error -> create collection locally
- val db = AppDatabase.getInstance(getApplication())
+ val db = get<AppDatabase>()
db.serviceDao().getByAccountAndType(account.name, serviceType)?.let { service ->
collection.serviceId = service.id
db.collectionDao().insert(collection)
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/DeleteCollectionFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/DeleteCollectionFragment.kt
index da6c5a89..081d0a8c 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/DeleteCollectionFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/DeleteCollectionFragment.kt
@@ -24,6 +24,8 @@ import at.bitfire.davdroid.ui.ExceptionInfoFragment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
class DeleteCollectionFragment: DialogFragment() {
@@ -81,12 +83,12 @@ class DeleteCollectionFragment: DialogFragment() {
class Model(
application: Application
- ): AndroidViewModel(application) {
+ ): AndroidViewModel(application), KoinComponent {
var account: Account? = null
var collectionInfo: Collection? = null
- val db = AppDatabase.getInstance(application)
+ val db by inject<AppDatabase>()
val confirmation = MutableLiveData<Boolean>()
val result = MutableLiveData<Exception>()
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/RenameAccountFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/RenameAccountFragment.kt
index e7d9b624..4ca95d85 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/RenameAccountFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/RenameAccountFragment.kt
@@ -30,8 +30,8 @@ import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.R
import at.bitfire.davdroid.closeCompat
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.resource.LocalTaskList
import at.bitfire.davdroid.settings.AccountSettings
@@ -40,6 +40,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.util.logging.Level
class RenameAccountFragment: DialogFragment() {
@@ -98,7 +100,7 @@ class RenameAccountFragment: DialogFragment() {
class Model(
application: Application
- ): AndroidViewModel(application) {
+ ): AndroidViewModel(application), KoinComponent {
val finished = MutableLiveData<Boolean>()
@@ -148,7 +150,7 @@ class RenameAccountFragment: DialogFragment() {
ContentResolver.cancelSync(addrBookAccount, null)
// update account name references in database
- val db = AppDatabase.getInstance(context)
+ val db = get<AppDatabase>()
try {
db.serviceDao().renameAccount(oldAccount.name, newName)
} catch (e: Exception) {
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/SettingsActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/SettingsActivity.kt
index c89b1a28..71465a7b 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/SettingsActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/SettingsActivity.kt
@@ -28,8 +28,8 @@ import androidx.preference.*
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.PermissionUtils
import at.bitfire.davdroid.R
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.Credentials
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.TaskUtils
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.SettingsManager
@@ -42,6 +42,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.apache.commons.lang3.StringUtils
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
class SettingsActivity: AppCompatActivity() {
@@ -72,10 +74,10 @@ class SettingsActivity: AppCompatActivity() {
}
- class AccountSettingsFragment: PreferenceFragmentCompat() {
+ class AccountSettingsFragment: PreferenceFragmentCompat(), KoinComponent {
private val account by lazy { requireArguments().getParcelable<Account>(EXTRA_ACCOUNT)!! }
- private val settings by lazy { SettingsManager.getInstance(requireActivity()) }
+ private val settings by inject<SettingsManager>()
val model by viewModels<Model>()
@@ -370,12 +372,12 @@ class SettingsActivity: AppCompatActivity() {
}
- class Model(app: Application): AndroidViewModel(app), SyncStatusObserver, SettingsManager.OnChangeListener {
+ class Model(app: Application): AndroidViewModel(app), KoinComponent, SyncStatusObserver, SettingsManager.OnChangeListener {
private var account: Account? = null
private var accountSettings: AccountSettings? = null
- private val settings = SettingsManager.getInstance(app)
+ private val settings by inject<SettingsManager>()
private var statusChangeListener: Any? = null
// settings
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/WebcalFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/WebcalFragment.kt
index 792d2682..7ba2b223 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/WebcalFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/WebcalFragment.kt
@@ -29,14 +29,16 @@ import at.bitfire.davdroid.PermissionUtils
import at.bitfire.davdroid.R
import at.bitfire.davdroid.closeCompat
import at.bitfire.davdroid.databinding.AccountCaldavItemBinding
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.log.Logger
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
import java.util.logging.Level
import kotlin.collections.component1
import kotlin.collections.component2
@@ -154,12 +156,12 @@ class WebcalFragment: CollectionsFragment() {
}
- class WebcalModel(application: Application): AndroidViewModel(application) {
+ class WebcalModel(application: Application): AndroidViewModel(application), KoinComponent {
private var initialized = false
private var serviceId: Long = 0
- private val db = AppDatabase.getInstance(application)
+ private val db by inject<AppDatabase>()
private val resolver = application.contentResolver
private var calendarPermission = false
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/intro/BatteryOptimizationsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/intro/BatteryOptimizationsFragment.kt
index ca70b74b..66759c3f 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/intro/BatteryOptimizationsFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/intro/BatteryOptimizationsFragment.kt
@@ -30,6 +30,8 @@ import at.bitfire.davdroid.ui.UiUtils
import at.bitfire.davdroid.ui.intro.BatteryOptimizationsFragment.Model.Companion.HINT_AUTOSTART_PERMISSION
import at.bitfire.davdroid.ui.intro.BatteryOptimizationsFragment.Model.Companion.HINT_BATTERY_OPTIMIZATIONS
import org.apache.commons.text.WordUtils
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
import java.util.*
class BatteryOptimizationsFragment: Fragment() {
@@ -81,7 +83,7 @@ class BatteryOptimizationsFragment: Fragment() {
}
- class Model(app: Application): AndroidViewModel(app) {
+ class Model(app: Application): AndroidViewModel(app), KoinComponent {
companion object {
@@ -129,7 +131,7 @@ class BatteryOptimizationsFragment: Fragment() {
true
}
- val settings = SettingsManager.getInstance(app)
+ val settings by inject<SettingsManager>()
val shouldBeWhitelisted = MutableLiveData<Boolean>()
val isWhitelisted = MutableLiveData<Boolean>()
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/intro/IntroActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/intro/IntroActivity.kt
index cabe2489..a26605c2 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/intro/IntroActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/intro/IntroActivity.kt
@@ -14,11 +14,13 @@ import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.intro.IIntroFragmentFactory.ShowMode
import com.github.appintro.AppIntro2
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.util.*
class IntroActivity: AppIntro2() {
- companion object {
+ companion object: KoinComponent {
private val serviceLoader = ServiceLoader.load(IIntroFragmentFactory::class.java)!!
private val introFragmentFactories = serviceLoader.toList()
@@ -29,7 +31,7 @@ class IntroActivity: AppIntro2() {
}
fun shouldShowIntroActivity(context: Context): Boolean {
- val settings = SettingsManager.getInstance(context)
+ val settings = get<SettingsManager>()
return introFragmentFactories.any {
val show = it.shouldBeShown(context, settings)
Logger.log.fine("Intro fragment $it: showMode=$show")
@@ -44,7 +46,7 @@ class IntroActivity: AppIntro2() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val settings = SettingsManager.getInstance(this)
+ val settings = get<SettingsManager>()
val factoriesWithMode = introFragmentFactories.associateWith { it.shouldBeShown(this, settings) }
val showAll = factoriesWithMode.values.any { it == ShowMode.SHOW }
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/intro/OpenSourceFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/intro/OpenSourceFragment.kt
index bc0f4f7b..07af999a 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/intro/OpenSourceFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/intro/OpenSourceFragment.kt
@@ -20,6 +20,8 @@ import at.bitfire.davdroid.databinding.IntroOpenSourceBinding
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.UiUtils
import at.bitfire.davdroid.ui.intro.OpenSourceFragment.Model.Companion.SETTING_NEXT_DONATION_POPUP
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
class OpenSourceFragment: Fragment() {
@@ -42,14 +44,14 @@ class OpenSourceFragment: Fragment() {
}
- class Model(app: Application): AndroidViewModel(app) {
+ class Model(app: Application): AndroidViewModel(app), KoinComponent {
companion object {
const val SETTING_NEXT_DONATION_POPUP = "time_nextDonationPopup"
}
val dontShow = object: ObservableBoolean() {
- val settings = SettingsManager.getInstance(getApplication())
+ val settings = get<SettingsManager>()
override fun set(dontShowAgain: Boolean) {
if (dontShowAgain) {
val nextReminder = System.currentTimeMillis() + 90*86400000L // 90 days (~ 3 months)
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt
index c669ca1a..35d6671d 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt
@@ -24,11 +24,11 @@ import at.bitfire.davdroid.DavService
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.LoginAccountDetailsBinding
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Credentials
import at.bitfire.davdroid.db.HomeSet
import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.TaskUtils
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.Settings
@@ -40,9 +40,12 @@ import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
+import org.koin.core.component.inject
import java.util.logging.Level
-class AccountDetailsFragment : Fragment() {
+class AccountDetailsFragment : Fragment(), KoinComponent {
val loginModel by activityViewModels<LoginModel>()
val model by viewModels<AccountDetailsModel>()
@@ -63,7 +66,7 @@ class AccountDetailsFragment : Fragment() {
?: loginModel.baseURI?.host
// CardDAV-specific
- val settings = SettingsManager.getInstance(requireActivity())
+ val settings = get<SettingsManager>()
v.carddav.visibility = if (config.cardDAV != null) View.VISIBLE else View.GONE
if (settings.containsKey(AccountSettings.KEY_CONTACT_GROUP_METHOD))
v.contactGroupMethod.isEnabled = false
@@ -134,7 +137,9 @@ class AccountDetailsFragment : Fragment() {
class AccountDetailsModel(
application: Application
- ) : AndroidViewModel(application) {
+ ) : AndroidViewModel(application), KoinComponent {
+
+ val db by inject<AppDatabase>()
val name = MutableLiveData<String>()
val nameError = MutableLiveData<String>()
@@ -162,11 +167,9 @@ class AccountDetailsFragment : Fragment() {
// add entries for account to service DB
Logger.log.log(Level.INFO, "Writing account configuration to database", config)
- val db = AppDatabase.getInstance(context)
try {
val accountSettings = AccountSettings(context, account)
- val settings = SettingsManager.getInstance(context)
- val defaultSyncInterval = settings.getLong(Settings.DEFAULT_SYNC_INTERVAL)
+ val defaultSyncInterval = get<SettingsManager>().getLong(Settings.DEFAULT_SYNC_INTERVAL)
val refreshIntent = Intent(context, DavService::class.java)
refreshIntent.action = DavService.ACTION_REFRESH_COLLECTIONS
@@ -174,7 +177,7 @@ class AccountDetailsFragment : Fragment() {
val addrBookAuthority = context.getString(R.string.address_books_authority)
if (config.cardDAV != null) {
// insert CardDAV service
- val id = insertService(db, name, Service.TYPE_CARDDAV, config.cardDAV)
+ val id = insertService(name, Service.TYPE_CARDDAV, config.cardDAV)
// initial CardDAV account settings
accountSettings.setGroupMethod(groupMethod)
@@ -191,7 +194,7 @@ class AccountDetailsFragment : Fragment() {
if (config.calDAV != null) {
// insert CalDAV service
- val id = insertService(db, name, Service.TYPE_CALDAV, config.calDAV)
+ val id = insertService(name, Service.TYPE_CALDAV, config.calDAV)
// start CalDAV service detection (refresh collections)
refreshIntent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, id)
@@ -220,7 +223,7 @@ class AccountDetailsFragment : Fragment() {
return result
}
- private fun insertService(db: AppDatabase, accountName: String, type: String, info: DavResourceFinder.Configuration.ServiceInfo): Long {
+ private fun insertService(accountName: String, type: String, info: DavResourceFinder.Configuration.ServiceInfo): Long {
// insert service
val service = Service(0, accountName, type, info.principal)
val serviceId = db.serviceDao().insertOrReplace(service)
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.kt
index e933b56d..f4f4b7bc 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.kt
@@ -13,8 +13,8 @@ import at.bitfire.dav4jvm.exception.UnauthorizedException
import at.bitfire.dav4jvm.property.*
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.HttpClient
-import at.bitfire.davdroid.log.StringHandler
import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.log.StringHandler
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.apache.commons.lang3.builder.ReflectionToStringBuilder
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/webdav/AddWebdavMountActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/webdav/AddWebdavMountActivity.kt
index e9364efc..626d81e1 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/webdav/AddWebdavMountActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/webdav/AddWebdavMountActivity.kt
@@ -21,10 +21,10 @@ import at.bitfire.davdroid.App
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.ActivityAddWebdavMountBinding
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Credentials
import at.bitfire.davdroid.db.WebDavMount
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.UiUtils
import at.bitfire.davdroid.webdav.CredentialsStore
import com.google.android.material.snackbar.Snackbar
@@ -33,6 +33,8 @@ import kotlinx.coroutines.launch
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.apache.commons.collections4.CollectionUtils
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
import java.net.URI
import java.net.URISyntaxException
import java.util.logging.Level
@@ -135,7 +137,7 @@ class AddWebdavMountActivity: AppCompatActivity() {
}
- class Model(app: Application): AndroidViewModel(app) {
+ class Model(app: Application): AndroidViewModel(app), KoinComponent {
val displayName = MutableLiveData<String>()
val displayNameError = MutableLiveData<String>()
@@ -161,8 +163,7 @@ class AddWebdavMountActivity: AppCompatActivity() {
return false
}
- val db = AppDatabase.getInstance(getApplication())
- val id = db.webDavMountDao().insert(mount)
+ val id = get<AppDatabase>().webDavMountDao().insert(mount)
val credentialsStore = CredentialsStore(getApplication())
credentialsStore.setCredentials(id, credentials)
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/webdav/WebdavMountsActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/webdav/WebdavMountsActivity.kt
index 88e8e5ce..ef5c743d 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/webdav/WebdavMountsActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/webdav/WebdavMountsActivity.kt
@@ -32,6 +32,8 @@ import at.bitfire.davdroid.webdav.CredentialsStore
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.apache.commons.io.FileUtils
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
class WebdavMountsActivity: AppCompatActivity() {
@@ -164,11 +166,12 @@ class WebdavMountsActivity: AppCompatActivity() {
}
- class Model(app: Application): AndroidViewModel(app) {
+ class Model(app: Application): AndroidViewModel(app), KoinComponent {
val authority = app.getString(R.string.webdav_authority)
- val db = AppDatabase.getInstance(app)
+ val db by inject<AppDatabase>()
+
val mountInfos = object: MediatorLiveData<List<MountInfo>>() {
var mounts: List<WebDavMount>? = null
var roots: List<WebDavDocument>? = null
diff --git a/app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt b/app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt
index 618f362f..e3352f90 100644
--- a/app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt
+++ b/app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt
@@ -15,7 +15,10 @@ import android.graphics.BitmapFactory
import android.graphics.Point
import android.media.ThumbnailUtils
import android.net.ConnectivityManager
-import android.os.*
+import android.os.Build
+import android.os.Bundle
+import android.os.CancellationSignal
+import android.os.ParcelFileDescriptor
import android.os.storage.StorageManager
import android.provider.DocumentsContract.*
import android.provider.DocumentsProvider
@@ -31,21 +34,23 @@ import at.bitfire.dav4jvm.property.*
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.MemoryCookieStore
import at.bitfire.davdroid.R
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.db.DaoTools
+import at.bitfire.davdroid.db.WebDavDocument
+import at.bitfire.davdroid.db.WebDavMount
import at.bitfire.davdroid.log.Logger
-import at.bitfire.davdroid.db.*
import at.bitfire.davdroid.ui.webdav.WebdavMountsActivity
import at.bitfire.davdroid.webdav.cache.HeadResponseCache
import okhttp3.CookieJar
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.logging.HttpLoggingInterceptor
+import org.koin.android.ext.android.inject
import java.io.ByteArrayOutputStream
import java.io.FileNotFoundException
import java.net.HttpURLConnection
import java.util.concurrent.*
import java.util.logging.Level
-import kotlin.collections.ArrayList
-import kotlin.collections.HashMap
import kotlin.math.min
class DavDocumentsProvider: DocumentsProvider() {
@@ -68,7 +73,7 @@ class DavDocumentsProvider: DocumentsProvider() {
lateinit var authority: String
- private val db: AppDatabase by lazy { AppDatabase.getInstance(context!!) }
+ private val db: AppDatabase by inject()
private val mountDao by lazy { db.webDavMountDao() }
private val documentDao by lazy { db.webDavDocumentDao() }
private val webdavMountsLive by lazy { mountDao.getAllLive() }
diff --git a/app/src/main/java/at/bitfire/davdroid/webdav/RandomAccessCallback.kt b/app/src/main/java/at/bitfire/davdroid/webdav/RandomAccessCallback.kt
index 4db3fb72..e0406f79 100644
--- a/app/src/main/java/at/bitfire/davdroid/webdav/RandomAccessCallback.kt
+++ b/app/src/main/java/at/bitfire/davdroid/webdav/RandomAccessCallback.kt
@@ -30,9 +30,12 @@ import okhttp3.HttpUrl
import okhttp3.MediaType
import org.apache.commons.io.FileUtils
import java.io.InterruptedIOException
+import java.lang.ref.WeakReference
import java.net.HttpURLConnection
import java.util.logging.Level
+typealias MemorySegmentCache = MemoryCache<SegmentedCache.SegmentKey<RandomAccessCallback.DocumentKey>>
+
@TargetApi(26)
class RandomAccessCallback private constructor(
val context: Context,
@@ -46,6 +49,25 @@ class RandomAccessCallback private constructor(
companion object {
/** one GET request per 2 MB */
const val PAGE_SIZE: Int = (2*FileUtils.ONE_MB).toInt()
+
+ private var _memoryCache: WeakReference<MemorySegmentCache>? = null
+
+ @Synchronized
+ fun getMemoryCache(context: Context): MemorySegmentCache {
+ val cache = _memoryCache?.get()
+ if (cache != null)
+ return cache
+
+ Logger.log.info("Creating memory cache")
+
+ val maxHeapSizeMB = ContextCompat.getSystemService(context, ActivityManager::class.java)!!.memoryClass
+ val cacheSize = maxHeapSizeMB * FileUtils.ONE_MB.toInt() / 2
+ val newCache = MemorySegmentCache(cacheSize)
+
+ _memoryCache = WeakReference(newCache)
+ return newCache
+ }
+
}
private val dav = DavResource(httpClient.okHttpClient, url)
@@ -67,11 +89,7 @@ class RandomAccessCallback private constructor(
private val workerThread = HandlerThread(javaClass.simpleName).apply { start() }
val workerHandler: Handler = Handler(workerThread.looper)
- val memoryCache = Singleton.getInstance(context) { appContext ->
- val maxHeapSizeMB = ContextCompat.getSystemService(appContext, ActivityManager::class.java)!!.memoryClass
- val cacheSize = maxHeapSizeMB * FileUtils.ONE_MB.toInt() / 2
- MemoryCache<SegmentedCache.SegmentKey<DocumentKey>>(cacheSize)
- }
+ val memoryCache = getMemoryCache(context)
val cache = SegmentedCache(PAGE_SIZE, this, memoryCache)
diff --git a/app/src/main/java/at/bitfire/davdroid/webdav/ThumbnailCache.kt b/app/src/main/java/at/bitfire/davdroid/webdav/ThumbnailCache.kt
index 3a73eb73..cb8f4c13 100644
--- a/app/src/main/java/at/bitfire/davdroid/webdav/ThumbnailCache.kt
+++ b/app/src/main/java/at/bitfire/davdroid/webdav/ThumbnailCache.kt
@@ -10,8 +10,8 @@ import android.os.Build
import android.os.storage.StorageManager
import androidx.annotation.WorkerThread
import androidx.core.content.ContextCompat
-import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.db.WebDavDocument
+import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.webdav.cache.CacheUtils
import at.bitfire.davdroid.webdav.cache.DiskCache
import org.apache.commons.io.FileUtils
diff --git a/app/src/test/java/at/bitfire/davdroid/SingletonTest.kt b/app/src/test/java/at/bitfire/davdroid/SingletonTest.kt
deleted file mode 100644
index 2a3b7f74..00000000
--- a/app/src/test/java/at/bitfire/davdroid/SingletonTest.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/***************************************************************************************************
- * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
- **************************************************************************************************/
-
-package at.bitfire.davdroid
-
-import org.junit.Assert.*
-import org.junit.Before
-import org.junit.Test
-import java.lang.ref.WeakReference
-
-class SingletonTest {
-
- @Before
- fun prepare() {
- Singleton.dropAll()
- }
-
-
- @Test
- fun testCache() {
- val obj1 = Singleton.getInstance { Any() }
- assertEquals(obj1, Singleton.getInstance {
- fail("No new Any must be created")
- Any()
- })
- }
-
- @Test
- fun testCacheUsesWeakReferences() {
- var obj1: Any? = Singleton.getInstance { Any() }
- val refObj1 = WeakReference(obj1)
- obj1 = null
-
- // no reference anymore, validate
- System.gc()
- Runtime.getRuntime().gc()
- assertNull(refObj1.get())
-
- // create a new instance
- val obj2 = Singleton.getInstance { Any() }
- assertEquals(obj2, Singleton.getInstance {
- fail("No new Any must be created")
- Any()
- })
- }
-
- @Test(expected = IllegalStateException::class)
- fun testRecursive() {
- Singleton.getInstance() {
- Singleton.getInstance() {
- Any()
- }
- }
- }
-
-} \ No newline at end of file