4

I'm making an App for Android 6.0 and I want to use the new class NetworkStatsManager for getting mobile data usage.

I added all permission I need in manifest and require the permission runtime.

When I call the method:

bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_WIFI, "", fromDate.getTime(), toDate.getTime());

return the right value for WIFI usage.

But if i replace TYPE_WIFI with TYPE_MOBILE the result is always 0.

    NetworkStats.Bucket bucket = null;
    try {
        bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE, "", fromDate.getTime(), toDate.getTime());

        if(bucket == null){
            Log.i("Info", "Error");
        }else{
            Log.i("Info", "Total: " + (bucket.getRxBytes() + bucket.getTxBytes()));
        }

    } catch (RemoteException e) {
        e.printStackTrace();
    }
Allen Walker
  • 866
  • 1
  • 9
  • 17

3 Answers3

8

I found a solution of this problem with hidden APIs (android statistic 3g traffic for each APP, how?) and when trying to retrieve mobile data usage information with TYPE_MOBILE was necessary to inform the SubscriberID, unlike when I tryed to get information TYPE WIFI.

Try this code

    TelephonyManager  tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
    String subscriberID = tm.getSubscriberId();

    NetworkStats networkStatsByApp = networkStatsManager.queryDetailsForUid(ConnectivityManager.TYPE_MOBILE, subscriberID, start, end, uid);

So when you are using TYPE_MOBILE, it's necessary to you use a valid subscriberID.

Community
  • 1
  • 1
0

As a follow up to the accepted answer, I would also like to point out that in the following code,

TelephonyManager  tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String subscriberID = tm.getSubscriberId(); //subscriberID is usually the IMSI number (for GSM phones)

TelephonyManager tm contains the information about the default telephony service (SIM card) that is being used for making calls. So, if you are using a phone with Dual SIM cards and SIM 1 is being used for calls and SIM 2 is being used for Data, then TelephonyManager tm will hold information about SIM 1 and in your use case, where you are using NetworkStatsManager for getting Data usage stats, SIM 1 info will be of no use as it is not being used for consuming Data. So, you somehow need to fetch the TelephonyManager for SIM 2 so that you can use the correct subscriber Id of SIM 2 in networkStatsManager.querySummaryForDevice() to get the mobile data usage stats. So, how do you do this?

One way that I figured out is like this:

public void subscriberIdsOfDualSim(){
    SubscriptionManager subscriptionManager = SubscriptionManager.from(this);
    //we'll now get a List of information of active SIM cards
    //for example, if there are 2 SIM slots and both the slots have 1 SIM card each, then the List size will be 2
    List<SubscriptionInfo> activeSubscriptionInfoList = subscriptionManager.getActiveSubscriptionInfoList();
    TelephonyManager manager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
    for (SubscriptionInfo subscriptionInfo : activeSubscriptionInfoList) {
        //loop through the SIM card info
        //if there are 2 SIM cards, then we'll try to print the subscriberId of each of the SIM cards
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            //the following createForSubscriptionId() is available from API 24 :(
            TelephonyManager manager1=manager.createForSubscriptionId(subscriptionInfo.getSubscriptionId());
            String operatorName=manager1.getNetworkOperatorName();
            String subscriberId=manager1.getSubscriberId(); //use this subscriberId to do NetworkStatsManager stuff
            System.out.println("subscriberIdsOfDualSim: Carrier Name: "+operatorName+", subscriber id: "+subscriberId);
        }
    }
}

Notice that I have used createForSubscriptionId() method. One limitation of this method is that it can be used from API 24 (Android 7.0 Nougat) only.

So, if you are using both SIM 1 and SIM 2 for data consumption, then you can get the data usage info for each of the SIM cards by providing the subscriberId of each of them to networkStatsManager.querySummaryForDevice(). But, if you want to get correct mobile data consumption (both SIM 1 and SIM 2 inclusive) and you want to support phones below Nougat, then the good old getMobileRxBytes() and getMobileTxBytes() methods in TrafficStats class is what you may have to use.

Nandan Desai
  • 397
  • 3
  • 10
  • Another limitation is that from API 28 (app targetting it), getSubscriberId() returns null, or an exception if targetting API 29! – 3c71 Jan 13 '20 at 12:59
0

Another follow up to the accepted answer and @Nandan, it's possible to obtain subscriber ids of both SIM cards using below code

SubscriptionManager subman = (SubscriptionManager)getSystemService(TELEPHONY_SUBSCRIPTION_SERVICE);
TelephonyManager telman = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);

List<SubscriptionInfo> li = subman.getActiveSubscriptionInfoList();

for(SubscriptionInfo info : li){
    int sid = info.getSubscriptionId(); //not the id we want

    try{
        Class c = Class.forName("android.telephony.TelephonyManager");
        Method m = c.getMethod("getSubscriberId", new Class[]{int.class});
        Object o = m.invoke(telman, new Object[]{sid});

        String subid = (String)o;  //id we want
        Log.i("SubscriptionId", subid);
    }
    catch(Exception e){}

}

Credit to answer link https://stackoverflow.com/a/38071705/9038181

N. Kyalo
  • 47
  • 3