Refactored deprecated methods of ConnectivityManager class.

This commit refactors the deprecated methods of the ConnectivityManager class to ensure compatibility with different Android versions. The changes include:
* Introducing a new CompatV23 class to handle the deprecation of NetworkInfo and utilize the new NetworkCapabilities APIs available from Android 23 onwards.
* Retaining the existing methods for Android versions below 23 to maintain backward compatibility.
* Updating the test cases to cover both the new and old APIs.

These updates address the deprecation warnings and ensure that the code functions correctly on different Android versions.
This commit is contained in:
MohitMaliFtechiz 2023-06-07 16:47:22 +05:30
parent 9e79f11253
commit 9b1186d555
11 changed files with 198 additions and 104 deletions

View File

@ -19,12 +19,13 @@
package org.kiwix.kiwixmobile
import android.net.ConnectivityManager
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.isNetworkAvailable
import org.kiwix.kiwixmobile.zimManager.NetworkState
import org.kiwix.kiwixmobile.zimManager.NetworkState.CONNECTED
import org.kiwix.kiwixmobile.zimManager.NetworkState.NOT_CONNECTED
val ConnectivityManager.networkState: NetworkState
get() = if (activeNetworkInfo?.isConnected == true)
get() = if (isNetworkAvailable())
CONNECTED
else
NOT_CONNECTED

View File

@ -135,7 +135,7 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
get() = sharedPreferenceUtil.prefWifiOnly && !NetworkUtils.isWiFi(requireContext())
private val isNotConnected: Boolean
get() = NetworkUtils.isNetworkAvailable(requireActivity())
get() = !NetworkUtils.isNetworkAvailable(requireActivity())
override fun inject(baseActivity: BaseActivity) {
baseActivity.cachedComponent.inject(this)

View File

@ -34,6 +34,7 @@ import io.reactivex.schedulers.Schedulers
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.StorageObserver
import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.isWifi
import org.kiwix.kiwixmobile.core.dao.FetchDownloadDao
import org.kiwix.kiwixmobile.core.dao.NewBookDao
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
@ -229,7 +230,7 @@ class ZimManageViewModel @Inject constructor(
)
) { _, _ -> }
.switchMap {
if (connectivityManager.activeNetworkInfo?.type == ConnectivityManager.TYPE_WIFI) {
if (connectivityManager.isWifi()) {
Flowable.just(Unit)
} else {
sharedPreferenceUtil.prefWifiOnlys

View File

@ -22,6 +22,7 @@ import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.net.ConnectivityManager
/**
* This interface defines a set of functions that are not available on all platforms.
@ -71,4 +72,8 @@ interface Compat {
packageManager: PackageManager,
flag: Int
): PackageInfo
fun isNetworkAvailable(connectivity: ConnectivityManager): Boolean
fun isWifi(connectivity: ConnectivityManager): Boolean
}

View File

@ -22,12 +22,14 @@ import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.net.ConnectivityManager
import android.os.Build
class CompatHelper private constructor() {
// Note: Needs ": Compat" or the type system assumes `Compat21`
private val compatValue: Compat = when {
sdkVersion >= Build.VERSION_CODES.TIRAMISU -> CompatV33()
sdkVersion >= Build.VERSION_CODES.M -> CompatV23()
else -> CompatV21()
}
@ -69,7 +71,14 @@ class CompatHelper private constructor() {
fun PackageInfo.getVersionCode() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
longVersionCode.toInt()
} else {
@Suppress("DEPRECATION")
versionCode
}
fun ConnectivityManager.isNetworkAvailable(): Boolean =
compat.isNetworkAvailable(this)
fun ConnectivityManager.isWifi(): Boolean =
compat.isWifi(this)
}
}

View File

@ -22,6 +22,9 @@ import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.net.ConnectivityManager
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.NetworkInfo.State.CONNECTED
@Suppress("Deprecation")
open class CompatV21 : Compat {
@ -36,4 +39,22 @@ open class CompatV21 : Compat {
packageManager: PackageManager,
flag: Int
): PackageInfo = packageManager.getPackageInfo(packageName, 0)
/**
* Checks if the device has a network connection with internet access.
*
* @param connectivity The ConnectivityManager instance.
* @return True if a network connection with internet access is available, false otherwise.
*/
override fun isNetworkAvailable(connectivity: ConnectivityManager): Boolean =
connectivity.allNetworkInfo.any { it.state == CONNECTED }
/**
* Checks if the device is connected to a Wi-Fi network.
*
* @param connectivity The ConnectivityManager instance.
* @return True if connected to a Wi-Fi network, false otherwise.
*/
override fun isWifi(connectivity: ConnectivityManager): Boolean =
connectivity.getNetworkInfo(TYPE_WIFI)?.isConnected == true
}

View File

@ -0,0 +1,70 @@
/*
* Kiwix Android
* Copyright (c) 2023 Kiwix <android.kiwix.org>
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.kiwix.kiwixmobile.core.compat
import android.annotation.TargetApi
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.net.ConnectivityManager
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.TRANSPORT_WIFI
const val API_23 = 23
@TargetApi(API_23)
open class CompatV23 : Compat {
private val compatV21 = CompatV21()
override fun queryIntentActivities(
packageManager: PackageManager,
intent: Intent,
flags: ResolveInfoFlagsCompat
): List<ResolveInfo> =
compatV21.queryIntentActivities(packageManager, intent, flags)
override fun getPackageInformation(
packageName: String,
packageManager: PackageManager,
flag: Int
): PackageInfo = compatV21.getPackageInformation(packageName, packageManager, flag)
/**
* Checks if the device has a network connection with internet access.
*
* @param connectivity The ConnectivityManager instance.
* @return True if a network connection with internet access is available, false otherwise.
*/
override fun isNetworkAvailable(connectivity: ConnectivityManager): Boolean {
return connectivity.getNetworkCapabilities(connectivity.activeNetwork)
?.hasCapability(NET_CAPABILITY_INTERNET) == true
}
/**
* Checks if the device is connected to a Wi-Fi network.
*
* @param connectivity The ConnectivityManager instance.
* @return True if connected to a Wi-Fi network, false otherwise.
*/
override fun isWifi(connectivity: ConnectivityManager): Boolean {
return connectivity.getNetworkCapabilities(connectivity.activeNetwork)
?.hasTransport(TRANSPORT_WIFI) == true
}
}

View File

@ -24,11 +24,13 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PackageInfoFlags
import android.content.pm.ResolveInfo
import android.net.ConnectivityManager
const val API_33 = 33
@TargetApi(API_33)
open class CompatV33 : Compat {
private val compatV23 = CompatV23()
override fun queryIntentActivities(
packageManager: PackageManager,
intent: Intent,
@ -44,4 +46,10 @@ open class CompatV33 : Compat {
flag: Int
): PackageInfo =
packageManager.getPackageInfo(packageName, PackageInfoFlags.of(flag.toLong()))
override fun isNetworkAvailable(connectivity: ConnectivityManager): Boolean =
compatV23.isNetworkAvailable(connectivity)
override fun isWifi(connectivity: ConnectivityManager): Boolean =
compatV23.isWifi(connectivity)
}

View File

@ -19,9 +19,8 @@
package org.kiwix.kiwixmobile.core.utils
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.wifi.WifiManager
import android.os.Build
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.isWifi
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import javax.inject.Inject
@ -32,13 +31,7 @@ class ConnectivityReporter @Inject constructor(
) {
fun checkWifi(): Boolean =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val capabilities =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
} else {
wifiManager.isWifiEnabled && wifiManager.connectionInfo.networkId != -1
}
connectivityManager.isWifi()
fun checkTethering(): Boolean = try {
val method: Method = wifiManager.javaClass.getDeclaredMethod("isWifiApEnabled")

View File

@ -19,12 +19,10 @@ package org.kiwix.kiwixmobile.core.utils
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.NetworkInfo
import android.os.Build
import android.util.Log
import androidx.annotation.VisibleForTesting
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.isNetworkAvailable
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.isWifi
import java.util.UUID
object NetworkUtils {
@ -36,25 +34,9 @@ object NetworkUtils {
fun isNetworkAvailable(context: Context): Boolean {
val connectivity: ConnectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network = connectivity.activeNetwork
if (network != null) {
val networkCapabilities = connectivity.getNetworkCapabilities(network)
networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
} else {
false
}
} else {
connectivity.allNetworkInfo.any(::isNetworkConnectionOK)
}
return connectivity.isNetworkAvailable()
}
fun isNetworkConnectionOK(networkInfo: NetworkInfo): Boolean =
networkInfo.state == NetworkInfo.State.CONNECTED
@VisibleForTesting
internal var sdkVersionForTesting = Build.VERSION.SDK_INT
/**
* check if network of type WIFI is connected
*
@ -66,14 +48,7 @@ object NetworkUtils {
fun isWiFi(context: Context): Boolean {
val connectivity = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return if (sdkVersionForTesting >= Build.VERSION_CODES.M) {
val network = connectivity.activeNetwork ?: return false
val networkCapabilities = connectivity.getNetworkCapabilities(network)
networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true
} else {
val wifi = connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
wifi != null && wifi.isConnected
}
return connectivity.isWifi()
}
fun getFileNameFromUrl(url: String?): String {

View File

@ -20,101 +20,112 @@ package org.kiwix.kiwixmobile.core.utils
import android.content.Context
import android.net.ConnectivityManager
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkInfo
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.jupiter.api.Test
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.compat.CompatV21
import org.kiwix.kiwixmobile.core.compat.CompatV23
import java.util.regex.Pattern
class NetworkUtilsTest {
private val context: Context = mockk()
private val connectivity: ConnectivityManager = mockk()
private val networkInfo: NetworkInfo = mockk()
private val networkInfo1: NetworkInfo = mockk()
private val networkInfo2: NetworkInfo = mockk()
private val networkCapabilities: NetworkCapabilities = mockk()
@Suppress("Deprecation")
@Test
fun testNetworkAvailability() {
val networkInfos = arrayOf(networkInfo1, networkInfo2)
fun testNetworkAvailability_CompatV21() {
every { context.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivity
every { connectivity.allNetworkInfo } returns networkInfos
val compatV21 = CompatV21()
val networkInfo: NetworkInfo = mockk()
// one network is connected
every { networkInfo1.state } returns NetworkInfo.State.CONNECTED
every { networkInfo2.state } returns NetworkInfo.State.DISCONNECTING
assertEquals(true, NetworkUtils.isNetworkAvailable(context))
every { connectivity.allNetworkInfo } returns arrayOf(networkInfo)
every { networkInfo.state } returns NetworkInfo.State.CONNECTED
every { networkInfo1.state } returns NetworkInfo.State.DISCONNECTING
every { networkInfo2.state } returns NetworkInfo.State.CONNECTING
assertEquals(false, NetworkUtils.isNetworkAvailable(context))
assertTrue(compatV21.isNetworkAvailable(connectivity))
// no network is available
every { networkInfo1.state } returns NetworkInfo.State.DISCONNECTED
every { networkInfo2.state } returns NetworkInfo.State.DISCONNECTED
assertEquals(false, NetworkUtils.isNetworkAvailable(context))
every { networkInfo.state } returns NetworkInfo.State.DISCONNECTED
assertFalse(compatV21.isNetworkAvailable(connectivity))
}
@Test
fun test_isNetworkConnectionOK() {
every { networkInfo2.state } returns NetworkInfo.State.CONNECTING
assertFalse(NetworkUtils.isNetworkConnectionOK(networkInfo2))
fun testNetworkAvailability_CompatV23() {
every { context.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivity
val compatV23 = CompatV23()
val network: Network = mockk()
every { networkInfo2.state } returns NetworkInfo.State.CONNECTED
assertTrue(NetworkUtils.isNetworkConnectionOK(networkInfo2))
every { connectivity.activeNetwork } returns network
every { connectivity.getNetworkCapabilities(network) } returns networkCapabilities
every { networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns true
assertTrue(compatV23.isNetworkAvailable(connectivity))
every { networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns false
assertFalse(compatV23.isNetworkAvailable(connectivity))
}
@Suppress("Deprecation")
@Test
fun testWifiAvailability() {
every { context.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivity
every { connectivity.activeNetworkInfo } returns networkInfo
fun test_isWifi_CompatV21() {
val compatV21 = CompatV21()
val networkInfo: NetworkInfo = mockk()
// SDK >= 23
NetworkUtils.sdkVersionForTesting = 23
// on Mobile Data
every { networkInfo.type } returns ConnectivityManager.TYPE_MOBILE
assertEquals(false, NetworkUtils.isWiFi(context))
// verify that the correct methods are used according to the build SDK version
verify {
connectivity.activeNetworkInfo
networkInfo.type
}
verify(exactly = 0) { connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI) }
// on WIFI connected
every { connectivity.getNetworkInfo(TYPE_WIFI) } returns networkInfo
every { networkInfo.type } returns ConnectivityManager.TYPE_WIFI
every { networkInfo.isConnected } returns java.lang.Boolean.TRUE
assertEquals(true, NetworkUtils.isWiFi(context))
verify(exactly = 2) { connectivity.activeNetworkInfo }
verify(exactly = 0) { connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI) }
// on WIFI disconnected
every { networkInfo.type } returns ConnectivityManager.TYPE_WIFI
every { networkInfo.isConnected } returns java.lang.Boolean.FALSE
assertEquals(false, NetworkUtils.isWiFi(context))
verify(exactly = 3) { connectivity.activeNetworkInfo }
verify(exactly = 0) { connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI) }
// SDK < 23
NetworkUtils.sdkVersionForTesting = 22
// WIFI connected
every { connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI) } returns networkInfo
every { networkInfo.isConnected } returns true
assertEquals(true, NetworkUtils.isWiFi(context))
verify { connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI) }
// WIFI disconnected
every { connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI) } returns networkInfo
assertTrue(compatV21.isWifi(connectivity))
every { networkInfo.isConnected } returns false
assertEquals(false, NetworkUtils.isWiFi(context))
verify(exactly = 2) { connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI) }
assertFalse(compatV21.isWifi(connectivity))
}
@Test
fun test_isWifi_CompatV23() {
val compatV23 = CompatV23()
val network: Network = mockk()
every { connectivity.activeNetwork } returns network
every { connectivity.getNetworkCapabilities(network) } returns networkCapabilities
every { networkCapabilities.hasTransport(TRANSPORT_WIFI) } returns true
assertTrue(compatV23.isWifi(connectivity))
every { networkCapabilities.hasTransport(TRANSPORT_WIFI) } returns false
assertFalse(compatV23.isWifi(connectivity))
}
@Suppress("Deprecation")
@Test
fun testNetworkAvailability_NoNetwork_CompatV21() {
every { context.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivity
val compatV21 = CompatV21()
every { connectivity.allNetworkInfo } returns arrayOf()
assertFalse(compatV21.isNetworkAvailable(connectivity))
}
@Test
fun testNetworkAvailability_NoNetwork_CompatV23() {
every { context.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivity
val compatV23 = CompatV23()
val network: Network = mockk()
every { connectivity.activeNetwork } returns network
every { connectivity.getNetworkCapabilities(network) } returns networkCapabilities
every { networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns false
assertFalse(compatV23.isNetworkAvailable(connectivity))
}
@Test