I am trying to write some code that will disconnect current wifi network (if any) and reconnect to a specific wifi network with known SSID.
I have been following the code used here; How do I connect to a specific Wi-Fi network in Android programmatically?
which works but the connection takes several seconds, upto about 10 seconds.
Specifically, I use the code as follows;
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
WifiConfiguration config;
I obtain the config, whether by creating a new one and setting the SSID and KeyMgmt to NONE and then adding it;
wifiManager.add(config);
or by getting a config that already exists;
List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
for( WifiConfiguration i : list ) {
if(i.SSID != null && i.SSID.equals("\"" + networkSSID + "\"")) {
config = i;
break;
}
}
Then I call;
wifiManager.disconnect();
wifiManager.enableNetwork(i.networkId, true);
wifiManager.reconnect();
I have a broadcast received checking the wifi state and when i get a connected for my correct SSID i can continue, however, this process takes upto 10 seconds, how can i set up the config or wifimanager to connect to this much quicker?
Thanks
I think this code is help to you..
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.network_test);
context = this;
mUpdate = new UpdateTimeTask();
mHandler = new Handler();
mHandler.post(mUpdate);
}
public Boolean isNetAvailable(Context con) {
try{
connectivityManager = (ConnectivityManager) con.getSystemService(Context.CONNECTIVITY_SERVICE);
wifiInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
mobileInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if(wifiInfo.isConnected() || mobileInfo.isConnected()) {
return true;
}
}catch(Exception e){
e.printStackTrace();
}
return false;
}
private class UpdateTimeTask implements Runnable{
public void run() {
boolean net = isNetAvailable(context);
if(net != false) {
Toast.makeText(getBaseContext(), "network Available", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(getBaseContext(), "network Not Available", Toast.LENGTH_SHORT).show();
}
mHandler.postDelayed(mUpdate, 30000);
}
}
}
Have you tried adding startScan() to your routine to force an immediate rescan for available networks at the time you wish to connect? I imagine forcing that command repeatedly with an alarmManager or something similar is possible, but I would think that has the potential to have an expensive performance/battery impact. If you have a specific trigger, it could be a solution.
See here: http://developer.android.com/reference/android/net/wifi/WifiManager.html#startScan()
Related
According to a lot of official documents also stackoverflow documents, I am trying to use wifimanager to get list of access points near me but that is not working. I want to tell you I tried to use below code in android 4.4 but right now not working in android 9. Have you any solution?
final WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
//****************** Enable Wifi And Connect To Hidden Access Point
if(wifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLING){
wifiManager.setWifiEnabled(true);
wifistate = true;
}
// Start lengthy operation in a background thread
new Thread(new Runnable() {
int count = 0;
public void run() {
while (wifiManager.isWifiEnabled() == false && count < 5) {
try {
// Here I'm making thread sleep to show progress
Thread.sleep(1000L);
count++;
} catch (Exception e) {
}
}
if (wifiManager.isWifiEnabled() == true) {
//
wifiManager.startScan();
List<ScanResult> wifiScanList =wifiManager.getScanResults();
Basically, what I need is check if my Wifi connection has Internet access. The most effective way I know is with sock.connect() but I need to be sure that the connection will be done through the Wifi network and this is my main issue,
I was searching for a few days about this and there is not a good response to this.
There are a lot of solutions like How do I see if Wi-Fi is connected on Android? but they only check if the device is connected to a router. I need to know if the router as internet access
My best approximation was this:
Socket sock = new Socket();
ConnectivityManager
cm = (ConnectivityManager) mContext.getApplicationContext()
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Network net = cm.getActiveNetwork();
net.bindSocket(sock);
}
sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
sock.close();
But this has some limitations. The biggest limitation is that only works for API >= 23.
Also, if I am in China I think that hostname "8.8.8.8" will not work, right?
And finally, cm.getActiveNetwork() will only be the WIFI network if my device is connected to a wifi network, and this is not totally true because it is possible to modify the default active network.
What I need to know is:
Is there any working alternative for API >= 16?
Is there a good hostname that will work fine in China?
Any help will be appreciated,
Thanks in advance!
Yes you have to check with a remote server in order to be sure.
A common way would be like this:
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (isConnected) {
try {
InetAddress ipAddr = InetAddress.getByName("google.com");
if (ipAddr.isReachable(5000)) {
// Internet access OK!
}
} catch (Exception e) {
// Error handling...
}
}
Prefer domain names when calling getByName rather than IPs (https://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#getByName(java.lang.String))
If you want to avoid the connectivity manager you can register a BroadcastReceiver for WifiManager.NETWORK_STATE_CHANGED_ACTION events and you will know if you are connected to a WiFi (the current state is received almost immediately).
As regards the region issue I am out of ideas, maybe use NTP servers instead of google (much more innocent servers) or try Baidu!?
Finally, I came to a solution:
public interface Consumer {
void accept(Boolean internet);
}
class InternetCheck extends AsyncTask<Void, Void, Boolean> {
private Consumer mConsumer;
public InternetCheck(Consumer consumer) {
mConsumer = consumer;
execute();
}
#Override
protected Boolean doInBackground(Void... voids) {
Socket socket = null;
try {
WifiManager wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager != null) {
socket = new Socket();
socket.setKeepAlive(false);
String localIpAddress = getIpAddress(wifiManager);
socket.bind(new InetSocketAddress(localIpAddress, 0));
socket.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
return true;
}
return false;
} catch (IOException e) {
//unbind();
return false;
}finally {
if(socket != null && !socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
#Override
protected void onPostExecute(Boolean internet) {
mConsumer.accept(internet);
}
}
public static String getIpAddress(WifiManager wifiManager) {
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
return String.format(Locale.getDefault(), "%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff),
(ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff));
}
I came to a solution after saw this question. With this, I obtained the IP address of my wifi connection and with this, I was able to bind the socket (socket.bind(...)) to the wifi connection and be check if my router had internet access.
I hope this solution helps somebody in the future :)
i want to make 3g works when wifi is enabled! Stop for a while wifi and connect through 3g. after that close 3g and work with wifi again! thanks!
Just disabling Wi-Fi? Both processes are automatic: connecting a Wi-Fi network when it is enabled and getting 3G when there isn't a Wi-Fi connection.
I don't think it is possible to switch to mobile data network when WiFi is enabled.
Perhaps you should silently disable the WiFi (from code) and wait for the 3G network to establish. Once your required task is done, turn the WiFi on again and your 3G network will be disconnected.
I think the following should work...
WifiManager wm = null;
WifiManager.WifiLock wfl = null;
// To disable wi-fi
wm = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
if (wm != null) {
wfl = wm.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "myWifiLock");
Boolean result = wm.setWifiEnabled(false);
Log.d(TAG, "wm.setWifiEnabled(false) result: " + result);
}
// To re-enable wi-fi
if (wfl != null)
wfl.release();
if (wm != null) {
Boolean result = wm.setWifiEnabled(true);
Log.d(TAG, "wm.setWifiEnabled(true) result: " + result);
}
here is a code that can enable and dissable inside your code!
wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Runnable runnable = new Runnable() {
// ginetai o kwdikas gia to anoigma kai to klisimo tou wifi
#Override
public void run() {
// new LongOperation().execute();
for (int i = 0; i <= 150; i++) {
try {
Thread.sleep(1000);
if (i >= 0 && i <18){
wifi.setWifiEnabled(true);
// wifi.setWifiEnabled(false);// Disabling WiFi
}
else if (i>= 18 && i < 40){
wifi.setWifiEnabled(true);
// wifi.setWifiEnabled(false); // Enabling WiFi
}
else if (i>= 40 && i < 58){
// wifi.setWifiEnabled(true); // Disabling WiFi
wifi.setWifiEnabled(false);
}
else if (i>= 58 && i < 78){
wifi.setWifiEnabled(true);
//wifi.setWifiEnabled(false); // Enabling WiFi
}
else{
// wifi.setWifiEnabled(true);
wifi.setWifiEnabled(false);// Disabling WiFi
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
new Thread(runnable).start();
I want to know how to detect state of WiFi tethering. I've seen an article: Android 2.3 wifi hotspot API But it doesn't work! It returns always WIFI_AP_STATE_DISABLED = 1. It doesn't depend on real state of WiFi tethering.
Using reflection:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Method[] wmMethods = wifi.getClass().getDeclaredMethods();
for (Method method: wmMethods) {
if (method.getName().equals("isWifiApEnabled")) {
try {
boolean isWifiAPenabled = method.invoke(wifi);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
As you can see here
In addition to the reflexion, to get the Wifi tethering status update, you can listen to this broadcast Action :
IntentFilter filter = new IntentFilter("android.net.wifi.WIFI_AP_STATE_CHANGED");
To get all tethering option update :
IntentFilter filter = new IntentFilter("android.net.conn.TETHER_STATE_CHANGED");
Those actions are hidden inside the Android source code
First, you need to get WifiManager:
Context context = ...
final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Then:
public static boolean isSharingWiFi(final WifiManager manager)
{
try
{
final Method method = manager.getClass().getDeclaredMethod("isWifiApEnabled");
method.setAccessible(true); //in the case of visibility change in future APIs
return (Boolean) method.invoke(manager);
}
catch (final Throwable ignored)
{
}
return false;
}
Also you need to request a permission in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
Here is the Xamarin C# version if anyone is looking:
static Method isWifiApEnabledMethod;
public static bool IsWifiApEnabled ()
{
var wifiManager = WifiManager.FromContext (Application.Context);
if (isWifiApEnabledMethod == null)
{
try
{
isWifiApEnabledMethod = wifiManager.Class.GetDeclaredMethod ("isWifiApEnabled");
isWifiApEnabledMethod.Accessible = true; //in the case of visibility change in future APIs
}
catch (NoSuchMethodException e)
{
Debug.WriteLine ("Can't get method by reflection" + e);
}
catch (System.Exception ex)
{
Debug.WriteLine ("Can't get method by reflection" + ex);
}
}
if (isWifiApEnabledMethod != null)
{
try
{
return (bool)isWifiApEnabledMethod.Invoke (wifiManager);
}
catch (System.Exception ex)
{
Debug.WriteLine ("Can't invoke by reflection" + ex);
}
}
return false;
}
(without using reflection since they say google is restricting it)
I'm writting this answer 10 years later. also I don't know if this can be considered a good aproach or not but I first get the Wlan network interface IPs
and if there is no address I assume that it tethering isn't enabled. if there is an address, I check using the connectivity manger whether WI-FI is connected to a network or not. if there is an IP for the Wlan network interface but it isn't connected to a network, I assume tethering is enabled.
you probably would need to add this line to your manifest file
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
code to get the ip of an inteface (this only gets the IPv4, you can modify it to get the IPv6 or both if you want)
// method used to retrieve Wlan ip addresses IPv4 of the device.
public static String IpAddresses() throws NoAddressFoundException, SocketException {
Enumeration<NetworkInterface> Nics = NetworkInterface.getNetworkInterfaces();
while (Nics.hasMoreElements()) {
NetworkInterface NIC = Nics.nextElement();
if (NIC.isUp() && !NIC.isLoopback() && NIC.getName().contains("wlan")) {
Enumeration<InetAddress> Addresses = NIC.getInetAddresses();
while (Addresses.hasMoreElements()) {
InetAddress WlanAddress = Addresses.nextElement();
if (WlanAddress instanceof Inet4Address)
return WlanAddress.getHostAddress();
}
}
}
throw new NoAddressFoundException("No suitable wifi address found");
}
then if there is an address i check if wifi is connected by this method:
//method to check if the device is connected to a Wi-Fi network; it doesn't matter if network has access to internet
public static boolean isWifiConnected(Context context) {
ConnectivityManager ConMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo WifiInfo = ConMan.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return WifiInfo.isConnected();
}
NOTE: the "NoAddressFoundException" is a custom exception in my app if anyone is wondering. it won't exist in your case.
Reflection is a poor way to achieve this.
We can inspect the DhcpInfo to determine if the device is allocating addresses (mobile hotspot) or is being allocated by another DHCP server.
Here is a kotlin function that will determine if a device is a mobile hotspot, it has not been widely tested so YMMV.
fun isMobileHotspot(manager: WifiManager): Boolean {
val info = manager.dhcpInfo
return (
info.ipAddress == 0
&& info.netmask == 0
&& info.gateway == 0
&& info.serverAddress == 16885952) // 192.168.1.1
}
My Android app can only function with WiFi connected to the Internet. Thus, I use the following code to check if the device is connected:
ConnectivityManager conMgr = (ConnectivityManager)getSystemService(Activity.CONNECTIVITY_SERVICE);
boolean wifi = conMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected();
However, very often when the application is launched and WiFi connected to the Internet, I get the notification that is only shown when wifi = false. Have I missed something, or the check is not that accurate?
My project also relies on Wifi (although I use a private network). The following is my code for setting up a Wifi connection on start up:
private void initWIFI (WifiManager wifiMgr, String SSID, String key)
{
WifiInfo curr;
if (null == (curr = wifiMgr.getConnectionInfo())) // Get current wifi state
{
joinNetwork (wifiMgr, SSID, key);
}
else switch (curr.getSupplicantState())
{
case DISCONNECTED:
case DORMANT:
case INACTIVE:
case SCANNING:
joinNetwork (wifiMgr, SSID, key);
break;
default:
if (!curr.getSSID().equals (SSID))
joinNetwork (wifiMgr, SSID, key);
}
while (wifiMgr.getConnectionInfo().getIpAddress() == 0)
{
try
{
Thread.sleep (1000);
}
catch (Exception e)
{ }
}
}
/**This method is used to join the proper WiFi network when necessary. Normally,
* the Android retains network configuration and it is not necessary to manually
* re-join the desired network on software startup. However, when it is determined
* that the Android is not currently attached to the proper network, this function
* is used to correct that situation. */
private void joinNetwork (WifiManager wifiMgr, String SSID, String key)
{
try
{
WifiConfiguration wc = new WifiConfiguration();
wc.allowedAuthAlgorithms.set (WifiConfiguration.AuthAlgorithm.OPEN);
wc.allowedAuthAlgorithms.set (WifiConfiguration.AuthAlgorithm.SHARED);
wc.allowedGroupCiphers.set (WifiConfiguration.GroupCipher.WEP40);
wc.allowedGroupCiphers.set (WifiConfiguration.GroupCipher.WEP104);
wc.allowedKeyManagement.set (WifiConfiguration.KeyMgmt.NONE);
wc.allowedPairwiseCiphers.set (WifiConfiguration.PairwiseCipher.TKIP);
wc.allowedPairwiseCiphers.set (WifiConfiguration.PairwiseCipher.CCMP);
wc.allowedProtocols.set (WifiConfiguration.Protocol.WPA);
wc.allowedProtocols.set (WifiConfiguration.Protocol.RSN);
wc.hiddenSSID = false;
wc.priority = 32;
wc.SSID = "\"" + SSID + "\"";
wc.status = WifiConfiguration.Status.ENABLED;
wc.wepKeys[0] = key;
wc.wepTxKeyIndex = 0;
int netID;
if (-1 == (netID = wifiMgr.addNetwork (wc)))
{
listener.lostConnection (true);
}
else
{
wifiMgr.enableNetwork (netID, true);
Thread.sleep (5000); // Delay to allow the DHCP process to work
}
}
catch (Exception e)
{
listener.lostConnection (true);
}
}
It should be pointed out that I always use the same wireless access point, and the code in joinNetwork() is specifically configured for it, so if your configuration needs to be more flexible, then your solution may be more complex. Sadly, I do not remember the web site where I found the starting point for this code, but it didn't take a ton of Googling to find it. Finally, I'm pretty sure your application needs to have the ACCESS_WIFI_STATE and CHANGE_WIFI_STATE permissions.
I use code like this:
public static String getCurrentSsid(Context context) {
final WifiInfo wifiInfo = getCurrentWifiInfo(context);
if (wifiInfo != null && !StringUtil.isBlank(wifiInfo.getSSID())) {
return wifiInfo.getSSID();
}
return null;
}
public static WifiInfo getCurrentWifiInfo(Context context) {
final ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo networkInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (networkInfo != null && networkInfo.isConnected()) {
final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
return wifiManager.getConnectionInfo();
}
return null;
}
At the same time be aware of this two issues 19078 and 3641.