79

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

Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382
Kevin Bradshaw
  • 6,327
  • 13
  • 55
  • 78
  • 1
    http://stackoverflow.com/questions/12686899/test-if-background-data-and-packet-data-is-enabled-or-not?rq=1 same thing – Kevin Bradshaw Oct 09 '12 at 20:27
  • 1
    have you tried: [getAllNetworkInfo()](http://developer.android.com/reference/android/net/ConnectivityManager.html#getAllNetworkInfo())? – dumbfingers Oct 10 '12 at 10:15
  • 1
    I can't recall off hand, but I will try it as soon as I get home and update. I presume that would return an array of available connections? And that I would need to traverse the array? – Kevin Bradshaw Oct 10 '12 at 10:23
  • 1
    yes, it will return an array. Honestly I haven't use this before, so you may need to print some log to see what it will get for you. And please let me know the result, good luck – dumbfingers Oct 10 '12 at 10:33

17 Answers17

131

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.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • 2
    Brilliant! absolutely perfect. Thank you very much, it cost me 1/3 of my reputation but it does exactly what I needed, so points very well spent. Can I ask you to give a little explanation on the code? It differs to what I had been trying and to what was being suggested to me as a solution. Would I be right in saying you are using reflection? Im a bit vague on reflection if thats what it is. Is it a back door trick or is it an authentic supported feature of Android? In any case, thanks again. Your a star! – Kevin Bradshaw Oct 12 '12 at 21:30
  • 1
    Wow. Thanks so much for that comment! Glad I could help. Yes, this code uses Java reflection. For some silly reason, the Android core developers decided not to expose the methods to get and set the "mobile data enabled" flag in the public API. So these methods are there, but they are marked as "private". Using reflection, we can get lots of information about classes, even the information that is considered "orivate". Since this is an "unsupported API" it may not work on all devices and it may be changed in a future release of Android. However, it does seem to work on most devices right now. – David Wasser Oct 12 '12 at 22:25
  • Most of the other suggestions were to use the public API of the `ConnectionManager` to access the current network state (which clearly wasn't what you wanted) or to use the `TelephonyManager` API (which unfortunately doesn't offer access to the information you wanted). – David Wasser Oct 12 '12 at 22:28
  • It seems a bit strange that this is not a method that is exposed to the API. especially since public API methods would seem to suggest that a mobile network is available when it is not. So, as a matter of interest, if reflection is unsupported how does one find out what can be done with it.? I presume you did not pull your answer from the official docs! :) – Kevin Bradshaw Oct 12 '12 at 22:42
  • First of all thanks, that's very useful. But if I may ask, if you were to use that code in order to get notified every time the user enables/disables the mobile data how would you do it? I know a comment is not the most appropriate place for this and I have already created a [question](http://stackoverflow.com/questions/20790483/monitor-when-the-user-enables-disables-mobile-data), but to no avail unfortunately :\ – Sakis Vtdk Jan 04 '14 at 23:19
  • How to toggle ON/OFF? – Muhammad Babar Sep 26 '14 at 07:19
  • The method getMobileDataEnabled doesn't exist anymore in IConnectivityManager – Romain Jan 22 '15 at 16:16
  • 2
    @DavidWasser amazing. But a I need to raise a concern, if using proguard "getMobileDataEnabled" string will be converted to something else which result in wrong results. Proguard doesn't work well with Reflection – Murtaza Khursheed Hussain Sep 18 '15 at 07:32
  • 3
    This works but it poses a big risk as API developers can remove the private methods at any time – Peter Chaula Aug 21 '17 at 09:56
  • @MurtazaKhursheedHussain your comment is nonsense. Proguard only obfuscates your own code, it doesn't obfuscate methods in the Android framework that you call! Since those methods need to be callable from other apps (even if they are private), these method names cannot be obfuscated. – David Wasser Aug 21 '17 at 10:00
  • @peter of course they can. This isn't guaranteed to work all the time on all devices forever and ever and ever. It is a workaround. Which is better than nothing. What is your point? – David Wasser Aug 21 '17 at 10:02
  • I upvoted the answer and posted a comment to warn someone that might blindly copy this code. That's my point – Peter Chaula Aug 21 '17 at 10:04
  • @DavidWasser before using harsh words like `nonsense` try to read what I meant. you are using reflection which does not work well with obfuscation. – Murtaza Khursheed Hussain Aug 21 '17 at 11:29
  • @MurtazaKhursheedHussain Sorry about the language. However, reflection works just fine with obfuscation, as long as you are using reflection on things that can not be obfuscated, such as frameworks or libraries. I see no point in bringing up the issue of obfuscation here, since obfuscation in this situation is not a problem. – David Wasser Aug 21 '17 at 12:43
  • 1
    `as long as you are using reflection on things that can not be obfuscated, such as frameworks or libraries` I didn't know that. Thank you – Murtaza Khursheed Hussain Aug 21 '17 at 12:59
  • Almost perfect, but not work for Wileyfox (Swift, Swift 2, Swift 2X, Swift Plus) devices with Android 7.1.2 (~30 affected users). I got **InvocationTargetException Caused by SecurityException not allowed to perform OP_READ_PHONE_STATE**. No workaround found to get this OP-permission. – Vadik Sirekanyan Aug 10 '18 at 10:09
  • Also this solution not work for Samsung Galaxy (S2 Plus, Trend Duos, Trend Lite, Fame, etc.) devices with Android 4.1.2 (~20 affected users). I got **NoSuchMethodException: getMobileDataEnabled**. But for this devices solution from @sNash is work. – Vadik Sirekanyan Aug 10 '18 at 10:14
  • 1
    @Vadik Samsung has their own custom versions of the `ConnectivityManager` and `TelephonyManager`, so a lot of the generic solutions for Android don't work on those devices. It's always a shot in the dark. – David Wasser Aug 15 '18 at 19:49
  • oh my god, it's so simple – Piyush Apr 05 '20 at 08:57
  • @DavidWasser When you try the same method with no sim cards in the phone, then its returning mobile data is enabled. when the device has no sim card then mobile data is always off by system functionality. – Narendra Sorathiya Apr 25 '20 at 07:51
  • Thanks for post i have one question I have running app with device wifi IOT device. so when App connected with wifi then device cellular data will work while we trying to apply some network operation ? – MARSH Nov 22 '22 at 14:32
37

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;
    }
}
sNash
  • 903
  • 10
  • 11
  • 1
    I don't see any such constant "mobile_data" under in Settings.Global https://developer.android.com/reference/android/provider/Settings.Global.html. I wonder how is it working or you. – LoveForDroid Oct 17 '16 at 21:48
  • 2
    @LoveForDroid It's a hidden member of Settings.Global class. You can find it in the aosp source code. – sNash Jan 12 '17 at 08:50
  • 1
    Settings.Global.getInt(context.getContentResolver(), "mobile_data",1) returns 1 although there is no sim card on the device. – Murat Jun 12 '17 at 08:36
  • 1
    @Murat I added some code to check if sim is available. – sNash Jun 15 '17 at 12:23
  • 1
    @sNash and SIM_STATE_UNKNOWN should be handled as well. In my device, it doesnt have a sim card and sim state is unknown. – Murat Jun 16 '17 at 10:54
  • 1
    @Murat it looks like SIM state have 9 items and only SIM_STATE_READY is valid one. so I changed the code to check it. – sNash Jun 16 '17 at 12:15
  • 1
    @sNash is it working excatly when you are getting notification for wifi turned off.the above method return false for me when im recieving notification for wifi – Jeeva Jan 18 '18 at 12:40
  • 3
    I've seen at least one device where the "disable mobile data" option in the settings doesn't change this setting (but does cause TelephonyManager.isDataEnabled() to return false). Might be a bug in the settings because the mobile data icon in the swipe-down menu also doesn't show disabled, but it definitely does disable mobile data. – Ben Kuhn Oct 05 '18 at 18:04
  • 1
    In some (probably custom) systems, there is a `mobile_data1` that seems to actually reflect the state. When this is present, `mobile_data` mostly holds `1` regardless of the current state. Check with `adb shell settings list global | grep mobile_data` – Lennoard Silva Jul 06 '20 at 14:31
23

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"

Community
  • 1
  • 1
Alessio
  • 3,063
  • 1
  • 15
  • 17
  • 1
    Wow, that would be much neater than the reflection method which apparently does not work with lollipop. what versions of android is this tested against? – Kevin Bradshaw Apr 14 '15 at 11:03
  • 3
    Tested against 4.4.4 and 5.0.1. – Alessio Apr 14 '15 at 11:09
  • 1
    Successfully tested against 4.2.2 – Jibran Khan Dec 22 '15 at 07:32
  • 3
    Will return true if no SIM, you should add SIM verification aswell – Joze Jan 19 '16 at 10:10
  • 1
    This returns true if there's no mobile data on the device (no mobile modem). – Jeffrey Blattman Jun 06 '16 at 20:56
  • 1
    I don't see any such constant "mobile_data" under in Settings.Global https://developer.android.com/reference/android/provider/Settings.Global.html I wonder how is it working or you. – LoveForDroid Oct 17 '16 at 21:48
  • 1
    @LoveForDroid as I wrote "it uses an hidden value in the API": the value is hidden, so you will not see it in the documented API (as that is for public methods only); you need to go and read the source code to see it. – Alessio Oct 18 '16 at 09:43
  • @Joze as you can see the default returned value in my call is '1', so assumption is it returns true unless it verifies is disabled in Settings. Generally speaking yes anyone who wants to use such code should combine it with similar checks. – Alessio Oct 18 '16 at 09:50
  • @Alessio you can see the current 'mobile_data' setting value if you type "settings list global | grep mobile_data". The real value for that setting is the one that is no followed by a number (e.g. mobile_data1 is not the real, but the config for your current SIM) – BamsBamx Nov 19 '16 at 10:59
  • @BamsBamx I ran that for my dual sim device and I got mixed results. mobile_data1-5 with different values. Any idea why I'm getting these results? – Peter Chaula Aug 21 '17 at 10:02
6

@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;
    }
MohK
  • 1,873
  • 1
  • 18
  • 29
5

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
    }
}
Janjan Medina
  • 59
  • 1
  • 1
4

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()

Ralph Chen
  • 61
  • 1
  • 4
3

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
Milos Cuculovic
  • 19,631
  • 51
  • 159
  • 265
  • 1
    That is not going to work as I pointed out to first ( and second ) responder, I am not looking to see if I am connected by Mobile, I am looking to see if the user has Mobile Data enabled. (they can turn this on and off by going to Settings -> Wireless and Network Settings ->Mobile Network Settings -> Data enabled) – Kevin Bradshaw Oct 12 '12 at 16:07
  • @KevinBradshaw, you can use this to check if Mobile Data is enabled. If the Mobile data is enabled, then you will get NetworkInfo.State.CONNECTED or NetworkInfo.State.CONNECTING == mobile. Because if mobile data is enablet, then the system will try to connect to the network or be connected. – Milos Cuculovic Oct 15 '12 at 06:38
  • I think you need to try this out. Disable Mobile Network Data on your phone (uncheck Settings -> Wireless and Network Settings ->Mobile Network Settings -> Data enabled). run your code and you will see it will report that there is a mobile connection. NetworkInfo State does not take into account whether or not User has mobile data enabled. See accepted answer for only way I have found to work. – Kevin Bradshaw Oct 15 '12 at 07:49
3

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;
        }
Brian Hong
  • 930
  • 11
  • 15
1

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;
tozka
  • 3,211
  • 19
  • 23
  • That is not going to work as I pointed out to first response, I am not looknig to see if I am connected by Mobile I am looking to see if the user has Mobile Data enabled. (htey can turn this on and off by going to Settings -> Wireless and Network Settings ->Mobile Network Settings -> Data enabled) – Kevin Bradshaw Oct 12 '12 at 16:06
  • 1
    Have you tried with TelephonyManager? It should show you if data is enabled or not. – tozka Oct 12 '12 at 16:28
1

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.

SubqueryCrunch
  • 1,325
  • 11
  • 17
1

There is simple API that seems to be working

TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.isDataEnabled();

Evgeny Pis
  • 11
  • 1
0

You must use the ConnectivityManager, and NetworkInfo details can be found here

CAM-Dev
  • 186
  • 3
0
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]
               .................
          }
}

}
amit
  • 1
  • 1
0
    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";
    }
Srishti Roy
  • 576
  • 5
  • 17
0

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();
Rémy
  • 313
  • 3
  • 17
0

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.
0
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

Annas Bin Waheed
  • 291
  • 1
  • 4
  • 12