I have asked the following quoted question but found that all working gone in vain as android is now not allowing to register the broadcast for network changes.
You can not do it in Manifest where as you can still get calls when you register it in your Activity and that context is still alive .
Now I have implemented in my activity and I am getting my broadcast receivers call and all is working as expected. But when I do start my activity , I received the call automatically. Can not I just skipp that thing on activity start ?
here is my old question that I have asked in this thread:
I have an application where I have implemented the BroadcastReceiver for the Network changes.
It alerts me when there is any change in the network connection, Like
the network gets disconnected, the network gets connected, the network
gets changed etc
But I have observe that it does not alert me when the Wifi is
connected but the Internet goes off from that network.
Is there something to check such case and can we make broadcast for it
??
I have searched alot but did not get any answer of this. I hope I made
myself quiet clear about my requirements.
Have you check the documentation here?
https://developer.android.com/training/monitoring-device-state/connectivity-monitoring?hl=es-419
It explains you how to use ConnectivityManager to check the changes on connectivity
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
You can even check the type:
boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;
Or even allow your app (via the Manifest) to consider the changes, by supporting this action:
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
Related
I am developing an app to be used on a specific tablet running Android 7.0. I'm using a Service to send periodic DatagramPackets. I can only use mobile networks. I check the connectivity status using ConnectivityManager, NetworkInfo and DetailedState. I get the network state with this code:
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
DetailedState networkState = activeNetwork.getDetailedState();
If the tablet is plugged in and the screen is on or off, I get CONNECTED state.
If the tabled is unplugged and the screen is on, I get CONNECTED state.
If the tabled is unplugged and the screen is off, I get BLOCKED state.
In my tablet the Data Saver is off. Just in case, I have run tests to verify there are no restrictions when the screen turns off, cm.getRestrictBackgroundStatus() always returns 1, which is RESTRICT_BACKGROUND_STATUS_DISABLED, even when the network is blocked.
So, why is the network blocked? Do my app need special permissions? Do my tablet need special configuration?
It's normal behaviour. When your screen is locked, it use doze mode. And Doze mode turn off internet communication and all background services. You need wakeup your device and after you can make all actions with internet. Documentations
In order to give a complete solution I will answer my question.
why is the network blocked?
As the documentation provided by Stanislav Kireev pointed, this BLOCKED network state happens because the device is in Doze. This device state does not allow internet access starting from Android 6.0 (API level 23).
But the documentation also says that "the system provides a configurable whitelist of apps that are partially exempt from Doze and App Standby optimizations". For more detailed explanation you can read Support for other use cases section. You can add your app to the whitelist from code or configuring the system.
Do my app need special permissions?
If you need to add your app to the whitelist from code, you need to add a permission in the manifest file:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
And add this code to your activity:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
}
}
I got this solution from this answer.
Do my tablet need special configuration?
If you want, you can add your app from Settings > Battery > 3 dots > Battery optimisation. Choose All apps in the pick list, select your app and choose Don’t optimise option.
I got this solution from this answer (it has more detailed explanation).
We have an app we are making that needs to switch to cellular for some requests even when WiFi is connected.
According to the ConnectionManager documentation these following methods are now deprecated, but is not so clear on what to use instead.
public void useMobileNetworkMode(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
cm.setNetworkPreference(ConnectivityManager.TYPE_MOBILE);
}
public void useDefaultNetworkMode(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
cm.setNetworkPreference(ConnectivityManager.DEFAULT_NETWORK_PREFERENCE);
}
Do these methods still work in android 5/6? and if anyone has info or something to replace these methods with I would be very grateful!
Ok little bit more on the problem :)
I have managed to investigate ConnectivityManager and can see the networks using :
Network networkToUse = null;
Network[] networks;
networks = cm.getAllNetworks();
for (Network network : networks) {
NetworkInfo ni = cm.getNetworkInfo(network);
Log.e("NETWORKINFO", ni.getType() + " " + ni.getExtraInfo());
if (ni.getType()== ConnectivityManager.TYPE_WIFI) {
Log.e("NETWORKINFO", "isWifi");
if (ni.isConnected()) {
Log.e("NETWORKINFO", "and is connected");
if (networkToUse == null) {
networkToUse = network;
}
}
}
if (ni.getType()== ConnectivityManager.TYPE_MOBILE) {
Log.e("NETWORKINFO", "HasMobile");
if (ni.isConnected()) {
Log.e("NETWORKINFO", "and is connected");
networkToUse = network;
}
}
}
It is here I kind of get stuck because I can't logically see a way of telling the app to use one of these networks when performing a HttpsURLConnection from URL.openLink();.
UPDATE:
I have just noticed that the mobile one disappears shortly after WiFi connects. There is a moment where I get both but not for long.
I have also tried this:
final ConnectivityManager connection_manager =
(ConnectivityManager)httpsClient.getCheckoutController().getCheckout().getCurrentActivity().getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder request = new NetworkRequest.Builder();
request.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
connection_manager.registerNetworkCallback(request.build(), new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
Log.e("NETWORKINFO", "FOUND A CELLULAR NETWORK " + connection_manager.getNetworkInfo(network));
}
});
request = new NetworkRequest.Builder();
request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
connection_manager.registerNetworkCallback(request.build(), new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
Log.e("NETWORKINFO", "FOUND A WIFI NETWORK "+connection_manager.getNetworkInfo(network));
}
});
but as with the "list" of networks" in previous try I only ever 1 callback, even if mobile data is on as well.
UPDATE;
Ok I seem to see mobile sometimes using above method. but it seems to create API level spaghetti hell. It sometimes also takes a very long time for the mobile callback to fire. I wonder if this is because it has to wake up the cellular modem and wait for it's handshake or something?
UPDATE;
I had another possible suggestion using Sockets (something I have little experience with..)
Does anyone know if it is possible to build a CELLULAR SSL connection socket to do https requests using HttpsURLConnection.getSocketFactory() and SSLSocket ?
Any info would be very welcome in this week long quest :D
UPDATE:
Found a good and categorical answer from someone at google:
How to stay connected through mobile network after WIFI is connected on Android?
However after implementation, i get a network callback for the mobile but when i open URL connection and perform a request it seems to get stuck for ages (about 4 minutes) before i get the response.
I have a Huawei 5.0.1 phone, which is the highest i have available. Obviously this is not good. However it is not tested on 5.1 galaxy S6 and works.. so could be the phone.
According to the Android documentation it is no longer working in Android version 5 and above.
This method was deprecated in API level 21.
Functionality has been removed as it no longer makes sense, with many more >than two networks - we'd need an array to express preference. Instead we >use dynamic network properties of the networks to describe their >precedence.
Found a good and categorical answer from someone at google: How to stay connected through mobile network after WIFI is connected on Android?
(Link is in edited info above)
However after implementation, i get a network callback for the mobile but when i open URL connection and perform a request it seems to get stuck for ages (about 4 minutes) before i get the response.
I have a Huawei 5.0.1 phone, which is the highest i have available. Obviously this is not good. However it is not tested on 5.1 galaxy S6 and works.. so could be the phone.
Is there a way to programatically identify the currently USB working mode?
I mean, some function that would return either if the device is at Host, Device or Accessory mode.
Not the best answer, but once you have a UsbManager you might be able to figure it out. Usually this UsbManager is created using a Context I believe, but it looks like you are switching modes so you hopefully can get a UsbManager instance, m in this case:
UsbManager m = createManagerSomehow
For accessory mode, this only has one callback. If this returns one then you know it is Accessory.
m.getAccessoryList()
So I'm thinking somehting like this might work:
if(m.getAccessoryList().size() > 0)
accessoryMode = true;
And for Host, if you have a UsbDevice device, or String deviceName you could use the same UsbManager m function to see if it contains that device.
if(m.getDeviceList().containsValue(device))
hostMode = true;
or
if(m.getDeviceList().containsKey(deviceName))
hostMode = true;
and I don't know about what Device is, but if none of the above are true then you know it is just a Device. You don't really need this boolean variable below, because you have the other two. It's just here to help with my explanation via state logic.
if(!hostMode && !accessoryMode)
deviceMode = true
Hope this helps. Check out UsbManager for more documentation and just search the page for Host and Accessory.
http://developer.android.com/reference/android/hardware/usb/UsbManager.html
NOTE: I am a little confused when you say you switch the modes in your comment. It conflicts with the Accessory call I make above and might not work, but what I would do then (if you don't need deviceMode) then just check if the usb device is a HOST mode and if not you know it is in application mode...
I would like to connect to WiFi network programmatically.
Here is my code:
wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
wifiManager.setWifiEnabled(true);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + ssid + "\"";
config.preSharedKey = "\""+ key +"\"";
int netId = wifiManager.addNetwork(config);
wifiManager.saveConfiguration();
wifiManager.disconnect();
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
When I have wifi enabled on my phone, it works as expected, but the problem is, when wifi is disabled. In this case the only result is enabling wifi adapter, but not connecting to the network. It seems like enabling takes to long so it won't get connected. Another strange thing to me is that wifiManager.getConfiguredNetworks() returns null. Do you know how to fix that?
Thank you
It seems like enabling takes to long so it won't get connected.
Yes. This is because enabling of the network is done async, it happens in parallel, and doesn't occur immediately. Here are two possible solutions to your problem:
1) This is the easiest solution, but not the best. Loop as described by another user checking for the scan results to come in. However, you should add a sleep of some sort between every cycle of the loop. I.E. you want to wait for 1ms, so as to not eat up all the CPU resources. I am not sure how to do this in Android off the top of my head. There is another problem with this method. If u are in the GUI thread, you will block all GUI events this way, as you wait for the connection to be established.
2) This is the proper solution. You can register for broadcast events after the network connection has been established. Then you will get an event when it finishes. From this event you can finish performing whatever operations are needed.
Sorry for the rushed answer. I am not an Android pro, so I can't explain the details as to how to do this off the top of my head, but I thought I would at least point you in the right direction.
Actually if you connect WiFi more than one time it will solve your issue.
One other thing I see if my WiFi is enabled and I connect to a specific WiFi network then it's working.
One other thing when I switch from mobile network to a specific WiFi network then it gives an unstable connection ..for this problem I connect WiFi through a specific WiFi network and then forget the network after a 3 second delay I again connect. Then it works properly.
I use this code for connecting to WiFi.
And for delay and for got WiFi network I use this code... .......
{
wifi(SSID,PASS);
final Handler handler = new Handler();
handler.postDelayed(
new Runnable()
{
Override public void run() { forgot(); }
}, 3000);
final Handler handler1 = new Handler();
handler1.postDelayed(
new Runnable()
{
Override public void run() {wifi(SSID,PASS); }
}, 3000);
}
I am using this code to check if a WiFi or mobile network is connected.
private boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected()) {
return true;
}
return false;
}
This works fine. But what if my user is on a prepaid plan but doesn't have any credit for data? This method will still return true if data is enabled but my app will crash when it tries to download data from a server. How can I check for something like this?
I guess there are also other things that can halt my app accessing a server even when a wifi/mobile network is available.
You shouldn't crash anyway. Your download code should use try-catch to handle such problems. Communication problems during download are possible as well.
As a mobile platform, internet access on Android is inherently unreliable. As you are starting to realise, you should be writing your app so it is tolerant of intermittent data access.
You are catching some exceptions, but not handling them - that means that your app will continue past the exception as though it didn't happen, and then crashes because your httpClient object is in an invalid state and is likely throwing new exceptions, which you are not catching.