Monday 20 June 2016

Android get cache size, data size, apk size for all installed application

I had to make one application which should show the list of installed applications and their size occupied in internal memory, i struggled a lot to find the complete solution at one place. Here I ‘m sharing the full solution which i achieved. 

We can’t get the cache size directly by using PackageManager. We need to use Java Reflection and AIDL  to achieve this. 

Steps to get get cache size, data size and apk size
1. Create AIDL package and add files.
2. Create Class AppDetails.java to get installed package list.
3. Create class by extending IPackageStatsObserver.Stub.
4. Use getPackageSizeInfo method to get data.
Android get app data size using AIDL

1. Create AIDL package and add files.
Create package android.content.pm inside src/main and add the below two files.
IPackageStatsObserver.aidl
package android.content.pm;

import android.content.pm.PackageStats;
/**
 * API for package data change related callbacks from the Package Manager.
 * Some usage scenarios include deletion of cache directory, generate
 * statistics related to code, data, cache usage(TODO)
 * {@hide}
 */
oneway interface IPackageStatsObserver {

    void onGetStatsCompleted(in PackageStats pStats, boolean succeeded);
}

PackageStats.aidl
package android.content.pm;
parcelable PackageStats;


Here is the snap for my project structure:




2. Create Class AppDetails.java to get installed package list.

AppDetails.java
import android.app.Activity;
import android.content.pm.PackageInfo;
import android.graphics.drawable.Drawable;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by mukeshk on 6/17/2016.
 */

    public class AppDetails {
        Activity mActivity;
        public ArrayList<PackageInfoStruct> res new ArrayList<PackageInfoStruct>();
        public ListView list;
        public String app_labels[];

        public AppDetails(Activity mActivity) {
            this.mActivity = mActivity;

        }

        public ArrayList<PackageInfoStruct> getPackages() {
            ArrayList<PackageInfoStruct> apps = getInstalledApps(false);
            final int max = apps.size();
            for (int i = 0; i < max; i++) {
                apps.get(i);
            }
            return apps;
        }

        private ArrayList<PackageInfoStruct> getInstalledApps(boolean getSysPackages) {

            List<PackageInfo> packs = mActivity.getPackageManager()
                    .getInstalledPackages(0);
            try {
                app_labels new String[packs.size()];
            } catch (Exception e) {
                Toast.makeText(mActivity.getApplicationContext(), e.getMessage(),
                        Toast.LENGTH_SHORT).show();
            }
            for (int i = 0; i < packs.size(); i++) {
                PackageInfo p = packs.get(i);
                if ((!getSysPackages) && (p.versionName == null)) {
                    continue;
                }
                PackageInfoStruct newInfo = new PackageInfoStruct();
                newInfo.appname = p.applicationInfo.loadLabel(
                        mActivity.getPackageManager()).toString();
                newInfo.pname = p.packageName;
                newInfo.datadir = p.applicationInfo.dataDir;
                newInfo.versionName = p.versionName;
                newInfo.versionCode = p.versionCode;
                newInfo.icon = p.applicationInfo.loadIcon(mActivity
                        .getPackageManager());
                res.add(newInfo);

                app_labels[i] = newInfo.appname;
            }
            return res;
        }

        class PackageInfoStruct {
            String appname "";
            String pname "";
            String versionName "";
            int versionCode 0;
            Drawable icon;
            String datadir "";
        }

3. Create class by extending IPackageStatsObserver.Stub.
 I have created separate class StorageInformation which will have getpackageSize method to execute the code to calculate cache and another data. One inner class cachePackState have to create by extending IPackageStatsObserver.Stub. Here we have to onGetStatsCompleted method. Here is the complete code: 

StorageInformation.java

import android.app.Activity;
import android.content.Context;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.os.RemoteException;
import android.util.Log;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * This class will perform data operation
 */
public class StorageInformation {

    long packageSize 0;
    AppDetails cAppDetails;
    public ArrayList<AppDetails.PackageInfoStruct> res;
    Context context;

    public StorageInformation(Context context){
        this.context=context;
    }

    public void getpackageSize() {
        cAppDetails new AppDetails((Activity) context);
        res cAppDetails.getPackages();
        if (res == null)
            return;
        for (int m = 0; m < res.size(); m++) {
            // Create object to access Package Manager
            PackageManager pm = context.getPackageManager();
            Method getPackageSizeInfo;
            try {
                getPackageSizeInfo = pm.getClass().getMethod(
                        "getPackageSizeInfo", String.class,
                        IPackageStatsObserver.class);
                getPackageSizeInfo.invoke(pm, res.get(m).pname,
                        new cachePackState()); //Call the inner class
            catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
/*
* Inner class which will get the data size for application
* */
    private class cachePackState extends IPackageStatsObserver.Stub {
        @Override
        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
                throws RemoteException {
            Log.w("Package Name", pStats.packageName "");
            Log.i("Cache Size", pStats.cacheSize "");
            Log.v("Data Size", pStats.dataSize "");
            packageSize = pStats.dataSize + pStats.cacheSize;
            Log.v("Total Cache Size"" " packageSize);
            Log.v("APK Size",pStats.codeSize+"");
        }
    }
}

Here I’m only logging the output data. You can display in list view with custom adapter.

Note: It may not work if in future the method name change or any thing changed in 
IPackageStatsObserver.Stub.

4. Use getPackageSizeInfo method to get data.

I have just called the getPackageSize method from MainActivity class. You can call call this method according to your project. 
MainActivity.java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Get the information of all the installed application data                 StorageInformation storageInformation = 
                                new  StorageInformation(MainActivity.this);
          storageInformation.getpackageSize();
   }
}

Run the application. The output can be seen in log. Here is the snap of AndroidMonitor with all data size logged. All the data unit is in byte. Please convert in to KB or MB according to your requirement. 


Please feel free to comment for any clarification or suggestion.















***

16 comments:

  1. Hello Mukesh, this is great and very understandable, sorry i'm still searching on how i can get uninstalled apps residual files. do you any knowledge of doing that in android programatically?

    ReplyDelete
  2. Bro you are life saver.
    Thanks
    Love you.

    ReplyDelete
  3. man you just saved me alot of work and research really thanks, i don't just know why the real function for doing this was deprecated in api 16 an no alternative was given

    ReplyDelete
  4. I truly delighted in perusing your article. I discovered this as an instructive and fascinating post, so I think it is extremely helpful and learned. I might want to thank you for the exertion you have made in composing this article
    please check this link

    ReplyDelete
  5. i love reading this article so beautiful!!great job! cyberflix tv apk for pc

    ReplyDelete
  6. Nice to be visiting your blog again, it has been months for me. Well this article that i’ve been waited for so long. I need this article to complete my assignment in the college, and it has same topic with your article. Thanks, great share. charlies-magazines.com

    ReplyDelete
  7. hi
    thank you
    i did all of these steps but didn't work for me.
    is there source of project in GitHub?
    because of some java files shown in your snap of project structure.

    ReplyDelete
  8. notwork
    java.lang.reflect.InvocationTargetException

    java.lang.UnsupportedOperationException: Shame on you for calling the hidden API getPackageSizeInfoAsUser(). Shame!

    ReplyDelete
  9. java.lang.UnsupportedOperationException: Shame on you for calling the hidden API getPackageSizeInfoAsUser(). Shame!

    ReplyDelete
    Replies
    1. Hello, I faced same problem. Did you understand that how to solve your problem ?

      Delete
    2. Hello, I faced same problem. Did you understand that how to solve your problem ?

      Delete
  10. Hi friend i have an error; IPackageStatsObserver.Stub returns error application couln't find "IPackageStatsObserver". Import IPackageStatsObserver returns error. Could you help me please?

    import android.content.pm.IPackageStatsObserver; // not working

    ReplyDelete
  11. A great degree energizing article thanks for sharing it to each one of us. Looking forward to more information and you have continually intrigued me.
    Best Info

    ReplyDelete
  12. Thanks for according to critical information including all of us. It was surprisingly soft to work. I absolutely like your opinions. I personally relish your work. Your article is very practical and helpful for us.
    click Here

    ReplyDelete
  13. Your posts are really inspiring and useful. I think you deserve better attention on Google search rankings.
    visit here Please

    ReplyDelete