diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4cd2f8b6d0391c26f60c98dca5a60b2f9fc4eec5..be9978293c225f7313c9efe74254fb448d6f955e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -427,6 +427,18 @@
android:resource="@xml/eelo_sync_app_data" />
+
+
+
+
+
+
()
val permissionEvent = _permissionEvent.asSharedFlow()
diff --git a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/PasswordSyncer.kt b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/PasswordSyncer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6f92dbe0e57c01293dc111324c6480b06f6e0144
--- /dev/null
+++ b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/PasswordSyncer.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright MURENA SAS 2026
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.ContentProviderClient
+import android.content.Context
+import android.content.SyncResult
+import at.bitfire.davdroid.network.HttpClient
+
+class PasswordSyncer(context: Context): Syncer(context) {
+
+ override fun sync(
+ account: Account,
+ extras: Array,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ //unused
+ }
+}
diff --git a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncAdapterServices.kt b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncAdapterServices.kt
index 1017ba6391c75c61963302b8e04909444499f1e0..9b4a910681234650d8dcc6ff640cd6f91d8088ce 100644
--- a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncAdapterServices.kt
+++ b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncAdapterServices.kt
@@ -134,6 +134,7 @@ class MurenaTasksSyncAdapterService: SyncAdapterService()
class MurenaMediaSyncAdapterService: SyncAdapterService()
class MurenaAppDataSyncAdapterService:SyncAdapterService()
class MurenaMeteredEdriveSyncAdapterService: SyncAdapterService()
+class MurenaPasswordSyncAdapterService: SyncAdapterService()
class GoogleAddressBooksSyncAdapterService: SyncAdapterService()
class GoogleCalendarsSyncAdapterService: SyncAdapterService()
diff --git a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncWorker.kt b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncWorker.kt
index ab2b5a9a17238d7ce9935e536ca1c21073976878..a698c574d594ed8a043a17da0326a886b2c88b18 100644
--- a/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncWorker.kt
+++ b/app/src/main/kotlin/at/bitfire/davdroid/syncadapter/SyncWorker.kt
@@ -330,6 +330,8 @@ class SyncWorker @AssistedInject constructor(
AppDataSyncer(applicationContext)
applicationContext.getString(R.string.metered_edrive_authority) ->
MeteredEDriveSyncer(applicationContext)
+ applicationContext.getString(R.string.password_authority) ->
+ PasswordSyncer(context = applicationContext)
else ->
throw IllegalArgumentException("Invalid authority $authority")
}
diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt
index aed9d9a73b468e47c2e29019fe14a9f4d4c9064c..46e2c974d7c5c0ed195bb124bc04c05f89f19973 100644
--- a/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt
+++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt
@@ -442,12 +442,17 @@ class AccountDetailsFragment : Fragment() {
var contactsSyncEnabled = true
var calendarSyncEnabled = true
var tasksSyncEnabled = true
+ var passwordSyncEnabled = true
if (shouldCopyExistingSettings) {
val oldSettings = AccountSettings(context, account)
val addressBookAuthority = context.getString(R.string.address_books_authority)
val taskProvider = TaskUtils.currentProvider(context)
+ passwordSyncEnabled = ContentResolver.getSyncAutomatically(
+ account,
+ context.getString(R.string.password_authority)
+ )
mediaSyncEnabled = ContentResolver.getSyncAutomatically(
account,
context.getString(R.string.media_authority)
@@ -516,6 +521,11 @@ class AccountDetailsFragment : Fragment() {
}
}
+ ContentResolver.setSyncAutomatically(
+ account,
+ context.getString(R.string.password_authority),
+ passwordSyncEnabled
+ )
ContentResolver.setSyncAutomatically(
account,
context.getString(R.string.notes_authority),
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 22dae92b4eb93c713503028076f74d66fdb898b2..61dafd445ba4359418a016e245b049f204a08fb5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -32,6 +32,7 @@
foundation.e.mail.provider.AppContentProvider
foundation.e.drive.providers.MediasSyncProvider
foundation.e.drive.providers.SettingsSyncProvider
+ foundation.e.passwords.providers.PasswordSyncProvider
Help
foundation.e.drive
foundation.e.drive.providers.MeteredConnectionAllowedProvider
diff --git a/app/src/main/res/xml/eelo_sync_password.xml b/app/src/main/res/xml/eelo_sync_password.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5326c1e4998e76d247f3023b8c1ad7bedd330d1f
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_password.xml
@@ -0,0 +1,5 @@
+