is there a way to get details about disconnected network using android broadcast receiver or networkcallback ?
EXTRA_NETWORK_INFO, getNetworkInfo(NetworkType) are deprecated.
getAllNetworks() Returns an array of all Network currently tracked by the framework but not the disconnected network.
yes, first register Broadcast receiver like this:
final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(receiver, intentFilter);
when receiver is:
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// this part is trigered when there is some network changes, do checks here
}
};
also don't forget to unregister it.
Yes. NetworkInfo class is deprecated from API Level 29 . Instead, the ConnectivityManager class can be helpful here. It helps in monitoring the network connections, and notify the application when network connectivity changes or when connectivity to a network is lost. It also facilitates by allowing applications to know the state of the available networks and allows applications to request and select networks for their data traffic.
However, the below list of methods are deprecated in ConnectvityManager class:
getNetworkInfo returns connection status about a particular
network type.
getAllNetworkInfo returns connection status information of all network types supported by device.
getActiveNetworkInfo returns currently active default data network
network.
The ConnectivityManager.NetworkCallback is currently actively available to determine the network change status. This base class for NetworkRequest callbacks is used for notifications about network changes which can be extended by applications that are in need of network change notifications.
The below list of methods are supported :
getAllNetworks returns an array of all networks currently
tracked.
getActiveNetwork returns a network object
of currently active default data network.
The NetworkCapabilities class shall help in representation of the capabilities of an active network.
In general, whenever the system invokes onAvailable(Network), it shall pass the network that is available and whenever the system invokes onLost(Network), it shall pass the network that was lost which refers to the particular network that was lost (disconnected) and the argument tells you which network got lost (disconnected).
The onCapabilitiesChanged gets invoked immediately after onAvailable and this can help in determining capabilities of the available network like whether it is cellular network or a WiFi network by querying the NetworkCapabilities with hasTransport() and the appropriate transport constant like TRANSPORT_CELLULAR or TRANSPORT_WIFI (network of interest).
The below snippet takes into consideration the above information and helps in determining whether you have cellular or wifi network connectivity which in turn enables one to confirm whether the disconnected network(lost) is indeed not in use.
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Network network = connectivityManager.getActiveNetwork();
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
return capabilities != null && (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) || capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI));
}
Related
My app needs to use a wifi network (without internet, thus android avoids it by default). And I want it to be simple to use (like Grandma doesn't have to be manually changing settings). This is just an personal IoT device so I want to use ConnectivityManager.BindProcessToNetwork(Android.Net.Network network). How do I get the Android.Net.Network associated with the currently connected wifi network so I can use BindProcessToNetwork?
//c#(Xamarin)
//my rudimentary attempt to get the connected wifi network:
var networks = ConnectivityManager.GetAllNetworks();
foreach (Network network in networks) {
NetworkCapabilities networkCability =ConnectivityManager.GetNetworkCapabilities(network);
if (networkCability.HasTransport(TransportType.Wifi))
{
currentWifiNetwork = network; // this is never reached
}
}
ConnectivityManager.BindProcessToNetwork( currentWifiNetwork );
Is there not a distinct Network object for all the phones currently in use WiFi, cellular, etc... networks?
This blog got me close: https://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html.
A binding socket method would work too (except the wifi network isn't an available network until the use network without internet box is checked). I just need to the App to use urls that are on port 8080 via the wifi.
I want to avoid having to manually telling Android to "use the network with no internet".
Cheers
Update
When I run this, there are only two Networks returned by ConnectivityManager.GetAllNetworks(), and looking at them in the debugger, one is the Cellular network with internet and mms, and the other is another Cellular network without internet and mms. So no ConnectivityManager.GetAllNetworks() doesn't get the wifi network as it appears android won't even add the wifi network unless it has internet! If the phones data is disabled Android will switch and use the internet-less wifi for all traffic (without having to check use the network anyways box).So their must be a way to get the WiFi network bound to the app! or...
How does one programmatically check the use network anyways box!?
I have not seen a solution to this. Just a bunch of open questions all over the web. At this rate I might just use dnsmasq on the iot device and a spoofing web server to make android think it has internet.
I also see that API 29 has NetworkBuilder and that you can specify a request for a WiFi network without internet capabilities...but I need lower API support.
Update:
Android now supports requesting local only wifi networks (networks without the NetworkCapabilities#NET_CAPABILITY_INTERNET capability) check out :
https://developer.android.com/reference/android/net/wifi/WifiNetworkSpecifier.Builder
Original Answer:
This is the solution that I came up with (for Api 28 ). It prioritizes WiFi over 4G/5G (Data) regardless of internet capability via a NetworkRequest, and then allows for both internet over 4G/5G (Data) and the app to use its local WiFi services:
public static WifiManager WifiManager { get; } = (WifiManager)Android.App.Application.Context.GetSystemService(Context.WifiService);
public static ConnectivityManager ConnectivityManager { get; set; } = (ConnectivityManager)Android.App.Application.Context.GetSystemService(Context.ConnectivityService);
public bool ConnectToWifi(string ssid, string password, bool previouslyConnected = true)
{
if (!WifiManager.IsWifiEnabled)
WifiManager.SetWifiEnabled(true); //turn on wifi if not on
var formattedSsid = $"\"{ssid}\"";
var formattedPassword = $"\"{password}\"";
var wifiConfig = new WifiConfiguration
{
Ssid = formattedSsid,
PreSharedKey = formattedPassword,
Priority = 0
};
_NetworkId = WifiManager.AddNetwork(wifiConfig);
WifiManager.Disconnect();
bool enableNetwork = WifiManager.EnableNetwork(_NetworkId, true);
NetworkRequest.Builder builder = new NetworkRequest.Builder(); //request that WiFi be prioritized over the 4G internet capable network.
builder.AddTransportType(TransportType.Wifi);
ConnectivityManager.RequestNetwork(builder.Build(), new BindNetworkCallBack ());
return enableNetwork;
}
This call back then binds the appropriate WIFI network to the app(process)! Allowing for the user to both simultaneously use the app with the local server over WIFI, and other apps that still require internet, as Android OS can allow other processes to access the internet via the 4G/5G data connection!
public class BindNetworkCallBack : ConnectivityManager.NetworkCallback
{
public override void OnAvailable(Network network)
{
if (WifiManager.ConnectionInfo.BSSID == NetworkBSSID) /*
The only way on Android (API 28+) to check if the acquired network is
the one you want is to use the BSSID (MAC address) of the network.
You can omit the if statement if you want to presume the acquired network is correct/
cannot know the MAC address...
*/
{
try
{
ConnectivityManager.BindProcessToNetwork(network);
}
catch (Exception ex)
{
Debug.WriteLine(#"\tERROR Unable to Bind process to network {0}", ex.Message);
}
}
}
}
"bindProcessToNetwork Binds the current process to network. All Sockets created in the future (and not explicitly bound via a bound SocketFactory from Network.getSocketFactory()) will be bound to network. All host name resolutions will be limited to network as well." - Android Docs
I noticed that while streaming audio from a remote server through 3G (mobile) connection and while the WIFI is disconnected or OFF, as soon as WIFI is activated and connected, connection through 3G is dropped.
I want the app keep using 3G even if WIFI is connected too now. I want to do this to keep continuity. (User may opt-in/out to/from this behaviour).
Is there a special flag, lock, etc.. For this purpose?
This isn't possible on devices before Android 5.0 (Lollipop). The OS only keeps one interface up at a time, and applications don't have any control over this choice.
On devices running Android 5.0 or newer, you can use the new multi-networking APIs to pick which interface you want to use for network traffic.
Here's the steps to do this, from the Android 5.0 changelog:
To select and connect to a network dynamically from your app, follow these steps:
Create a ConnectivityManager.
Use the NetworkRequest.Builder class to create an NetworkRequest object and specify the network features and transport type your app is interested in.
To scan for suitable networks, call requestNetwork() or registerNetworkCallback(), and pass in the NetworkRequest object and an implementation of ConnectivityManager.NetworkCallback. Use the requestNetwork() method if you want to actively switch to a suitable network once it’s detected; to receive only notifications for scanned networks without actively switching, use the registerNetworkCallback() method instead.
When the system detects a suitable network, it connects to the network and invokes the onAvailable() callback. You can use the Network object from the callback to get additional information about the network, or to direct traffic to use the selected network.
Specifically, if you want to force your traffic over 3G/LTE, even if there's a WiFi signal present, you'd use something like this:
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder req = new NetworkRequest.Builder();
req.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
cm.requestNetwork(req.build(), new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
// If you want to use a raw socket...
network.bindSocket(...);
// Or if you want a managed URL connection...
URLConnection conn = network.openConnection(...);
}
// Be sure to override other options in NetworkCallback() too...
}
I'm making a app that is displaying the available wireless networks and a user can choose one network and connect to it.
I have a broadcast receiver and I receive the status of the connection :connected , when the connection is done , but I would like also to display more info to the user like , Authenticating, Obtaining IP address , cause now I only know when network is connected but noting till then.
Any idea how to do this?
Thanks you very much
Fine-grained connection state is available from the NetworkInfo object - getDetailedState
NetworkInfo ni = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
DetailedState state = ni.getDetailedState();
You also need to register your broadcast receiver to receive state change events from WifiManager
IntentFilter filter =
new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
I want my app to automatically notify the user when the networkType changes(eg from EDGE to 3G or 3G to 1XRTT etc).
Using the getNetworkType() method, I have to continuously check for a change in networkType. Is there some kind of intent being broadcasted throughout the system when a change is detected.
Look at the ConnectivityManger.CONNECTIVITY_ACTION Ref
From Documentation
A change in network connectivity has occurred. A default connection has either been established or lost. The NetworkInfo for the affected network is sent as an extra; it should be consulted to see what kind of connectivity event occurred.
I would like to know if there is any way in Android to read some configurable property from a WiFi access points without getting connected/authenticated to the network. Basically I would like to list only the networks that implements/advertises a specific web service I am working on.
Thanks,
- Rafael
You can retrieve WifiManager instance:
WifiManager wifiManager = ( WifiManager ) mContext.getSystemService ( mContext.WIFI_SERVICE ) ;
You can also get NetworkInfo object:
ConnectivityManager connManager = ( ConnectivityManager ) context
.getSystemService ( Context.CONNECTIVITY_SERVICE ) ;
NetworkInfo mWifi = connManager.getNetworkInfo ( ConnectivityManager.TYPE_WIFI ) ;
You can use the WifiManager.
This class provides the primary API for managing all aspects of Wi-Fi connectivity. Get an instance of this class by calling Context.getSystemService(Context.WIFI_SERVICE). It deals with several categories of items:
The list of configured networks. The list can be viewed and updated, and attributes of individual entries can be modified.
The currently active Wi-Fi network, if any. Connectivity can be established or torn down, and dynamic information about the state of the network can be queried.
Results of access point scans, containing enough information to make decisions about what access point to connect to.
It defines the names of various Intent actions that are broadcast upon any sort of change in Wi-Fi state.
This is the API to use when performing Wi-Fi specific operations. To perform operations that pertain to network connectivity at an abstract level, use ConnectivityManager.
This is the link:
http://developer.android.com/reference/android/net/wifi/WifiManager.html