Skip to content

Instantly share code, notes, and snippets.

@webserveis
Created January 19, 2020 22:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save webserveis/cc9009f40aa865c23775f14e2cad0732 to your computer and use it in GitHub Desktop.
Save webserveis/cc9009f40aa865c23775f14e2cad0732 to your computer and use it in GitHub Desktop.
Show app usage with UsageStatsManager
import android.Manifest
import android.app.AppOpsManager
import android.app.usage.StorageStats
import android.app.usage.StorageStatsManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Process
import android.os.storage.StorageManager
import android.provider.Settings
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.snackbar.Snackbar
import com.webserveis.testnavigationcomponent.util.navigateSafe
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
setupNavigation()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getStorageStats("com.android.vending")
}
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
startActivityForResult(
Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY),
1
)
navController.navigateSafe(R.id.action_fragmentA_to_fragmentB)
}
}
@RequiresApi(Build.VERSION_CODES.O)
private fun getStorageStats(packageName: String) {
val granted = hasPermissionPackageUsageStats()
Log.d("diskusages", "granted:" + granted)
if (granted) {
val stats = getPackageStorageStats(packageName)
stats?.let {
Log.d(TAG, "total app size" + android.text.format.Formatter.formatShortFileSize(this, stats.totalBytes))
Log.d(TAG, "app size" + android.text.format.Formatter.formatShortFileSize(this, stats.appBytes))
Log.d(TAG, "data size" + android.text.format.Formatter.formatShortFileSize(this, stats.dataBytes))
Log.d(TAG, "cache size" + android.text.format.Formatter.formatShortFileSize(this, stats.cacheBytes))
}
} else {
val snack = Snackbar.make(
window.decorView.findViewById(android.R.id.content),
"Need special permission package usage stats", Snackbar.LENGTH_INDEFINITE
)
snack.setAction("SETTINGS") {
startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY))
}
snack.show()
}
}
private fun setupNavigation() {
val host: NavHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?
?: return
navController = host.navController
toolbar.setupWithNavController(navController)
}
private fun hasPermissionPackageUsageStats(): Boolean {
val appOpsManager = this.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
val mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, Process.myUid(), this.packageName)
return if (mode == AppOpsManager.MODE_DEFAULT) {
this.checkCallingOrSelfPermission(Manifest.permission.PACKAGE_USAGE_STATS) == PackageManager.PERMISSION_GRANTED
} else {
mode == AppOpsManager.MODE_ALLOWED
}
}
@RequiresApi(Build.VERSION_CODES.O)
private fun getPackageStorageStats(packageName: String): PackageStorageStat? {
try {
val storageStatsManager: StorageStatsManager =
getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager
//val storageManager: StorageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val stats: StorageStats = storageStatsManager.queryStatsForPackage(
StorageManager.UUID_DEFAULT, packageName, Process.myUserHandle()
)
return PackageStorageStat(packageName, stats.appBytes, stats.cacheBytes, stats.dataBytes)
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
companion object {
val TAG: String = MainActivity::class.java.simpleName
}
}
data class PackageStorageStats(val packageName: String?, val appBytes: Long, val cacheBytes: Long, val dataBytes: Long) {
val totalBytes: Long = appBytes + cacheBytes + dataBytes
}

Show app usage with UsageStatsManager

UsageStatsManager es una nueva API introducida en Android 5.0 Lollipop (API Nivel 21) que nos permite recuperar estadísticas sobre el uso de las aplicaciones instaladas en el dispositivo. Con esa API podemos obtener los diferentes espacios que ocupa una aplicación, su total, data y cache

Para usar el UsageStatsManager debemos añadir el permiso en nuestra app en AndroidManifest.xml

<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />

Comprobar el permiso PACKAGE_USAGE_STATS

Para comprobar si el permiso está otorgado, usaremos loa función hasPermissionPackageUsageStats devuelve un booleano

private fun hasPermissionPackageUsageStats(): Boolean {
    val appOpsManager = this.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
    val mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, Process.myUid(), this.packageName)

    return if (mode == AppOpsManager.MODE_DEFAULT) {
        this.checkCallingOrSelfPermission(Manifest.permission.PACKAGE_USAGE_STATS) == PackageManager.PERMISSION_GRANTED
    } else {
        mode == AppOpsManager.MODE_ALLOWED
    }
}

Si no está otorgado deberemos pedir al usuario que de acceso desde la ventana de configuración del sistema “Applicaciones con acceso al uso”

if (!hasPermissionPackageUsageStats) {
startActivity(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY))
} else {
//obtener espacios
}

Obtener lo que ocupa Data, Cache

Definimos la variable packageName con el id del paquete, por ejemplo:

com.android.vending Y con el método queryStatsForPackage se puede obtener lo que ocupa el paquete/aplicación, disponible a partir de Android O

try {
    val storageStatsManager: StorageStatsManager =
        getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager
    val storageManager: StorageManager =
        getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val stats: StorageStats = storageStatsManager.queryStatsForPackage(
        StorageManager.UUID_DEFAULT, packageName, Process.myUserHandle()
    )
    Log.d(TAG, "app size" + android.text.format.Formatter.formatShortFileSize(this, stats.appBytes))
    Log.d(TAG, "data size" + android.text.format.Formatter.formatShortFileSize(this, stats.dataBytes))
    Log.d(TAG, "cache size" + android.text.format.Formatter.formatShortFileSize(this, stats.cacheBytes))
} catch (e: Exception) {
    e.printStackTrace()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment