Loading .gitlab-ci.yml +5 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,11 @@ stages: - build before_script: - echo MURENA_CLIENT_ID=$MURENA_CLIENT_ID >> local.properties - echo MURENA_REDIRECT_URI=$MURENA_REDIRECT_URI >> local.properties - echo MURENA_LOGOUT_REDIRECT_URI=$MURENA_LOGOUT_REDIRECT_URI >> local.properties - echo MURENA_BASE_URL=$MURENA_BASE_URL_STAGING >> local.properties - echo MURENA_DISCOVERY_END_POINT=$MURENA_DISCOVERY_END_POINT_STAGING >> local.properties - export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 - export GRADLE_USER_HOME=$(pwd)/.gradle - chmod +x ./gradlew Loading app/build.gradle.kts +23 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,19 @@ android { if (versionName != null) { setProperty("archivesBaseName", "AccountManager-$versionName") } buildConfigField("String", "MURENA_CLIENT_ID", "\"${retrieveKey("MURENA_CLIENT_ID")}\"") buildConfigField("String", "MURENA_REDIRECT_URI", "\"${retrieveKey("MURENA_REDIRECT_URI")}\"") buildConfigField("String", "MURENA_LOGOUT_REDIRECT_URI", "\"${retrieveKey("MURENA_LOGOUT_REDIRECT_URI")}\"") buildConfigField("String", "MURENA_BASE_URL", "\"${retrieveKey("MURENA_BASE_URL")}\"") buildConfigField("String", "MURENA_DISCOVERY_END_POINT", "\"${retrieveKey("MURENA_DISCOVERY_END_POINT")}\"") manifestPlaceholders.putAll( mapOf<String, Any>( "murenaAuthRedirectScheme" to retrieveKey("MURENA_REDIRECT_URI"), "murenaAuthLogoutRedirectScheme" to retrieveKey("MURENA_LOGOUT_REDIRECT_URI") ) ) } } Loading Loading @@ -168,6 +181,15 @@ android { } } fun retrieveKey(keyName: String): String { val properties = Properties().apply { load(rootProject.file("local.properties").inputStream()) } return properties.getProperty(keyName) ?: throw GradleException("$keyName property not found in local.properties file") } ksp { arg("room.schemaLocation", "$projectDir/schemas") } Loading Loading @@ -257,6 +279,7 @@ dependencies { implementation(libs.commons.lang) // e-Specific dependencies implementation(libs.androidx.runtime.livedata) implementation(libs.elib) implementation(libs.ez.vcard) implementation(libs.synctools) { Loading app/src/main/kotlin/at/bitfire/davdroid/repository/AccountRepository.kt +2 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import at.bitfire.vcard4android.GroupMethod import dagger.Lazy import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.accountmanager.AccountTypes import foundation.e.accountmanager.pref.AuthStatePrefUtils import foundation.e.accountmanager.utils.AccountHelper import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.awaitClose Loading Loading @@ -75,6 +76,7 @@ class AccountRepository @Inject constructor( // create Android account val userData = AccountSettings.initialUserData(credentials) AuthStatePrefUtils.saveAuthState(context, account, credentials?.authState?.jsonSerializeString()) logger.log(Level.INFO, "Creating Android account with initial config", arrayOf(account, userData)) if (!SystemAccountUtils.createAccount(context, account, userData, credentials?.password)) Loading app/src/main/kotlin/at/bitfire/davdroid/settings/AccountSettings.kt +6 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.accountmanager.AccountTypes import foundation.e.accountmanager.pref.AuthStatePrefUtils import net.openid.appauth.AuthState import java.util.Collections import java.util.logging.Level Loading Loading @@ -72,7 +73,7 @@ class AccountSettings @AssistedInject constructor( *AccountTypes.getAccountTypes().toTypedArray(), "at.bitfire.davdroid.test" // R.strings.account_type_test in androidTest ) if (!allowedAccountTypes.contains(account.type)) if (!allowedAccountTypes.any { it == account.type }) throw IllegalArgumentException("Invalid account type for AccountSettings(): ${account.type}") // synchronize because account migration must only be run one time Loading Loading @@ -131,6 +132,7 @@ class AccountSettings @AssistedInject constructor( fun updateAuthState(authState: AuthState) { accountManager.setAndVerifyUserData(account, KEY_AUTH_STATE, authState.jsonSerializeString()) AuthStatePrefUtils.saveAuthState(context, account, authState.jsonSerializeString()) } /** Loading @@ -156,6 +158,7 @@ class AccountSettings @AssistedInject constructor( SyncDataType.CONTACTS -> KEY_SYNC_INTERVAL_ADDRESSBOOKS SyncDataType.EVENTS -> KEY_SYNC_INTERVAL_CALENDARS SyncDataType.TASKS -> KEY_SYNC_INTERVAL_TASKS else -> KEY_SYNC_INTERVAL_DEFAULT } val seconds = accountManager.getUserData(account, key)?.toLong() return when (seconds) { Loading @@ -176,6 +179,7 @@ class AccountSettings @AssistedInject constructor( SyncDataType.CONTACTS -> KEY_SYNC_INTERVAL_ADDRESSBOOKS SyncDataType.EVENTS -> KEY_SYNC_INTERVAL_CALENDARS SyncDataType.TASKS -> KEY_SYNC_INTERVAL_TASKS else -> KEY_SYNC_INTERVAL_DEFAULT } val newValue = seconds ?: SYNC_INTERVAL_MANUALLY accountManager.setAndVerifyUserData(account, key, newValue.toString()) Loading Loading @@ -362,6 +366,7 @@ class AccountSettings @AssistedInject constructor( /** Stores the tasks sync interval (in seconds) so that it can be set again when the provider is switched */ const val KEY_SYNC_INTERVAL_TASKS = "sync_interval_tasks" const val KEY_SYNC_INTERVAL_DEFAULT = "sync_interval_default" const val KEY_USERNAME = "user_name" const val KEY_CERTIFICATE_ALIAS = "certificate_alias" Loading app/src/main/kotlin/at/bitfire/davdroid/sync/AutomaticSyncManager.kt +12 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import at.bitfire.davdroid.resource.LocalAddressBookStore import at.bitfire.davdroid.settings.AccountSettings import at.bitfire.davdroid.sync.adapter.SyncFrameworkIntegration import at.bitfire.davdroid.sync.worker.SyncWorkerManager import foundation.e.accountmanager.Authority import kotlinx.coroutines.runBlocking import javax.inject.Inject import javax.inject.Provider Loading Loading @@ -92,6 +93,11 @@ class AutomaticSyncManager @Inject constructor( SyncDataType.CONTACTS -> throw IllegalStateException() // handled above SyncDataType.EVENTS -> CalendarContract.AUTHORITY SyncDataType.TASKS -> tasksAppManager.get().currentProvider()?.authority SyncDataType.EMAIL -> Authority.Email.authority SyncDataType.MEDIA -> Authority.Media.authority SyncDataType.NOTES -> Authority.Notes.authority SyncDataType.APP_DATA -> Authority.AppData.authority SyncDataType.E_DRIVE -> Authority.MeteredEDrive.authority } if (authority != null && syncInterval != null) { // enable given authority, but completely disable all other possible authorities Loading Loading @@ -132,7 +138,12 @@ class AutomaticSyncManager @Inject constructor( val serviceType = when (dataType) { SyncDataType.CONTACTS -> Service.TYPE_CARDDAV SyncDataType.EVENTS, SyncDataType.TASKS -> Service.TYPE_CALDAV SyncDataType.TASKS, SyncDataType.EMAIL, SyncDataType.MEDIA, SyncDataType.NOTES, SyncDataType.APP_DATA, SyncDataType.E_DRIVE -> Service.TYPE_CALDAV } val hasService = runBlocking { serviceRepository.getByAccountAndType(account.name, serviceType) != null } Loading Loading
.gitlab-ci.yml +5 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,11 @@ stages: - build before_script: - echo MURENA_CLIENT_ID=$MURENA_CLIENT_ID >> local.properties - echo MURENA_REDIRECT_URI=$MURENA_REDIRECT_URI >> local.properties - echo MURENA_LOGOUT_REDIRECT_URI=$MURENA_LOGOUT_REDIRECT_URI >> local.properties - echo MURENA_BASE_URL=$MURENA_BASE_URL_STAGING >> local.properties - echo MURENA_DISCOVERY_END_POINT=$MURENA_DISCOVERY_END_POINT_STAGING >> local.properties - export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 - export GRADLE_USER_HOME=$(pwd)/.gradle - chmod +x ./gradlew Loading
app/build.gradle.kts +23 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,19 @@ android { if (versionName != null) { setProperty("archivesBaseName", "AccountManager-$versionName") } buildConfigField("String", "MURENA_CLIENT_ID", "\"${retrieveKey("MURENA_CLIENT_ID")}\"") buildConfigField("String", "MURENA_REDIRECT_URI", "\"${retrieveKey("MURENA_REDIRECT_URI")}\"") buildConfigField("String", "MURENA_LOGOUT_REDIRECT_URI", "\"${retrieveKey("MURENA_LOGOUT_REDIRECT_URI")}\"") buildConfigField("String", "MURENA_BASE_URL", "\"${retrieveKey("MURENA_BASE_URL")}\"") buildConfigField("String", "MURENA_DISCOVERY_END_POINT", "\"${retrieveKey("MURENA_DISCOVERY_END_POINT")}\"") manifestPlaceholders.putAll( mapOf<String, Any>( "murenaAuthRedirectScheme" to retrieveKey("MURENA_REDIRECT_URI"), "murenaAuthLogoutRedirectScheme" to retrieveKey("MURENA_LOGOUT_REDIRECT_URI") ) ) } } Loading Loading @@ -168,6 +181,15 @@ android { } } fun retrieveKey(keyName: String): String { val properties = Properties().apply { load(rootProject.file("local.properties").inputStream()) } return properties.getProperty(keyName) ?: throw GradleException("$keyName property not found in local.properties file") } ksp { arg("room.schemaLocation", "$projectDir/schemas") } Loading Loading @@ -257,6 +279,7 @@ dependencies { implementation(libs.commons.lang) // e-Specific dependencies implementation(libs.androidx.runtime.livedata) implementation(libs.elib) implementation(libs.ez.vcard) implementation(libs.synctools) { Loading
app/src/main/kotlin/at/bitfire/davdroid/repository/AccountRepository.kt +2 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import at.bitfire.vcard4android.GroupMethod import dagger.Lazy import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.accountmanager.AccountTypes import foundation.e.accountmanager.pref.AuthStatePrefUtils import foundation.e.accountmanager.utils.AccountHelper import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.awaitClose Loading Loading @@ -75,6 +76,7 @@ class AccountRepository @Inject constructor( // create Android account val userData = AccountSettings.initialUserData(credentials) AuthStatePrefUtils.saveAuthState(context, account, credentials?.authState?.jsonSerializeString()) logger.log(Level.INFO, "Creating Android account with initial config", arrayOf(account, userData)) if (!SystemAccountUtils.createAccount(context, account, userData, credentials?.password)) Loading
app/src/main/kotlin/at/bitfire/davdroid/settings/AccountSettings.kt +6 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.accountmanager.AccountTypes import foundation.e.accountmanager.pref.AuthStatePrefUtils import net.openid.appauth.AuthState import java.util.Collections import java.util.logging.Level Loading Loading @@ -72,7 +73,7 @@ class AccountSettings @AssistedInject constructor( *AccountTypes.getAccountTypes().toTypedArray(), "at.bitfire.davdroid.test" // R.strings.account_type_test in androidTest ) if (!allowedAccountTypes.contains(account.type)) if (!allowedAccountTypes.any { it == account.type }) throw IllegalArgumentException("Invalid account type for AccountSettings(): ${account.type}") // synchronize because account migration must only be run one time Loading Loading @@ -131,6 +132,7 @@ class AccountSettings @AssistedInject constructor( fun updateAuthState(authState: AuthState) { accountManager.setAndVerifyUserData(account, KEY_AUTH_STATE, authState.jsonSerializeString()) AuthStatePrefUtils.saveAuthState(context, account, authState.jsonSerializeString()) } /** Loading @@ -156,6 +158,7 @@ class AccountSettings @AssistedInject constructor( SyncDataType.CONTACTS -> KEY_SYNC_INTERVAL_ADDRESSBOOKS SyncDataType.EVENTS -> KEY_SYNC_INTERVAL_CALENDARS SyncDataType.TASKS -> KEY_SYNC_INTERVAL_TASKS else -> KEY_SYNC_INTERVAL_DEFAULT } val seconds = accountManager.getUserData(account, key)?.toLong() return when (seconds) { Loading @@ -176,6 +179,7 @@ class AccountSettings @AssistedInject constructor( SyncDataType.CONTACTS -> KEY_SYNC_INTERVAL_ADDRESSBOOKS SyncDataType.EVENTS -> KEY_SYNC_INTERVAL_CALENDARS SyncDataType.TASKS -> KEY_SYNC_INTERVAL_TASKS else -> KEY_SYNC_INTERVAL_DEFAULT } val newValue = seconds ?: SYNC_INTERVAL_MANUALLY accountManager.setAndVerifyUserData(account, key, newValue.toString()) Loading Loading @@ -362,6 +366,7 @@ class AccountSettings @AssistedInject constructor( /** Stores the tasks sync interval (in seconds) so that it can be set again when the provider is switched */ const val KEY_SYNC_INTERVAL_TASKS = "sync_interval_tasks" const val KEY_SYNC_INTERVAL_DEFAULT = "sync_interval_default" const val KEY_USERNAME = "user_name" const val KEY_CERTIFICATE_ALIAS = "certificate_alias" Loading
app/src/main/kotlin/at/bitfire/davdroid/sync/AutomaticSyncManager.kt +12 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import at.bitfire.davdroid.resource.LocalAddressBookStore import at.bitfire.davdroid.settings.AccountSettings import at.bitfire.davdroid.sync.adapter.SyncFrameworkIntegration import at.bitfire.davdroid.sync.worker.SyncWorkerManager import foundation.e.accountmanager.Authority import kotlinx.coroutines.runBlocking import javax.inject.Inject import javax.inject.Provider Loading Loading @@ -92,6 +93,11 @@ class AutomaticSyncManager @Inject constructor( SyncDataType.CONTACTS -> throw IllegalStateException() // handled above SyncDataType.EVENTS -> CalendarContract.AUTHORITY SyncDataType.TASKS -> tasksAppManager.get().currentProvider()?.authority SyncDataType.EMAIL -> Authority.Email.authority SyncDataType.MEDIA -> Authority.Media.authority SyncDataType.NOTES -> Authority.Notes.authority SyncDataType.APP_DATA -> Authority.AppData.authority SyncDataType.E_DRIVE -> Authority.MeteredEDrive.authority } if (authority != null && syncInterval != null) { // enable given authority, but completely disable all other possible authorities Loading Loading @@ -132,7 +138,12 @@ class AutomaticSyncManager @Inject constructor( val serviceType = when (dataType) { SyncDataType.CONTACTS -> Service.TYPE_CARDDAV SyncDataType.EVENTS, SyncDataType.TASKS -> Service.TYPE_CALDAV SyncDataType.TASKS, SyncDataType.EMAIL, SyncDataType.MEDIA, SyncDataType.NOTES, SyncDataType.APP_DATA, SyncDataType.E_DRIVE -> Service.TYPE_CALDAV } val hasService = runBlocking { serviceRepository.getByAccountAndType(account.name, serviceType) != null } Loading