This question already has answers here:
Check INTENT internet connection
(13 answers)
Closed 3 months ago.
I am working on an Android app that will continuously remain connected to Internet. If Internet is dow, it should give an appropriate message to the User.
Is there any thing like Internet Listener? Or how to implement this event that whenever Internet connection is not available it should give alert.
The code from Chirag Raval above certainly works. The trouble is that the listener will get invoked even when the application is not running in foreground.
IMHO, the better approach is to register / unregister the receiver in the onResume() / onPause() methods of all your application activities. This code should do it:
private final NetworkStateReceiver stateReceiver = new NetworkStateReceiver();
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(stateReceiver, filter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(stateReceiver);
}
Obviously, remove the registration from AndroidManifest.xml file.
Using this solution, the receiver will be called also when switching between activities of your application (assuming you are closing them). In such a case, use a static flag (being shared between all your activities) like in the example below (called online):
public class NetworkStateReceiver extends BroadcastReceiver {
private static boolean online = true; // we expect the app being online when starting
public static final String TAG = NetworkStateReceiver.class.getSimpleName();
public void onReceive(Context context, Intent intent) {
Log.d(TAG,"Network connectivity change");
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = manager.getActiveNetworkInfo();
if (ni == null || ni.getState() != NetworkInfo.State.CONNECTED) {
Log.d(TAG,"There's no network connectivity");
if (online) // don't show the message if already offline
Toast.makeText(context, R.string.noInternet, Toast.LENGTH_SHORT).show();
online = false;
} else {
Log.d(TAG,"Network "+ni.getTypeName()+" connected");
if (!online) // don't show the message if already online
Toast.makeText(context, R.string.backOnline, Toast.LENGTH_SHORT).show();
online = true;
}
}
}
If starting your app when being offline, the Toast message will appear; otherwise it appears only when losing / re-establishing the connection .
Related
So I'm working for a company that requires a VPN in order to connect to the database server. I'm facing an issue with disconnecting programmatically from the VPN service (or disabling it) upon onPause / onStop.
In order to ensure the user is indeed connected to a VPN, I'm using a network listener and if the user is not connected, a dialog is being shown and navigates the user to the VPN Settings Configuration. Once the user connects and resumes the application, the listener recognizes the VPN IP and everything runs great.
My issue is that I want to disable the VPN connection once the user has stopped using the application. Therefore, I've been trying to search for a solution that disables the VPN connection without requesting the user to go to the VPN Settings again. Is there an option to toggle the VPN off programmatically without navigating to the VPN Settings page?
Network Service:
public class NetworkSchedulerService extends JobService implements
ConnectivityReceiver.ConnectivityReceiverListener {
private ConnectivityReceiver mConnectivityReceiver;
#Override
public void onCreate() {
super.onCreate();
mConnectivityReceiver = new ConnectivityReceiver(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
#Override
public boolean onStartJob(JobParameters params) {
registerReceiver(mConnectivityReceiver, new IntentFilter(Constants.CONNECTIVITY_ACTION));
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
unregisterReceiver(mConnectivityReceiver);
return true;
}
#Override
public void onNetworkConnectionChanged(boolean isConnected) {
String message = isConnected ? "מחובר לרשת" : "אין חיבור פעיל לרשת";
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
Listener:
private void scheduleJob() {
JobInfo myJob = new JobInfo.Builder(0, new ComponentName(this, NetworkSchedulerService.class))
.setRequiresCharging(true)
.setMinimumLatency(1000)
.setOverrideDeadline(2000)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.build();
JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(myJob);
}
#Override
protected void onStop() {
stopService(new Intent(this, NetworkSchedulerService.class));
super.onStop();
}
#Override
protected void onStart() {
super.onStart();
Intent startServiceIntent = new Intent(this, NetworkSchedulerService.class);
startService(startServiceIntent); // INTERNET LISTENER
}
Dialog:
public void dialogVPN() {
builder = new AlertDialog.Builder(LoadingSplash.this);
builder.setMessage("Please ensure VPN Connection");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent("android.net.vpn.SETTINGS");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intent, 10);
}
});
builder.show();
}
And the returnConnType:
public String returnConnType() {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(this.CONNECTIVITY_SERVICE);
String result = "None";
if (connectivityManager != null) {
Network network = connectivityManager.getActiveNetwork();
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
if (capabilities == null) {
result = "None";
}
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
result = "WIFI";
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
result = "MOBILE";
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
result = "VPN";
}
}
return result;
}
Any suggestions as to how to solve this? A proper solution or an alternative one would be appreciated.
I don't think you can disable the VPN settings from inside the app using an API provided by Android, as I do not know about any such APIs. However, as a workaround, you can consider doing the following.
While exiting the application (on a back button press), you can use the same listener to pop up another dialog saying the user to turn off the VPN. Hence, turning off the VPN will follow the same tasks that the user had to do while turning on the VPN.
When a user exits the application using a home button press, you might consider using a JobScheduler in your onDestroy function of the exiting activity, so that you can check if the VPN connection is alive in a background service when the application is not running and create a notification which will tell the user that, the VPN is alive. Then on clicking the notification, redirect the user to the VPN configuration settings and guide the user to turn it off.
Hope that helps!
So thanks to #Reaz I've managed to find the proper solution for now.
Tested on Oreo
In case someone else is intrested..
app
implementation 'android.arch.lifecycle:extensions:1.1.1'
AppLifecycleObserver
public class AppLifecycleObserver extends MultiDexApplication implements LifecycleObserver {
public static final String TAG = AppLifecycleObserver.class.getName();
Notifications notif = new Notifications();
Context mContext;
public AppLifecycleObserver(Context context) {
mContext = context;
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onEnterForeground() {
Log.v(TAG,"FOREGROUND");
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onEnterBackground() {
Log.v(TAG,"BACKGROUND");
notif.createVPNNotification(mContext,"VPN","Please make sure to turn VPN off");
}
}
on Any activity you wish to implement # onCreate:
AppLifecycleObserver appLifecycleObserver = new AppLifecycleObserver(this);
ProcessLifecycleOwner.get().getLifecycle().addObserver(appLifecycleObserver);
For the many threads, blogs, examples and tutorials on the topic of Broadcast Receivers and mobile data connectivity i have not seen this question asked or answered.
I believe, based on experimenting with one of my Apps, that the answer to this question is a distinct NO, that while WiFi is enabled, a Broadcast Receiver listening for Mobile Data CONNECTIVITY_CHANGE does not receive a broadcast notification when that event occurs. If i am wrong and have missed something please let me know.
My App is a home screen Widget with two classes, ActiveMobileData is the AppWidgetProvider and ConnectivityChangeReceiver is the BroadcastReceiver. The AppWidgetProvider class is my first App which i put together earlier this year mainly from code widely available in a book, on StackOverflow and on various blogs etc. There is no App just the home screen widget. It simply toggles a home screen icon between red and green to indicate the current mobile data state. It has worked perfectly for several months with about 100 users.
I decided to add the BroadcastReceiver to pick up clicks from Settings. This code is also straight forward - it determines the current state of mobile data, and uses a global boolean variable set by AppWidgetProvider to determine if the home screen icon is red or green. Then it simply ensures that the icon color matches the mobile data state.
It all works except when WiFi is enabled it does not get a notification. If there is a way around this limitation i would appreciate hearing about it.
Following is the code for the widget and then for the receiver. I left out some details to keep it somewhat brief. iconEnabled is the shared global boolean variable ...
public class ActiveMobileData extends AppWidgetProvider {
static boolean iconEnabled;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null)
super.onReceive(context, intent);
else {
context.startService(new Intent(context, ToggleService.class));
}
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[]appWidgetIds) {
context.startService(new Intent(context, ToggleService.class));
}
public static class ToggleService extends IntentService {
public ToggleService() {
super("ActiveMobileData$ToggleService");
}
#Override
protected void onHandleIntent(Intent intent) {
ComponentName cn = new ComponentName(this, ActiveMobileData.class);
AppWidgetManager mgr = AppWidgetManager.getInstance(this);
mgr.updateAppWidget(cn, buildUpdate(this));
}
private RemoteViews buildUpdate(Context context) {
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget);
if (!isMobileDataEnabled(getApplicationContext())) {
updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_g);
enableMobileData(getApplicationContext(), true);
iconEnabled = true;
} else {
updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_r);
enableMobileData(getApplicationContext(), false);
iconEnabled = false;
}
Intent i = new Intent(this, ActiveMobileData.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.mobileDataState, pi);
return updateViews;
}
public boolean isMobileDataEnabled(Context context) {
// ... the code here is the one that uses Java reflection
}
private void enableMobileData(Context context, boolean enabled) {
// ... the code here is the one that uses Java reflection
}
} // public static class ToggleService
} // public class ActiveMobileData
Following is the code for the BroadcastReceiver ...
public class ConnectivityChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive (Context context, Intent intent) {
handleIntent(context);
}
protected void handleIntent(Context context) {
ComponentName cn = new ComponentName(context, ActiveMobileData.class);
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
mgr.updateAppWidget(cn, buildUpdate(context));
}
private RemoteViews buildUpdate(Context context) {
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget);
if (!ActiveMobileData.iconEnabled && isMobileDataEnabled(context)) {
ActiveMobileData.iconEnabled = true;
updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_g);
Intent i = new Intent(context, ActiveMobileData.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.mobileDataState, pi);
} else
if (ActiveMobileData.iconEnabled && !isMobileDataEnabled(context)) {
ActiveMobileData.iconEnabled = false;
updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_r);
Intent i = new Intent(context, ActiveMobileData.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.mobileDataState, pi);
}
return updateViews;
}
private boolean isMobileDataEnabled(Context context) {
// ... Identical code to that in the AppWidgetProvider
}
} // class ConnectivityChangeReceiver
I don't know offhand, but I can point you to the 2 best places to look.
Best bet would be to look in detail into the JavaDoc for ConnectivityManager.html#CONNECTIVITY_ACTION and then the source code for the ConnectivityManager that is online on GrepCode
In particular comments within the source code often have very informative information that doesn't exist elsewhere.
Update:
After reading the javadoc for CONNECTIVITY_ACTION again, I believe that you are correct because it say A change in network connectivity has occurred. A default connection has either been established or lost. NOTE: Default Conn. NOT 'A Conn.' So it only gets launched when the 'default' changes. So if you lose 3g/4g/etc while on WIFI then I don't think this gets launched.
However there 'is' something you 'can' do... (but only when your widget is running) (I'm actually not 100% sure a 'widget' CAN do this... b/c I generally work with teaching services/AIDL/ContentProviders/etc (aka. 'backend' stuff within the platform) But you can put a 'refresh' button on your widget that can query to GET ALL NETWORKS and then parse through all that data and display which networks 'are' active, etc.
Also there is the option. You could make pending intents for your broadcast receiver(s) (I'd recommend just 1 BR and have different payloads so you can sort them for what is being notified) then register each of those pending intents as a call back with the ConnectivityManager to notify it whenever a 'network' that 'matches' the NetworkRequest exists. This will notify you at least when they 'come alive'...
(this next idea would likely require you to make a service with a separate thread to prevent ANR)
now when they 'die'... you 'could' setup a TCP connection and see when it dies... (not 'good' but might be only 'viable' option) (and if you are are 'generous' with trying to not wake up the phone, the battery impact could be minimal)
I need my application to give a notification whenever a specific WiFi goes offline.
I got it to give a notification every time the WiFi connection disconnects. But I need it to only give a notification when a specific WiFi network disconnects. Is my code suitable for this? I read something about class wifiinfo, is this the solution?
My question is, how do I alter the code to only give a notification when a specific WiFi goes offline? Any help in the right direction would be nice! Some examples would be even more awesome.
Thanks in advance!
(Eventually I need a button and when you press this the specific wifi your on atm will become that specific wifi when you disconnect from it you get a notification. If that makes sense.)
The code:
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.registerReceiver(this.mConnReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
setContentView(R.layout.activity_hoofdmenu);
}
private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if(!isNetworkConnectionAvailable(context)){
showNotification();
}
}
};
public static boolean isNetworkConnectionAvailable(Context context)
{
boolean isNetworkConnectionAvailable = false;
ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService("connectivity");
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
if(activeNetworkInfo != null)
{
isNetworkConnectionAvailable = activeNetworkInfo.getState() == NetworkInfo.State.CONNECTED;
}
return isNetworkConnectionAvailable;
}
To detect SSID changes, listen for WifiManager.NETWORK_STATE_CHANGED_ACTION, grab the SSID from the intent extra WifiManager.EXTRA_BSSID.
See: Execute code when wifi SSID changes
I would like to know how can I check when mobile data is connected using BroadcastReceiver.
Here's what I have so far:
private BroadcastReceiver MobileDataStateChangedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(TelephonyManager.EXTRA_STATE,
TelephonyManager.DATA_DISCONNECTED);
if (state == TelephonyManager.DATA_CONNECTED) {
mobileStatus.setText("Connected");
} else if (state == TelephonyManager.DATA_DISCONNECTED) {
mobileStatus.setText("Disconnected");
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.status_page);
mobileStatus = (TextView) this.findViewById(R.id.textView4);
registerReceiver(MobileDataStateChangedReceiver, new IntentFilter(
TelephonyManager.ACTION_PHONE_STATE_CHANGED));
}
What am I doing wrong in here?
I used the same concept on Wi-Fi checking and it worked great?
I am using the permissions of:
<uses-permission android:name="android.permission.INTERNET"/>
The TelephonyManager.ACTION_PHONE_STATE_CHANGED does not seem to work because as I could read in TelephonyManager class description it only fires with calls, but not with networks or mobile data.
Instead of this, I suggest you try setting a listener. It would be something like this:
1) Get the service with TelephonyManager tm = (TelephonyManager)Context.getSystemService(Context.TELEPHONY_SERVICE)
2) Set a listener with tm.listen(myCustomPhoneStateListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
3) Once you have the listener you will be able to send custom intents to your BroadcastReceiver, if you still want to do that.
I have an Activity which looks up data from the web in its onCreate method. The Activity is activated by the user hitting a notification. So it is a common problem that the user will quickly turn on their phone, unlock it, slide open notifications, tap the notification, and the Activity will activate before the phone is done connecting to internet.
I do have a friendly AlertDialog that pops up informing the user that the data couldn't be received and to try again when the network is connected; but is there a way for the Activity to actively tell the phone to connect and detect that a connection is being made and then wait for the connection to establish, and then load its data successfully?
Usually, you would do something like this:
#Override
public void onResume(){
super.onResume();
// first, check connectivity
if ( isOnline ){
// do things if it there's network connection
}else{
// as it seems there's no Internet connection
// ask the user to activate it
new AlertDialog.Builder(YourActivity.this)
.setTitle("Connection failed")
.setMessage("This application requires network access. Please, enable " +
"mobile network or Wi-Fi.")
.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// THIS IS WHAT YOU ARE DOING, Jul
YourActivity.this.startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
YourActivity.this.finish();
}
})
.show();
}
}
The idea is ask the user to go and configure a network connection. Then, if the user does want to configure it, you will call the Settings.ACTION_WIRELESS_SETTINGS intent.
Also, notice the isOnline variable, which is a boolean that tells whether there's a network connection or not. In order to set that variable you can use an external simple class like this:
public class CheckConnectivity {
public static boolean isOnline(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if( cm == null )
return false;
NetworkInfo info = cm.getActiveNetworkInfo();
if( info == null )
return false;
return info.isConnectedOrConnecting();
}
}
Also, you will have to add this permission to your AndroidManifest.xml file:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
From this last statement by Cristian
'return
info.isConnectedOrConnecting();' It seems you can do whatever you want to do with the activity based on the boolean value returned by the method.
Since what you after is a positive return value you can use it's variable to callback your activity's next action