geekorum: add isSyncActiveFlow()
authorDa Risk <da_risk@geekorum.com>
Mon, 17 Feb 2025 22:28:33 -0400
changeset 85 3b8739febbfe
parent 84 b3dd237df1bd
child 86 84e46eaf1ea0
geekorum: add isSyncActiveFlow()
geekdroid/src/main/java/com/geekorum/geekdroid/accounts/SyncInProgressLiveData.kt
geekdroid/src/test/java/com/geekorum/geekdroid/accounts/SyncIsActiveFlowTest.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
--- /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 <http://www.gnu.org/licenses/>.
+ */
+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