I plan to make an app that checks if a certain wifi network uses common password. I have a list of most common passwords, but the following function:
public boolean connectTo(String psKey){
WifiConfiguration wc = new WifiConfiguration();
wc.SSID = "\"" + dbw.getSsid() + "\"";
wc.preSharedKey = "\"" + psKey + "\"";
wc.status = WifiConfiguration.Status.ENABLED;
wc = configureCapabs(wc, dbw.getCapability());
int res = wifi.addNetwork(wc);
Toast.makeText(this, "add Network returned " + res , Toast.LENGTH_SHORT).show();
boolean b = wifi.enableNetwork(res, true);
Toast.makeText(this, "enableNetwork returned " + b , Toast.LENGTH_SHORT).show();
if(!b) return false;
boolean fin = /*b ? wifi.reassociate() : */wifi.reconnect();
return fin;
}
it returns true, even if the password was incorrect. Is there a way of checking if the password that I tried to log in with was accepted or rejected?
You are using the reconnect() / reassociate() methods of WiFiManager to check weather or not the connection succeeded but the boolean value that they return means something else. The returned value only tells you about the result of STARTING a given operation. This is because associating and connecting to a WiFi network takes time. These methods however will return instantly and will not block. The actual task of connecting or associating with the network is done asynchronously in the background.
You can monitor the what is happening with the WiFi connection by listening to a specific system wide broadcast:
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
<action android:name="android.net.wifi.STATE_CHANGE"/>
You can find more info about this HERE - Check Torsten's answer.
As far as checking if the password was accepted or rejected by way of a return value, I don't actually know however I can think of two 'possible' alternate strategies that might net the same result?
Not 100% sure as I haven't done it before, however I wonder if Pinging the supplicant would work?
http://developer.android.com/reference/android/net/wifi/WifiManager.html#pingSupplicant()
Either that or checking if you have an IP address now?
http://developer.android.com/reference/android/net/wifi/WifiInfo.html
Related
I am creating a list of in-range wifis and show it to the user. I want to the user can select each of the items in the list and insert the password in order to connect to the selected SSID.
I wrote this method for wifi connection:
private WifiConfiguration wifiConf; /* WifiConfiguration object */
private WifiManager wifiMgr; /* WifiManager object */
private WifiInfo wifiInfo; /* WifiInfo object */
public boolean connectToSelectedNetwork(String networkSSID, String networkPassword, String securityType) {
int networkId;
int SecurityProtocol;
if (securityType.contains("WEP")) {
SecurityProtocol = 1;
Log.i(TAG, "Security: WEP");
} else if (securityType.contains("WPA2")) {
Log.i(TAG, "Security: WPA2");
SecurityProtocol = 2;
} else if (securityType.contains("WPA")) {
Log.i(TAG, "Security: WPA");
SecurityProtocol = 3;
} else {
Log.i(TAG, "Security: OPEN");
SecurityProtocol = 4;
}
// Clear wifi configuration variable
clearWifiConfig();
// Sets network SSID name on wifiConf
wifiConf.SSID = "\"" + networkSSID + "\"";
Log.i(TAG, "SSID Received: " + wifiConf.SSID);
switch (SecurityProtocol) {
// WEP "security".
case WEP:
wifiConf.wepKeys[0] = "\"" + networkPassword + "\"";
wifiConf.wepTxKeyIndex = 0;
wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
wifiConf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
break;
// WAP security. We have to set preSharedKey.
case WPA2:
wifiConf.preSharedKey = "\"" + networkPassword + "\"";
wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
wifiConf.allowedProtocols.set(WifiConfiguration.Protocol.RSN); // For WPA2
wifiConf.allowedProtocols.set(WifiConfiguration.Protocol.WPA); // For WPA
wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
wifiConf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
wifiConf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
wifiConf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
wifiConf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
break;
case WPA:
wifiConf.preSharedKey = "\"" + networkPassword + "\"";
// Network without security.
case OPEN_NETWORK:
wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
break;
}
// Add WiFi configuration to list of recognizable networks
if ((networkId = wifiMgr.addNetwork(wifiConf)) == -1) {
Log.i("TAG", "Failed to add network configuration!");
return false;
}
// Disconnect from current WiFi connection
if (!disconnectFromWifi()) {
Log.i("TAG", "Failed to disconnect from network!");
return false;
}
// Enable network to be connected
if (!wifiMgr.enableNetwork(networkId, true)) {
Log.i("TAG", "Failed to enable network!");
return false;
}
// Connect to network
if (!wifiMgr.reconnect()) {
Log.i("TAG", "Failed to connect!");
return false;
}
return true;
}
But when I call this function in order to connect to the selected wifi I always get false! I debugged it a lot of times and it goes into first if in this method And doesn't connect to the wifi.
Please help me with your answers.
Thank you.
addNetwork() returns -1 on failure.
One common reason for it to fail is when the network was previously configured by the user (through the wifi setting screen) or programmatically, via an app with different Unix User ID (i.e. UID). Recall that every app is associated with a UID.
If the same UID calls addNetwork() for the second time, it will be allowed to override the configuration and the function will succeed.
A similar related behavior is with regards to removing a configuration via the removeNetwork() API. Only the app with the UID that added the configuration can remove it.
This behavior makes sense since you wouldn't want a malicious (or just buggy) app, to override or remove configurations done by either the user or other apps.
So far so good, but there's a complication - when an app is reinstalled (read: uninstalled and then installed again), the OS will provide it with a different UID. Now the same app which previously added the configuration, following the reinstall, can no longer remove or update it. Ouch!
It would have been nice to allow the same application ID to be able to update/remove a network. Oh well.
I am trying to connect to a specific wifi network, as described here. However, while sometimes it works, most of the times it doesn't. I do not really understand why if I run the app, let's say 10 times, the device connects to my network 2 times, and the other 8 it doesn't.
In the following is the code I use in a Fragment.
WifiConfiguration wificonfiguration = new WifiConfiguration();
wificonfiguration.SSID = "\"" + networkSSID + "\"";
wificonfiguration.priority = 40;
wificonfiguration.status = WifiConfiguration.Status.ENABLED;
// WPA management
wificonfiguration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
wificonfiguration.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
wificonfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
wificonfiguration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
wificonfiguration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
wificonfiguration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
wificonfiguration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
wificonfiguration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
wificonfiguration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
wificonfiguration.preSharedKey = "\"" + networkPass + "\"";
WifiManager wifiManager = (WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE);
int networkId = wifiManager.addNetwork(wificonfiguration);
if (networkId > -1) {
boolean status = wifiManager.enableNetwork(networkId, true);
}
The network configuration is actually added to the manager and status value is true. I have run it on several devices running Lollipop. Also, the network I want to connect to does not provide internet access, so I also thought that may be a problem for what stated in the note here. Can anybody tell me if the code is ok?
Solved
The problem was solved by adding wifiManager.disconnect(); before adding the new network configuration.
You could disable all the network via below described method before adding the network. This would disable all the configured networks to auto-connect.
for (WifiConfiguration wifiConfiguration_ : wifiManager.getConfiguredNetworks()) {
wifiConfiguration_.status = WifiConfiguration.Status.DISABLED;
int returnNetworkId_ = wifiManager.updateNetwork(wifiConfiguration_);
}
In my music streaming app for Android, the code path below helps decides between a high bitrate stream vs. a lower bitrate based on values returned by the ConnectivityManager class instance.
I am trying to understand why ConnectivityManager.isActiveNetworkMetered() would return "true", when it's evident I'm on a local Wifi network. Take the following Android/Java code:
boolean isMetered = false;
boolean isWifi = false;
boolean isEthernet = false;
boolean isRoaming = false;
boolean isConnected = false;
NetworkInfo netinfo = connManager.getActiveNetworkInfo();
if (netinfo != null)
{
isWifi = (netinfo.getType() == ConnectivityManager.TYPE_WIFI);
isEthernet = (netinfo.getType() == ConnectivityManager.TYPE_ETHERNET);
isRoaming = netinfo.isRoaming();
isConnected = netinfo.isConnected();
Log.d(TAG, "active network type = " + netinfo.getTypeName());
Log.d(TAG, "active network subtype = " + netinfo.getSubtypeName());
Log.d(TAG, "isConnected = " + isConnected);
Log.d(TAG, "isWifi = " + isWifi);
Log.d(TAG, "isEthernet = " + isEthernet);
Log.d(TAG, "isRoaming = " + isRoaming);
}
// isActiveNetworkMetered was introduced in API 16 (Jelly Bean)
if (android.os.Build.VERSION.SDK_INT >= 16)
{
isMetered = connManager.isActiveNetworkMetered();
Log.d(TAG, "isMetered = " + isMetered);
}
When I have Wifi turned off and my only connection is to AT&T's LTE network, it prints out the following to the log console:
active network type = mobile
active network subtype = LTE
isConnected = true
isWifi = false
isEthernet = false
isRoaming = false
isMetered = true
Everything above matches expectations - I'm on a mobile carrier network that is metered.
Now switch to my home Wifi and the same block of code prints this:
active network type = WIFI
active network subtype =
isConnected = true
isWifi = true
isEthernet = false
isRoaming = false
isMetered = true
Why is isMetered, the result of isActiveNetworkMetered, still showing as true? This is causing the following code path to favor the lower bitrate stream even though I'm on my home wifi network:
if ((isWifi || isEthernet) && !isMetered)
{
result = BITRATE_HIGH_KBIT_SEC;
}
else
{
result = BITRATE_LOW_KBIT_SEC;
}
How does isActiveNetworkMetered() decide if the network is metered? Is this part of the WIFI negotiation or a bit in the SSID broadcast? A network setting on Android? I couldn't find any setting on my Android Kitkat device that let me toggle or discover the setting for a metered network.
Last week I my ISP (Frontier) sent me a new Wifi router. Possibly related? I didn't see anything on the router's firmware pages for such a setting.
I'm going to swing by work later today to see how it behaves on another network. In any case, I'm likely to edit the above code to skip the metered check unless I can prove its just an incorrect setting somewhere.
UPDATE - issue of always returning metered network reproduces on my HTC One M8 phone (running Kitkat), but not on my Nexus 7 from 2012 (also upgraded to Android 4.4 Kitkat).
PROBLEM SOLVED - it turns out my Wifi was flagged by my phone as a "Mobile Hotspot". More details on how to find and toggle this flag is here.
I've tested this too, but I'm observing the "expected" result: false for WiFi and true for 3G. This is in a Nexus 4 with Android 4.4.2.
Curiously enough the ConnectivityManagerCompat class in the support library does return false for WiFi.
final int type = info.getType();
switch (type) {
case TYPE_MOBILE:
return true;
case TYPE_WIFI:
return false;
default:
// err on side of caution
return true;
}
EDIT - Found it (I think)
NetworkPolicyManagerService seems to be the class that ultimately produces the result for this method. And according to it, WiFi connections can indeed be metered. It contains a BroadcastReceiver that "listen(s) for wifi state changes to catch metered hint" (line 567). This information is obtained from NetworkInfo.getMeteredHint(), which, on closer inspection, contains this interesting comment:
/**
* Flag indicating that AP has hinted that upstream connection is metered,
* and sensitive to heavy data transfers.
*/
private boolean mMeteredHint;
This flag is loaded from DhcpResults.hasMeteredHint()
/**
* Test if this DHCP lease includes vendor hint that network link is
* metered, and sensitive to heavy data transfers.
*/
public boolean hasMeteredHint() {
if (vendorInfo != null) {
return vendorInfo.contains("ANDROID_METERED");
} else {
return false;
}
}
So it would seem that, indeed, the AP may notify its WiFi clients that the underlying internet connection is metered by using this flag.
EDIT #2 Relevant information, from http://www.lorier.net/docs/android-metered
When an android phone is using another android phone's hotspot, it
knows it's on a "metered connection" and therefore disables the
expensive sync options ( eg: photo sync). How does it know this? The
android hotspot sends DHCP Option 43 (Vendor specific options) with
the value ANDROID_METERED. The client, if it sees ANDROID_METERED
anywhere in the option 43 values, turns on the "expensive data
connection" option.
Looks like this flag was added to "play nice" with a hotspot offered by another Android device.
EDIT #3 The commit that introduced this feature:
Connect metered DHCP hint for Wi-Fi networks.
When DHCP lease includes vendor info indicating that remote Wi-Fi
network is metered, advise NetworkPolicy. Users can still manually
change the metered flag in Settings.
You can access this setting by going:
Settings -> Data Usage -> (Overflow Menu) -> Mobile Hotspots
I'm working on a MDM solution for iPhone and Android.
The iPhone part is done and is working great:)
On the android part there are a couple of things left.
I have never used an Android phone before, so its kinda new for me.
First of is how to add an email account (exchange, gmail and IMAP).
And if I understand it correct there are a couple of different native mail apps that are bundle with different versions of android and phone models.
I've tried to add an exchange account with
AccountManager am = AccountManager.get(context);
am.addAccount("my_exchange_mail#company.com", "com.htc.android.mail.eas", null, null, null, null, null);
But it does not show up in Settings -> Accounts & Sync.
Does anyone have a clue on how to do this?
Second thing is how to add APN settings to the phone.
What I understand is that google removed that ability in Ice cream sandwich, if that's correct then we don't want to add it to our MDM solution.
Third thing is how to force a user to add a PIN code (or password or the thing where you swipe of the 9 dots)
For now I set a a minimum length of the password and a password quality (to something)
mDPM.setPasswordMinimumLength(mAdminName, 4);
mDPM.setPasswordQuality(mAdminName, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mDPM.setPasswordExpirationTimeout(mAdminName, 1);
}
Then I show the set new password intent.
Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
This makes the set new password intent show and the user can select between PIN, password and the swipe-thingy. The option "No password" is disabled. But the user can use the back button on the phone to skip setting a new password.
Are there any way to really force the user to set a PIN?
Fourth thing is about auto joining a newly added WiFi.
I can add a WiFi with the following code. But is there any way to make the phone automatically connect to the WiFi when it is in range?
public boolean addWifi(String SSID, String encryptionType, String password, boolean hiddenNetowrk, boolean autoJoin) {
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + SSID + "\"";
if (encryption.trim().equals("WEP")) {
config.wepKeys[0] = "\"" + password + "\"";
config.wepTxKeyIndex = 0;
} else if (encryption.trim().equals("WPA")) {
config.preSharedKey = "\"" + password + "\"";
} else {
return false;
}
config.hiddenSSID = hiddenNetwork;
int id = wifi.addNetwork(config);
wifi.enableNetwork(id, false);
return true;
}
Well, that was a long question:) Hoping for some answer on some of the four problems:)
This is killing me and any help would be greatly appreciated.
I want to connect to an open network using wifi manager. The problem I am having is that the code claims connection to any network - even non-existing ones. Below is the entire code that gets executed and gets called with the SSID of a network. It does not matter what string you pass to it as the SSID of a network, even if no such network exists in any shape or form, the enableNetwork claims returns true, which I believe means it connected to the network.
What I need to do is to make sure I have a connection. So if I pass a network SSID that does not exist (for example, it is out of range) the API should return a failure when attempting to connect.
Any ideas/hints/suggestions would be greatly appreciated.
public boolean conto (String network){
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
List<WifiConfiguration> configs = null;
int inetId = -1;
// make sure there are no funny stuff in the config
configs = wifi.getConfiguredNetworks();
for (WifiConfiguration config : configs) {
wifi.removeNetwork(config.networkId);
Log.d("********", "Removed Network: SSID=[" + config.SSID + "] and ID=[" + config.networkId + "]");
}
// Now add the network
wifiConfiguration.SSID = "\"" + network + "\"";
wifiConfiguration.hiddenSSID = false;
//wifiConfiguration.priority = 1;
//wifiConfiguration.networkId = 999;
inetId = wifi.addNetwork(wifiConfiguration);
if(inetId < 0) {
Log.d("********", "Could Not Add Network......... [" + wifiConfiguration.SSID + "]");
}
else {
Log.d("********", "Added Network......... [" + wifiConfiguration.SSID + "]");
// Lets be paranoid and double check the config file
Log.d("********", " +++++++++++++++++++++++++ This is what I have in Config File");
configs = wifi.getConfiguredNetworks();
for (WifiConfiguration config : configs) {
Log.d("********", "In the Config file after add, SSID=[" + config.SSID + "], ID=[" + config.networkId + "]");
}
// Now Enable the network
boolean successConnected = wifi.enableNetwork(inetId, true);
//boolean successAssociated = wifi.reassociate(); This did not change the results
if(successConnected) {
Log.d("********", "Connected to......... [" + inetId + "]");
}
else {
Log.d("********", "Could Not Connect to......... [" + inetId + "]");
}
}
return false;
}
I think the problem is that your code is based on the assumption that connecting to a WiFi network is a synchronous process, which it is not. The method enableNetwork() does not block while the connection occurs and then return the resulting success or failure of the connection, it returns immediately and the result is simply whether the request properly reached the WiFi service and the supplicant.
If you want visibility into what is going on with the connection status of the device, you need to monitor the WifiManager. SUPPLICANT_STATE_CHANGED_ACTION and WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION broadcast Intent actions with a BroadcastReceiver. Once you initiate the connection process, these callbacks will tell you how things progress. For example, if you pass in a network that doesn't exist, the connection status should almost immediately go straight to DISCONNECTED. While a valid network will go through the process of associating, authenticating, and connecting. All these steps are enumerated through these broadcasts.