I have a function similar to this:
private bool IsConnected()
{
if (DeviceInfo.DeviceType == DeviceType.Unknown)
return false;
var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
return true;
return false;
}
My teammates have reported zero issues with this function, and are using a variety of devices. My personal device is a Google Pixel 3, using Google Fi and Google VPN. When I cut it into airplane mode, I see Connectivity.NetworkAccess is set to NetworkAccess.None. However, when I leave airplane mode off and turn both Mobile Data and Wifi off explicitly, I see Connectivity.NetworkAccess is set to NetworkAccess.Internet.
Related to this, the Connectivity.ConnectionProfiles reports a single profile: ConnectionProfile.Unknown.
Is this expected behavior? Should I check a combination of Connectivity.ConnectionProfiles as well as Connectivity.NetworkAccess in attempting to determine if the device actually is connected to a network?
If you can't access the internet and Connectivity.NetworkAccess is NetworkAccess.Internet then it is not expected behavior.
You can submit the issue on their github: https://github.com/xamarin/Essentials/issues
Related
I have an Android VPN application. When I fire the intent to start the VPN (via VPNService.prepare), it fails immediately if there's an always-on VPN already configured on the device. That seems reasonable, but I'd like to be able to easily detect that case, so I can show a helpful message to the user.
By 'always on' I mean the specific VPN always-on Android VPN flag: https://developer.android.com/guide/topics/connectivity/vpn#always-on
I can't seem to find a way to access that info, even though it is used internally in Android (e.g. here but that getAlwaysOnVpnPackage doesn't seem to be available publicly AFAICT).
The best option I've seen is Check if a VPN connection is active in Android?, which will tell you if any VPN connection is currently active, but that's not enough, because:
I don't want to know about temporary VPN connections: I'm only interested if it's an always-on VPN connection.
Sometimes 'always-on' connections aren't actually always on. If you have a disconnected connection and set it as 'always-on', it's configured as such, and blocks all other VPN installs, but there's no network connection created (Android shows a persistent warning instead, which takes you to the other app to activate the connection). Because there's no connection, the above technique doesn't work. I still need to detect this case, since it still blocks my VPN setup.
Is there any way to check whether the device currently has a VPN configured as 'always-on'?
You can use this method
private fun isVpnAlwaysOn(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
val alwaysOn = Settings.Secure.getString(contentResolver, "always_on_vpn_app")
return !alwaysOn.isNullOrEmpty()
} else false
}
'alwaysOn' contains the package name of the app for which always-on is configured.
In the end, it seems this isn't possible on a normal device any way that I can find. I think is possible if you're a device admin, but that requires managed enterprise devices etc.
For now, I've handled this by watching for near-instant (less than 200ms) VPN setup failures (between running startActivityForResult(vpnIntent) and receiving onActivityResult with RESULT_CANCELED) and then showing a helpful message in that case.
Full implementation is in https://github.com/httptoolkit/httptoolkit-android/commit/928fbf92a4f868042789471be0d42800a226194b in case you're trying to do the same.
I am analysing Android JellyBean 4.3 source code.I could find the varialbe p2p_supported in HAL layer for Wi-Fi Direct support. In the below code snippet from wifi_ath.c
int wifi_start_supplicant(int p2p_supported)
{
if (p2p_supported)
{
strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
strcpy(supplicant_prop_name, P2P_PROP_NAME); // for P2P support
.......................
}
else {
strcpy(supplicant_name, SUPPLICANT_NAME);
strcpy(supplicant_prop_name, SUPP_PROP_NAME); //for station support
}
The values of the macros are:
P2P_SUPPLICANT_NAME = p2p_supplicant ,P2P_PROP_NAME= init.svc.p2p_supplicant
SUPPLICANT_NAME=wpa_supplicant ,SUPP_PROP_NAME=init.svc.wpa_supplicant
Even while connecting in station mode the if part is getting executed and I could not make the WiFi up. Where in the code exactly p2p_supported variable is enabled and disabled so that both the P2P and Wi-Fi works smoothly?
From Jelly Bean(4.1) you only need to turn WiFi on to use WiFi Direct functionality, though using both together depends upon whether your chip supports it.(For that see this SO question)
I would like some clarifications on the behavior of WifiManager.getScanResults(), namely :
When wireless is enabled
Does android scan for access points on a fixed interval ? Can one query/change the interval ? Can one query the time of the last scan ? For a discussion see this answer
What happens when the wireless radio is turned off (sleeps) - while wifi is still enabled - will getScanResults() go on returning the last scan results ? How would one know if it's time for startScan()?
When wireless is disabled
getScanResults() would return the last scan results ? Or an empty List ? Or null (it does return null at times and this is not handled by 90% of the snippets posted in SO) ?
The answer to 1 would be true even after a reboot (the phone booting with wifi off) ?
The reason I ask is I need to get the list of the available access points periodically and I'd rather call getScanResults() at once, than WifiManager.startScan() and then getScanResults() if I really do not have to - as this involves acquiring wifi locks and the like and is rather subtle. I am not also sure how much do the API level and phone hardware come into play.
For a good discussion of difficulties see this answer
When wireless is disabled
getScanResults() will return null...
...even after a reboot (that's to be expected - this would be disputed if it did not return null in the first place)
When wireless is enabled
2.Surprisingly enough getScanResults() will return null after some time (on a Nexus One, Android 2.3.7, Cyanogen mod - but I suspect this is not really relevant). So yes, apparently one has to initiate a scan irrespective of the wireless status
I guess this is true also if the state is WIFI_STATE_DISABLING
I am still interested in the answer in the case wireless is enabled - in particular question 2, if the device is asleep. Google groups won't let me post (hint)
public List getScanResults ()
Added in API LEVEL 1
Return the results of the latest access point scan.
Returns
the list of access points found in the most recent scan. An app must hold ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission in order to get valid results.
I have an Android app I'd like to offer on the Amazon's AppStore. My app has some location-based features and camera features which I need to disable if the user's device is a Kindle. Is there a way to programmatically detect if a user's Device is a Kindle? I'm aware I can build different versions for Kindle and non-Kindle but I thought I'd first ask if there's a way to detect this in code.
To check if the device has a certain feature, you PackageManager.hasSystemFeature(String name) which should be sufficient in your case.
To check for location and camera you can use FEATURE_LOCATION and FEATURE_CAMERA as argument to hasSystemFeature
If you still need to know the hardware of your device, you can check
android.os.Build.MANUFACTURER
android.os.Build.BRAND
android.os.Build.BOARD
android.os.Build.DEVICE
If you want to detect Kindle, check for manufacturer (Amazon) using Build.MANUFACTURER and model using Build.MODEL. The value of model in case of Kindle will vary, it can be KFTT, KFOT, Kindle Fire, etc. See this for model nos.
You can use this method in identifying a Kindle Device(s)
public static boolean isKindle(){
final String AMAZON = "Amazon";
final String KINDLE_FIRE = "Kindle Fire";
return (Build.MANUFACTURER.equals(AMAZON) && Build.MODEL.equals(KINDLE_FIRE) ) || Build.MODEL.startsWith("KF");
}
I know that this post is old, but the approach to this is wrong. If your concern with Kindles is hardware related i.e. Kindles do not have a camera or camera support then you need to check for camera support not device type. What if other devices do not offer camera support? Instead of suggested answer, try this
public static boolean isCameraAvailable(Context context) {
PackageManager packageManager=context.getPackageManager();
if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
This is much better than detecting for if device is a kindle, otherwise do another build specific for kindle.
I have check for internet connectivity that goes like this:
public static boolean isInternetAvailable(Context ctx)
{
NetworkInfo info = ((ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
if (info == null || !info.isConnected()) return false;
if (info.isRoaming())
{
return Preferences.getIsRoamingAllowed(ctx);
}
return true;
}
It's been working good for all installations so far. Today user came in with a phone where everything worked (browser, email, etc) and it wasn't roaming. But my app due to this check was giving "No connection" error.
Phone is HTC Droid ERIS with 2.1
Anyone saw this issue? Any pointers why?
Ok I have written a test application that gets the activenetwork and all networks and lets me see what is happening, I am about to go out and test this since the anomalies I am seeing happen when switching from one network to the other (as in when you go out of wifi range and into cdma etc)
Couple of things that might help regardless first you can change info.isConnected to the following
if (info == null || !info.isConnectedOrConnecting()) return false;
This makes it a little more robust in that if you are in the middle of switch over you still let the user logon
Second thing is that you said that your app denied login if roaming because your apps allow roaming preference was set to false
return Preferences.getIsRoamingAllowed(ctx);
I think you need to follow a different pattern (just my opinion) first because If the user has disallowed roaming via their settings (phone not your app) and they are on a roaming network then the .getActiveNetwork() will return null, or not connected or not available (in which case the .getReason returns "noroaming")
Personally I would let the phone decide, but if you need to restrict it then he pattern I would follow would be
Set the default to true, but note that it's the first time your activity has started and the user has had no chance to set anything (since no pref's are set this should be easy enough to detect) Detect your network connection, if you have one then also note if they are roaming
Prompt them with an alert dialog which warns them they are currently roaming and Ask them if they want to login now or wait until later
OR
Normal Login if they are not roaming
But in either case offer them the ability to set the "roaming" option the first time instead of having them figure it out themselves.
That would address your catch 22 situation and save you some phone calls, anyway that's a design decision but I think it would work out better for you than your current pattern.
Also I think instead of just telling them there is no connection you might want to tell them why, return an enum instead of a boolean and then format dependent on that.
Finally I am going to test a bit more before my final answer because I am seeing some oddity's in the network state but want to confirm my findings before giving you the results, I need this as well so it was a good time for me to dig into this.