Sfoglia il codice sorgente

DownloadJob: Network check changes (#10242)

Mostly pulled from WorkManager
Ivan Iskandar 1 anno fa
parent
commit
f9b57800b1

+ 34 - 19
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadJob.kt

@@ -13,13 +13,17 @@ import androidx.work.WorkManager
 import androidx.work.WorkerParameters
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.notification.Notifications
-import eu.kanade.tachiyomi.util.system.isConnectedToWifi
-import eu.kanade.tachiyomi.util.system.isOnline
+import eu.kanade.tachiyomi.util.system.NetworkState
+import eu.kanade.tachiyomi.util.system.activeNetworkState
+import eu.kanade.tachiyomi.util.system.networkStateFlow
 import eu.kanade.tachiyomi.util.system.notificationBuilder
 import eu.kanade.tachiyomi.util.system.setForegroundSafely
-import kotlinx.coroutines.delay
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combineTransform
+import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import tachiyomi.domain.download.service.DownloadPreferences
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
@@ -50,7 +54,11 @@ class DownloadJob(context: Context, workerParams: WorkerParameters) : CoroutineW
     }
 
     override suspend fun doWork(): Result {
-        var active = checkConnectivity() && downloadManager.downloaderStart()
+        var networkCheck = checkNetworkState(
+            applicationContext.activeNetworkState(),
+            downloadPreferences.downloadOnlyOverWifi().get(),
+        )
+        var active = networkCheck && downloadManager.downloaderStart()
 
         if (!active) {
             return Result.failure()
@@ -58,29 +66,36 @@ class DownloadJob(context: Context, workerParams: WorkerParameters) : CoroutineW
 
         setForegroundSafely()
 
+        coroutineScope {
+            combineTransform(
+                applicationContext.networkStateFlow(),
+                downloadPreferences.downloadOnlyOverWifi().changes(),
+                transform = { a, b -> emit(checkNetworkState(a, b)) },
+            )
+                .onEach { networkCheck = it }
+                .launchIn(this)
+        }
+
         // Keep the worker running when needed
         while (active) {
-            delay(100)
-            active = !isStopped && downloadManager.isRunning && checkConnectivity()
+            active = !isStopped && downloadManager.isRunning && networkCheck
         }
 
         return Result.success()
     }
 
-    private fun checkConnectivity(): Boolean {
-        return with(applicationContext) {
-            if (isOnline()) {
-                val noWifi = downloadPreferences.downloadOnlyOverWifi().get() && !isConnectedToWifi()
-                if (noWifi) {
-                    downloadManager.downloaderStop(
-                        applicationContext.getString(R.string.download_notifier_text_only_wifi),
-                    )
-                }
-                !noWifi
-            } else {
-                downloadManager.downloaderStop(applicationContext.getString(R.string.download_notifier_no_network))
-                false
+    private fun checkNetworkState(state: NetworkState, requireWifi: Boolean): Boolean {
+        return if (state.isOnline) {
+            val noWifi = requireWifi && !state.isWifi
+            if (noWifi) {
+                downloadManager.downloaderStop(
+                    applicationContext.getString(R.string.download_notifier_text_only_wifi),
+                )
             }
+            !noWifi
+        } else {
+            downloadManager.downloaderStop(applicationContext.getString(R.string.download_notifier_no_network))
+            false
         }
     }
 

+ 67 - 0
app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkStateTracker.kt

@@ -0,0 +1,67 @@
+package eu.kanade.tachiyomi.util.system
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.net.ConnectivityManager
+import android.net.ConnectivityManager.NetworkCallback
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.os.Build
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.callbackFlow
+
+data class NetworkState(
+    val isConnected: Boolean,
+    val isValidated: Boolean,
+    val isWifi: Boolean,
+) {
+    val isOnline = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+        isConnected && isValidated
+    } else {
+        isConnected
+    }
+}
+
+@Suppress("DEPRECATION")
+fun Context.activeNetworkState(): NetworkState {
+    val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
+    return NetworkState(
+        isConnected = connectivityManager.activeNetworkInfo?.isConnected ?: false,
+        isValidated = capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) ?: false,
+        isWifi = wifiManager.isWifiEnabled && capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ?: false,
+    )
+}
+
+@Suppress("DEPRECATION")
+fun Context.networkStateFlow() = callbackFlow {
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+        val networkCallback = object : NetworkCallback() {
+            override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
+                trySend(activeNetworkState())
+            }
+            override fun onLost(network: Network) {
+                trySend(activeNetworkState())
+            }
+        }
+
+        connectivityManager.registerDefaultNetworkCallback(networkCallback)
+        awaitClose {
+            connectivityManager.unregisterNetworkCallback(networkCallback)
+        }
+    } else {
+        val receiver = object : BroadcastReceiver() {
+            override fun onReceive(context: Context, intent: Intent) {
+                if (intent.action == ConnectivityManager.CONNECTIVITY_ACTION) {
+                    trySend(activeNetworkState())
+                }
+            }
+        }
+
+        registerReceiver(receiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
+        awaitClose {
+            unregisterReceiver(receiver)
+        }
+    }
+}