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

Unverified Commit fe4282a0 authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #5368 from k9mail/connectivity_manager_network_change

Make ConnectivityManager notify when the active network changes
parents 84fc7c38 0ca3c557
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()
        }
    }
}