Before Android 7 we could define a broadcast receiver as below to get the notified about the changes in the network including mobile data.
<receiver android:name=".reciever.DataStateChangedReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
But as of Android 7, OS does not execute this broadcast receiver anymore as it's deprecated. I'm looking for a similar solution to achieve the same thing on Android 7 (figure out when mobile data state changes). Also, I'm aware that I can do this with dynamically registring broadcast in my Activity but That's not going to work for me because my app may be closed.
I'm looking for a solution to wake up my app whenever connectivity changes.
Using a service:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(broadcastReceiver,intentFilter);
return START_STICKY;
}
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
ConnectivityManager connectivityManager = (ConnectivityManager)context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE){
notifyMobileNetworkChange(context);
}
else {
notifyWifiNetworkChange(context);
}
}
....
}
Wake up app:
private void notifyMobileNetworkChange(Context context) {
//Run anything you want here
Intent dialogIntent = new Intent(this, WiFiName.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(dialogIntent);
}
In Manifest:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
You can find the complete project here:
https://github.com/stupidly-logical/WiFiName
You can modify the same for Mobile Data
This question already has answers here:
How to check internet access on Android? InetAddress never times out
(64 answers)
Closed 5 years ago.
I'm using Firebase. Some features of my app can't using was offline (or maybe offline mode can make in future). So how I can detect of connection was lost, or wifi/otherNetwork is off while running activity. I following this doc but only use when start app... not working on running app. So you guys any solution for my problem ?
Use this method to check the internet connection in the app:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Intent networkStateIntent = new Intent(Constants.NETWORK_AVAILABLE_ACTION);
networkStateIntent.putExtra(Constants.IS_NETWORK_AVAILABLE, isConnectedToInternet(context));
LocalBroadcastManager.getInstance(context).sendBroadcast(networkStateIntent);
}
public boolean isConnectedToInternet(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
//should check null because in airplane mode it will be null
if (netInfo != null && netInfo.isConnected()) {
return true;
} else {
return false;
}
}
Register the reciever in the manifest file like this:
<receiver android:name=".utils.NetwrokConnection.NetworkChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
use this method in the activity where you want to check the connection:
public void networkConnection() {
IntentFilter intentFilter = new IntentFilter(Constants.NETWORK_AVAILABLE_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
boolean isNetworkAvailable = intent.getBooleanExtra(Constants.IS_NETWORK_AVAILABLE, false);
Dialogs.getInstance().showSnackbar(activity,(View) rootlayout, isNetworkAvailable);
}
}, intentFilter);
}
Also add the permission in the menifest file:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
This is manifest part
<receiver
android:name="my.com.app.ConnectivityModifiedReceiver"
android:label="NetworkConnection" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
This is java code
public class my.com.app.ConnectivityModifiedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.sendBroadcast(new Intent("ConnectivityModified"));
}
}
The ConnectivityModifiedReceiver will send intents according to network connectivity change.In my case VPN connection and disconnection.
I am getting intents in Lollipop But not in JellyBean.
Plz help
So far in my findings
In Lollipop
android.net.conn.CONNECTIVITY_CHANGE broadcast is fired Only when either VPN is connected or disconnected.
So you can use the following code snippet along with the logic you have for pre-lollipop devices.
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
String KeyNI="networkInfo";
android.net.NetworkInfo bundleNetworkInfo=(android.net.NetworkInfo)bundle.get(KeyNI);
if(!bundleNetworkInfo.getTypeName().toString().equalsIgnoreCase("VPN"))
{
context.sendBroadcast(new Intent("ConnectivityModified"));
}
}
Hope this helps.
You might give this a try on your onReceive if it helps:
#Override
public void onReceive(Context context, Intent intent) {
final ConnectivityManager connMgr = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = connMgr.getActiveNetworkInfo();
// should check null because in air plan mode it will be null
if (netInfo != null && netInfo.isConnected()) {
System.out.println("INTERNET IS AVAILABLE");
} else {
System.out.println("INTERNET UNAVAILABLE");
}
}
You can place your logic inside the if statement.
Why on receive called twice, when Network state changed.
Manifest:
<receiver android:name="tv.meterreading.network.NetworkChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" >
</action>
</intent-filter>
</receiver>
Receiving multiple broadcast is a device specific problem. Some phones just send one broadcast while other send 2 or 3. But there is a work around:
Assuming you get the disconnect message when the wifi is disconnected, I would guess the first one is the correct one and the other 2 are just echoes for some reason.
To know that the message has been called, you could have a static boolean that gets toggled between connect and disconnect and only call your sub-routines when you receive a connection and the boolean is true. Something like:
public class ConnectionChangeReceiver extends BroadcastReceiver {
private static boolean firstConnect = true;
#Override
public void onReceive(Context context, Intent intent) {
final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null) {
if(firstConnect) {
// do subroutines here
firstConnect = false;
}
}
else {
firstConnect= true;
}
}
}
Which listener does my class have to implement inorder to automatically check code if the wifi connects/disconnects?
I'm able to manually check for wifi connection/disconnection but each time I need to connect/disconnect WIFI from android settings and then run my program for the result.
My current code is as simple as:
WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
if (wifi.isWifiEnabled()==true)
{
tv.setText("You are connected");
}
else
{
tv.setText("You are NOT connected");
}
Actually you're checking for whether Wi-Fi is enabled, that doesn't necessarily mean that it's connected. It just means that Wi-Fi mode on the phone is enabled and able to connect to Wi-Fi networks.
This is how I'm listening for actual Wi-Fi connections in my Broadcast Receiver:
public class WifiReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = conMan.getActiveNetworkInfo();
if (netInfo != null && netInfo.getType() == ConnectivityManager.TYPE_WIFI)
Log.d("WifiReceiver", "Have Wifi Connection");
else
Log.d("WifiReceiver", "Don't have Wifi Connection");
}
};
In order to access the active network info you need to add the following uses-permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
And the following intent receiver (or you could add this programmatically...)
<!-- Receive Wi-Fi connection state changes -->
<receiver android:name=".WifiReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
EDIT: In Lollipop, Job Scheduling may help if you're looking to perform an action when the user connects to an unmetered network connection. Take a look: http://developer.android.com/about/versions/android-5.0.html#Power
EDIT 2: Another consideration is that my answer doesn't check that you have a connection to the internet. You could be connected to a Wi-Fi network which requires you to sign in. Here's a useful "IsOnline()" check: https://stackoverflow.com/a/27312494/1140744
Create your own class that extends BroadcastReceiver...
public class MyNetworkMonitor extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Process the Intent here
}
}
In AndroidManifest.xml
<receiver
android:name=".MyNetworkMonitor" >
<intent-filter>
<action android:name="android.net.wifi.STATE_CHANGE" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
See WIFI_STATE_CHANGED_ACTION and CONNECTIVITY_ACTION for an explanation of using the Intent.
Check out these two pages of javadoc:
ConnectivityManager
WiFiManager
Notice that each one defines broadcast actions. If you need to learn more about registering broadcast receivers, check this out:
Programmatically register a broadcast receiver
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (wifi.isWifiEnabled()) {
tv.setText("You are connected");
} else {
tv.setText("You are NOT connected");
}
}
};
And in your manifest you could do something like this (if you would prefer to NOT register the receiver in code):
<application android:icon="#drawable/icon" android:label="#string/app_name">
<receiver android:name=".WiFiReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.net.ConnectivityManager.CONNECTIVITY_ACTION" />
</intent-filter>
</receiver>
</application>
EDIT:
I should add that it would be better to register this broadcast receiver in your code rather than in the manifest if you only need to receive the broadcast while the app is running. By specifying it in the manifest your process will be notified of a connection change even when it was not previously running.
Apps targeting Android 7.0 (API level 24) and higher do not receive this broadcast if they declare the broadcast receiver in their manifest. Apps will still receive broadcasts if they register their android.content.BroadcastReceiver} with android.content.Context#registerReceiver Context.registerReceiver() and that context is still valid.
I agree with #tanner-perrien's answer, and for 2020, Kotlin represent:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
registerReceiver(wifiBroadcastReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
}
private val wifiBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
Log.d("TUT", "Wifi is ${wifiManager.isWifiEnabled}")
}
}
override fun onDestroy() {
unregisterReceiver(wifiBroadcastReceiver)
super.onDestroy()
}
}
But might want to move with the times: https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Activity:
lateinit var connec: ConnectivityManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
connec = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkRequestWiFi = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build()
connec.registerNetworkCallback(networkRequestWiFi, networkCallbackWiFi)
}
private var networkCallbackWiFi = object : ConnectivityManager.NetworkCallback() {
override fun onLost(network: Network?) {
Log.d("TUT", "WiFi disconnected")
}
override fun onAvailable(network: Network?) {
Log.d("TUT", "WiFi connected")
}
}
override fun onDestroy() {
connec.unregisterNetworkCallback(networkCallbackWiFi)
super.onDestroy()
}
In AndroidManifest.xml add following permission.
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Create new Receiver class.
public class ConnectionChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null
&& activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
Toast.makeText(context, "Wifi Connected!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Wifi Not Connected!", Toast.LENGTH_SHORT).show();
}
}
And add that receiver class to AndroidManifest.xml file.
<receiver android:name="ConnectionChangeReceiver"
android:label="NetworkConnection">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
In response to sabsab. To hook into the Connectivity Change broadcast receiver I utilized warbi's answer and added a class with static methods.
public class WifiHelper
{
private static boolean isConnectedToWifi;
private static WifiConnectionChange sListener;
public interface WifiConnectionChange {
void wifiConnected(boolean connected);
}
/**
* Only used by Connectivity_Change broadcast receiver
* #param connected
*/
public static void setWifiConnected(boolean connected) {
isConnectedToWifi = connected;
if (sListener!=null)
{
sListener.wifiConnected(connected);
sListener = null;
}
}
public static void setWifiListener(WifiConnectionChange listener) {
sListener = listener;
}
}
Then I made changes to the receiver class on the first answer shown above.
public class ConnectivityReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = conMan.getActiveNetworkInfo();
if (netInfo != null && netInfo.getType() == ConnectivityManager.TYPE_WIFI)
{
Log.d("WifiReceiver", "Have Wifi Connection");
WifiHelper.setWifiConnected(true);
} else
{
Log.d("WifiReceiver", "Don't have Wifi Connection");
WifiHelper.setWifiConnected(false);
}
}
}
Finally, in your activity you can add a listener to utilize this callback.
wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
wasWifiEnabled = (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED || wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING);
WifiHelper.setWifiListener(new WifiHelper.WifiConnectionChange()
{
#Override
public void wifiConnected(boolean connected)
{
//Do logic here
}
});
Notice the listener is removed after the callback fires, this is because it's a static listener. Anyhow this implementation works for me and is one way to hook into your activity, or anywhere gives it's static.
There's also WifiManager.NETWORK_STATE_CHANGED_ACTION:
Broadcast intent action indicating that the state of Wi-Fi connectivity
has changed. An extra provides the new state in the form of a
NetworkInfo object. No network-related permissions are required to subscribe to this broadcast.
Then there is getState(), which has states like CONNECTING/DISCONNECTING, for example, which CONNECTIVITY_ACTION doesn't. Also, CONNECTING means there's no Internet. CONNECTED means there is Internet: https://android.googlesource.com/platform/frameworks/base/+/android10-release/core/java/android/net/NetworkInfo.java#122. Or there's getDetailedState(), which includes "infinity".
Though, NetworkInfo has been deprecated since API 29, so there's that too. But for me seems better than to use CONNECTIVITY_ACTION on supported devices, because of many and accurate states.