How to get SSID for Android 12 API level 31 [duplicate] - android

Description
I am unable to get WIFI SSID using the onCapabilitiesChanged in the ConnectivityManager.NetworkCallback class in Android-12.
In Android-12, getConnectionInfo is deprecated. So, as the android document suggests I am trying to get the WifiInfo object using onCapabilitiesChanged.
Like this,
#Override
public void onCapabilitiesChanged(#NonNull Network network, #NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
}
But, when I print the WifiInfo object. it will print SSID: <unknown ssid> and getHiddenSSID return true.
Unexpected behavior is,
Android-12 device is connected with one WIFI (Ex. ABC)
When I try to get WIFI SSID using getConnectionInfo. it return
SSID: ABC and getHiddenSSID : false
But, for the same network when I try to get WIFI SSID using
onCapabilitiesChanged, it returns SSID: <unknown ssid> and
getHiddenSSID : true
Note: Location permission is provided.

After spending few days, finally found why I am not getting SSID in onCapabilitiesChanged.
We need to pass FLAG_INCLUDE_LOCATION_INFO in the ConnectivityManager.NetworkCallback constructor while creating an object.
in the default constructor, location sensitive information is hidden due to that we are not able to get SSID in onCapabilitiesChanged. Once we create NetworkCallback object with a flag we will get SSID.
Link

Get SSID and BSSID API31 Xamarin C# Example
Required permissions: CHANGE_NETWORK_STATE, ACCESS_FINE_LOCATION
If API<31 TransportInfo will return Null
using Android.Content;
using Android.Net;
using Android.Net.Wifi;
protected override void OnStart()
{
base.OnStart();
NetworkRequest request = new NetworkRequest.Builder().AddTransportType(transportType: TransportType.Wifi).Build();
ConnectivityManager connectivityManager = Android.App.Application.Context.GetSystemService(Context.ConnectivityService) as ConnectivityManager;
NetworkCallbackFlags flagIncludeLocationInfo = NetworkCallbackFlags.IncludeLocationInfo;
NetworkCallback networkCallback = new NetworkCallback((int)flagIncludeLocationInfo);
connectivityManager.RequestNetwork(request, networkCallback);
}
private class NetworkCallback : ConnectivityManager.NetworkCallback
{
public NetworkCallback(int flags) : base(flags)
{
}
public override void OnCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)
{
base.OnCapabilitiesChanged(network, networkCapabilities);
WifiInfo wifiInfo = (WifiInfo)networkCapabilities.TransportInfo;
if (wifiInfo != null)
{
string ssid = wifiInfo.SSID.Trim(new char[] {'"', '\"' });
string bssid = wifiInfo.BSSID;
}
}
}
Click Android API reference.ConnectivityManager.NetworkCallback(int)!

Replace from new NetworkCallback() to new NetworkCallback(ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO).
Example Code:
final NetworkRequest request =
new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
final ConnectivityManager connectivityManager =
context.getSystemService(ConnectivityManager.class);
final NetworkCallback networkCallback = new NetworkCallback(ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) {
...
#Override
void onAvailable(Network network) {}
#Override
void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
}
// etc.
};
connectivityManager.requestNetwork(request, networkCallback); // For request
connectivityManager.registerNetworkCallback(request, networkCallback); // For listen
Reference Link:
https://developer.android.com/reference/android/net/wifi/WifiManager#getConnectionInfo()
https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#NetworkCallback(int)

this method work for me in all android versions, but For Android 8.0 (Oreo) and later versions, you need to have location services (GPS) turned on to access the Wi-Fi SSID. Also, you need to request the ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions at runtime and declare them in the manifest file.
If you want to access the Wi-Fi SSID in the background, you can write a foreground service to handle that.
private fun checkWIFIName(context: Context) : Boolean {
val wifiManager = context.applicationContext.getSystemService(WIFI_SERVICE) as WifiManager
val wifiInfo = wifiManager.connectionInfo
println("SSID : ${wifiInfo.ssid}")
return wifiInfo.ssid.trim().equals("\"$SSID\"", true)
}

Related

Unable to get WIFI SSID using onCapabilitiesChanged in Android 12

Description
I am unable to get WIFI SSID using the onCapabilitiesChanged in the ConnectivityManager.NetworkCallback class in Android-12.
In Android-12, getConnectionInfo is deprecated. So, as the android document suggests I am trying to get the WifiInfo object using onCapabilitiesChanged.
Like this,
#Override
public void onCapabilitiesChanged(#NonNull Network network, #NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
}
But, when I print the WifiInfo object. it will print SSID: <unknown ssid> and getHiddenSSID return true.
Unexpected behavior is,
Android-12 device is connected with one WIFI (Ex. ABC)
When I try to get WIFI SSID using getConnectionInfo. it return
SSID: ABC and getHiddenSSID : false
But, for the same network when I try to get WIFI SSID using
onCapabilitiesChanged, it returns SSID: <unknown ssid> and
getHiddenSSID : true
Note: Location permission is provided.
After spending few days, finally found why I am not getting SSID in onCapabilitiesChanged.
We need to pass FLAG_INCLUDE_LOCATION_INFO in the ConnectivityManager.NetworkCallback constructor while creating an object.
in the default constructor, location sensitive information is hidden due to that we are not able to get SSID in onCapabilitiesChanged. Once we create NetworkCallback object with a flag we will get SSID.
Link
Get SSID and BSSID API31 Xamarin C# Example
Required permissions: CHANGE_NETWORK_STATE, ACCESS_FINE_LOCATION
If API<31 TransportInfo will return Null
using Android.Content;
using Android.Net;
using Android.Net.Wifi;
protected override void OnStart()
{
base.OnStart();
NetworkRequest request = new NetworkRequest.Builder().AddTransportType(transportType: TransportType.Wifi).Build();
ConnectivityManager connectivityManager = Android.App.Application.Context.GetSystemService(Context.ConnectivityService) as ConnectivityManager;
NetworkCallbackFlags flagIncludeLocationInfo = NetworkCallbackFlags.IncludeLocationInfo;
NetworkCallback networkCallback = new NetworkCallback((int)flagIncludeLocationInfo);
connectivityManager.RequestNetwork(request, networkCallback);
}
private class NetworkCallback : ConnectivityManager.NetworkCallback
{
public NetworkCallback(int flags) : base(flags)
{
}
public override void OnCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)
{
base.OnCapabilitiesChanged(network, networkCapabilities);
WifiInfo wifiInfo = (WifiInfo)networkCapabilities.TransportInfo;
if (wifiInfo != null)
{
string ssid = wifiInfo.SSID.Trim(new char[] {'"', '\"' });
string bssid = wifiInfo.BSSID;
}
}
}
Click Android API reference.ConnectivityManager.NetworkCallback(int)!
Replace from new NetworkCallback() to new NetworkCallback(ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO).
Example Code:
final NetworkRequest request =
new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
final ConnectivityManager connectivityManager =
context.getSystemService(ConnectivityManager.class);
final NetworkCallback networkCallback = new NetworkCallback(ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) {
...
#Override
void onAvailable(Network network) {}
#Override
void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
}
// etc.
};
connectivityManager.requestNetwork(request, networkCallback); // For request
connectivityManager.registerNetworkCallback(request, networkCallback); // For listen
Reference Link:
https://developer.android.com/reference/android/net/wifi/WifiManager#getConnectionInfo()
https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#NetworkCallback(int)
this method work for me in all android versions, but For Android 8.0 (Oreo) and later versions, you need to have location services (GPS) turned on to access the Wi-Fi SSID. Also, you need to request the ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions at runtime and declare them in the manifest file.
If you want to access the Wi-Fi SSID in the background, you can write a foreground service to handle that.
private fun checkWIFIName(context: Context) : Boolean {
val wifiManager = context.applicationContext.getSystemService(WIFI_SERVICE) as WifiManager
val wifiInfo = wifiManager.connectionInfo
println("SSID : ${wifiInfo.ssid}")
return wifiInfo.ssid.trim().equals("\"$SSID\"", true)
}

Android: How to check internet connectivity on API level 29 or higher in android studio?

Before i was using these few lines of codes to check if the device is connected to the internet or not:
fun isOnline(): Boolean {
val cm = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val netInfo = cm.activeNetworkInfo
return netInfo != null && netInfo.isConnectedOrConnecting
}
But getActiveNetworkInfo() was deprecated in Android 10 and official documentation is suggesting to use NetworkCallbacks instead for apps that target Android 10 (API level 29) and higher.
So here's the problem, i didn't find any resources that might help to implement the NetworkCallbacks except the one here: on medium.com. But it's too complicated.
Is there any better or simpler way to implement this or i must go through the whole lengthy process?
You can use NetworkCapablities class for checking internet connectivity before making the network request.
fun internetCheck(c: Context): Boolean {
val cmg = c.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// Android 10+
cmg.getNetworkCapabilities(cmg.activeNetwork)?.let { networkCapabilities ->
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|| networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
}
} else {
return cmg.activeNetworkInfo?.isConnectedOrConnecting == true
}
return false
}
But if your activity needs to listen to Network connectivity changes, you should implement NetworkCallbacks.
You can check it by getting all networks with getAllNetworks() and loop through each of them to see if any is connected.
#RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun isOnline(): Boolean {
val connectivityMgr = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val allNetworks: Array<Network> = connectivityMgr.allNetworks // added in API 21 (Lollipop)
for (network in allNetworks) {
val networkCapabilities = connectivityMgr!!.getNetworkCapabilities(network)
return (networkCapabilities!!.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) &&
(networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|| networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|| networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)))
}
}
return false
}
Also add the below permission in manifest:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
UPDATE
Can you tell me some other possible internet providers other than TRANSPORT_CELLULAR, TRANSPORT_WIFI and TRANSPORT_ETHERNET?
The answer to this can change over time; although, to the date, these transport technologies are sufficient for accessing the internet on mobile sets in terms of the technology capabilities provided nowadays.
Although there are other transport methods that might be utilized by device manufactures in the future.
For instance: TRANSPORT_WIFI_AWARE which is a technology that enable devices running Android 8.0 (API level 26) and higher to discover and connect directly to each other without any other type of connectivity between them. So, it's a transport method between devices over the Wi-Fi; but so far it doesn't pass internet between devices; maybe that can be used in the future.
Similarly, TRANSPORT_LOWPAN allows Android devices to communicate directly with other peer devices, even ultra-low power battery operated nodes that may not have WiFi or Bluetooth connectivity (such as door locks and window sensors). Again today TRANSPORT_LOWPAN doesn't pass the internet between those devices, but it facilitates the communication locally among them.
TRANSPORT_VPN Allows the communication between devices over a private network which should be explicitly coded by you; unless you do that, you don't have to use it to check the internet availability.
you Can create an extension like this
fun Context.isOnline(): Boolean {
return try {
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val netInfo = cm.activeNetworkInfo
//should check null because in airplane mode it will be null
netInfo != null && netInfo.isConnected
} catch (e: NullPointerException) {
e.printStackTrace()
false
}
}
And create BroadcastReceiver like this
class Connection : BroadcastReceiver() {
lateinit var dialog: Dialog
override fun onReceive(context: Context, intent: Intent) {
dialog = Dialog(context)
dialog.apply {
setContentView(R.layout.dialog_connection)
setCancelable(false)
window!!.setBackgroundDrawableResource(android.R.color.transparent)
window!!.setGravity(Gravity.CENTER)
window!!.attributes.windowAnimations = R.style.AnimationPopup
}
check(context = context) {
if (!it) {
dialog.show()
} else {
dialog.cancel()
}
}
}
private fun check(context: Context, result: (Boolean) -> Unit) {
try {
if (context.isOnline()) {
result(true)
} else {
result(false)
}
} catch (e: java.lang.NullPointerException) {
e.printStackTrace()
}
}
}
public boolean checkNetworkConnection(Context context){
ConnectivityManager connectivityManager =
(ConnectivityManager)context.getSystemService(ConnectivityManager.class);
Network currentNetwork = connectivityManager.getActiveNetwork();
if(currentNetwork==null){
return false;
}
else {
return true;
}
}

after called BindProcessToNetwork(network). APP never connect to internet through mobile data

My APP use WifiNetworkSpecifier to connect to a router.
And once connect to the router. APP called
connection_manager.BindProcessToNetwork(network);
After called this function. Even I turn off the WiFi. And turn on the mobile data.
The APP will not able to connect to internet anymore.
If this function is not called. APP will be able to connect to internet through mobile data.
What is the mechanism of BindProcessToNetwork()?
Here is my code. (ref from ref 1 ref 2)
private void RequestNetwork()
{
var specifier = new WifiNetworkSpecifier.Builder()
.SetSsid(_ssid.Text)
.SetWpa2Passphrase(_passphrase.Text)
.Build();
var request = new NetworkRequest.Builder()
.AddTransportType(TransportType.Wifi)
.RemoveCapability(NetCapability.Internet)
.SetNetworkSpecifier(specifier)
.Build();
var connectivityManager = GetSystemService(ConnectivityService) as ConnectivityManager;
if (_requested)
{
connectivityManager.UnregisterNetworkCallback(_callback);
}
connectivityManager.RequestNetwork(request, _callback);
_requested = true;
}
private class NetworkCallback : ConnectivityManager.NetworkCallback
{
public Action<Network> NetworkAvailable { get; set; }
public Action NetworkUnavailable { get; set; }
public static Context _context = Android.App.Application.Context;
ConnectivityManager connection_manager = (ConnectivityManager)_context.GetSystemService(Context.ConnectivityService);
public override void OnAvailable(Network network)
{
base.OnAvailable(network);
NetworkAvailable?.Invoke(network);
connection_manager.BindProcessToNetwork(network);
}
public override void OnUnavailable()
{
base.OnUnavailable();
NetworkUnavailable?.Invoke();
}
}
Once BindProcessToNetwork is called, ALL networking sockets are bound to that network for the lifecycle of that app (this is mainly a security feature so packets will not "leak" another network).
You can clear that network binding by calling BindProcessToNetwork again, but passing in null as your network type.
connection_manager.BindProcessToNetwork(null);

Notify user when Internet connection is lost in android

I am trying to make an app where I need to notify the user via a toast when the connection to the internet is lost(either mobile data or wifi) and possibly launch another activity and return back to the main activity as soon as the user is back online.
Can someone please guide me in doing this.
Thank you.
Use NetworRequestCallBack provided by the Android to get the Internet connection changes. https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkRequest = NetworkRequest.Builder().build()
connectivityManager.registerNetworkCallback(networkRequest, object :
ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
// "Net connected"
}
override fun onLost(network: Network) {
super.onLost(network)
// "Network lost"
}
})
You can use this to check if network is available
public static boolean isNetworkAvailable(Context activity) {
ConnectivityManager connectivityManager
= (ConnectivityManager) activity.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
Use the above method as
if(isNetworkAvailable(context)){
//Network is available}
else {
//Network Unavailable
}
The behaviour you want to achieve can be achieved seamlessly using Reactive Network library. If you already use RxJava in your project then it is even more convenient!
Here it is documented how you can observe network connectivity https://github.com/pwittchen/ReactiveNetwork#observing-network-connectivity

How make a SMB connection through Network object in Android?

I'm trying to make a SMB (Samba) connection to get a list of files and download them with the SMBClient of smbj library.
To that I have to connect to a specific network and use that class, but in Android Q I have to change the way to connect to the wireless, like this:
val wifiNetworkSpecifier: WifiNetworkSpecifier = WifiNetworkSpecifier.Builder().apply {
setSsid(ssid)
setWpa2Passphrase(password)
}.build()
val networkRequest: NetworkRequest = NetworkRequest.Builder().apply {
addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
setNetworkSpecifier(wifiNetworkSpecifier)
}.build()
val networkCallback: ConnectivityManager.NetworkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d(tag, "::onAvailable - Entry")
super.onAvailable(network)
}
override fun onUnavailable() {
Log.d(tag, "::onUnavailable - Entry")
super.onUnavailable()
}
}
This makes a connection in the app, but establishes the main connection via mobile data and I can't establish a connection because the server is unreachable. I have to find a way to make the connection through the network object in the onAvailable function.
Did you know how or is there an alternative way?
Solution
I found a method in the ConnectivityManager class the method is bindProcessToNetwork
connectivityManager.bindProcessToNetwork(network)
I found a method in the ConnectivityManager class the method is bindProcessToNetwork
connectivityManager.bindProcessToNetwork(network)

Categories

Resources