Cómo obtener el historial de uso de datos móviles con NetworkStatsManager

Quiero saber la historia de uso de datos y noté el "nuevo" androide-6 NetworkStatsManager que parece positivo (he usado TrafficStats un rato pero eso no cubrirá nada anterior un reinicio).

De la documentación de la API:

NOTA: Esta API requiere el permiso PACKAGE_USAGE_STATS, que es un permiso a nivel de sistema y no se concederá a aplicaciones de terceros. Sin embargo, declarar el permiso implica la intención de utilizar la API y el usuario del dispositivo puede conceder permiso a través de la aplicación Configuración. Las aplicaciones de propietario de perfil se conceden automáticamente permiso para consultar datos en el perfil que administran (es decir, para cualquier consulta excepto querySummaryForDevice (int, String, long, long)). Las aplicaciones de propietario de dispositivo también obtienen acceso a los datos de uso del usuario principal.

Quiero saber el uso de datos en un nivel agregado y no hacia abajo a qué aplicación que utiliza los datos así que traté de usarlo de esta manera:

 NetworkStatsManager service = context.getSystemService(NetworkStatsManager.class); NetworkStats.Bucket bucket = service.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE, null, from, to); ... 

Desafortunadamente, se lanza una SecurityException :

 java.lang.SecurityException: NetworkStats: Neither user 10174 nor current process has android.permission.READ_NETWORK_USAGE_HISTORY. at android.os.Parcel.readException(Parcel.java:1620) at android.os.Parcel.readException(Parcel.java:1573) at android.net.INetworkStatsSession$Stub$Proxy.getDeviceSummaryForNetwork(INetworkStatsSession.java:259) at android.app.usage.NetworkStats.getDeviceSummaryForNetwork(NetworkStats.java:316) at android.app.usage.NetworkStatsManager.querySummaryForDevice(NetworkStatsManager.java:100) ... 

El permiso android.permission.READ_NETWORK_USAGE_HISTORY no está permitido para aplicaciones de terceros. Así que esto parecía un callejón sin salida.

Sin embargo, he perforado un poco en el interior y se enteró de que puede utilizar la API interna / oculta para hacer lo mismo sin solicitar permisos:

 INetworkStatsService service = INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); INetworkStatsSession session = service.openSession(); NetworkTemplate mobileTemplate = NetworkTemplate.buildTemplateMobileWildcard(); int fields = NetworkStatsHistory.FIELD_RX_BYTES | NetworkStatsHistory.FIELD_TX_BYTES; NetworkStatsHistory mobileHistory = session.getHistoryForNetwork(mobileTemplate, fields); for (int i = 0; i < mobileHistory.size(); i++) { NetworkStatsHistory.Entry entry = mobileHistory.getValues(i, null); ... } session.close(); 

Realmente quiero hacer lo mismo con la API pública, así que, ¿cómo puedo hacer eso?

Hay manera de obtener el acceso a NetworkStateManager sin tener acceso a la API privada. Estos son los pasos:

  1. Declare los permisos necesarios en AndroidManifest.xml :

     <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions"/> 
    1. Solicitar permiso en Activity

    android.permission.PACKAGE_USAGE_STATS no es un permiso normal, no puede ser solicitado simplemente. Para comprobar si se ha concedido el permiso, compruebe:

     AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE); int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), getPackageName()); if (mode == AppOpsManager.MODE_ALLOWED) { return true; } 

    Para solicitar este permiso, simplemente llame a Intent :

     Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); startActivity(intent); 

    También se necesita otra autorización: Manifest.permission.READ_PHONE_STATE . Sólo se necesita, cuando se necesita obtener estadísticas de datos móviles . Sin embargo, esto es permiso normal, así que se puede solicitar como cualquier otro permiso

    1. Utilizar NetworkStatsManager :

Hizo una muestra de Reps Github demostrando el uso.

 /* getting youtube usage for both mobile and wifi. */ public long getYoutubeTotalusage(Context context) { String subId = getSubscriberId(context, ConnectivityManager.TYPE_MOBILE); return getYoutubeUsage(ConnectivityManager.TYPE_MOBILE, subId) + getYoutubeUsage(ConnectivityManager.TYPE_WIFI, ""); } private long getYoutubeUsage(int networkType, String subScriberId) { NetworkStats networkStatsByApp; long currentYoutubeUsage = 0L; try { networkStatsByApp = networkStatsManager.querySummary(networkType, subScriberId, 0, System.currentTimeMillis()); do { NetworkStats.Bucket bucket = new NetworkStats.Bucket(); networkStatsByApp.getNextBucket(bucket); if (bucket.getUid() == packageUid) { //rajeesh : in some devices this is immediately looping twice and the second iteration is returning correct value. So result returning is moved to the end. currentYoutubeUsage = (bucket.getRxBytes() + bucket.getTxBytes()); } } while (networkStatsByApp.hasNextBucket()); } catch (RemoteException e) { e.printStackTrace(); } return currentYoutubeUsage; } private String getSubscriberId(Context context, int networkType) { if (ConnectivityManager.TYPE_MOBILE == networkType) { TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); return tm.getSubscriberId(); } return ""; } 
  • Unidad de pruebas de Android y permisos
  • Obtener permiso error java.lang.SecurityException: Permiso de denegación en 3.x dispositivos Android al obtener el nombre del archivo adjunto de correo electrónico
  • Permiso para escribir en la tarjeta SD android
  • Problema al solicitar actualizaciones de la ubicación por red
  • ¿Tengo que declarar WRITE_EXTERNAL_STORAGE y READ_EXTERNAL_STORAGE?
  • Permiso: INJECT_EVENTS para Instrumenation a otras aplicaciones
  • Android: Crear nuevo permiso del sistema a través del código fuente de AOSP.
  • SecurityException: Permiso Negación: lectura (sólo en emulador)
  • Android 6 Permisos => Crash al deshabilitar permiso y volver a la aplicación
  • ¿Cómo dar permisos / dev / bus / usb para aplicaciones libusb android?
  • Titanium SDK 5.1.2 - Permisos de Android 6.0
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.