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-29 15:59:23 +0300
committerRicki Hirner <hirner@bitfire.at>2022-05-29 16:03:36 +0300
commit99325e893008f98d3244fbfdee586da40f36412f (patch)
treea4d9e148798f6b71b2aa2e07b86076d3c6e20632
parent0a11a0bcfcd5a3494eb5a1c36524ccce4e1b30df (diff)
Sync adapter: improve HttpClient and cancellation (#100)
* Sync adapter: share single HttpClient between all SyncManagers (should fix bitfireAT/davx5#99) * HttpClient: use producer for CertManager * Call setAccountVisibility only when necessary * Fix tests
-rw-r--r--app/src/androidTest/java/at/bitfire/davdroid/settings/AccountSettingsTest.kt10
-rw-r--r--app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/AccountUtilsTest.kt23
-rw-r--r--app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncAdapterTest.kt2
-rw-r--r--app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt2
-rw-r--r--app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/TestSyncManager.kt4
-rw-r--r--app/src/main/java/at/bitfire/davdroid/HttpClient.kt56
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt3
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt4
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt5
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.kt5
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt3
-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.kt4
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAdapterService.kt11
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt10
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt17
-rw-r--r--app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt4
-rw-r--r--app/src/main/res/xml/account_authenticator.xml2
-rw-r--r--app/src/main/res/xml/account_authenticator_address_book.xml2
-rw-r--r--app/src/main/res/xml/sync_address_books.xml2
20 files changed, 114 insertions, 60 deletions
diff --git a/app/src/androidTest/java/at/bitfire/davdroid/settings/AccountSettingsTest.kt b/app/src/androidTest/java/at/bitfire/davdroid/settings/AccountSettingsTest.kt
index 1d7644c8..612f3899 100644
--- a/app/src/androidTest/java/at/bitfire/davdroid/settings/AccountSettingsTest.kt
+++ b/app/src/androidTest/java/at/bitfire/davdroid/settings/AccountSettingsTest.kt
@@ -33,20 +33,16 @@ class AccountSettingsTest {
@Inject
lateinit var settingsManager: SettingsManager
- @Before
- fun inject() {
- hiltRule.inject()
- }
-
val context = InstrumentationRegistry.getInstrumentation().targetContext
val account = Account("Test Account", context.getString(R.string.account_type))
val fakeCredentials = Credentials("test", "test")
-
@Before
- fun prepareAccount() {
+ fun setUp() {
+ hiltRule.inject()
+
assertTrue(AccountUtils.createAccount(context, account, AccountSettings.initialUserData(fakeCredentials)))
ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 1)
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0)
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/AccountUtilsTest.kt b/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/AccountUtilsTest.kt
index 4e48435a..bda06c6d 100644
--- a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/AccountUtilsTest.kt
+++ b/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/AccountUtilsTest.kt
@@ -9,15 +9,34 @@ import android.accounts.AccountManager
import android.os.Bundle
import androidx.test.platform.app.InstrumentationRegistry
import at.bitfire.davdroid.R
+import at.bitfire.davdroid.settings.SettingsManager
+import dagger.hilt.android.testing.HiltAndroidRule
+import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+@HiltAndroidTest
class AccountUtilsTest {
- val context = InstrumentationRegistry.getInstrumentation().targetContext
- val account = Account("Test Account", context.getString(R.string.account_type))
+ @get:Rule
+ val hiltRule = HiltAndroidRule(this)
+
+ @Inject
+ lateinit var settingsManager: SettingsManager
+
+ @Before
+ fun inject() {
+ hiltRule.inject()
+ }
+
+
+ val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext }
+ val account by lazy { Account("Test Account", context.getString(R.string.account_type)) }
@Test
fun testCreateAccount() {
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncAdapterTest.kt b/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncAdapterTest.kt
index b7288cc6..a4a7f03b 100644
--- a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncAdapterTest.kt
+++ b/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncAdapterTest.kt
@@ -10,6 +10,7 @@ import android.content.Context
import android.content.SyncResult
import android.os.Bundle
import androidx.test.platform.app.InstrumentationRegistry
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.settings.SettingsManager
@@ -135,6 +136,7 @@ class SyncAdapterTest {
account: Account,
extras: Bundle,
authority: String,
+ httpClient: Lazy<HttpClient>,
provider: ContentProviderClient,
syncResult: SyncResult
) {
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt b/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt
index e5821748..b494110c 100644
--- a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt
+++ b/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt
@@ -14,6 +14,7 @@ import at.bitfire.dav4jvm.PropStat
import at.bitfire.dav4jvm.Response
import at.bitfire.dav4jvm.Response.HrefRelation
import at.bitfire.dav4jvm.property.GetETag
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.db.Credentials
import at.bitfire.davdroid.db.SyncState
@@ -74,6 +75,7 @@ class SyncManagerTest {
account,
Bundle(),
"TestAuthority",
+ HttpClient.Builder().build(),
SyncResult(),
collection,
server
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/TestSyncManager.kt b/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/TestSyncManager.kt
index 5203b1c7..6e664bed 100644
--- a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/TestSyncManager.kt
+++ b/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/TestSyncManager.kt
@@ -13,6 +13,7 @@ import at.bitfire.dav4jvm.DavResponseCallback
import at.bitfire.dav4jvm.Response
import at.bitfire.dav4jvm.property.GetCTag
import at.bitfire.davdroid.DavUtils
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.resource.LocalResource
import at.bitfire.davdroid.settings.AccountSettings
@@ -27,10 +28,11 @@ class TestSyncManager(
account: Account,
extras: Bundle,
authority: String,
+ httpClient: HttpClient,
syncResult: SyncResult,
localCollection: LocalTestCollection,
val mockWebServer: MockWebServer
-): SyncManager<LocalTestResource, LocalTestCollection, DavCollection>(context, account, AccountSettings(context, account), extras, authority, syncResult, localCollection) {
+): SyncManager<LocalTestResource, LocalTestCollection, DavCollection>(context, account, AccountSettings(context, account), httpClient, extras, authority, syncResult, localCollection) {
override fun prepare(): Boolean {
collectionURL = mockWebServer.url("/")
diff --git a/app/src/main/java/at/bitfire/davdroid/HttpClient.kt b/app/src/main/java/at/bitfire/davdroid/HttpClient.kt
index a968961d..9e1863bc 100644
--- a/app/src/main/java/at/bitfire/davdroid/HttpClient.kt
+++ b/app/src/main/java/at/bitfire/davdroid/HttpClient.kt
@@ -91,7 +91,13 @@ class HttpClient private constructor(
val logger: java.util.logging.Logger? = Logger.log,
val loggerLevel: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.BODY
) {
- private var certManager: CustomCertManager? = null
+
+ fun interface CertManagerProducer {
+ fun certManager(): CustomCertManager
+ }
+
+ private var appInForeground = false
+ private var certManagerProducer: CertManagerProducer? = null
private var certificateAlias: String? = null
private var offerCompression: Boolean = false
@@ -136,9 +142,11 @@ class HttpClient private constructor(
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
}
- // TODO don't instantiate CustomCertManager in .Builder (causes service leaks)
- customCertManager(CustomCertManager(context, true /*BuildConfig.customCertsUI*/,
- !(settings.getBoolean(Settings.DISTRUST_SYSTEM_CERTIFICATES))))
+ customCertManager() {
+ // by default, use a CustomCertManager that respects the "distrust system certificates" setting
+ val trustSystemCerts = !settings.getBoolean(Settings.DISTRUST_SYSTEM_CERTIFICATES)
+ CustomCertManager(context, true /*BuildConfig.customCertsUI*/, trustSystemCerts)
+ }
}
// use account settings for authentication and cookies
@@ -178,11 +186,11 @@ class HttpClient private constructor(
return this
}
- fun customCertManager(manager: CustomCertManager) {
- certManager = manager
+ fun customCertManager(producer: CertManagerProducer) {
+ certManagerProducer = producer
}
fun setForeground(foreground: Boolean): Builder {
- certManager?.appInForeground = foreground
+ appInForeground = foreground
return this
}
@@ -208,15 +216,6 @@ class HttpClient private constructor(
// offer Brotli and gzip compression
orig.addInterceptor(BrotliInterceptor)
- val trustManager = certManager ?: run {
- val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
- factory.init(null as KeyStore?)
- factory.trustManagers.first() as X509TrustManager
- }
-
- val hostnameVerifier = certManager?.hostnameVerifier(OkHostnameVerifier)
- ?: OkHostnameVerifier
-
var keyManager: KeyManager? = null
certificateAlias?.let { alias ->
val context = requireNotNull(context)
@@ -249,15 +248,30 @@ class HttpClient private constructor(
orig.protocols(listOf(Protocol.HTTP_1_1))
}
- val sslContext = SSLContext.getInstance("TLS")
- sslContext.init(
+ if (certManagerProducer != null || keyManager != null) {
+ val certManager = certManagerProducer?.certManager()
+ certManager?.appInForeground = appInForeground
+
+ val trustManager = certManager ?: { // fall back to system default trust manager
+ val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ factory.init(null as KeyStore?)
+ factory.trustManagers.first() as X509TrustManager
+ }()
+
+ val hostnameVerifier = certManager?.hostnameVerifier(OkHostnameVerifier)
+ ?: OkHostnameVerifier
+
+ val sslContext = SSLContext.getInstance("TLS")
+ sslContext.init(
if (keyManager != null) arrayOf(keyManager) else null,
arrayOf(trustManager),
null)
- orig.sslSocketFactory(sslContext.socketFactory, trustManager)
- orig.hostnameVerifier(hostnameVerifier)
+ orig.sslSocketFactory(sslContext.socketFactory, trustManager)
+ orig.hostnameVerifier(hostnameVerifier)
- return HttpClient(orig.build(), certManager)
+ return HttpClient(orig.build(), certManager)
+ } else
+ return HttpClient(orig.build(), null)
}
}
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 bc270e07..275ab782 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt
@@ -13,6 +13,7 @@ import android.content.pm.PackageManager
import android.os.Bundle
import android.provider.ContactsContract
import androidx.core.content.ContextCompat
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.closeCompat
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
@@ -34,7 +35,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
appDatabase: AppDatabase
) : SyncAdapter(context, appDatabase) {
- override fun sync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
+ override fun sync(account: Account, extras: Bundle, authority: String, httpClient: Lazy<HttpClient>, provider: ContentProviderClient, syncResult: SyncResult) {
try {
val accountSettings = AccountSettings(context, account)
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 2e2d2588..c3840055 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt
@@ -14,6 +14,7 @@ import at.bitfire.dav4jvm.Response
import at.bitfire.dav4jvm.exception.DavException
import at.bitfire.dav4jvm.property.*
import at.bitfire.davdroid.DavUtils
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.log.Logger
@@ -46,10 +47,11 @@ class CalendarSyncManager(
account: Account,
accountSettings: AccountSettings,
extras: Bundle,
+ httpClient: HttpClient,
authority: String,
syncResult: SyncResult,
localCalendar: LocalCalendar
-): SyncManager<LocalEvent, LocalCalendar, DavCalendar>(context, account, accountSettings, extras, authority, syncResult, localCalendar) {
+): SyncManager<LocalEvent, LocalCalendar, DavCalendar>(context, account, accountSettings, httpClient, extras, authority, syncResult, localCalendar) {
override fun prepare(): Boolean {
collectionURL = (localCollection.name ?: return false).toHttpUrlOrNull() ?: return false
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 0570c10b..83633b5b 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt
@@ -10,6 +10,7 @@ import android.content.Context
import android.content.SyncResult
import android.os.Bundle
import android.provider.CalendarContract
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
@@ -34,7 +35,7 @@ class CalendarsSyncAdapterService: SyncAdapterService() {
appDatabase: AppDatabase
) : SyncAdapter(context, appDatabase) {
- override fun sync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
+ override fun sync(account: Account, extras: Bundle, authority: String, httpClient: Lazy<HttpClient>, provider: ContentProviderClient, syncResult: SyncResult) {
try {
val accountSettings = AccountSettings(context, account)
@@ -58,7 +59,7 @@ class CalendarsSyncAdapterService: SyncAdapterService() {
.sortedByDescending { priorityCalendars.contains(it.id) }
for (calendar in calendars) {
Logger.log.info("Synchronizing calendar #${calendar.id}, URL: ${calendar.name}")
- CalendarSyncManager(context, account, accountSettings, extras, authority, syncResult, calendar).use {
+ CalendarSyncManager(context, account, accountSettings, extras, httpClient.value, authority, syncResult, calendar).let {
it.performSync()
}
}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.kt
index e41f6dbc..83aa7496 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.kt
@@ -11,6 +11,7 @@ import android.content.Context
import android.content.SyncResult
import android.os.Bundle
import android.provider.ContactsContract
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalAddressBook
@@ -31,7 +32,7 @@ class ContactsSyncAdapterService: SyncAdapterService() {
appDatabase: AppDatabase
) : SyncAdapter(context, appDatabase) {
- override fun sync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
+ override fun sync(account: Account, extras: Bundle, authority: String, httpClient: Lazy<HttpClient>, provider: ContentProviderClient, syncResult: SyncResult) {
try {
val addressBook = LocalAddressBook(context, account, provider)
val accountSettings = AccountSettings(context, addressBook.mainAccount)
@@ -62,7 +63,7 @@ class ContactsSyncAdapterService: SyncAdapterService() {
Logger.log.info("Synchronizing address book: ${addressBook.url}")
Logger.log.info("Taking settings from: ${addressBook.mainAccount}")
- ContactsSyncManager(context, account, accountSettings, extras, authority, syncResult, provider, addressBook).use {
+ ContactsSyncManager(context, account, accountSettings, httpClient.value, extras, authority, syncResult, provider, addressBook).let {
it.performSync()
}
} catch(e: Exception) {
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 3f6e940a..2401a0a0 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt
@@ -82,12 +82,13 @@ class ContactsSyncManager(
context: Context,
account: Account,
accountSettings: AccountSettings,
+ httpClient: HttpClient,
extras: Bundle,
authority: String,
syncResult: SyncResult,
val provider: ContentProviderClient,
localAddressBook: LocalAddressBook
-): SyncManager<LocalAddress, LocalAddressBook, DavAddressBook>(context, account, accountSettings, extras, authority, syncResult, localAddressBook) {
+): SyncManager<LocalAddress, LocalAddressBook, DavAddressBook>(context, account, accountSettings, httpClient, extras, authority, syncResult, localAddressBook) {
companion object {
infix fun <T> Set<T>.disjunct(other: Set<T>) = (this - other) union (other - this)
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 9d8e6526..2653a184 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncAdapterService.kt
@@ -12,6 +12,7 @@ import android.content.Context
import android.content.SyncResult
import android.os.Build
import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
@@ -37,7 +38,7 @@ class JtxSyncAdapterService: SyncAdapterService() {
appDatabase: AppDatabase
) : SyncAdapter(context, appDatabase) {
- override fun sync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
+ override fun sync(account: Account, extras: Bundle, authority: String, httpClient: Lazy<HttpClient>, provider: ContentProviderClient, syncResult: SyncResult) {
try {
// check whether jtx Board is new enough
@@ -62,7 +63,7 @@ class JtxSyncAdapterService: SyncAdapterService() {
val collections = JtxCollection.find(account, provider, context, LocalJtxCollection.Factory, null, null)
for (collection in collections) {
Logger.log.info("Synchronizing $collection")
- JtxSyncManager(context, account, accountSettings, extras, authority, syncResult, collection).use {
+ JtxSyncManager(context, account, accountSettings, extras, httpClient.value, authority, syncResult, collection).let {
it.performSync()
}
}
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 638c36f5..c003e659 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt
@@ -14,6 +14,7 @@ import at.bitfire.dav4jvm.Response
import at.bitfire.dav4jvm.exception.DavException
import at.bitfire.dav4jvm.property.*
import at.bitfire.davdroid.DavUtils
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.log.Logger
@@ -38,10 +39,11 @@ class JtxSyncManager(
account: Account,
accountSettings: AccountSettings,
extras: Bundle,
+ httpClient: HttpClient,
authority: String,
syncResult: SyncResult,
localCollection: LocalJtxCollection
-): SyncManager<LocalJtxICalObject, LocalJtxCollection, DavCalendar>(context, account, accountSettings, extras, authority, syncResult, localCollection) {
+): SyncManager<LocalJtxICalObject, LocalJtxCollection, DavCalendar>(context, account, accountSettings, httpClient, extras, authority, syncResult, localCollection) {
override fun prepare(): Boolean {
collectionURL = (localCollection.url ?: return false).toHttpUrlOrNull() ?: return false
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 7fbb2a3a..969cbd25 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAdapterService.kt
@@ -13,6 +13,7 @@ import android.net.wifi.WifiManager
import android.os.Bundle
import androidx.core.content.getSystemService
import at.bitfire.davdroid.ConcurrentUtils
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.PermissionUtils
import at.bitfire.davdroid.db.AppDatabase
@@ -103,7 +104,7 @@ abstract class SyncAdapterService: Service() {
}
- abstract fun sync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult)
+ abstract fun sync(account: Account, extras: Bundle, authority: String, httpClient: Lazy<HttpClient>, provider: ContentProviderClient, syncResult: SyncResult)
override fun onPerformSync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
Logger.log.log(Level.INFO, "$authority sync of $account has been initiated", extras.keySet().joinToString(", "))
@@ -114,11 +115,14 @@ abstract class SyncAdapterService: Service() {
// required for ServiceLoader -> ical4j -> ical4android
Thread.currentThread().contextClassLoader = context.classLoader
+ val accountSettings by lazy { AccountSettings(context, account) }
+ val httpClient = lazy { HttpClient.Builder(context, accountSettings).build() }
+
try {
val runSync = /* always true in open-source edition */ true
if (runSync)
- sync(account, extras, authority, provider, syncResult)
+ sync(account, extras, authority, httpClient, provider, syncResult)
} catch (e: InvalidAccountException) {
Logger.log.log(
@@ -126,6 +130,9 @@ abstract class SyncAdapterService: Service() {
"Account was removed during synchronization",
e
)
+ } finally {
+ if (httpClient.isInitialized())
+ httpClient.value.close()
}
})
Logger.log.log(Level.INFO, "Sync for $currentSyncKey finished", syncResult)
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 ac143ab6..443f75ba 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt
@@ -66,11 +66,12 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
val context: Context,
val account: Account,
val accountSettings: AccountSettings,
+ val httpClient: HttpClient,
val extras: Bundle,
val authority: String,
val syncResult: SyncResult,
val localCollection: CollectionType
-): AutoCloseable {
+) {
@EntryPoint
@InstallIn(SingletonComponent::class)
@@ -122,8 +123,6 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
protected val notificationManager = NotificationManagerCompat.from(context)
protected val notificationTag = localCollection.tag
- protected val httpClient = HttpClient.Builder(context, accountSettings).build()
-
protected lateinit var collectionURL: HttpUrl
protected lateinit var davCollection: RemoteType
@@ -132,11 +131,6 @@ abstract class SyncManager<ResourceType: LocalResource<*>, out CollectionType: L
val workDispatcher = getWorkDispatcher()
- override fun close() {
- httpClient.close()
- }
-
-
fun performSync() {
// dismiss previous error notifications
notificationManager.cancel(notificationTag, NotificationUtils.NOTIFY_SYNC_ERROR)
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 b6e496d5..8b03e803 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt
@@ -11,6 +11,7 @@ import android.content.Context
import android.content.SyncResult
import android.os.Build
import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
@@ -37,14 +38,20 @@ open class TasksSyncAdapterService: SyncAdapterService() {
appDatabase: AppDatabase,
) : SyncAdapter(context, appDatabase) {
- override fun sync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
+ override fun sync(account: Account, extras: Bundle, authority: String, httpClient: Lazy<HttpClient>, provider: ContentProviderClient, syncResult: SyncResult) {
try {
val providerName = TaskProvider.ProviderName.fromAuthority(authority)
val taskProvider = TaskProvider.fromProviderClient(context, providerName, provider)
// make sure account can be seen by task provider
- if (Build.VERSION.SDK_INT >= 26)
- AccountManager.get(context).setAccountVisibility(account, providerName.packageName, AccountManager.VISIBILITY_VISIBLE)
+ if (Build.VERSION.SDK_INT >= 26) {
+ /* Warning: If setAccountVisibility is called, Android 12 broadcasts the
+ AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION Intent. This cancels running syncs
+ and starts them again! So make sure setAccountVisibility is only called when necessary. */
+ val am = AccountManager.get(context)
+ if (am.getAccountVisibility(account, providerName.packageName) != AccountManager.VISIBILITY_VISIBLE)
+ am.setAccountVisibility(account, providerName.packageName, AccountManager.VISIBILITY_VISIBLE)
+ }
val accountSettings = AccountSettings(context, account)
/* don't run sync if
@@ -62,7 +69,7 @@ open class TasksSyncAdapterService: SyncAdapterService() {
.sortedByDescending { priorityTaskLists.contains(it.id) }
for (taskList in taskLists) {
Logger.log.info("Synchronizing task list #${taskList.id} [${taskList.syncId}]")
- TasksSyncManager(context, account, accountSettings, extras, authority, syncResult, taskList).use {
+ TasksSyncManager(context, account, accountSettings, httpClient.value, extras, authority, syncResult, taskList).let {
it.performSync()
}
}
@@ -114,4 +121,4 @@ open class TasksSyncAdapterService: SyncAdapterService() {
}
-}
+} \ No newline at end of file
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 3987c498..d1dbc363 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt
@@ -14,6 +14,7 @@ import at.bitfire.dav4jvm.Response
import at.bitfire.dav4jvm.exception.DavException
import at.bitfire.dav4jvm.property.*
import at.bitfire.davdroid.DavUtils
+import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.log.Logger
@@ -40,11 +41,12 @@ class TasksSyncManager(
context: Context,
account: Account,
accountSettings: AccountSettings,
+ httpClient: HttpClient,
extras: Bundle,
authority: String,
syncResult: SyncResult,
localCollection: LocalTaskList
-): SyncManager<LocalTask, LocalTaskList, DavCalendar>(context, account, accountSettings, extras, authority, syncResult, localCollection) {
+): SyncManager<LocalTask, LocalTaskList, DavCalendar>(context, account, accountSettings, httpClient, extras, authority, syncResult, localCollection) {
override fun prepare(): Boolean {
collectionURL = (localCollection.syncId ?: return false).toHttpUrlOrNull() ?: return false
diff --git a/app/src/main/res/xml/account_authenticator.xml b/app/src/main/res/xml/account_authenticator.xml
index bf6bd348..85eaa203 100644
--- a/app/src/main/res/xml/account_authenticator.xml
+++ b/app/src/main/res/xml/account_authenticator.xml
@@ -3,4 +3,4 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:smallIcon="@mipmap/ic_launcher"
- android:accountPreferences="@xml/sync_prefs" />
+ android:accountPreferences="@xml/sync_prefs" /> \ No newline at end of file
diff --git a/app/src/main/res/xml/account_authenticator_address_book.xml b/app/src/main/res/xml/account_authenticator_address_book.xml
index 5ad7d913..6305f31e 100644
--- a/app/src/main/res/xml/account_authenticator_address_book.xml
+++ b/app/src/main/res/xml/account_authenticator_address_book.xml
@@ -3,4 +3,4 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/account_title_address_book"
android:smallIcon="@mipmap/ic_launcher"
- android:accountPreferences="@xml/sync_prefs" />
+ android:accountPreferences="@xml/sync_prefs" /> \ No newline at end of file
diff --git a/app/src/main/res/xml/sync_address_books.xml b/app/src/main/res/xml/sync_address_books.xml
index f7284820..61bfbaeb 100644
--- a/app/src/main/res/xml/sync_address_books.xml
+++ b/app/src/main/res/xml/sync_address_books.xml
@@ -2,4 +2,4 @@
android:accountType="@string/account_type"
android:contentAuthority="@string/address_books_authority"
android:allowParallelSyncs="true"
- android:supportsUploading="false" />
+ android:supportsUploading="false" /> \ No newline at end of file