I am developing an SMS app and want to check for network (cellular) connection. With API level 29, checking for connection requires use of ConnectivityManager.NetworkCallback. What I have managed is to get 'onAvailable()` to inform me when a network becomes available. However, that will also inform me if it connects to WiFi (so I could have no service to send an SMS but if WiFI connects then onAvailable() will fire).
I tried onCapabilitiesChanged() and .hasTransport(TRANSPORT_CELLULAR) but that reports false if I am connected to WiFi.
I also thought to try hasCapability(NET_CAPABILITY_MMS) but that informs if MMS is possible. It's not clear to me if there is a scenario/network where SMS is possible but MMS is not? So could I get this reporting false because network does not support MMS but can still send SMS?
What is the correct method for checking if cellular network is available?
Maybe you can try the following
Network activeNetwork = connectivityManager.getActiveNetwork();
NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(activeNetwork);
boolean cellular = caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
if(cellular){
// do your stuff
}
Late to the pary, and I'm not sure about 29... and I guess it is quite lame... but this is how I did it:
public boolean isCellularAvailable()
{
TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
String opetarorName = telephonyManager.getNetworkOperatorName();
Log.i(LOG_TAG, "#### isCellularAvailable(): NetworkOperatorName is: " + opetarorName );
if (opetarorName .compareTo("") == 0)
{
Log.i(LOG_TAG, "#### isCellularAvailable(): NOPE");
Toast.makeText(context, "Turn off airplane mode and try again :)", Toast.LENGTH_LONG).show();
return false;
}
else
{
Log.i(LOG_TAG, "#### isCellularAvailable(): YES!");
return true;
}
}
The idea here is that if you are connected to a cellular network you should be able to get the name of your network provider.
If you get the name of one, then you are connected to that network, and should will be able to use it.
If you are in e.g. airplane mode, you will not be connected to a network, and will not get a name.
Noted that documentation says “Result may be unreliable on CDMA networks”… whatever that means.
But the “telephonyManager” offers a few similar functions, e.g. “getNetworkType()” might be another way to go if you know you´re favorable network types:
public boolean isCellularAvailable()
{
TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
int networkType = telephonyManager.getNetworkType();// .getNetworkOperatorName();
Log.i(LOG_TAG, "#### isCellularAvailable(): Network type is: " + networkType);
switch (networkType)
{
// Return true for networks that suits your purpose
case TelephonyManager.NETWORK_TYPE_1xRTT: return true;
case TelephonyManager.NETWORK_TYPE_CDMA: return true;
case TelephonyManager.NETWORK_TYPE_EDGE: return true;
case TelephonyManager.NETWORK_TYPE_EHRPD: return true;
case TelephonyManager.NETWORK_TYPE_EVDO_0: return true;
case TelephonyManager.NETWORK_TYPE_EVDO_A: return true;
case TelephonyManager.NETWORK_TYPE_EVDO_B: return true;
case TelephonyManager.NETWORK_TYPE_GPRS: return true;
case TelephonyManager.NETWORK_TYPE_GSM: return true;
case TelephonyManager.NETWORK_TYPE_HSDPA: return true;
case TelephonyManager.NETWORK_TYPE_HSPA: return true;
case TelephonyManager.NETWORK_TYPE_HSPAP: return true;
case TelephonyManager.NETWORK_TYPE_HSUPA: return true;
case TelephonyManager.NETWORK_TYPE_IDEN: return true;
case TelephonyManager.NETWORK_TYPE_IWLAN: return true;
case TelephonyManager.NETWORK_TYPE_LTE: return true;
//case TelephonyManager.NETWORK_TYPE_NR: return true; // Not supported by my API
case TelephonyManager.NETWORK_TYPE_TD_SCDMA: return true;
case TelephonyManager.NETWORK_TYPE_UMTS: return true;
// Return false for unacceptable networks, UNKNOWN id no network e.g. airplane mode.
case TelephonyManager.NETWORK_TYPE_UNKNOWN: return false;
// Future unknown network types, handle as you please.
default: return false;
}
Try using following code to check if device is connected to internet or not.
ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = conMgr.getActiveNetworkInfo();
if (netInfo == null) {
Toast.makeText(this, "Please turn on Internet ", Toast.LENGTH_SHORT).show();
} else {
//do what you want
}
You need to use Network Callback.
try {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
connectivityManager.registerNetworkCallback(builder.build(),new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
Variables.isNetworkConnected = true; // Global Static Variable
}
#Override
public void onLost(Network network) {
Variables.isNetworkConnected = false; // Global Static Variable
}
}
);
Variables.isNetworkConnected = false;
}catch (Exception e){
Variables.isNetworkConnected = false;
}
Variables.isNetworkConnected - Here I used a Global Static Variable, So I can use it to access the network state in anyware of the application.
Please refer this gist for full code implementation.
Related
My application completely depends on the network so I have to check whether the data communication is there between the application and my server and make a popup on communication lost and if not connected to Wifi or Mobile Data and if the connected service is having slow connection.
I am using the following code where I can get whether the device is connected to the Wifi or mobile data and get the type of connection and also got the code to get the type of mobile network connected which is not working at all.
please refer the following code...
public void CheckInternet()
{
Plugin.Connectivity.CrossConnectivity.Current.ConnectivityChanged += delegate
{
if (!(Plugin.Connectivity.CrossConnectivity.Current.IsConnected))
{
StartActivity(typeof(InternetCheckingView));
}
if (Plugin.Connectivity.CrossConnectivity.Current.IsConnected)
{
ConnectivityManager connectivityManager = (ConnectivityManager)GetSystemService(ConnectivityService);
NetworkInfo networkInf = connectivityManager.ActiveNetworkInfo;
bool isOnline = networkInf.IsConnected;
NetworkInfo networkInfo = connectivityManager.ActiveNetworkInfo;
bool isWifi = networkInfo.Type == ConnectivityType.Wifi;
bool isdata = networkInfo.Type == ConnectivityType.Mobile;
if (!isOnline)
{ StartActivity(typeof(InternetCheckingView)); }
else if(isWifi)
{
Toast.MakeText(_context, "Wifi Connected", ToastLength.Short).Show();
}
else if (isdata)
{
Toast.MakeText(_context, "Mobile Data Connected", ToastLength.Short).Show();
bool datatype = IsConnectionFast(subType);
if(!(datatype))
{StartActivity(typeof(InternetCheckingView));}
}
}
};
}
public bool IsConnectionFast(object networkType)
{
switch (subType)
{
//case TelephonyManager.NETWORK_TYPE_1xRTT:
case NetworkType.OneXrtt:
return false; // ~ 50-100 kbps//case TelephonyManager.NETWORK_TYPE_CDMA:
case NetworkType.Cdma:
return false; // ~ 14-64 kbps//case TelephonyManager.NETWORK_TYPE_EDGE:
case NetworkType.Edge:
return false; // ~ 50-100 kbps//case TelephonyManager.NETWORK_TYPE_EVDO_0:
case NetworkType.Evdo0:
return true; // ~ 400-1000 kbps //case TelephonyManager.NETWORK_TYPE_EVDO_A:
case NetworkType.EvdoA:
return true; // ~ 600-1400 kbps//case TelephonyManager.NETWORK_TYPE_GPRS:
case NetworkType.Gprs:
return false; // ~ 100 kbps//case TelephonyManager.NETWORK_TYPE_HSDPA:
case NetworkType.Hsdpa:
return true; // ~ 2-14 Mbps//case TelephonyManager.NETWORK_TYPE_HSPA:
case NetworkType.Hspa:
return true; // ~ 700-1700 kbps//case TelephonyManager.NETWORK_TYPE_HSUPA:
case NetworkType.Hsupa:
return true; // ~ 1-23 Mbps//case TelephonyManager.NETWORK_TYPE_UMTS:
case NetworkType.Umts:
return true; // ~ 400-7000 kbps
/*
* Above API level 7, make sure to set android:targetSdkVersion
* to appropriate level to use these
*/
//case TelephonyManager.NETWORK_TYPE_EHRPD: // API level 11
case NetworkType.Ehrpd:
return true; // ~ 1-2 Mbps//case TelephonyManager.NETWORK_TYPE_EVDO_B: // API level 9
case NetworkType.EvdoB:
return true; // ~ 5 Mbps//case TelephonyManager.NETWORK_TYPE_HSPAP: // API level 13
case NetworkType.Hspap:
return true; // ~ 10-20 Mbps//case TelephonyManager.NETWORK_TYPE_IDEN: // API level 8
case NetworkType.Iden:
return false; // ~25 kbps//case TelephonyManager.NETWORK_TYPE_LTE: // API level 11
case NetworkType.Lte:
return true; // ~ 10+ Mbps// Unknown//case TelephonyManager.NETWORK_TYPE_UNKNOWN:
case NetworkType.Unknown:
return false;
default:
return false;
}
}
Here I would like to detect the slow network or not and if that is a slow network I have to call StartActivity(typeof(InternetCheckingView))
Can any one please help me to do that in I would like to open a popup whenever there is no data communication available like a onclicklisner in so that the even filers when ever there is a data loss even when the network is connected
(Added--)
I am checking for the data communication by pinging a url when the network connected change like disconnected or changes between wifi and mobile data but i would like to know the solution to get a popup to connect network whenever the data communication is lost even if it is connected to the network only when the app is opened.
I need to stop the Android app from syncing data to the server when it is using 2G network connection and allow it when it is using 3G/4G or WiFi connection, the data/WiFi identification is easy but how can I know if the phone is currently using 2G mode or 3G/4G mode?
Using TelephonyManager can identify the SIM mode but not the actual data carrier being used in real-time, since Android assigns E icon for 2G and H,H+for 3G then there must be a way to identify this. Any ideas?
Yes, there is.
On TelephonyManager you have some constants like TelephonyManager.NETWORK_TYPE_EDGE to check that. Use those constants along with the methods getType() and getSubtype() from NetworkInfo.
EDIT: I was being stupid. You can simply call NetworkInfo.getSubtypeName and you're good to go.
NetworkInfo info = Connectivity.getNetworkInfo(context);
Log.d("tag","Network type: " + info.getSubtypeName());
Or you could also try the other solution.
OLD SOLUTION
Try something like:
NetworkInfo info = Connectivity.getNetworkInfo(context);
getConnectionType(info.getType(),info.getSubtype());
And call this function:
private String getConnectionType(int type, int subType) {
if(type==ConnectivityManager.TYPE_WIFI){
return "WiFi";
}
else if(type==ConnectivityManager.TYPE_MOBILE){
switch(subType){
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_CDMA:
return "1G"; // ~ 50-100 kbps
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_GPRS:
return "2G"; // ~ 50-100 kbps
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_UMTS:
return "3G"; // ~ 2-14 Mbps
case TelephonyManager.NETWORK_TYPE_LTE: // API level 11
return "4G"; // ~ 10+ Mbps
// Unknown
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
default:
return "Not defined";
}
}
else{
return "Not defined";
}
}
Of course, the method above is just a suggestion to show how it works, you can change it for your own purposes, and make it more complete, change the return type, etc.
How to determine if a android device supports 4G/LTE networks?
Checking the current network type is not an option, because I have to check it even if the current network type is 3G.
UPDATE:
OK, I have managed to detect the prefered_network_mode by:
Settings.Secure.getInt(context.getContentResolver(), "preferred_network_mode", -1);
It work's fine on HTC One but on Samsung devices it always returns a 0 value when it should return more then a 0 value and that is the main problem now ;/
Does Samsung phones store the preferred network mode somewhere else ?
/**
* 获取当前网络类型
*
* #param context
* #return 2G/3G/4G/WIFI/no/unknown
*/
public static String getNetType(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo info = cm.getActiveNetworkInfo();
if (info == null || !info.isAvailable()) {
return "no";
}
if (info.getType() == ConnectivityManager.TYPE_WIFI) {
return "WIFI";
}
if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
int sub = info.getSubtype();
switch (sub) {
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_CDMA://电信的2G
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
//以上的都是2G网络
return "2G";
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
case TelephonyManager.NETWORK_TYPE_HSPAP:
//以上的都是3G网络
return "3G";
case TelephonyManager.NETWORK_TYPE_LTE:
return "4G";
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
return "unknown";
default:
return "unknown";
}
}
return "unknown";
}
I know how to Get Network type. But I need to identify the related standard to each release, grouping by GSM, WCDMA and LTE (others standards will not be used). I could filter it like this:
switch (networkType) {
case TelephonyManager.NETWORK_TYPE_GPRS:
tech = "GPRS";
standard = "GSM";
break;
case TelephonyManager.NETWORK_TYPE_HSDPA:
tech = "HSDPA";
standard = "WCDMA";
break;
}
Is there some information from Android API that I can use to retrieve this information on a elegant way?
It will help me to work with some information about mobile netowrk that is handle in diffrent ways between WCDMA, LTE and GSM.
UPDATE:
It is not exactly what I am asking, but is very near.
How to determine if network type is 2G, 3G or 4G
Use NetworkInfo.
For instance, here you are a method which gives you if a device has or not network.
public Boolean hasDeviceConnectionToInternet(Context context) {
ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo i = conMgr.getActiveNetworkInfo();
if (i == null)
return false;
if (!i.isConnected())
return false;
if (!i.isAvailable())
return false;
return true;
}
For your case, you can ask i.getType() for getting the connection type, or i.getTypeName() for a human-readable description.
You can see API here: http://developer.android.com/reference/android/net/NetworkInfo.html
My Application send SMS only if Mobile Network is available.
Currently i have set ON WIFI as well MOBILE NETWORK is present.
The following code snippet when executed gives me:
public boolean isNetworkAvailable(Context context) {
final ConnectivityManager connMgr = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
// WIFI is ON and MOBILE Network is present.
final NetworkInfo mobileNetwork = connMgr
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
final State mobileState = mobileNetwork.getState();
if(mobileNetwork!=null)
{
// RETURNS FALSE
Log.d("Contacts","mobileNetwork.isConnected() "+mobileNetwork.isConnected());
// RETURNS FALSE
Log.d("Contacts","isConnectedOrConnecting() "+mobileNetwork.isConnectedOrConnecting());
// RETURNS TRUE
Log.d("Contacts","mobileNetwork.isAvailable()() "+mobileNetwork.isAvailable());
return mobileNetwork.isAvailable();
}
return false;
}
The question is how to detect now whether i can send SMS or not based on the value returned by the above three lines?
Since isAvailable() returns true and the other 2 lines returns false;
SOLUTION
i have came up with this code:
TelephonyManager telMgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
int simCardState = telMgr.getSimState();
int simNetworkType = telMgr.getNetworkType();
int simDataState = telMgr.getDataState();
if(simCardState == TelephonyManager.SIM_STATE_READY && simDataState == TelephonyManager.DATA_CONNECTED)
{
//NETWORK IS AVAILABLE FOR SENDING SMS
}
this code should help you to detect different states
TelephonyManager telMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
int simCardState = telMgr.getSimState();
switch (simCardState) {
case TelephonyManager.SIM_STATE_ABSENT:
// do something
break;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
// do something
break;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
// do something
break;
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
// do something
break;
case TelephonyManager.SIM_STATE_READY:
// here you may set a flag that the phone is ready to send SMS
break;
case TelephonyManager.SIM_STATE_UNKNOWN:
// do something
break;
}