Getter for activeNetworkInfo is deprecated, Deprecated in Java. How to fix this?
I used code below, but the android studio tells me that 'activeNetworkInfo' is deprecated.
Application Manifest:
minSdkVersion 21
targetSdkVersion 29
#Provides
#Singleton
fun provideIsNetworkAvailable(application: Application): Boolean {
var isConnected = false
val connectivityManager = application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val actNw = connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
isConnected = when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
connectivityManager.run {
connectivityManager.activeNetworkInfo?.run {
isConnected = when (type) {
ConnectivityManager.TYPE_WIFI -> true
ConnectivityManager.TYPE_MOBILE -> true
ConnectivityManager.TYPE_ETHERNET -> true
else -> false
}
}
}
}
return isConnected
}
I'm using this code :
private fun isInternetAvailable(context: Context): Boolean {
var result = false
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val actNw =
connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
result = when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
connectivityManager.run {
connectivityManager.activeNetworkInfo?.run {
result = when (type) {
ConnectivityManager.TYPE_WIFI -> true
ConnectivityManager.TYPE_MOBILE -> true
ConnectivityManager.TYPE_ETHERNET -> true
else -> false
}
}
}
}
return result
}
You can view the address below to get detailed information.
activeNetworkInfo.type is deprecated in API level 28
Use this , its works fine in
#RequiresApi(Build.VERSION_CODES.M)
fun provideIsNetworkAvailable(application: Application): Boolean{
private val applicationContext = application.applicationContext
val connectivityManager = applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork = connectivityManager.activeNetwork
connectivityManager.getNetworkCapabilities(activeNetwork).also {
return it!= null && it.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
}
Related
I have tried to make a session after login using data store. but i faced my read token didnt function and no idea to resolve it. please help me if you familiar with this case. and why it's work?
please help me for solve this case. i have new in android development
SplashViewModel
#HiltViewModel
class SplashViewModel #Inject constructor(
private val datastore: AppDatastore
) : ViewModel() {
private val _onBoardingCompleted = mutableStateOf(false)
val onBoardingCompleted get() = _onBoardingCompleted
private val _tokenIsEmpty = mutableStateOf("")
val tokenIstEmpty get() = _tokenIsEmpty
private val _startDestination: MutableState<String> = mutableStateOf(Screen.HomeScreen.route)
val startDestination: State<String> = _startDestination
init {
viewModelScope.launch {
datastore.readOnBoardingState().collect { completed ->
if (completed) {
_startDestination.value = Screen.LoginScreen.route
} else {
_startDestination.value = Screen.OnBoardingScreen.route
}
_onBoardingCompleted.value = true
}
datastore.readUserTokenState().collect { token ->
if (token != ""){
_startDestination.value = Screen.HomeScreen.route
}else{
_startDestination.value = Screen.OnBoardingScreen.route
}
_tokenIsEmpty.value = token
}
}
}
}
DataStore Class
class AppDatastore(context: Context) {
companion object {
val Context.datastore: DataStore<Preferences> by preferencesDataStore(name = "app_datastore")
private val TOKEN = stringPreferencesKey(name = "token")
private val ONBOARD = booleanPreferencesKey("onboard")
}
private val dataStore = context.datastore
suspend fun saveOnBoardState(isCompleted: Boolean) {
dataStore.edit { preferences ->
preferences[ONBOARD] = isCompleted
}
}
fun readOnBoardingState(): Flow<Boolean> {
return dataStore.data
.catch { exception ->
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preferences ->
val onBoardingState = preferences[ONBOARD] ?: false
onBoardingState
}
}
suspend fun saveUserToken(token: String) {
dataStore.edit { preferences ->
preferences[TOKEN] = token
}
}
fun readUserTokenState(): Flow<String> {
return dataStore.data
.catch { exception ->
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preferences ->
val tokenState = preferences[TOKEN] ?: ""
tokenState
}
}
suspend fun deleteToken() {
dataStore.edit { preferences ->
preferences.remove(TOKEN)
}
}
}
LoginViewModel
#HiltViewModel
class LoginViewModel #Inject constructor(
private val loginUseCase: LoginUseCase,
private val datastore: AppDatastore
) : ViewModel() {
private val _loginState: MutableState<LoginState> = mutableStateOf(LoginState())
val loginState: LoginState by _loginState
fun login(username: String, password: String) {
_loginState.value.isLoading
viewModelScope.launch {
loginUseCase.execute(LoginRequest(username, password)).collect { result ->
when (result) {
is Resource.Success -> {
_loginState.value = LoginState().copy(
isLoading = false,
login = result.data,
error = null
)
saveToken(result.data?.token.toString())
Log.d("TAG", "login: ${result.data?.token}")
}
is Resource.Error -> {
_loginState.value = LoginState().copy(
isLoading = false,
login = null,
error = result.message.toString()
)
}
is Resource.Loading -> {
_loginState.value = LoginState().copy(
isLoading = true,
login = null,
error = null
)
}
}
}
}
}
fun saveToken(token: String) {
viewModelScope.launch(Dispatchers.IO) {
datastore.saveUserToken(token)
}
}
}
SplashScreen
#Composable
fun SplashScreen(
navController: NavController,
loginViewModel: LoginViewModel = hiltViewModel(),
splashViewModel: SplashViewModel = hiltViewModel()
) {
var startAnimation by remember { mutableStateOf(false) }
val alphaAnim = animateFloatAsState(
targetValue = if (startAnimation) 0.8f else 0f,
animationSpec = tween(
durationMillis = 800,
easing = {
OvershootInterpolator(4f).getInterpolation(it)
})
)
LaunchedEffect(key1 = true) {
val token = splashViewModel.tokenIstEmpty.value
val screen by splashViewModel.startDestination
startAnimation = true
delay(3000)
navController.popBackStack()
// if (splashViewModel.onBoardingCompleted.value){
// val screen by splashViewModel.startDestination
// navController.navigate(screen)
// }
when (token) {
"" -> navController.navigate(screen)
else -> navController.navigate(screen)
}
}
Splash(scale = alphaAnim.value)
}
Starting from a week ago, in the application some of my users had this crash. This is the detail log of the crash:
Fatal Exception: java.lang.RuntimeException
Unable to resume activity {com.myapp/com.myapp.ui.layout.modules.intro.activities.ActivitySplash}: java.lang.IllegalArgumentException
android.app.ActivityThread.performResumeActivity (ActivityThread.java:4016)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:965)
Caused by java.lang.IllegalArgumentException
android.os.Parcel.createException (Parcel.java:1970)
android.app.Activity.performResume (Activity.java:7572)
android.app.ActivityThread.performResumeActivity (ActivityThread.java:4008)
android.app.ActivityThread.handleResumeActivity (ActivityThread.java:4048)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:965)
Caused by android.os.RemoteException
Remote stack trace: at com.android.server.am.ActivityManagerService.isTopOfTask(ActivityManagerService.java:18227) at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2042) at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:4151) at android.os.Binder.execTransact(Binder.java:739)
As far as I'm concerned and relating to the crash logs, this issue is happening on my ActivitySplash activity which is also designated as the first activity after application class.
I tried to find the main reason that triggers this crash in order to re-live the scenario and make the crash happen again. However, I could not find what triggers this. How can I deal with this thread issue. In my Splash Activity, I do not use the override fun onResume().
Also as a statistics, since last week, more than 20 users faced this issue and now it is a little bit concerning.
And this is my ActivitySplash file:
class ActivitySplash : Activity() {
private lateinit var utilPreferences: UtilPreferences
private lateinit var userService: UserService
private var httpsLink: String = ""
var hasNotification = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
utilPreferences = UtilPreferences(this)
userService = UserService(this)
this.hasNotification = intent.getStringExtra("route_name") != null
this.controlSession()
}
private fun controlSession() {
if (!NetworkUtils.checkForInternet(this)) {
val builder = AlertDialog.Builder(this)
builder.setTitle(R.string.guiding_no_connection.localized())
builder.setMessage(R.string.shared_check_network.localized())
builder.setPositiveButton(R.string.shared_try_again.localized()) { dialog, _ ->
dialog.dismiss()
}
builder.setOnDismissListener { controlSession() }
builder.show()
} else if (utilPreferences.getApiToken() == null || utilPreferences.getRefreshApiToken() == null || !utilPreferences.getIsLoggedIn()) {
SessionManager.fetchStaticVariables(this)
this.openOnBoardingPage()
} else {
val isTokenExpiringSoon = checkRefreshToken()
if (isTokenExpiringSoon) {
this.userService.refreshToken {
if (it.status) {
runOnUiThread {
this.getUser()
}
}
}
} else {
this.getUser()
}
}
}
private fun getUser() {
userService.getUserSession {
runOnUiThread {
if (it != null) {
SessionManager.fetchStaticVariables(this)
FreshChatHelper().configureFreshChatUser(this)
FirebaseAnalyticsHelper.setUserAnalytics(utilPreferences, this)
if (userService.isAppNotUpdated(it)) {
this.openForceToUpdatePage()
return#runOnUiThread
}
if (userService.isPaymentNotCompleted(it)) {
this.openPaymentPage(it)
return#runOnUiThread
}
val deviceId = userService.getDeviceId()
if (deviceId.isEmpty()) {
this.redirectToHomePage()
} else {
checkDevice(deviceId)
}
} else {
userService.logOutApp()
}
}
}
}
private fun checkDevice(deviceId: String) {
userService.checkDevice(deviceId) {
runOnUiThread {
if (!it.status) {
this.redirectToHomePage()
return#runOnUiThread
}
if (!it.data.isNullOrEmpty()) {
this.redirectToHomePage()
} else {
checkDeviceLimit()
}
}
}
}
private fun checkDeviceLimit() {
userService.userDeviceLimit { response ->
runOnUiThread {
if (response.status) {
val remaining = response.data?.remaining ?: -1
if (remaining == -1 || remaining > 0) {
redirectToHomePage()
} else {
val intent = Intent(applicationContext, ActivityDeviceLimit::class.java)
startActivity(intent)
}
} else {
this.redirectToHomePage()
}
}
}
}
private fun redirectToHomePage() {
userService.createUserDevice()
if (this.hasNotification) {
this.redirectNotification()
} else {
val userLanguageId = utilPreferences.getLanguageId()
this.controlLanguage(userLanguageId)
}
}
private fun checkRefreshToken(): Boolean {
if (utilPreferences.getLoginDate() != null && utilPreferences.getApiTokenExpiration() != null) {
val expireIn = utilPreferences.getApiTokenExpiration()?.toInt() ?: 0
if (expireIn == 0) {
return false
}
val expireMinute = (expireIn / 60).toDouble()
val percentageValue = (expireMinute - (expireMinute * 0.20)).toInt()
val date: Date? = DateHelper.getDate(utilPreferences.getLoginDate())
val diff = DateHelper.getMinuteDifferenceBetweenDates(date ?: Date(), Date())
if (diff >= percentageValue) {
return true
}
return false
} else {
return false
}
}
private fun redirectNotification() {
if (intent.getStringExtra("route_name") != null) {
var routeId = ""
if (intent.getStringExtra("route_id") != null) {
routeId = intent.getStringExtra("route_id")!!
}
var payload = ""
if (intent.getStringExtra("payload") != null) {
payload = intent.getStringExtra("payload")!!
}
val mainIntent = Intent(applicationContext, ActivityMain::class.java)
mainIntent.putExtra("route_name", intent.getStringExtra("route_name"))
mainIntent.putExtra("route_id", routeId)
mainIntent.putExtra("payload", payload)
startActivity(mainIntent)
} else {
this.openHomePage()
}
}
private fun openOnBoardingPage() {
val intent = Intent(applicationContext, ActivityIntro::class.java)
startActivity(intent)
}
private fun openHomePage() {
if (!isDestroyed) {
checkShareListingUrl()
val intent = Intent(applicationContext, ActivityMain::class.java)
if (!this.intent.getStringExtra("instaRedirectNotify").isNullOrEmpty()) {
intent.putExtra(
"instaRedirectNotify",
this.intent.getStringExtra("instaRedirectNotify")
)
}
if (httpsLink.isNotEmpty()) intent.putExtra("getListingUrl", httpsLink)
if (this.intent.data != null) intent.putExtra("dynamicLink", this.intent.data)
startActivity(intent)
}
}
private fun controlLanguage(userLanguageId: Int) {
val languages = Language.getLanguages("")
val controlledLanguage = languages.filter { it.id == userLanguageId }
if (controlledLanguage.size == 1) {
if (controlledLanguage[0].key != utilPreferences.getAppLanguage()) {
utilPreferences.setAppLanguage(controlledLanguage[0].key)
}
}
if (userLanguageId != -1) {
utilPreferences.setLanguageId()
} else {
utilPreferences.setLanguageId()
}
this.openHomePage()
}
private fun openForceToUpdatePage() {
val startActivity = Intent()
startActivity.setClass(applicationContext, ActivityUpdateApp::class.java)
startActivity.flags =
Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(startActivity)
}
private fun openPaymentPage(user: FragmentUser) {
val startActivity = Intent()
startActivity.putExtra("url", user.payment_url() ?: "")
startActivity.setClass(applicationContext, ActivityPaymentFailed::class.java)
startActivity.flags =
Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(startActivity)
}
private fun checkShareListingUrl() {
if (intent?.action == Intent.ACTION_SEND) {
if ("text/plain" == intent.type) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
val pattern: Pattern = Patterns.WEB_URL
val matcher: Matcher = pattern.matcher(it)
if (matcher.find()) {
this.httpsLink = matcher.group()
}
}
}
}
}
}
Is there a way to make this crash happen on purpose and solve it. I am also open to learn any knowledge about this ActivityThread performResumeActivity issue.
This is my code below:
#SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
}
When I run the above code, I am getting a Deprecated warning saying that getActiveNetworkInfo and isConnected methods are deprecated.
I don't want to continue this code for any longer. What are some of the alternatives of the above code?
Can someone please help me? Thanks in Advance
Below is my code which I use in my application to check if device is connected to network. It does not contain any deprecated code as of now.
Kotlin
private fun isInternetAvailable(): Boolean {
var result = false
val connectivityManager = applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
connectivityManager?.let {
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
result = when {
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
else -> false
}
}
}
return result
}
Java
public static boolean isInternetAvailable(Context context) {
boolean result = false;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
if (networkCapabilities != null) {
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
result = true;
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
result = true;
} else {
result = false;
}
}
}
return result;
}
Read more about Connectivity Manager and Network Capabilities here.
I want to use ConnectivityManager to check if an active network can access the internet or not ie. getActiveNetworkInfo().isConnected().
I read that we can still use getActiveNetwork() to get an active network, but there doesn't seem to be a similar method like isConnected for Network objects. How to workaround?
The deprecated code is found here: https://codelabs.developers.google.com/codelabs/android-training-asynctask-asynctaskloader/index.html?index=..%2F..%2Fandroid-training#4
You can use this method to check the connectivity. connectivityManager.getActiveNetwork() is added in SDK 29.
public static boolean isNetworkAvailable(Context context) {
if (context == null) return false;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
if (capabilities != null) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return true;
}
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return true;
}
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET);
} else {
return false;
}
} else {
NetworkInfo info = connectivityManager.getActiveNetworkInfo();
return info != null && info.isConnected();
}
}
return false;
}
NetworkInfo deprecated: https://developer.android.com/reference/android/net/NetworkInfo
getActiveNetworkInfo deprecated on API 29.
getAllNetworkInfo deprecated on API 23.
You should use this code.
private fun isAvailableNetwork(context: Context): Boolean {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val network = connectivityManager.activeNetwork ?: return false
val networkCapabilities =
connectivityManager.getNetworkCapabilities(network) ?: return false
return when {
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true
else -> false
}
}
You shall use new implementation for SDK_INT >= Q and for older versions you use old api and suppress deprecation like this:
In kotlin:
val Context.isNetworkConnected: Boolean
get() {
val manager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
return if (SDK_INT >= Q)
manager.getNetworkCapabilities(manager.activeNetwork)?.let {
it.hasTransport(TRANSPORT_WIFI) || it.hasTransport(TRANSPORT_CELLULAR) ||
it.hasTransport(TRANSPORT_BLUETOOTH) ||
it.hasTransport(TRANSPORT_ETHERNET) ||
it.hasTransport(TRANSPORT_VPN)
} ?: false
else
#Suppress("DEPRECATION")
manager.activeNetworkInfo?.isConnected == true
}
I use the following method for checking the internet connectivity:
public boolean isInternetConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
Though, I have discovered that NetworkInfo, getActiveNetworkInfo(), and isConnected() are all now deprecated. I have checked several threads on SO:
ConnectivityManager getNetworkInfo(int) deprecated
activeNetworkInfo.type is deprecated in API level 28
Though, they all offer answers with deprecated methods. I have been looking around without any luck. Is there any simple way to check for internet connectivity or should I continue using my method and disregard the deprecated since it works up to API29?
Thank you.
Have a look at .hasTransport
val networkAvailability = cm.getNetworkCapabilities(cm.activeNetwork)
if(networkAvailability !=null && networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED))
{
//has network
if (networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { //wifi
} else if (networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { //cellular
}
}
Here is my solution for SDK 29: A class called NetworkWatcher which observes the changes of the network. It offers primitive variables such as isWifiOn and the option to observe network changes over time via Flow and LiveData.
#ExperimentalCoroutinesApi
class NetworkWatcher
#RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
private constructor(
application: Application
) {
private val connectivityManager =
application.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
// general availability of Internet over any type
var isOnline = false
get() {
updateFields()
return field
}
var isOverWifi = false
get() {
updateFields()
return field
}
var isOverCellular = false
get() {
updateFields()
return field
}
var isOverEthernet = false
get() {
updateFields()
return field
}
companion object {
#Volatile
private var INSTANCE: NetworkWatcher? = null
fun getInstance(application: Application): NetworkWatcher {
synchronized(this) {
if (INSTANCE == null) {
INSTANCE = NetworkWatcher(application)
}
return INSTANCE!!
}
}
}
#Suppress("DEPRECATION")
private fun updateFields() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkAvailability =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (networkAvailability != null &&
networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
) {
//has network
isOnline = true
// wifi
isOverWifi =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
// cellular
isOverCellular =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
// ethernet
isOverEthernet =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
} else {
isOnline = false
isOverWifi = false
isOverCellular = false
isOverEthernet = false
}
} else {
val info = connectivityManager.activeNetworkInfo
if (info != null && info.isConnected) {
isOnline = true
val wifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
isOverWifi = wifi != null && wifi.isConnected
val cellular = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
isOverCellular = cellular != null && cellular.isConnected
val ethernet = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET)
isOverEthernet = ethernet != null && ethernet.isConnected
} else {
isOnline = false
isOverWifi = false
isOverCellular = false
isOverEthernet = false
}
}
}
fun watchNetwork(): Flow<Boolean> = watchWifi()
.combine(watchCellular()) { wifi, cellular -> wifi || cellular }
.combine(watchEthernet()) { wifiAndCellular, ethernet -> wifiAndCellular || ethernet }
fun watchNetworkAsLiveData(): LiveData<Boolean> = watchNetwork().asLiveData()
fun watchWifi(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_WIFI)
fun watchWifiAsLiveData() = watchWifi().asLiveData()
fun watchCellular(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_CELLULAR)
fun watchCellularAsLiveData() = watchCellular().asLiveData()
fun watchEthernet(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_ETHERNET)
fun watchEthernetAsLiveData() = watchEthernet().asLiveData()
private fun callbackFlowForType(#IntRange(from = 0, to = 7) type: Int) = callbackFlow {
offer(false)
val networkRequest = NetworkRequest.Builder()
.addTransportType(type)
.build()
val callback = object : ConnectivityManager.NetworkCallback() {
override fun onLost(network: Network?) {
offer(false)
}
override fun onUnavailable() {
offer(false)
}
override fun onLosing(network: Network?, maxMsToLive: Int) {
// do nothing
}
override fun onAvailable(network: Network?) {
offer(true)
}
}
connectivityManager.registerNetworkCallback(networkRequest, callback)
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}
}
For instance, you could subscribe to updates about the network state of the phone in your Application such as:
GlobalScope.launch {
NetworkWatcher.getInstance(this#MyApplication).watchNetwork().collect { connected ->
Log.d("TAG", "Network In App: $connected")
}
}
Or to answer your question, simply read the Wifi value such as:
if (NetworkWatcher.getInstance(this#BaseApp).isOverWifi) {
// do stuff
}
Side note: Rather than using getInstance() all the time, I use a DI framework such as Koin to inject the NetworkWatcher where I need it.
in AndroidManifest.xml add :
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
now for checking network status :
#IntRange(from = 0, to = 3)
fun getConnectionType(context: Context): Int {
var result = 0 // Returns connection type. 0: none; 1: mobile data; 2: wifi
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val capabilities =
cm.getNetworkCapabilities(cm.activeNetwork)
if (capabilities != null) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
result = 2
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
result = 1
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
result = 3
}
}
} else {
val activeNetwork = cm.activeNetworkInfo
if (activeNetwork != null) {
// connected to the internet
if (activeNetwork.type === ConnectivityManager.TYPE_WIFI) {
result = 2
} else if (activeNetwork.type === ConnectivityManager.TYPE_MOBILE) {
result = 1
} else if (activeNetwork.type === ConnectivityManager.TYPE_VPN) {
result = 3
}
}
}
return result
}
My answer which is clean and in Kotlin and also handles different API levels
fun isOnline(): Boolean {
val connectivityManager =
ContextCompat.getSystemService(DreamPad.appContext, ConnectivityManager::class.java)
connectivityManager ?: return false
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val nw = connectivityManager.activeNetwork ?: return false
val actNw = connectivityManager.getNetworkCapabilities(nw) ?: return false
when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
// for other device how are able to connect with Ethernet
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
// for check internet over Bluetooth
actNw.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true
// for check internet over USB tethering
actNw.hasTransport(NetworkCapabilities.TRANSPORT_USB) -> true
else -> false
}
} else {
#Suppress("DEPRECATION")
connectivityManager.activeNetworkInfo?.isConnected ?: false
}
}