Check internet connection with target sdk 29 and without deprecated methods - android

I have the
compileSdkVersion 29
and
targetSdkVersion 29
in my android app. And to check if there is a connection I use the next code:
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
return connectivityManager?.activeNetworkInfo?.isConnected ?: false
But with my targetSdk the activeNetworkInfo is deprecated. How can I check the connection status without deprecated methods and variables?

You can do it as below:
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
return capabilities != null && (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || capabilities.hasTransport(
NetworkCapabilities.TRANSPORT_CELLULAR
))
}

Use ConnectivityManager.NetworkCallback instead, here is the link for documentation

Related

ConnectivityManager only can detect connectivity but not network availability

The code below is used to detect network connectivity. The scenario is the software connected to the phone's hotspot but the phone's cellular network doesn't switch on. The code below return isConnected = true, which means it is only detects connectivity? The question is how I change it to detect network availability?
fun Context.isOnline(): Boolean {
val connectivityManager =
this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = connectivityManager.activeNetworkInfo
if (networkInfo == null) {
log(message = "Network info is **NULL**")
return false
} else {
val isConnected = when(networkInfo.detailedState) {
NetworkInfo.DetailedState.CONNECTING -> true
NetworkInfo.DetailedState.AUTHENTICATING -> true
NetworkInfo.DetailedState.OBTAINING_IPADDR -> true
NetworkInfo.DetailedState.CONNECTED -> true
NetworkInfo.DetailedState.VERIFYING_POOR_LINK -> true
else -> false
}
if (!isConnected) {
log(message = "Network state is **${networkInfo.detailedState?.name ?: "NULL"}**")
}
return isConnected
}
}
You're using a deprecated API with NetworkInfo. You should be using NetworkCapabilities.NET_CAPABILITY_VALIDATED
Indicates that connectivity on this network was successfully validated. For example, for a network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully detected.
SDK >= 23
You could change your code to something like this to see if that's true to confirm internet connectivity:
connectivityManager
.getNetworkCapabilities(connectivityManager.getActiveNetwork())
.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
SDK >= 21
If you are using anything as old as SDK 21, you can use the ConnectivityManager.registerNetworkCallback API.
boolean isConnected = false;
final NetworkRequest request =
new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
final ConnectivityManager connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkCallback networkCallback = new NetworkCallback() {
#Override
void onAvailable(Network network) {
// Triggers when this network is available.
isConnected = true;
}
#Override
void onLost(Network network) {
// Triggers when this network is lost.
isConnected = false;
}
};
connectivityManager.requestNetwork(request, networkCallback);

How to check connectivity status of android device?

I have tried so many solutions to get to the answer but nothing helped,
I want your help.
I am developing android app which targets the minimum sdk of (4.4.4)
and when I am checking the status of the connection it's not working because of deprecated functions.
On the official site of android developers the solution is the same and I could not fix my problem.
Any help ( with code if it is possible )
Thanks.
private fun isOnLine(): Boolean {
val connectivityManager = appContext.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo != null && networkInfo.isConnected
}
You can use ConnectivityManager if your app targets api 24 or later.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val connectivityManager = it.getSystemService(Context.CONNECTIVITY_SERVICE) as
ConnectivityManager
connectivityManager.registerDefaultNetworkCallback(object : NetworkCallback() {
override fun onAvailable(network: Network) {
//take action when network connection is gained
}
override fun onLost(network: Network?) {
//take action when network connection is lost
}
})
}
This is good enough:
final ConnectivityManager connectivity = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
final boolean isNetworkAvailable = connectivity.getActiveNetwork() == null;

getActiveNetworkInfo() is deprecated in API 29 [duplicate]

This question already has answers here:
activeNetworkInfo.type is deprecated in API level 28
(16 answers)
Closed 3 years ago.
I am using a code that check if user has internet active or not but after targeting sdk29 the functions bellow became deprecated
NetworkInfo
NetworkInfo.isConnected()
getActiveNetworkInfo()
Here is the code :
public static boolean isNetworkAvailable(Context context) {
if(context == null) { return false; }
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
// if no network is available networkInfo will be null, otherwise check if we are connected
try {
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
Log.i("update_statut","Network is available : true");
return true;
}
} catch (Exception e) {
Log.i("update_statut",""+ e.getMessage());
}
Log.i("update_statut","Network is available : FALSE ");
return false;
}
It's deprecated base on Google Document
getActiveNetworkInfo is deprecated on API 29.
getAllNetworkInfo is deprecated on API 23.
So, If you want to find the Network Connection status, you can use this code.
kotlin :
private fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val nw = connectivityManager.activeNetwork ?: return false
val actNw = connectivityManager.getNetworkCapabilities(nw) ?: return false
return 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
else -> false
}
} else {
val nwInfo = connectivityManager.activeNetworkInfo ?: return false
return nwInfo.isConnected
}
}
Java :
private Boolean isNetworkAvailable(Application application) {
ConnectivityManager connectivityManager = (ConnectivityManager) application.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Network nw = connectivityManager.getActiveNetwork();
if (nw == null) return false;
NetworkCapabilities actNw = connectivityManager.getNetworkCapabilities(nw);
return actNw != null && (actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) || actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) || actNw.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH));
} else {
NetworkInfo nwInfo = connectivityManager.getActiveNetworkInfo();
return nwInfo != null && nwInfo.isConnected();
}
}
you can see all NetworkCapability here.
I have finally found a code that works on all APIs in case anybody want it
NetworkCapabilities is not deprecated in API 29 but it requires API 21 so I have called it on API 29 only.
However getActiveNetworkInfo() is deprecated only in API 29 and works on all APIs , so we can use it in all apis bellow 29
here's the code
public static boolean isNetworkAvailable(Context context) {
if(context == null) return false;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
if (android.os.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;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return true;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)){
return true;
}
}
}
else {
try {
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
Log.i("update_statut", "Network is available : true");
return true;
}
} catch (Exception e) {
Log.i("update_statut", "" + e.getMessage());
}
}
}
Log.i("update_statut","Network is available : FALSE ");
return false;
}
You can find all the info in the official doc
This class was deprecated in API level 29.
Callers should instead use the ConnectivityManager.NetworkCallback API to learn about connectivity changes, or switch to use ConnectivityManager#getNetworkCapabilities or ConnectivityManager#getLinkProperties to get information synchronously. Keep in m`ind that while callbacks are guaranteed to be called for every event in order, synchronous calls have no such constraints, and as such it is unadvisable to use the synchronous methods inside the callbacks as they will often not offer a view of networking that is consistent (that is: they may return a past or a future state with respect to the event being processed by the callback). Instead, callers are advised to only use the arguments of the callbacks, possibly memorizing the specific bits of information they need to keep from one callback to another.
You can use something like:
if (connectivityManager != null) {
if (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
if (capabilities != null) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
//...
}
}
} else {
// current code
}
}

how to fix connectionManager.activeNetworkInfo must not be null ? using kotlin

i'm trying to check the connectivity and do some actions in each state but when i turn of the connection in my mobile the app crash and it give me this error 'cnxManager .activeNetworkInfo must not be null'
My code
private fun isConnected(webView: WebView){
val cnxManager : ConnectivityManager = baseContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val netInfo : NetworkInfo = cnxManager.activeNetworkInfo
if (netInfo.isConnected && netInfo.isConnectedOrConnecting){
cnx_failed.visibility=View.INVISIBLE
webView.visibility=View.VISIBLE
}else{
webView.visibility=View.INVISIBLE
cnx_failed.visibility=View.VISIBLE
}
}
This is due to what is called a "platform type" in Kotlin. Since getActiveNetworkInfo() is not annotated as #Nullable or #NonNull you can choose to declare it as either type. So both:
val netInfo: NetworkInfo = cnxManager.activeNetworkInfo
and
val netInfo: NetworkInfo? = cnxManager.activeNetworkInfo
are valid declarations. However, as Markus mentioned this method can return null, so you should declare it as the latter (nullable type). Any time you're doing interop with Java platform types, you have to be sure you declare it correctly.
With this in mind, you could rewrite your code as:
private fun updateConnectionStatus(webView: WebView) {
val cnxManager = baseContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
// Declare as a nullable type
val netInfo : NetworkInfo? = cnxManager.activeNetworkInfo
// Safe check -- assigns to false if netInfo is null
val connected = netInfo?.isConnectedOrConnecting ?: false
cnx_failed.visibility = if (connected) View.INVISIBLE else View.VISIBLE
webView.visibility = if (connected) View.VISIBLE else View.INVISIBLE
}

Force Android to Use Wifi network with no internet

I am building an android app that needs to communicate over a WiFi network that will not have any internet access. The problem is that even when the WiFi is connected android chooses to use cellular/mobile data when no connection internet is present on the wifi network.
I have read many posts on the issue many of which involve rooting the device but that is not possible with a production app (rooting devices is not an option). other solution (like my code bellow) suggest using bindProcessToNetwork() which works perfectly on my Sony Z2 but not on other devices I have tested on (all running 6.0.1)
private void bindToNetwork() {
final ConnectivityManager connectivityManager = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder = new NetworkRequest.Builder();
//set the transport type do WIFI
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
connectivityManager.bindProcessToNetwork(null);
if (barCodeData.getSsid().contains("ap-name")) {
connectivityManager.bindProcessToNetwork(network);
}
} else {
//This method was deprecated in API level 23
ConnectivityManager.setProcessDefaultNetwork(null);
if (barCodeData.getSsid().contains("ap-name")) {
ConnectivityManager.setProcessDefaultNetwork(network);
}
}
connectivityManager.unregisterNetworkCallback(this);
}
});
}
}
You can solve this by setting captive_portal_detection_enabled to 0 (false).
What's actually happening is that by default, everytime you connect to a wifi, the FW will test against a server (typically google) to see if it's a captive wifi (needs login). So if your wifi is not connected to google, this check will fail. After that, the device knows that wifi has no internet connection and simply will not autoconnect to it.
Setting this setting to 0 will avoid this check.
Programatically:
Settings.Global.putInt(getContentResolver(), Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 0);
Edit: You may need to use the string "captive_portal_detection_enabled" directly, instead of the constant that's not visible depending on Android version.
you'd need to disable mobile data in the Settings (not certain, if this can be done programmatically, which might be a possible option) - or take out the USIM;
else the common behavior is, that it will always fall back to the best available connection (while a connection with internet gateway might be preferred, because it is used by most application).
also see this answer.
Solution on Kotlin
class ConnectWithoutInternetTest constructor(
private val mContext: Context,
private val connectivityManager: ConnectivityManager,
private val wifiManager: WifiManager
) {
private val mWifiBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
WifiManager.NETWORK_STATE_CHANGED_ACTION -> {
val info = intent.getParcelableExtra<NetworkInfo>(WifiManager.EXTRA_NETWORK_INFO)
val isConnected = info.isConnected
val ssid: String? = normalizeAndroidWifiSsid(wifiManager.connectionInfo?.ssid)
if (isConnected) {
val builder = NetworkRequest.Builder()
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
connectivityManager.registerNetworkCallback(
builder.build(),
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
val networkInfo = connectivityManager.getNetworkInfo(network)
val networkSsid = networkInfo.extraInfo
if (networkSsid == ssid) {
connectivityManager.unregisterNetworkCallback(this)
}
}
})
}
}
}
}
}
private fun init() {
val intentFilter = IntentFilter()
intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
mContext.registerReceiver(mWifiBroadcastReceiver, intentFilter)
}
private fun destroy() {
mContext.unregisterReceiver(mWifiBroadcastReceiver)
}
private fun normalizeAndroidWifiSsid(ssid: String?): String? {
return ssid?.replace("\"", "") ?: ssid
}
fun connectToWifi(ssidParam: String, password: String?) {
init()
val ssid = "\"$ssidParam\""
val config = wifiManager.configuredNetworks.find { it.SSID == ssid }
val netId = if (config != null) {
config.networkId
} else {
val wifiConfig = WifiConfiguration()
wifiConfig.SSID = ssid
password?.let { wifiConfig.preSharedKey = "\"$password\"" }
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
wifiManager.addNetwork(wifiConfig)
}
wifiManager.disconnect()
val successful = wifiManager.enableNetwork(netId, true)
}
You're in the right path, the solution is indeed with ConnectivityManager.bindProcessToNetwork(network). This information was posted on the Android Developers Blog in this article: Connecting your App to a Wi-Fi Device.
Looking into your code this barCodeData.getSsid() doesn't look that is getting the SSID of the currently connected wifi network. If that's the case your code will never successfully bind to the network.
Try replace your if statement
if (barCodeData.getSsid().contains("ap-name"))
With
if (getNetworkSsid(context).equals("ap-name"))
Helper method in kotlin to retrieve the SSID of the connected wifi network
private fun getNetworkSsid(context: Context?): String {
// WiFiManager must use application context (not activity context) otherwise a memory leak can occur
val mWifiManager = context?.applicationContext?.getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiInfo: WifiInfo? = mWifiManager.connectionInfo
if (wifiInfo?.supplicantState == SupplicantState.COMPLETED) {
return wifiInfo.ssid.removeSurrounding("\"")
}
return ""
}
If still doesn't work please follow my complete solution where I used the same method but with some extra checks. I tested it in the Android versions 5.1.1, 6.0, 6.0.1, 7.1.1 and 8.1.0.
You're on the right path, you only need to tweak what you have a bit. One of the main issues I see is that you unregister the network callback on onAvailable() which is not a good idea as networks tend to switch between available/unavailable from time-to-time which would cause issues on your device.
The other thing to consider is requesting a network that's Wi-Fi and clearing the other network capabilities as they may cause you issues depending on your network's setup.
Here is another version of how to do that which is hopefully a bit simpler.
final NetworkRequest requestForWifi =
new NetworkRequest.Builder()
.clearCapabilities() // We only care about Wi-Fi
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
final ConnectivityManager connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkCallback networkCallbackWifi = new NetworkCallback() {
#Override
void onAvailable(Network network) {
// Once this callback triggers, a Wi-Fi network is available
WifiInfo wifiInfo = connectivity.getNetworkCapabilities(network).TransportInfo;
string ssid = wifiInfo.SSID.Trim(new char[] {'"', '\"' });
if (!ssid.contains("ap-name")) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
connectivityManager.bindProcessToNetwork(network);
} else {
ConnectivityManager.setProcessDefaultNetwork(network);
}
}
};
// Last thing is to actually request a network.
connectivityManager.requestNetwork(requestForWifi, networkCallbackWifi);
You can check if wifi is connected then proceed else show a dialog to user asking him to connect to a wifi network
Since the method NetworkInfo.isConnected() is now deprecated in API-23, here is a method which detects if the Wi-Fi adapter is on and also connected to an access point using WifiManager instead:
private boolean checkWifiOnAndConnected() {
WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (wifiMgr.isWifiEnabled()) { // Wi-Fi adapter is ON
WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
if( wifiInfo.getNetworkId() == -1 ){
return false; // Not connected to an access point
}
return true; // Connected to an access point
}
else {
return false; // Wi-Fi adapter is OFF
}
}

Categories

Resources