package com.ittianyu.mobileguard.engine; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageManager; import android.content.pm.PackageStats; import android.os.Environment; import android.os.RemoteException; import android.text.TextUtils; import com.ittianyu.mobileguard.domain.AppInfoBean; import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; /** * Created by yu on. * provide app info */ public class AppManagerEngine { /** * get the sd card free space * * @return the byte of free space */ public static long getSdCardFreeSpace() { File directory = Environment.getExternalStorageDirectory(); return directory.getFreeSpace(); } /** * get the rom free space * * @return the byte of free space */ public static long getRomFreeSpace() { File directory = Environment.getDataDirectory(); return directory.getFreeSpace(); } /** * get all installed app info * Attention: the app size is asynchronous. * so you can set a app info listener. * you can also set null for listener If you don't use the size info or don't care it. * @param context * @param listener will be call when app info get completed if not null. The timeout is 3s. It will be call whether success or not. * @return a AppInfoBean list. It would never be null. */ public static List<AppInfoBean> getInstalledAppInfo(Context context, final AppInfoListener listener) { // get manager PackageManager pm = context.getPackageManager(); // get all installed app info final List<ApplicationInfo> infos = pm.getInstalledApplications(PackageManager.GET_META_DATA); // use for counting the progress of getting size class CompletedCountBean { int completedCount; } final CompletedCountBean count = new CompletedCountBean(); // Create bean list. Here input the certain init count for list final List<AppInfoBean> appInfos = new ArrayList<>(infos.size()); // start a timer to manager the max wait time final Timer timer = new Timer(true); // if have listener, start it if (null != listener) { TimerTask timerTask = new TimerTask() { @Override public void run() { synchronized (count) { // change the cout first // prevent the if(count.completedCount == infos.size()) count.completedCount = -1; listener.onGetInfoCompleted(appInfos); } } }; timer.schedule(timerTask, 3000); } for (ApplicationInfo info : infos) { // new a AppInfoBean and add to list final AppInfoBean bean = new AppInfoBean(); appInfos.add(bean); // set value to bean bean.setIcon(info.loadIcon(pm)); bean.setName(info.loadLabel(pm).toString()); bean.setPackageName(info.packageName); // according to flag to check system and sd card app if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { // if have system flag, it is a system app, the value should be true bean.setSystemApp(true); }// if not have, it should be false. Actually it is. if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { // if have EXTERNAL_STORAGE flag, it is a sd card app, the value should be true bean.setSystemApp(true); }// if not have, it should be false. Actually it is. // get apk path bean.setApkPath(info.sourceDir); // get app size getAppSize(context, info.packageName, new AppSizeInfoListener() { @Override public void onGetSizeInfoCompleted(AppSizeInfo sizeInfo) { // set size long totalSize = sizeInfo.cacheSize + sizeInfo.codeSize + sizeInfo.dataSize; bean.setSize(totalSize); bean.setCacheSize(sizeInfo.cacheSize); // if listener is null, no need to call this if(null == listener) return; synchronized (count) { count.completedCount++; // if the all app size are got, call the listener if(count.completedCount == infos.size()) { // stop the timer first timer.cancel(); listener.onGetInfoCompleted(appInfos); } } } }); } return appInfos; } /** * get app size by package name * @param context * @param packageName package name * @param listener it will be call when success to get size */ public static void getAppSize(Context context, String packageName, final AppSizeInfoListener listener) { // check argument if(null == listener) { throw new NullPointerException("listener can't be null"); } if(TextUtils.isEmpty(packageName)) { throw new IllegalArgumentException("packageName can't be empty"); } // get pm PackageManager pm = context.getPackageManager(); Method getPackageSizeInfo = null; try { // get method getPackageSizeInfo getPackageSizeInfo = pm.getClass().getMethod( "getPackageSizeInfo", String.class, IPackageStatsObserver.class); // call method getPackageSizeInfo.invoke(pm, packageName, new IPackageStatsObserver.Stub() { @Override public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException { // call listener listener.onGetSizeInfoCompleted( new AppSizeInfo(pStats.cacheSize, pStats.dataSize, pStats.codeSize)); } }); } catch (Exception e) { e.printStackTrace(); } } /** * clear all app cache * @param context * @param listener the completion listener, it can be null if you don't care the result. * onClearCompleted run on child thread. * onClearFailed run on UI thread. */ public static void clearAllCache(Context context, final ClearCacheListener listener) { /* public void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer) { freeStorageAndNotify(null, freeStorageSize, observer); } */ PackageManager pm = context.getPackageManager(); try { Method freeStorageAndNotify = pm.getClass().getDeclaredMethod("freeStorageAndNotify", long.class, IPackageDataObserver.class); freeStorageAndNotify.invoke(pm, Long.MAX_VALUE, new IPackageDataObserver.Stub(){ @Override public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException { if(null != listener) listener.onClearCompleted(); } }); } catch (Exception e) { e.printStackTrace(); if(null != listener) listener.onClearFailed(); } } /** * will be call when clear completed */ public static interface ClearCacheListener { /** * will be call when success */ void onClearCompleted(); /** * will be call when failed */ void onClearFailed(); } /** * will be call when app info get completed */ public static interface AppInfoListener { void onGetInfoCompleted(List<AppInfoBean> apps); } /** * will be call when size info get completed */ public static interface AppSizeInfoListener { void onGetSizeInfoCompleted(AppSizeInfo sizeInfo); } /** * app size info bean */ public static class AppSizeInfo { private long cacheSize; private long dataSize; private long codeSize; public AppSizeInfo() { } public AppSizeInfo(long cacheSize, long dataSize, long codeSize) { this.cacheSize = cacheSize; this.dataSize = dataSize; this.codeSize = codeSize; } public long getCacheSize() { return cacheSize; } public void setCacheSize(long cacheSize) { this.cacheSize = cacheSize; } public long getDataSize() { return dataSize; } public void setDataSize(long dataSize) { this.dataSize = dataSize; } public long getCodeSize() { return codeSize; } public void setCodeSize(long codeSize) { this.codeSize = codeSize; } } }