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

Commit 0ca3c557 authored by cketti's avatar cketti
Browse files

Make ConnectivityManager notify when the active network changes

Also fix how isNetworkAvailable() works. We now always query the active network (if there is one).
parent 00f1d684
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
    xmlns:tools="http://schemas.android.com/tools"
    package="com.fsck.k9.core">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />

    <application>
+14 −81
Original line number Diff line number Diff line
package com.fsck.k9.network

import android.annotation.SuppressLint
import android.net.ConnectivityManager.NetworkCallback
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import android.net.ConnectivityManager as SystemConnectivityManager

@SuppressLint("MissingPermission")
class ConnectivityManager(private val systemConnectivityManager: SystemConnectivityManager) {
    private var isRunning = false
    private val listeners = mutableSetOf<ConnectivityChangeListener>()
    private var isNetworkAvailable: Boolean? = null

    private val networkCallback = object : NetworkCallback() {
        override fun onAvailable(network: Network) {
            synchronized(this@ConnectivityManager) {
                isNetworkAvailable = true
                notifyListeners()
            }
        }

        override fun onLost(network: Network) {
            synchronized(this@ConnectivityManager) {
                isNetworkAvailable = false
                notifyListeners()
            }
        }
    }

    @Synchronized
    fun start() {
        if (!isRunning) {
            isRunning = true

            val networkRequest = NetworkRequest.Builder().build()
            systemConnectivityManager.registerNetworkCallback(networkRequest, networkCallback)
        }
    }

    @Synchronized
    fun stop() {
        if (isRunning) {
            isRunning = false

            systemConnectivityManager.unregisterNetworkCallback(networkCallback)
        }
    }

    @Synchronized
    fun addListener(listener: ConnectivityChangeListener) {
        listeners.add(listener)
    }

    @Synchronized
    fun removeListener(listener: ConnectivityChangeListener) {
        listeners.remove(listener)
    }

    @Synchronized
    fun notifyListeners() {
        for (listener in listeners) {
            listener.onConnectivityChanged()
        }
interface ConnectivityManager {
    fun start()
    fun stop()
    fun isNetworkAvailable(): Boolean
    fun addListener(listener: ConnectivityChangeListener)
    fun removeListener(listener: ConnectivityChangeListener)
}

    fun isNetworkAvailable(): Boolean {
        return synchronized(this) { isNetworkAvailable } ?: isNetworkConnected()
fun interface ConnectivityChangeListener {
    fun onConnectivityChanged()
}

    @Suppress("DEPRECATION")
    private fun isNetworkConnected(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val activeNetwork = systemConnectivityManager.activeNetwork
            if (activeNetwork != null) {
                val networkCapabilities = systemConnectivityManager.getNetworkCapabilities(activeNetwork)
                networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false
internal fun ConnectivityManager(systemConnectivityManager: SystemConnectivityManager): ConnectivityManager {
    return if (Build.VERSION.SDK_INT >= 23) {
        ConnectivityManagerApi23(systemConnectivityManager)
    } else {
                false
        ConnectivityManagerApi21(systemConnectivityManager)
    }
        } else {
            systemConnectivityManager.activeNetworkInfo?.isConnected == true
        }
    }
}

fun interface ConnectivityChangeListener {
    fun onConnectivityChanged()
}
+62 −0
Original line number Diff line number Diff line
package com.fsck.k9.network

import android.net.ConnectivityManager.NetworkCallback
import android.net.Network
import android.net.NetworkRequest
import timber.log.Timber
import android.net.ConnectivityManager as SystemConnectivityManager

@Suppress("DEPRECATION")
internal class ConnectivityManagerApi21(
    private val systemConnectivityManager: SystemConnectivityManager
) : ConnectivityManagerBase() {
    private var isRunning = false
    private var lastNetworkType: Int? = null
    private var wasConnected: Boolean? = null

    private val networkCallback = object : NetworkCallback() {
        override fun onAvailable(network: Network) {
            Timber.v("Network available: $network")
            notifyIfConnectivityHasChanged()
        }

        override fun onLost(network: Network) {
            Timber.v("Network lost: $network")
            notifyIfConnectivityHasChanged()
        }

        private fun notifyIfConnectivityHasChanged() {
            val networkType = systemConnectivityManager.activeNetworkInfo?.type
            val isConnected = isNetworkAvailable()

            synchronized(this@ConnectivityManagerApi21) {
                if (networkType != lastNetworkType || isConnected != wasConnected) {
                    lastNetworkType = networkType
                    wasConnected = isConnected
                    notifyListeners()
                }
            }
        }
    }

    @Synchronized
    override fun start() {
        if (!isRunning) {
            isRunning = true

            val networkRequest = NetworkRequest.Builder().build()
            systemConnectivityManager.registerNetworkCallback(networkRequest, networkCallback)
        }
    }

    @Synchronized
    override fun stop() {
        if (isRunning) {
            isRunning = false

            systemConnectivityManager.unregisterNetworkCallback(networkCallback)
        }
    }

    override fun isNetworkAvailable(): Boolean = systemConnectivityManager.activeNetworkInfo?.isConnected == true
}
+69 −0
Original line number Diff line number Diff line
package com.fsck.k9.network

import android.net.ConnectivityManager.NetworkCallback
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import androidx.annotation.RequiresApi
import timber.log.Timber
import android.net.ConnectivityManager as SystemConnectivityManager

@RequiresApi(Build.VERSION_CODES.M)
internal class ConnectivityManagerApi23(
    private val systemConnectivityManager: SystemConnectivityManager
) : ConnectivityManagerBase() {
    private var isRunning = false
    private var lastActiveNetwork: Network? = null
    private var wasConnected: Boolean? = null

    private val networkCallback = object : NetworkCallback() {
        override fun onAvailable(network: Network) {
            Timber.v("Network available: $network")
            notifyIfActiveNetworkOrConnectivityHasChanged()
        }

        override fun onLost(network: Network) {
            Timber.v("Network lost: $network")
            notifyIfActiveNetworkOrConnectivityHasChanged()
        }

        private fun notifyIfActiveNetworkOrConnectivityHasChanged() {
            val activeNetwork = systemConnectivityManager.activeNetwork
            val isConnected = isNetworkAvailable()

            synchronized(this@ConnectivityManagerApi23) {
                if (activeNetwork != lastActiveNetwork || isConnected != wasConnected) {
                    lastActiveNetwork = activeNetwork
                    wasConnected = isConnected
                    notifyListeners()
                }
            }
        }
    }

    @Synchronized
    override fun start() {
        if (!isRunning) {
            isRunning = true

            val networkRequest = NetworkRequest.Builder().build()
            systemConnectivityManager.registerNetworkCallback(networkRequest, networkCallback)
        }
    }

    @Synchronized
    override fun stop() {
        if (isRunning) {
            isRunning = false

            systemConnectivityManager.unregisterNetworkCallback(networkCallback)
        }
    }

    override fun isNetworkAvailable(): Boolean {
        val activeNetwork = systemConnectivityManager.activeNetwork ?: return false
        val networkCapabilities = systemConnectivityManager.getNetworkCapabilities(activeNetwork)
        return networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
    }
}
+24 −0
Original line number Diff line number Diff line
package com.fsck.k9.network

import java.util.concurrent.CopyOnWriteArraySet

internal abstract class ConnectivityManagerBase : ConnectivityManager {
    private val listeners = CopyOnWriteArraySet<ConnectivityChangeListener>()

    @Synchronized
    override fun addListener(listener: ConnectivityChangeListener) {
        listeners.add(listener)
    }

    @Synchronized
    override fun removeListener(listener: ConnectivityChangeListener) {
        listeners.remove(listener)
    }

    @Synchronized
    protected fun notifyListeners() {
        for (listener in listeners) {
            listener.onConnectivityChanged()
        }
    }
}