diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAllAccountWorker.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAllAccountWorker.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ae3b0c1e4e07ca2993a9f0af069260812d968c36
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncAllAccountWorker.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright MURENA SAS 2023
+ * 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.content.Context
+import androidx.hilt.work.HiltWorker
+import androidx.work.Data
+import androidx.work.ExistingWorkPolicy
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkManager
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import at.bitfire.davdroid.log.Logger
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedInject
+import java.util.concurrent.TimeUnit
+import java.util.logging.Level
+
+/** Right after login to the cloud account, there is no guarantee the sync setup is finished, so user's might not see the calendar, task, contact accounts setup.
+ * To resolve this we need to try syncing for a specific time limit with a multiplying wait time.
+ * We need to use OneTimeWorker instead of PeriodicTimeWorker, because PeriodicTimWorker requires >= 15 min between it's job. But in our case, the job delays are in seconds.
+ **/
+@HiltWorker
+class SyncAllAccountWorker @AssistedInject constructor(
+ @Assisted appContext: Context,
+ @Assisted workerParameters: WorkerParameters,
+) : Worker(appContext, workerParameters) {
+
+ companion object {
+ private const val NAME = "sync-all-accounts"
+ private const val WAIT_SEC = "wait-sec"
+ private const val DEFAULT_WAIT_SEC: Long = 5
+ private const val WAIT_LIMIT_IN_SEC: Long = 120
+
+ fun enqueue(context: Context, waitSec: Long = DEFAULT_WAIT_SEC) {
+ if (waitSec > WAIT_LIMIT_IN_SEC) {
+ return
+ }
+
+ val data = Data.Builder()
+ data.putLong(WAIT_SEC, waitSec)
+
+ WorkManager.getInstance(context).enqueueUniqueWork(
+ NAME, ExistingWorkPolicy.REPLACE,
+ OneTimeWorkRequestBuilder()
+ .setInitialDelay(
+ waitSec,
+ TimeUnit.SECONDS
+ ) // wait some time before sync all accounts
+ .setInputData(data.build())
+ .build()
+ )
+ }
+ }
+
+ override fun doWork(): Result {
+ Logger.log.log(Level.FINE, "sync all accounts work started")
+
+ val result = SyncUtils.syncAllAccounts(applicationContext)
+ if (!result) {
+ return Result.success()
+ }
+
+ enqueueNext()
+ return Result.success()
+ }
+
+ private fun enqueueNext() {
+ var waitSec = inputData.getLong(WAIT_SEC, DEFAULT_WAIT_SEC)
+
+ if (waitSec < DEFAULT_WAIT_SEC) {
+ waitSec = DEFAULT_WAIT_SEC
+ }
+
+ enqueue(applicationContext, waitSec * 2)
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncUtils.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncUtils.kt
index 4b3278562109fd86ada6967424d54641e40a2ada..b2d663b69a0c74e2b5622cc4a5eb1700c0db3c20 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncUtils.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncUtils.kt
@@ -14,10 +14,13 @@ import android.content.pm.PackageManager
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.os.Build
+import android.view.MenuItem
+import androidx.annotation.StringRes
import androidx.annotation.WorkerThread
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import at.bitfire.davdroid.Constants
+import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.PermissionUtils
import at.bitfire.davdroid.R
@@ -157,4 +160,32 @@ object SyncUtils {
}
}
-}
\ No newline at end of file
+ private fun allAccounts(context: Context): List {
+ val accountManager = AccountManager.get(context)
+ val accounts = mutableListOf()
+
+ accounts.addAll(getAccountsByType(context, accountManager, R.string.account_type))
+ accounts.addAll(getAccountsByType(context, accountManager, R.string.eelo_account_type))
+ accounts.addAll(getAccountsByType(context, accountManager, R.string.google_account_type))
+
+ return accounts
+ }
+
+ private fun getAccountsByType(context: Context, accountManager: AccountManager, @StringRes type: Int): Array {
+ val accountType = context.getString(type)
+ return accountManager.getAccountsByType(accountType)
+ }
+
+ fun syncAllAccounts(context: Context): Boolean {
+ val accounts = allAccounts(context)
+ if (accounts.isEmpty()) {
+ return false
+ }
+
+ accounts.forEach {
+ DavUtils.requestSync(context, it)
+ }
+
+ return true
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AccountsActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/AccountsActivity.kt
index e24ab4f805f4f9371d37d9278648f106e4f5c05f..1a51058d8d5150aa1fa356e17067ab4df65d8e3a 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/AccountsActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/AccountsActivity.kt
@@ -4,28 +4,19 @@
package at.bitfire.davdroid.ui
-import android.accounts.AccountManager
import android.app.Activity
import android.content.Intent
-import android.content.SyncStatusObserver
-import android.content.pm.ShortcutManager
-import android.os.Build
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GravityCompat
-import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.ActivityAccountsBinding
+import at.bitfire.davdroid.syncadapter.SyncUtils
import at.bitfire.davdroid.ui.setup.LoginActivity
import com.google.android.material.navigation.NavigationView
import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.lifecycle.HiltViewModel
-import dagger.hilt.android.qualifiers.ApplicationContext
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
@@ -92,14 +83,7 @@ class AccountsActivity: AppCompatActivity(), NavigationView.OnNavigationItemSele
return true
}
-
- private fun allAccounts() =
- AccountManager.get(this).getAccountsByType(getString(R.string.account_type))
-
fun syncAllAccounts(item: MenuItem? = null) {
- val accounts = allAccounts()
- for (account in accounts)
- DavUtils.requestSync(this, account)
+ SyncUtils.syncAllAccounts(this)
}
-
}
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 90c1e729784b84ccd4a154d9dade0eb04bfb02e0..235eb48eb65736de396ec6bd7d13adf66ee43a63 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,7 +24,11 @@ import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
-import androidx.lifecycle.*
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.InvalidAccountException
@@ -41,6 +45,7 @@ import at.bitfire.davdroid.servicedetection.RefreshCollectionsWorker
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.syncadapter.AccountUtils
+import at.bitfire.davdroid.syncadapter.SyncAllAccountWorker
import at.bitfire.vcard4android.GroupMethod
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
@@ -352,6 +357,7 @@ class AccountDetailsFragment : Fragment() {
}
DavUtils.requestSync(activity, account)
+ SyncAllAccountWorker.enqueue(context, 2)
result.postValue(true)
}