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:
- SecurityException con grantUriPermission al compartir un archivo con FileProvider
- java.lang.SecurityException: Ni el usuario 10032 ni el proceso actual tiene android.permission.MODIFY_PHONE_STATE
- ¿Leer contactos sin permiso?
- Listando los permisos de la aplicación de Android vía adb
- Android facebook sdk - establece permisos para openActiveSession
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?
- ¿Cómo puede la aplicación del sistema ubicada en / system / app tener permiso del sistema en Android 4.4 KitKat construir?
- Android 6.0 necesita reiniciar después de conceder permiso de usuario en tiempo de ejecución
- Lo que puede causar un error socket () "Permiso denegado"?
- INSTALL_FAILED_UPDATE_INCOMPATIBLE pero la aplicación no está instalada
- ¿Valgrind no puede ejecutar la herramienta memcheck en el sistema operativo Android?
- Android OS 2.2 Permisos: No tengo ni idea de por qué este simple código no funciona. ¿Qué estoy haciendo mal?
- ¿Qué tipo de aplicación de Android requerirá permiso de android.permission.READ_PHONE_STATE?
- Permiso del receptor de facturación en la aplicación
Hay manera de obtener el acceso a NetworkStateManager
sin tener acceso a la API privada. Estos son los pasos:
-
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"/>
- 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- Utilizar
NetworkStatsManager
:
- Solicitar permiso en
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 ""; }
- Insertar evento en el calendario con la intención
- ¿Cómo actualizar un TextView en una actividad constantemente en un bucle infinito?