# HG changeset patch # User Da Risk # Date 1739845713 14400 # Node ID 3b8739febbfe2e54ae22bf407b4fc7b9b901905d # Parent b3dd237df1bdc98e16699779f7d39c2ddce14e29 geekorum: add isSyncActiveFlow() diff -r b3dd237df1bd -r 3b8739febbfe geekdroid/src/main/java/com/geekorum/geekdroid/accounts/SyncInProgressLiveData.kt --- a/geekdroid/src/main/java/com/geekorum/geekdroid/accounts/SyncInProgressLiveData.kt Mon Feb 17 21:58:32 2025 -0400 +++ b/geekdroid/src/main/java/com/geekorum/geekdroid/accounts/SyncInProgressLiveData.kt Mon Feb 17 22:28:33 2025 -0400 @@ -28,12 +28,15 @@ import android.content.ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE import androidx.annotation.RequiresPermission import androidx.lifecycle.LiveData +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.callbackFlow /** * Allows to observe if a Sync operation is active for a given account. * * @see ContentResolver.isSyncActive */ +@Deprecated("Use isSyncActiveFlow(account, authority)") class SyncInProgressLiveData @RequiresPermission(Manifest.permission.READ_SYNC_STATS) constructor( @@ -62,3 +65,24 @@ postValue(isSyncing) } } + +/** + * Allows to observe if a Sync operation is active for a given account. + * + * @RequiresPermission(Manifest.permission.READ_SYNC_STATS) when collecting the flow + * @see ContentResolver.isSyncActive + */ +fun isSyncActiveFlow(account: Account, authority: String) = callbackFlow { + fun sendCurrent() { + val isActive = ContentResolver.isSyncActive(account, authority) + trySend(isActive) + } + val handle = ContentResolver.addStatusChangeListener(SYNC_OBSERVER_TYPE_ACTIVE) { which -> + if (which == SYNC_OBSERVER_TYPE_ACTIVE) { + sendCurrent() + } + } + sendCurrent() + + awaitClose { ContentResolver.removeStatusChangeListener(handle) } +} \ No newline at end of file diff -r b3dd237df1bd -r 3b8739febbfe geekdroid/src/test/java/com/geekorum/geekdroid/accounts/SyncIsActiveFlowTest.kt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/geekdroid/src/test/java/com/geekorum/geekdroid/accounts/SyncIsActiveFlowTest.kt Mon Feb 17 22:28:33 2025 -0400 @@ -0,0 +1,82 @@ +/* + * Geekdroid is a utility library for development on the Android + * Platform. + * + * Copyright (C) 2017-2025 by Frederic-Charles Barthelery. + * + * This file is part of Geekdroid. + * + * Geekdroid 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. + * + * Geekdroid 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 Geekdroid. If not, see . + */ +package com.geekorum.geekdroid.accounts + +import android.accounts.Account +import android.content.ContentResolver +import android.os.Build +import android.os.Bundle +import androidx.test.ext.junit.runners.AndroidJUnit4 +import app.cash.turbine.test +import com.geekorum.geekdroid.shadows.ShadowContentResolver +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.runner.RunWith +import org.robolectric.annotation.Config +import kotlin.test.Test + +@RunWith(AndroidJUnit4::class) +@Config(shadows = [ShadowContentResolver::class], sdk = [Build.VERSION_CODES.Q]) +class SyncIsActiveFlowTest { + + private val account = Account("test", "test") + + private val AUTHORITY: String = "authority" + + @Test + fun testWhenActiveAndNoSyncGetTheCorrectData() = runTest { + isSyncActiveFlow(account, AUTHORITY).test { + assertThat(awaitItem()).isFalse() + + ContentResolver.requestSync(account, AUTHORITY, Bundle()) + assertThat(awaitItem()).isTrue() + + ContentResolver.cancelSync(account, AUTHORITY) + assertThat(awaitItem()).isFalse() + + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun testThatWhenInactiveGetLaterUpdates() = runTest { + // start a sync + ContentResolver.requestSync(account, AUTHORITY, Bundle()) + isSyncActiveFlow(account, AUTHORITY).test { + assertThat(awaitItem()).isTrue() + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun testThatWhenInactiveGetOnlyCorrectUpdates() = runTest { + // start a sync with another account + val otherAccount = Account("toto", "toto") + ContentResolver.requestSync(otherAccount, AUTHORITY, Bundle()) + + isSyncActiveFlow(account, AUTHORITY).test { + assertThat(awaitItem()).isFalse() + cancelAndIgnoreRemainingEvents() + } + } + +} \ No newline at end of file