I've got a very simple app which lists the available WiFi access points (routers).
I have an AlertDialog set up whenever the app opens or resumes & WiFi isn't enabled. This takes a user to the WiFi settings where they turn on WiFi.
The user then hits the back button and returns to my app. My app then sees that WiFi is enabled and outputs a list.
The problem is, even though WiFi is enabled - the AP list isn't yet done (even though I'm checking if the scan has finished.
So, how can I pause my activity long enough so that I get a complete list?
WifiManager oWiFiManager = (WifiManager) getSystemService(WIFI_SERVICE);
// Only proceed if WiFi is Enabled
if (oWiFiManager.isWifiEnabled())
{
boolean bScanComplete = oWiFiManager.startScan();
if (bScanComplete)
{
/* Scan is complete. Safe to proceed.
* This is the problem area because for some reason there are no networks listed (but there are in reality).
*/
}
}
else
{
// Tell user WiFi is Disabled & take back to settings dialog
}
You should be able to use the ConnectivityManager to get the state of the Wifi adapter. From there you can check if it is connected or even available.
ConnectivityManager connManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (mWifi.isConnected()) {
// Do whatever
}
Dont forget to add android.permission.ACCESS_NETWORK_STATE to your AndroidManifest.xml for this to work
Related
i've making a file transfer app. i am using download manager in this. if backgroud data restriction is enabled, the transfers are being queued by the download manager.
i want to warn the user that file transfer doenst work if it is enabled.
is there a way to know if background data restriction is enabled programatically?
I want this to happen even in Android Marshmallow.
Thanks in advance.
The below code works for my phone of Android 10 .
#RequiresApi(api = Build.VERSION_CODES.N)
public boolean checkBackgroundDataRestricted() {
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
Log.i("test","getRestrictBackgroundStatus ="+connMgr.getRestrictBackgroundStatus());
switch (connMgr.getRestrictBackgroundStatus()) {
case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED:
// Background data usage and push notifications are blocked for this app
return true;
case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED:
case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED:
// Data Saver is disabled or the app is whitelisted
return false;
}
return false;
}
I am developing an Android Application and I need to make sure that the user is connected to the internet somehow. I can already check for WiFi, however, not everyone will be near a WiFi zone all the time, so I am thinking that Mobile Data is a valid alternative (of course assuming that the device is capable of having a SIM and all). So far, I can check if the user has enabled his or her mobile data as follows:
if(checkForMobileNetworkActive()){
//with mobile active
}
else{ // mobile not active
}
What I want to do is this: If the mobile network is NOT active, I will ask the user to turn it on. Very similar to what I have done in the past where I prompt the user to turn on their Bluetooth or the Location services. However, upon searching online, most answers pointed me to opening the WiFi settings via intent as such:
Intent i = new Intent(Settings.ACTION_WIFI_SETTINGS);
startActivity(i);
I have 2 issues with this solution:
This opens a new activity and not an alert dialog-style prompt to turn the WiFi on.
This turns on the WiFi and not the Mobile Data.
Has anyone tried to prompt the user to turn on their Mobile Data? As much as possible, I want it to look like the dialog box prompt and not an entire new activity (which is bad user experience in my opinion). I've looked on how to do it programmatically, however, what I stumbled upon no longer works for non-rooted device on Android Lollipop+ and I don't want to run the risk of the app no longer running when users upgrade the OS of their Android Devices.
Edit
I saw the link posted in the comment below, and I've tried this:
if(checkForMobileNetworkActive()){
}
else{
Intent i = new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS);
startActivity(i);
}
But it opens the Mobile Data/Data Roaming Settings as a new activity. While it works, it enables the user to check the checkbox for Mobile Data and pressing the back button goes back to my app, it is not a very smooth user experience.
First of all, you have to use this permission:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
After that, with this code, you can know whether it connected to internet by mobile data or not:
public static boolean isConnectedMobile(Context context){
NetworkInfo info = Connectivity.getNetworkInfo(context);
return (info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_MOBILE);
}
UPDATE 1:
If you want to enable/disable the mobile network in your app, you can use this solution:
private void enableMobileData(Context context, boolean enabled) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final Class conmanClass = Class.forName(cm.getClass().getName());
final Field connectivityManagerField = conmanClass.getDeclaredField("mService");
connectivityManagerField.setAccessible(true);
final Object connectivityManager = connectivityManagerField.get(cm);
final Class connectivityManagerClass = Class.forName(connectivityManager.getClass().getName());
final Method setMobileDataEnabledMethod = connectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
setMobileDataEnabledMethod.setAccessible(true);
setMobileDataEnabledMethod.invoke(connectivityManager, enabled);
}
And don't forget to use this permission:
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
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.
I am currently using a background IntentService in my Android App to connect to my server to fetch some data and update the App only if connection is available. If the device is connected to mobile network data or a authenticated wifi connection or open wifi connection it works perfectly.
The problem occurs when the device does not have access to Mobile Data Network and is connected to a Wifi source that requires authentication and the connection is not authenticated yet, the service force closes since it is unable to transfer any data through the unauthenticated connection.
My check to the entry point to connect to the server and do the background task is the check below.
ConnectivityManager conMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
if((conMgr.getActiveNetworkInfo() != null &&
conMgr.getActiveNetworkInfo().isAvailable() &&
conMgr.getActiveNetworkInfo().isConnected()) || WifiConnected() == true){
//do background processing
}
The WifiConnected() method looks like this below.
private boolean WifiConnected() {
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
SupplicantState supState;
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
supState = wifiInfo.getSupplicantState();
return (networkInfo != null && networkInfo.isConnected() && supState.toString().contentEquals("COMPLETED"));
}
So basically what I am checking before doing the background task is whether the device has active network connectivity and is connected or if the connection is wifi, if that connection is authentication complete so that data transfer is possible.
This doesn't seem to work and fails too making the service still force close.
What is the right way to do this check for network connectivity when wifi authentication is involved and then do the background processing?
Thanks.
A good example of this problem is when you are in any starbucks nationwide your android device will automatically connect to attwifi and the wifi status changes to connected because i check isConnected returns true but you will notice that the attwifi at starbucks will not let you transfer any data until you pseudo sign in by navigating to a browser page and accepting their terms of usage and agreement
Method conMgr.getActiveNetworkInfo() calls into ConnectivityService and the result of this call can be null. In the statement (conMgr.getActiveNetworkInfo() != null && conMgr.getActiveNetworkInfo().isAvailable() && conMgr.getActiveNetworkInfo().isConnected()) you call three times. I suspect there can be NPE here, as one of these calls can return null if network changes from 3g to WiFi at that time. What if you get NetworkInfo instance first, and them call isAvailable() and isConnected() on it (similar to how you did it in WifiConnected())?
You could move the connectivity check in your activity (or wherever else you have the context) and start the service from there.
Thus you won't have the force close constraint of the intentService and it should work fine.
Edit:
Ok got it! Here's what you can do to be sure that the user has access to Internet:
private boolean hasInternetAccess() {
boolean hasInternetAccess = false;
try {
//I set google but you can try anything "reliable"...
//isReachable(1) the timeout in seconds
hasInternetAccess = InetAddress.getByName("www.google.com").isReachable(1);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return hasInternetAccess;
}
So your check becomes:
If(WifiConnected() && hasInternetAccess()){
//Do background Work...
}
This is does some sort of ping to ensure the user has internet.
Don't forget that this method needs to be executed in a separate thread or it'll throw a NetworkOnMainthreadException. Here you're safe since you are in an IntentService that has its own thread. But I precise for the ones that might see this thread. By the way I suggest you to change the title of the this thread since the actual problem is not really related to the service but the access to internet.
Here's the reference: Test Internet Connection Android
I hope this helps.
or you can write a receiver for Connectivity change. It would be the best in your case.
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
I have am having some issues with getting consistent results when checking if the network is available or not.
I use this code snippet inside a class AppPreferences to check the availability of a network.
/**
* #return the networkAvailable
*/
public boolean isNetworkAvailable() {
connectionManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
networkAvailable = connectionManager.getActiveNetworkInfo() != null && connectionManager.getActiveNetworkInfo().isConnected();
return networkAvailable;
}
Before each run I set the context as below:
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
appPreferences.setContext(getBaseContext());
if (appPreferences.isNetworkAvailable()){
// perform task
}
}
},
0,
UPDATE_INTERVAL);
I do know it is not tied to the background thread as I have a onReceive call doing the same logic and still this check fails.
It seems to predominantly happen when it moves between a cellular data connection and to wifi, or vice versa. The Context in which it was started seems to stay even though I update it.
Does anyone have any idea what could be the issue here?
It seems as if the active network info will stay on the state of when the Context of the Service/Activity/Receiver is started. Hence if you start it on a network, and then later disconnect from that (i.e. moves from 3G to Wifi and disconnect the 3G connection) it will stay on the first active connection making the app believe the phone is offline even though it is not.
It seems to me that the best solution is to user getApplicationContext instead as that will not be tied to when you started the particular "task".
Update: Related is that if you run applications on Androids (in particular Nexus One) for a long period of time when connected to Wifi do check that you make sure you do not let the Wifi sleep when the screen sleeps. You will be able to set that at the Advanced option under Wireless Networks.