1

I am trying to calculate apk file size of the installed applications. Here is the code

 public class PackageTabActivity extends ListActivity{

  private static final String APP_NAME = "app_name";
  private static final String APP_ICON = "app_icon";
  private static final String APP_SIZE = "app_size";
  Method getPackageSizeInfo = null;
  PackageManager pm  ;
@Override
public void onCreate(Bundle icicle){
    super.onCreate(icicle);
    pm = getPackageManager();


    try {
        getPackageSizeInfo = pm.getClass().getMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
    } catch (SecurityException e1) {

        e1.printStackTrace();
    } catch (NoSuchMethodException e1) {

        e1.printStackTrace();
    } 
    new AppDetails().execute();
}

private boolean isSystemPackage(PackageInfo pkgInfo) {
    return ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ? true
            : false;
}


class AppDetails extends AsyncTask<Void, Void, ArrayList<HashMap<String , Object>>>
{
     private  long   app_apk_size;
     ProgressDialog mDialog;
     @Override
     public void onPreExecute()
     {
             mDialog = new ProgressDialog(PackageTabActivity.this);
             mDialog.setCancelable(true);
             mDialog.setMessage("Loading... " );
             mDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
             mDialog.setProgress(0);
             mDialog.show();
     }
    @Override
    protected ArrayList<HashMap<String, Object>> doInBackground(
            Void... params) {

        ArrayList<HashMap<String,Object>> applistwithicon = new ArrayList<HashMap<String,Object>>();
        HashMap<String,Object> hm;
        String appname;
        Drawable icon = null;
        List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);   

        for(int i=0;i<packs.size();i++) {

            PackageInfo p = packs.get(i);


            if(!isSystemPackage(p))
            {
                hm = new HashMap<String, Object>();
                appname = p.applicationInfo.loadLabel(getPackageManager()).toString();

                icon = p.applicationInfo.loadIcon(getPackageManager());
                Log.v("package name", "package name =" + p.packageName);
                try {
                  getPackageSizeInfo.invoke(pm,  p.packageName, new IPackageStatsObserver.Stub()  {

                    public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException {

                                   app_apk_size = pStats.codeSize;    
                                   Log.v("apksize", "appsize = "+app_apk_size);
                    }           
            });
                }catch(IllegalAccessException e) {}
                catch(IllegalArgumentException r) {}
                catch(InvocationTargetException w){}

            hm.put(APP_SIZE, (app_apk_size/(1024)));
            hm.put(APP_ICON, icon);
            hm.put(APP_NAME, appname);
            applistwithicon.add(hm);
            }
        }

        return applistwithicon;
    }
    @Override
    public void onPostExecute(ArrayList<HashMap<String, Object>> result)
    {
        mDialog.dismiss();
         CustomAdapterList myAdapter = new CustomAdapterList(result,PackageTabActivity.this );

          setListAdapter(myAdapter);

    }
}
}

Here IPackageStatsObserver is an interface (aidl file). This gives me correct result on emulator but on phone. It gives mixture of right and wrong size of application.

I am now totally stuck and can't find any workaround.

Any help would be higly appreciated.

Sunny
  • 14,522
  • 15
  • 84
  • 129
  • Could you give more details about the incorrect result? When does the incorrect package size is got? Here you check if the app is system package, if yes, bypass the size check, why? As I've ever tested system app codeSize and always got ZERO. I am quite curious why system app codeSize could not be retrieved always. Is there any permission restriction or other cause? – user1391143 May 12 '12 at 14:20
  • Here the problem was that the codeSize of app may be calculated in different thread. So using `CountdownTimer` class we can wait untill the app size is calculated. I did not need to do anything with system app so i just left them. I don't know about any permission which restrict to calculate the system app size. We only require the GET_PACKAGE_SIZE permission to calculate the app size. – Sunny May 12 '12 at 16:58

3 Answers3

2
ApplicationInfo tmpInfo = context.getPackageManager().getApplicationInfo(packageName,-1);
long size = new File(tmpInfo.sourceDir).length();
Yan
  • 1,569
  • 18
  • 22
0

IPackageStatsObserver it is the very hard-level code, I use the code to archive apks size:

ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName, 0);
String sourceDir = appInfo.publicSourceDir;
File file = new File(sourceDir);
long bytes = file.length();      // main apk, devide 1024 to get KB, etc.

String[] splitSourceDirs = appInfo.splitPublicSourceDirs;
for(String str: splitSourceDirs){
    File file = new File (str);  // split apks, do the same to get size

Result: enter image description here

Alias
  • 39
  • 1
  • 4
0

Here is a hack from Joseph that worked for me. His original post can be found here

PackageManager pm = getPackageManager();

Method getPackageSizeInfo = pm.getClass().getMethod(
    "getPackageSizeInfo", String.class, IPackageStatsObserver.class);

getPackageSizeInfo.invoke(pm, "com.android.mms",
    new IPackageStatsObserver.Stub() {

        @Override
        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
            throws RemoteException {

            Log.i(TAG, "codeSize: " + pStats.codeSize);
        }
    });
Community
  • 1
  • 1
Semere Taézaz Sium
  • 4,036
  • 3
  • 21
  • 26