I read all posts about getAllCellInfo() and have a similar situation like this.
The code posted below runs well on Android 6 (OnePlus One) but returns an empty list of Cellinfo on Google Nexus 5x Android 8.1 API 27.
I have set the Permission ACCESS CORSE LOCATION in the manifest and asking for permission when running the app first time.
Here is a code snippet:
try {
TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
String networkOperator = "";
if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
networkOperator = tm.getNetworkOperator();
}
if (!TextUtils.isEmpty(networkOperator)) { //is not empty with Nexus 5x
mcc = networkOperator.substring(0, 3);
mnc = networkOperator.substring(3);
} else {
mcc = "Unbekannt";
mnc = "Unbekannt";
}
List<CellInfo> cell = tm.getAllCellInfo();
System.out.println("List: "+cell);
if (cell != null) { //Always null with Nexus 5x
// TODO
} else {
cellID = "ERROR";
lac = "ERROR";
}
}
catch(Exception ex) {
mcc = "No Permission";
mnc = "No Permission";
cellID = "ERROR";
lac = "ERROR";
}
}
When trying other apps like "Network Cell Info lite" these apps get all the cellinformation :(
Any Help is very appreciated.
In Android 8.0 and above,to access getAllCellInfo() your app should be in the foreground.
If you want to access getAllCellInfo() you need to enable Location Service too.
I am building a network monitor app. Here I have successfully implemented all the things like track data usage from Wifi or mobile data, but I want to know which SIM is connected to internet and consuming mobile data.
Using below code I am able to know if my dual sim phone is connected to Wifi or mobile data.
public static String isInternetConnected (Context ctx) {
ConnectivityManager connectivityMgr = (ConnectivityManager) ctx
.getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo wifi = connectivityMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobile = connectivityMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
// Check if wifi or mobile network is available or not. If any of them is
// available or connected then it will return true, otherwise false;
if (wifi != null) {
if (wifi.isConnected()) {
return "wifi";
}
}
if (mobile != null) {
if (mobile.isConnected()) {
return "mobile";
}
}
return "none";
}
How can I get SIM Index or sim operator name that is consuming mobile data in dual sim android phone?
I had searched a lot and I saw many question posted in SO without answer like this.
I am able to get subId of both SIM in dual SIM phone but I am phasing problem to know which SIM is using internet.
Many other application are able to do this like Mubble.
Can any one provide me a solution for it?
After api level 22, you can use the hidden
system api android.telephony.SubscriptionManager#getDefaultDataSubId via reflection to get current active data sim subscription index.
After api level 24, there is a public system api android.telephony.SubscriptionManager#getDefaultDataSubscriptionId to get current active data sim subscription index.
Then, you can create a android.telephony.TelephonyManager or android.telephony.SubscriptionManager#getActiveSubscriptionInfo from subscription index to obtain sim operator information.
Here is a simple solution to get data sim operator for dual sim phone.
public static String getDataSimOperator(Context context) {
if (context == null) {
return null;
}
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (tm != null) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
TelephonyManager dataSimManager = tm.createForSubscriptionId(dataSubId);
return dataSimManager.getSimOperator();
} else {
String operator = getDataSimOperatorBeforeN(context);
if (operator != null) {
return operator;
} else {
return tm.getSimOperator();
}
}
} else {
return tm.getSimOperator();
}
}
return null;
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
private static String getDataSimOperatorBeforeN(Context context) {
if (context == null) {
return null;
}
int dataSubId = -1;
try {
Method getDefaultDataSubId = SubscriptionManager.class.getDeclaredMethod("getDefaultDataSubId");
if (getDefaultDataSubId != null) {
getDefaultDataSubId.setAccessible(true);
dataSubId = (int) getDefaultDataSubId.invoke(null);
}
} catch (Exception e) {
e.printStackTrace();
}
if (dataSubId != -1) {
SubscriptionManager sm = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
if (sm != null && ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED) {
SubscriptionInfo si = sm.getActiveSubscriptionInfo(dataSubId);
if (si != null) {
// format keep the same with android.telephony.TelephonyManager#getSimOperator
// MCC + MNC format
return String.valueOf(si.getMcc()) + si.getMnc();
}
}
}
return null;
}
i am trying to get a list of all available cells the device can find. But i am stuck, as my CellInfo is always null and i don't figure why. Can someone give me a hint? There is pretty few info on onCellInfoChanged() at google.
MainActivity:
CellListener cellListener = new CellListener(this);
cellListener.start();
CellListener:
public class CellListener extends PhoneStateListener {
private static final String TAG = "CellListener";
private TelephonyManager telephonyManager = null;
private PhoneStateListener listener = null;
private String newCell = null;
private int events = PhoneStateListener.LISTEN_CELL_LOCATION | PhoneStateListener.LISTEN_CELL_INFO;
private Context context = null;
public CellListener(Context context) {
this.context = context;
}
public void start() {
telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
CellLocation.requestLocationUpdate();
telephonyManager.listen(this, events);
}
#Override
public void onCellInfoChanged(List<CellInfo> cellInfo) {
Log.i("CellListener","onCellInfoChanged(List<CellInfo> cellInfo) ");
super.onCellInfoChanged(cellInfo);
if(cellInfo == null) return; // this always null here
for (CellInfo c : cellInfo) {
Log.i("CellListener"," c = "+c);
}
}
#Override
public void onCellLocationChanged(CellLocation location) {
if (!(location instanceof GsmCellLocation)) {
return;
}
GsmCellLocation gsmCell = (GsmCellLocation) location;
String operator = telephonyManager.getNetworkOperator();
if (operator == null || operator.length() < 4) {
return;
}
newCell = operator.substring(0, 3) + ':' + operator.substring(3) + ':'
+ gsmCell.getLac() + ':' + gsmCell.getCid();
Log.i(TAG,"newCell = "+newCell);
}
}
Logcat:
11-18 14:50:23.806: I/CellListener(4953): newCell = 262:02:4311:99031735
11-18 14:50:23.814: I/CellListener(4953): onCellInfoChanged(List<CellInfo> cellInfo)
As you can see both events (onCellInfoChanged & onCellLocationChanged) get triggered once and the latter is correctly returning the current cell the device is using.
The real reason you are only being called exactly once and with null as an argument is the following: there appears to be a rate-limiting setting in place by default, as can be observed in the "testing" app, which can be accessed by dialing *#*#INFO#*#* (i.e. *#*#4636#*#*).
In the testing app, choose "Phone Information" and scroll down to the button CELLINFOLISTRATE xxxx, in your case presumably CELLINFOLISTRATE 2147483647. As 2147483647 == MAX_INT, this probably means no calls at all
For me (stock android 6.0, nexus 6), there's the a choice between MAX_INT (one call with null), 0 and 1000.
I'm not 100% sure what these values mean, but presumably the 0 stands for instant (and thus very many) calls, and 1000 for something like at least a second between calls. Keep in mind though, this is pure speculation.
I will edit this answer as I find out more, for example by looking at the implementation of said testing app.
#bofredo: It is returning null because you haven't defined CellInfo yet.
Can't see from your question if you're using CDMA, GSM, or LTE. From memory, CDMA doesn't seem to return anything, but GSM (CellInfoGsm) and LTE (CellInfoLte) do. So doing something like for example:
CellInfoGsm cellInfoGsm = (CellInfoGsm) cellInfo;
CellInfoLte cellInfoLte = (CellInfoLte) cellInfo;
will return an instance of CellInfoGsm or CellInfoLte which will then allow you to retrieve more information about a cell like:
CellIdentityGsm cellIdentityGsm = cellInfoGsm.getCellIdentity();
CellIdentityLte cellIdentityLte = cellInfoLte.getCellIdentity();
or
CellSignalStrengthGsm cellSignalStrengthGsm = cellInfoGsm.getCellSignalStrength();
CellSignalStrengthLte cellSignalStrengthLte = cellInfoLte.getCellSignalStrength();
Then use cellIdentityGsm, cellIdentityLte, cellSignalStrengthGsm and cellSignalStrengthLte to do what you want in onCellInfoChanged.
In addition to #bimmlerd answer. If you are updating the Phone Information via dialing *#*#INFO#*#* (i.e. *#*#4636#*#*). There are chances that the hidden menu doesn't appear. In that case, use default dialer if you are using some 3rd party call management application (Worked for me as it was not showing any hidden menu for phone information).
https://www.reddit.com/r/GooglePixel/comments/6xc40q/4636_service_menu_not_available_in_oreo/
Note:
The following picture will help you with the latest Android OS. Just update the mobile info refresh rate in phone information 1/2 option (I hope multiple phone information because of multiple sim cards)
How can I find out for sure that device really has gsm, cdma or other cellular network equipment (not just WiFi)?
I don't want to check current connected network state, because device can be offline in the moment.
And I don't want to check device id via ((TelephonyManager) act.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId() because some devices would just give you polymorphic or dummy device ID.
Actualy, I need to check cell equipment exactly for skipping TelephonyManager.getDeviceId and performing Settings.Secure.ANDROID_ID check on those devices that don't have cellular radio. I have at least one tablet (Storage Options Scroll Excel 7") which returns different IMEIs every time you ask it, although it should return null as it has no cell radio (the same situation here: Android: getDeviceId() returns an IMEI, adb shell dumpsys iphonesubinfo returns Device ID=NULL). But I need to have reliable device id that is the same every time I ask.
I'd be glad to hear your thoughts!
If you're publishing in the store, and you want to limit your application only being visible to actual phones, you could add a <uses-feature> into your manifest that asks for android.hardware.telephony. Check out if that works for you from the documentation.
Just in case somebody needs complete solution for this:
Reflection is used because some things may not exist on some firmware versions.
MainContext - main activity context.
static public int getSDKVersion()
{
Class<?> build_versionClass = null;
try
{
build_versionClass = android.os.Build.VERSION.class;
}
catch (Exception e)
{
}
int retval = -1;
try
{
retval = (Integer) build_versionClass.getField("SDK_INT").get(build_versionClass);
}
catch (Exception e)
{
}
if (retval == -1)
retval = 3; //default 1.5
return retval;
}
static public boolean hasTelephony()
{
TelephonyManager tm = (TelephonyManager) Hub.MainContext.getSystemService(Context.TELEPHONY_SERVICE);
if (tm == null)
return false;
//devices below are phones only
if (Utils.getSDKVersion() < 5)
return true;
PackageManager pm = MainContext.getPackageManager();
if (pm == null)
return false;
boolean retval = false;
try
{
Class<?> [] parameters = new Class[1];
parameters[0] = String.class;
Method method = pm.getClass().getMethod("hasSystemFeature", parameters);
Object [] parm = new Object[1];
parm[0] = "android.hardware.telephony";
Object retValue = method.invoke(pm, parm);
if (retValue instanceof Boolean)
retval = ((Boolean) retValue).booleanValue();
else
retval = false;
}
catch (Exception e)
{
retval = false;
}
return retval;
}
I have an app that I want to be able to use to get a connection status report from a remote query.
I want to know if WiFi is connected, and if data access is enabled over mobile network.
If the WiFi goes out of range I want to know if I can rely on the mobile network.
The problem is that data enabled is always returned as true when I am connected by WiFi, and I can only properly query the mobile network when not connected by WiFi.
all the answers I have seen suggest polling to see what the current connection is, but I want to know if mobile network is available should I need it, even though I might be connected by WiFi at present.
Is there anyway of telling whether mobile network data is enabled without polling to see if is connected?
EDIT
So when connected by WiFi If I go to settings and deselect 'Data Enabled' and then in my app I do this:
boolean mob_avail =
conMan.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isAvailable();
mob_avail is returned as 'true', but I have disabled Mobile Network Data, so I would expect it to be 'false'
If I turn off the WiFi, there is (rightly) no connection as I have disabled mobile network data.
so how do I check if mobile network data is enabled when I am connected by WiFi?
UPDATE
I took a look at getAllNetworkInfo() as suggested in the comments by ss1271
I outputted the info returned about the mobile network under the following 3 conditions
WiFi Off - Mobile Data on
WiFi On - Mobile Data off
WiFi On - Mobile Data on
and got the following results:
With WiFi OFF:
mobile[HSUPA], state: CONNECTED/CONNECTED, reason: unknown, extra:
internet, roaming: false, failover: false, isAvailable: true,
featureId: -1, userDefault: false
With WiFi On / Mobile OFF
NetworkInfo: type: mobile[HSUPA], state: DISCONNECTED/DISCONNECTED,
reason: connectionDisabled, extra: (none), roaming: false,
failover: false, isAvailable: true, featureId: -1, userDefault:
false
With WiFi On / Mobile On
NetworkInfo: type: mobile[HSPA], state: DISCONNECTED/DISCONNECTED,
reason: connectionDisabled, extra: (none), roaming: false,
failover: false, isAvailable: true, featureId: -1, userDefault:
false
So as you can see isAvailable returned true each time, and state only showed as Disconnected when WiFi was in affect.
CLARIFICATION
I am NOT looking to see if my phone is currently connected by Mobile Network. I AM trying to establish whether or not the user has enabled / disabled Data access over mobile network. They can turn this on and off by going to Settings -> Wireless and Network Settings ->Mobile Network Settings -> Data enabled
The following code will tell you if "mobile data" is enabled or not, regardless of whether or not there is a mobile data connection active at the moment or whether or not wifi is enabled/active or not. This code only works on Android 2.3 (Gingerbread) and later. Actually this code also works on earlier versions of Android as well ;-)
boolean mobileDataEnabled = false; // Assume disabled
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
try {
Class cmClass = Class.forName(cm.getClass().getName());
Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true); // Make the method callable
// get the setting for "mobile data"
mobileDataEnabled = (Boolean)method.invoke(cm);
} catch (Exception e) {
// Some problem accessible private API
// TODO do whatever error handling you want here
}
Note: you will need to have permission android.permission.ACCESS_NETWORK_STATE to be able to use this code.
I've upgraded Allesio's answer. Settings.Secure's mobile_data int has moved to Settings.Global since 4.2.2.
Try This code when you want to know if mobile network is enabled even when wifi is enabled and connected.
Updated to check if SIM Card is available. Thanks for pointing out murat.
boolean mobileYN = false;
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
{
mobileYN = Settings.Global.getInt(context.getContentResolver(), "mobile_data", 1) == 1;
}
else{
mobileYN = Settings.Secure.getInt(context.getContentResolver(), "mobile_data", 1) == 1;
}
}
One way is to check whether the user has mobile data activated in the Settings, which most likely will be used if wifi goes off.
This works (tested), and it doesn't use reflection, although it uses an hidden value in the API:
boolean mobileDataAllowed = Settings.Secure.getInt(getContentResolver(), "mobile_data", 1) == 1;
Depending on the API, you need to check Settings.Global instead of Settings.Secure, as pointed out by #user1444325.
Source:
Android API call to determine user setting "Data Enabled"
Since ConnectivityManager.allNetworkInfo is deprecated, Android suggested using getNetworkCapabilities
fun isOnMobileData(): Boolean {
val connectivityManager =
context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val all = connectivityManager.allNetworks
return all.any {
val capabilities = connectivityManager.getNetworkCapabilities(it)
capabilities?.hasTransport(TRANSPORT_CELLULAR) == true
}
}
#sNash's function works great. But in few devices I found it returns true even if data is disabled.
So I found one alternate solution which is in Android API.
getDataState() method of TelephonyManager will be very useful.
I updated #snash's function with the above function used. Below function returns false when cellular data is disabled otherwise true.
private boolean checkMobileDataIsEnabled(Context context){
boolean mobileYN = false;
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) {
// if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
// {
// mobileYN = Settings.Global.getInt(context.getContentResolver(), "mobile_data", 0) == 1;
// }
// else{
// mobileYN = Settings.Secure.getInt(context.getContentResolver(), "mobile_data", 0) == 1;
// }
int dataState = tm.getDataState();
Log.v(TAG,"tm.getDataState() : "+ dataState);
if(dataState != TelephonyManager.DATA_DISCONNECTED){
mobileYN = true;
}
}
return mobileYN;
}
You can try something like that:
ConnectivityManager conMan = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
//mobile
State mobile = conMan.getNetworkInfo(0).getState();
//wifi
State wifi = conMan.getNetworkInfo(1).getState();
if (mobile == NetworkInfo.State.CONNECTED || mobile == NetworkInfo.State.CONNECTING)
{
//mobile
}
else if (wifi == NetworkInfo.State.CONNECTED || wifi == NetworkInfo.State.CONNECTING)
{
//wifi
}
If you are interested if you are realy connected, use
NetworkInfo.State.CONNECTED
only, instead of
NetworkInfo.State.CONNECTED || NetworkInfo.State.CONNECTING
use TelephonyManager
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
tm.isDataEnabled()
According to android documentation
https://developer.android.com/reference/android/telephony/TelephonyManager.html#isDataEnabled()
I think using NetworkInfo class and isConnected should work:
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
return info != NULL || info.isConnected();
And to check mobile data is connected perhaps. I can not be sure until I test it. Which I cannot do until tommorrow.
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if(tm .getDataState() == tm .DATA_CONNECTED)
return true;
Here is a xamarin solution to this problem:
public static bool IsMobileDataEnabled()
{
bool result = false;
try
{
Context context = //get your context here or pass it as a param
if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr1)
{
//Settings comes from the namespace Android.Provider
result = Settings.Global.GetInt(context.ContentResolver, "mobile_data", 1) == 1;
}
else
{
result = Settings.Secure.GetInt(context.ContentResolver, "mobile_data", 1) == 1;
}
}
catch (Exception ex)
{
//handle exception
}
return result;
}
PS: Make sure you have all the permissions for this code.
Here is a simple solution from two other answers:
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return tm.isDataEnabled();
} else {
return tm.getSimState() == TelephonyManager.SIM_STATE_READY && tm.getDataState() != TelephonyManager.DATA_DISCONNECTED;
}
You must use the ConnectivityManager, and NetworkInfo details can be found here
To identify which SIM or slot is making data connection active in mobile, we need to register action android:name="android.net.conn.CONNECTIVITY_CHANGE" with permission
uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" & uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"
public void onReceive(Context context, Intent intent)
if (android.net.conn.CONNECTIVITY_CHANGE.equalsIgnoreCase(intent
.getAction())) {
IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
NetworkState[] states = service.getAllNetworkState();
for (NetworkState state : states) {
if (state.networkInfo.getType() == ConnectivityManager.TYPE_MOBILE
&& state.networkInfo.isConnected()) {
TelephonyManager mTelephonyManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
int slotList = { 0, 1 };
int[] subId = SubscriptionManager.getSubId(slotList[0]);
if(mTelephonyManager.getDataEnabled(subId[0])) {
// this means data connection is active for SIM1 similary you
//can chekc for SIM2 by slotList[1]
.................
}
}
}
ConnectivityManager cm = (ConnectivityManager) activity
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
String networkType = "";
if (info.getType() == ConnectivityManager.TYPE_WIFI) {
networkType = "WIFI";
}
else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
networkType = "mobile";
}
According to android documentation https://developer.android.com/training/monitoring-device-state/connectivity-monitoring#java
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
Well there is a workaround to check if the data connection is on. But I am not sure whether it will work on every device. You need to check that. (It worked on Android one device)
long data = TrafficStats.getMobileRxBytes();
if(data > 0){
//Data is On
}
else{
//Data is Off
}
If you are not aware about this method, it returns the total of bytes recieved through mobile network since the device boot up. When you turn off the mobile data connection, it will return Zero (0). When you turn on, it will return the total of bytes again. But you need to aware that there is a problem which can happen when using this workaround.
This method will also return 0 when you reboot the phone because the calculation starts from 0 bytes.
private boolean haveMobileNetworkConnection() {
boolean haveConnectedMobile = false;
ConnectivityManager cm = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo[] netInfo = cm.getAllNetworkInfo();
for (NetworkInfo ni : netInfo) {
if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
if (ni.isConnected())
haveConnectedMobile = true;
}
return haveConnectedMobile;
}
Note: you will need to have permission android.permission.ACCESS_NETWORK_STATE to be able to use this code
There is simple API that seems to be working
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.isDataEnabled();