I am trying to define WiFi connection state on its changing. But I need a bit more - to get BSSID for WiFi network.
I didn't use BroadcastReceiver approach, instead I just poll WifiInfo#getBssid() every second. Most of time it works correct, but after my phone goes sleep for relatively long time (>~hour) WifiInfo#getBssid() returns null when my phon is connected to the WiFi.
public String getBssid() {
WifiManager wifiMgr = (WifiManager);
getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
String bssid = wifiInfo.getBSSID();
}
I call this function from Qt code via JNI.
The problem is not in Android but in Qt. I used QNetworkConfigurationManager as a member of my NetworkMonitor class and checked QNetworkConfigurationManager#defaultConfiguration().bearerType() == QNetworkConfiguration::BearerWLAN prior to check bssid. So, the bearerType was returning wrong value after device sleep-wakeup until I implemented recreation of QNetworkConfigurationManager instance on every wakeup.
Related
Been struggling with connecting to WiFi network in Android 5 and 6 for a while and other similar questions don't seem to work for me. I could get the same code working in Android 4.4.2
Adding the code snippet below.
String networkSSID = getSsid();
String networkPass = getNetworkPass();
WifiConfiguration conf = new WifiConfiguration();
conf.SSID = "\"" + networkSSID + "\"";
conf.status = WifiConfiguration.Status.ENABLED;
conf.priority = 40;
conf.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
conf.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
conf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
conf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
conf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
conf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
conf.preSharedKey = "\""+ networkPass +"\"";
int value = mWifiManager.addNetwork(conf);
Log.i(TAG_CHECK, "Connecting to : " + value);
boolean enabled = mWifiManager.enableNetwork(value, true);
Log.i(TAG_CHECK, "enabled to : " + enabled);
mWifiManager.reconnect();
And here is what I noticed.
mWifiManager.addNetwork(conf)
returns some (+) integer with Android 5(phone) and Android 6(tab).
But both don't connect unless I open the wifi settings (I don't have to do anything and just landing there connects) or I manually turn off and turn on Wifi from the top bar to automatically connect.
The listeners to detect connection to the network are in tact for both the versions to precisely know when the connection get established - confirming the above behaviour. Have attached a pic of the permissions granted below.
Any pointers as to what I am missing?
EDIT: Upon digging into WifiManager class, looks like the Access Point remains in WIFI_AP_STATE_DISABLED state. I should also highlight that everything worked as expected while trying on a different Android M phone.
EDIT2
I have the following observations.
1. The issue so far is specific to 1 android 6.0.1 Samsung tablet and 1 android 5.0.2 Micromax phone. It works just fine on 3 other android 6.0.1 phones, 1 android N phone and Android 4.4.2 phone.
2. The access point ends up in wifi_ap_disabled state in the problematic cases consistently. Both addNetwork and enableNetwork calls are affirmative.
3. These access points are not that of a router wifi but that of other phones that broadcast. The problematic phones can programatically connect to wifi hotspots (setup manually and not in the programatic way as I would like to) without any issue.
4. Mobile data enabled/disabled state or wifi state with a different connected network doesn't change the dynamics for both working and problematic phones.
This makes me think that it is a combination of phones/tabs (and not OS) and the access point broadcast configuration. Do you think I should be playing around with some config parameters?
Edit 3 - Important Update
So the wifimanager is obtained like below
WifiManager mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
I instantiate mWifiManager in a service (inside onCreate method) and use that later to scan and connect with inputs from front-end activity. While it doesn't work in the way as described earlier, using the same snippet seems to work when the enableNetwork call is done right in the onCreate method - working just as expected. It also works fine when called from front-end activity but only when I don't instantiate mWifiManager in the service.
Though I would expect only one reference to a system service - WifiManager i.e, I think the subsequent usage of that reference (or a different reference to WifiManager) gets a lower priority (or gets deprioritized by the previous reference) and hence doesn't get completely executed leaving the access point in disabled state and requiring manual intervention to help complete the execution by WifiManager and other wifi system services.
Also, I notice the same in Android 5.0.2 phone, the asynchronous enableNetwork does get executed, but it takes some time to execute it.
My questions
1. It is no more a question about the correctness of the code. Services in general have lesser priority compared to front-end threads So, is there is way I could prioritise the enableNetwork call so that it gets immediately executed?
2. What happens in case of multiple references to WifiManager?
I believe if you add a disconnect() it will do what you want. I've added a check here because addNetwork() can fail to add your network. For Android 6.0+, you can't add a network if it exists already but if this fails you can try getting the network id then connecting. (For instance, it will be there if added (and saved) if you re-install) I also do not add quotes to SSID in Lollipop (ver 21)+.
int value = mWifiManager.addNetwork(conf);
// need to check the result if successful
if (value == -1) {
return; // network not added successfully
}
Log.i(TAG_CHECK, "Connecting to : " + value);
mWifiManager.disconnect(); // add a disconnect
boolean enabled = mWifiManager.enableNetwork(value, true);
Log.i(TAG_CHECK, "enabled to : " + enabled);
mWifiManager.reconnect();
I'm using the following code to detect and connect to specific WiFi ssid when I press a button in android. Below is the code. Any help will be appreciated.
ssid :- "myHotspot" & password:- "12345678"
Button b1 = (Button) findViewById(R.id.button); <br>
b1.setOnClickListener(new View.OnClickListener() {
<br><br>#Override
<br>public void onClick(View v) {
wifiConfiguration.SSID = "\"myHotspot\"";
wifiConfiguration.preSharedKey ="\"12345678\"";
WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
int netId = wifiManager.updateNetwork(wifiConfiguration);
if (wifiManager.isWifiEnabled()) { //---wifi is turned on---
//---disconnect it first---
wifiManager.disconnect();
} else { //---wifi is turned off---
//---turn on wifi---
wifiManager.setWifiEnabled(true);
}
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
}
});
The main problem I'm getting is that my phone gets connected to the ssid and after 2-3 seconds it loses the connection and gets connected to my home Wifi router (which has internet connectivity)
Note:- The ssid I'm trying to connect is just a local hotspot without any internet connection.
and if I try with "addNetwork(wifiConfiguration)" it creates multiple networks of the same name. so Now how do I resolve this ?!
I think the problem here is you try to enableNetwork immediately after the call to wifiManager.setWifiEnabled(true). Generally, switching on wifi will take 5-10 seconds depending on the device, until then any call to wifiManager.enableNetwork will be lost. Hence, your call to connect to the desired network is getting lost and as soon as the wifi is switched on, your device connects to the last network it remembers.
Try to create a loop where you keep checking if wifiManager.isWifiEnabled() == true and keep looping until it returns true (with Thread.sleep() obviously and doing this in an AsyncTask or separate Thread). Only after that try to call enableNetwork.
What philosophy of startscan is better to use when i wanna get list of available wifi network?
I'm do this in main thread:
List<ScanResult> wifiList;
wifiManager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
if (!wifiManager.isWifiEnabled()) wifiManager.setWifiEnabled(true);
wifiManager.startScan();
wifiList = wifiManager.getScanResults();
for (int i = 0; i < wifiList.size(); i++) {
String[] networkInfo = wifiList.get(i).toString().split(",");
if (networkInfo[0].trim().equals(AP_SEARCH_SSID))
petcub_networks++;
}
In all device which i'm use for test, it's work fine, except few samsung smartphone. It's happened on customer device and i can't debug it quickly.
Is some one have same problem with samsung? Or will be better scan AP in background? Can it solve my problem?
**UPD:**Essence of my problem in next: i'm wanna scan available wifi networks, then if needs network was found i'm make connect to it(to socket). This procedure used in pipeline like first step.
I'm sorry to inform you but the code snippets had lots of missing elements (in term of efficiency) and is also incorrect, Let me elaborate this in points:
startScan() only request a scan from the OS , it does not initiate a scan right away in some cases. so you need to check the return boolean from the call
Before calling startScan you should register a BroadcastReceiver for WifiManager.SCAN_RESULTS_AVAILABLE_ACTION and only in after that even you should get the results
You might not need to initiate a scan at a lot. a relatively fresh result may already be available. You can take a look on the timestamp value (API 17) of ScanResult to estimate how "fresh" the scan is
You don't check if the device has WIFI hardware at all
You only initiate a scan if the Wifi is on, Android devices (since API 16 I think) can scan for networks even if the WIFI is off
To check if you can initiate a scan use this (In a function the returns boolean):
if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
return false;
}
WifiManager mWifiManager = (WifiManager) context
.getSystemService(Context.WIFI_SERVICE);
boolean ret = mWifiManager.isWifiEnabled();
ret = ret || ((android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) &&
mWifiManager.isScanAlwaysAvailable());
return ret;
I use getSSID() to get the name of the wifi network as soon as a new connection is made.
But sometimes I get null for that value. This is my code:
Permissions in manifest are correct, because, as I said, most of the times it works.
I use this filter for the broadcast receiver:
<action android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
In the broadcast I do this:
if("android.net.wifi.supplicant.CONNECTION_CHANGE".equals(intent.getAction()))
{ boolean bConected = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false);
if(bConnected == true)
{ WifiManager wifi = (WifiManager) Contexto.getSystemService(Context.WIFI_SERVICE);
String MyName = wifi.getConnectionInfo().getSSID();
Sometimes MyName is null here even if Wifi is connected correctly
}
}
Any ideas?
I use similar code regularly and I have never received null when connected.
Here is my code:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
String myName = info.getSSID();
Therefore, I propose that you should wait 400 to 1000ms or so after receipt of the CONNECTION_CHANGE broadcast before requesting the information.
Here is one example that will implement the delay:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
String myName = info.getSSID();
}
}, 1000);
The Android Developers website states that :
The SSID may be null if there is no network currently connected.
You're listening to a CONNECTION_CHANGE event, what if the state of the connection changed from connected to disconnected ?
Wifi devices gets sometimes disconnected from an access point and they do reconnect silently without you even noticed it was disconnected.
I've found out the hard way that the supplicant subsystem is only relevant to the WPA security mechanism, and is really not a good choice to use for monitoring general wifi connection status. The verbiage in the documentation would lead you to believe that it's possible, but I had a lot of trouble when trying to use the supplicant actions, including issues similar to the one you describe.
From the SupplicantState enum documenation:
These enumeration values are used to indicate the current
wpa_supplicant state. This is more fine-grained than most users will
be interested in. In general, it is better to use NetworkInfo.State.
Using the NETWORK_STATE_CHANGED_ACTION and looking at the NetworkInfo extra I was able to get expected, stable behavior.
I am trying to get the MAC address, BSSID and LINK_speed of the Wifi. I notice that all three show up with values even when Wifi is turned off. I turn the phone off and then on again but do not turn wifi on. The app crashes on any interrogation of the three items and I cant try/catch the errors. If I turn wifi on then off I can interrogate the items and app runs fine. Its like BSSID and LINKSPEED are really 'LAST'BSSID and 'LAST'LINKSPEED. Is being blind to the MAC address after power on but not turning wifi on normal behavior? And is there a way to trap the error to keep from force close of the app?
WifiManager wifi;
wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifi.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
ipAddress = wifiInfo.getIpAddress();
//above work no matter whether wifi on or off before
String BSSID=wifiInfo.getBSSID(); //<<<<< ERRORS FORCE CLOSE IF NOT EVER CONNECTED
int WifiLinkSpeed=wifiInfo.getLinkSpeed(); printi("link speed",WifiLinkSpeed);
String MacAddress=wifiInfo.getMacAddress(); Log.e("MAC address",MacAddress);
//All three of these FORCE close if WIFI has never been turn on
Try this,
WifiManager wifiManager = (WifiManager) Settings.cntxt.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
strMacAddr = wifiInfo.getMacAddress();
if(strMacAddr==null) {
strMacAddr = "Unknown MAC";
}
Although you did say you tried try/catch... which errors/exceptions are you catching? Evidently not the right one(s).
It's been a while since I did any Android programming, but that's the crux of the matter... figuring out which exception is firing when you try those functions.
try {
// don't declare variables inside block, you'll limit scope
BSSID=wifiInfo.getBSSID(); //<<<<< ERRORS FORCE CLOSE IF NOT EVER CONNECTED
WifiLinkSpeed=wifiInfo.getLinkSpeed(); printi("link speed",WifiLinkSpeed);
MacAddress=wifiInfo.getMacAddress(); Log.e("MAC address",MacAddress);
//All three of these FORCE close if WIFI has never been turn on
}
catch { /* something bad happened, handle it */ }
// continue on since all is good in the world today...