Android wifimanager.startscan() in main thread or in background? - android

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;

Related

Inconsistent result of WifiInfo#getBssid() behavior

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.

failed to connect to specific WiFi in android programmatically

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.

Wifi getSSID() returns null

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.

BUG or Normal Behavior on Android MAC-Address?

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...

Can you explain the Functionality of requestRouteToHost() in android?

In my code I am using requestRouteToHost() method:
Does this routing means changing the WIFI to 3G or vice versa??
My code is not working...
public static boolean isHostAvailable(Context context, String urlString) throws UnknownHostException, MalformedURLException {
boolean ret = false;
int networkType = ConnectivityManager.TYPE_WIFI;
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if(cm != null){
NetworkInfo nf = cm.getActiveNetworkInfo();
if(nf != null){
networkType = nf.getType();
}
URL url = new URL(urlString);
InetAddress iAddress = InetAddress.getByName(url.getHost());
ret = cm.requestRouteToHost(networkType, ipToInt(iAddress.getHostAddress()));
}
return ret;
}
public static int ipToInt(String addr) {
String[] addrArray = addr.split("\\.");
int num = 0;
for (int i=0;i<addrArray.length;i++) {
int power = 3-i;
num += ((Integer.parseInt(addrArray[i])%256 * Math.pow(256,power)));
}
return num;
}
Thanks
I think this is an extremely poorly documented method, and while an above comment saying "consider it a ping" might be a reasonable interpretation, I don't think it's correct. The fact that it takes an int as a host address suggests it is a much lower-level method than that, and the comment in the JavaDoc This method requires the caller to hold the permission CHANGE_NETWORK_STATE is another clue, suggesting that this makes a change in the internal routing table of the device. This link provides a better explanation:
requestRouteToHost() doesn't establish connectivity on any network, it
only ensures that any traffic for the specified host will be routed
via the specified network type (wifi or mobile). Connectivity must
already exist on the specified network.
This explanation makes MUCH more sense, considering the permission required. It also appears that it will not work with WiFi. So, it appears what this method is useful for is the following: You wish to ensure that the connection made to a particular host will be made via a SPECIFIC interface and that interface is not WiFi. This might make sense for a long-term, low traffic, battery efficient connection, such as when you wish to keep a socket open to a server and wait for the server to send the occasional message. The mobile data interface would make more sense than WiFi, since you wouldn't need to keep the WiFi radio active the whole time, and the mobile network radio is always on anyway. Incidentally, this is EXACTLY how an iPhone's server "push" mechanism works: It keeps a socket to an Apple server constantly connected over the mobile data interface, waiting for the server to say something.
So, in opposition to the (currently chosen) correct answer, I suggest that the answer to the asker's question: Does this routing means changing the WIFI to 3G or vice versa?? is actually, "Yes, sort of!" If the method returns true, the caller is assured that connections to that IP address will happen over the indicated interface.
And to Google: Boo on you for not documenting some of your APIs better!
Method requestRouteToHost() does not change wifi to 3G or vice versa!
Official Documentation :
public boolean requestRouteToHost (int networkType, int hostAddress)
Ensure that a network route exists to deliver traffic to the specified host via the specified network interface. An attempt to add a route that already exists is ignored, but treated as successful.
Parameters
networkType the type of the network over which traffic to the specified host is to be routed
hostAddress the IP address of the host to which the route is desired
Returns
true on success, false on failure

Categories

Resources