Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef3c726e authored by Mohammed Althaf T's avatar Mohammed Althaf T 😊
Browse files

AM: Fix sync always pending on Android 14+

parent 447070b8
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -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. */
+23 −27
Original line number Diff line number Diff line
@@ -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.
     *