Skip to content Skip to sidebar Skip to footer

How To Use Storagestatsmanager.querystatsforpackage On Android O?

Background Before Android O, in order to get an app size, you had to have a special permission for it, and use a hidden API. The problem Such a solution won't work anymore, but ins

Solution 1:

OK, I've found out how to use the new API. I've prepared a small sample of this, fetching some information about the volume storage and of a specific app (this time of the Play Store, but you can change it if needed) :

publicclassMainActivityextendsAppCompatActivity {

    publicstaticfinalStringPACKAGE_NAME="com.android.vending";

    @OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @OverrideprotectedvoidonResume() {
        super.onResume();
        if (!hasUsageStatsPermission(this))
            startActivityForResult(newIntent(Settings.ACTION_USAGE_ACCESS_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY), 1);
        else {
            finalContextcontext=this;
            AsyncTask.execute(newRunnable() {
                @TargetApi(VERSION_CODES.O)@Overridepublicvoidrun() {
                    @SuppressLint("WrongConstant")finalStorageStatsManagerstorageStatsManager= (StorageStatsManager) getSystemService(Context.STORAGE_STATS_SERVICE);
                    finalStorageManagerstorageManager= (StorageManager) getSystemService(Context.STORAGE_SERVICE);
                    final List<StorageVolume> storageVolumes = storageManager.getStorageVolumes();
                    finalUserHandleuser= android.os.Process.myUserHandle();
                    for (StorageVolume storageVolume : storageVolumes) {
                        finalStringuuidStr= storageVolume.getUuid();
                        finalUUIDuuid= uuidStr == null ? StorageManager.UUID_DEFAULT : UUID.fromString(uuidStr);
                        try {
                            Log.d("AppLog", "storage:" + uuid + " : " + storageVolume.getDescription(context) + " : " + storageVolume.getState());
                            Log.d("AppLog", "getFreeBytes:" + Formatter.formatShortFileSize(context, storageStatsManager.getFreeBytes(uuid)));
                            Log.d("AppLog", "getTotalBytes:" + Formatter.formatShortFileSize(context, storageStatsManager.getTotalBytes(uuid)));
                            Log.d("AppLog", "storage stats for app of package name:" + PACKAGE_NAME + " : ");

                            finalStorageStatsstorageStats= storageStatsManager.queryStatsForPackage(uuid, PACKAGE_NAME, user);
                            Log.d("AppLog", "getAppBytes:" + Formatter.formatShortFileSize(context, storageStats.getAppBytes()) +
                                    " getCacheBytes:" + Formatter.formatShortFileSize(context, storageStats.getCacheBytes()) +
                                    " getDataBytes:" + Formatter.formatShortFileSize(context, storageStats.getDataBytes()));
                        } catch (NameNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });

        }
    }

    @TargetApi(VERSION_CODES.M)publicstaticbooleanhasUsageStatsPermission(Context context) {
        //http://stackoverflow.com/a/42390614/878126if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)
            returnfalse;
        AppOpsManagerappOps= (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        finalintmode= appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), context.getPackageName());
        booleangranted=false;
        if (mode == AppOpsManager.MODE_DEFAULT)
            granted = (context.checkCallingOrSelfPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) == PackageManager.PERMISSION_GRANTED);
        elsegranted= (mode == AppOpsManager.MODE_ALLOWED);
        return granted;
    }
}

manifest file should have this:

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

EDIT: note that the part of UUID.fromString(uuidStr) could fail for SD-cards, and the reason by Google is this:

Android can't maintain quota-style statistics for public volumes (SD card etc.). Apps will need to build size calculation logic themselves.

Sadly, on Android 11, due to the new restrictions of reaching "Android" folder, even this is impossible. Requested here to change it:

@t0m But even with what they wrote, it's not officially impossible to do what they said to do, as storage permission got very restricted on Android 11, not allowing you to reach Android folder properly. Requested to solve this here:

Please consider starring.

Solution 2:

An alternative approach for getting UUID.

To get UUIDs, you can also use StorageManager.getUuidForPath(File path) function. As to the path, use Context.getFilesDir() and Context.getExternalFilesDirs() to get all possibles directories that an app data will be saved to.

Please note that different path may return the same UUID, so you have to use a hash set to collect unique UUIDs

Solution 3:

Pass null as the VolumeUuid, to get values for the default internal storage, or get specific volumes via the StorageManager system service.

You can get your own UserHandle via Process.myUserHandle(). Other users of the system occur when you give someone a guest login on your device, or when there is an Android for Work profile installed on the device. I don't think there is a simple way to enumerate all the users that have access to the device.

Post a Comment for "How To Use Storagestatsmanager.querystatsforpackage On Android O?"