Loading app/src/main/kotlin/at/bitfire/davdroid/sync/adapter/SyncAdapterImpl.kt +0 −9 Original line number Diff line number Diff line Loading @@ -117,15 +117,6 @@ class SyncAdapterImpl @Inject constructor( logger.fine("Starting OneTimeSyncWorker for $account $authority and waiting for it") val workerName = syncWorkerManager.enqueueOneTime(account, dataType = SyncDataType.Companion.fromAuthority(authority), fromUpload = upload) // Android 14+ does not handle pending sync state correctly. // As a defensive workaround, we can cancel specifically this still pending sync only // See: https://github.com/bitfireAT/davx5-ose/issues/1458 if (Build.VERSION.SDK_INT >= 34) { logger.fine("Android 14+ bug: Canceling forever pending sync adapter framework sync request for " + "account=$account authority=$authority upload=$upload") syncFrameworkIntegration.cancelSync(account, authority, extras) } /* Because we are not allowed to observe worker state on a background thread, we can not use it to block the sync adapter. Instead we use a Flow to get notified when the sync has finished. */ Loading app/src/main/kotlin/at/bitfire/davdroid/sync/adapter/SyncFrameworkIntegration.kt +23 −27 Original line number Diff line number Diff line Loading @@ -183,39 +183,35 @@ class SyncFrameworkIntegration @Inject constructor( * @return flow emitting true if any of the given data types has a sync pending, false otherwise */ @OptIn(ExperimentalCoroutinesApi::class) fun isSyncPending(account: Account, dataTypes: Iterable<SyncDataType>): Flow<Boolean> = if (Build.VERSION.SDK_INT >= 34) { // On Android 14+ pending sync checks always return true (bug), so we don't need to check. // See: https://github.com/bitfireAT/davx5-ose/issues/1458 flowOf(false) } else { fun isSyncPending(account: Account, dataTypes: Iterable<SyncDataType>): Flow<Boolean> { val authorities = dataTypes.flatMap { it.possibleAuthorities() } // Use address book accounts if needed val accountsFlow = if (dataTypes.contains(SyncDataType.CONTACTS)) localAddressBookStore.get().getAddressBookAccountsFlow(account) else flowOf(listOf(account)) // Observe sync pending state for the given accounts and authorities accountsFlow.flatMapLatest { accounts -> return accountsFlow.flatMapLatest { accounts -> callbackFlow { // Observe sync pending state val listener = ContentResolver.addStatusChangeListener( ContentResolver.SYNC_OBSERVER_TYPE_PENDING ) { runCatching { trySend(anyPendingSync(accounts, authorities)) } } // Emit initial value trySend(anyPendingSync(accounts, authorities)) runCatching { trySend(anyPendingSync(accounts, authorities)) } // Clean up listener on close awaitClose { ContentResolver.removeStatusChangeListener(listener) } awaitClose { ContentResolver.removeStatusChangeListener(listener) } } }.distinctUntilChanged() } /** * Check if any of the given accounts and authorities have a sync pending. * Loading Loading
app/src/main/kotlin/at/bitfire/davdroid/sync/adapter/SyncAdapterImpl.kt +0 −9 Original line number Diff line number Diff line Loading @@ -117,15 +117,6 @@ class SyncAdapterImpl @Inject constructor( logger.fine("Starting OneTimeSyncWorker for $account $authority and waiting for it") val workerName = syncWorkerManager.enqueueOneTime(account, dataType = SyncDataType.Companion.fromAuthority(authority), fromUpload = upload) // Android 14+ does not handle pending sync state correctly. // As a defensive workaround, we can cancel specifically this still pending sync only // See: https://github.com/bitfireAT/davx5-ose/issues/1458 if (Build.VERSION.SDK_INT >= 34) { logger.fine("Android 14+ bug: Canceling forever pending sync adapter framework sync request for " + "account=$account authority=$authority upload=$upload") syncFrameworkIntegration.cancelSync(account, authority, extras) } /* Because we are not allowed to observe worker state on a background thread, we can not use it to block the sync adapter. Instead we use a Flow to get notified when the sync has finished. */ Loading
app/src/main/kotlin/at/bitfire/davdroid/sync/adapter/SyncFrameworkIntegration.kt +23 −27 Original line number Diff line number Diff line Loading @@ -183,39 +183,35 @@ class SyncFrameworkIntegration @Inject constructor( * @return flow emitting true if any of the given data types has a sync pending, false otherwise */ @OptIn(ExperimentalCoroutinesApi::class) fun isSyncPending(account: Account, dataTypes: Iterable<SyncDataType>): Flow<Boolean> = if (Build.VERSION.SDK_INT >= 34) { // On Android 14+ pending sync checks always return true (bug), so we don't need to check. // See: https://github.com/bitfireAT/davx5-ose/issues/1458 flowOf(false) } else { fun isSyncPending(account: Account, dataTypes: Iterable<SyncDataType>): Flow<Boolean> { val authorities = dataTypes.flatMap { it.possibleAuthorities() } // Use address book accounts if needed val accountsFlow = if (dataTypes.contains(SyncDataType.CONTACTS)) localAddressBookStore.get().getAddressBookAccountsFlow(account) else flowOf(listOf(account)) // Observe sync pending state for the given accounts and authorities accountsFlow.flatMapLatest { accounts -> return accountsFlow.flatMapLatest { accounts -> callbackFlow { // Observe sync pending state val listener = ContentResolver.addStatusChangeListener( ContentResolver.SYNC_OBSERVER_TYPE_PENDING ) { runCatching { trySend(anyPendingSync(accounts, authorities)) } } // Emit initial value trySend(anyPendingSync(accounts, authorities)) runCatching { trySend(anyPendingSync(accounts, authorities)) } // Clean up listener on close awaitClose { ContentResolver.removeStatusChangeListener(listener) } awaitClose { ContentResolver.removeStatusChangeListener(listener) } } }.distinctUntilChanged() } /** * Check if any of the given accounts and authorities have a sync pending. * Loading