package biz.bokhorst.xprivacy; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; @SuppressLint("DefaultLocale") public class ApplicationInfoEx implements Comparable<ApplicationInfoEx> { private int mUid; private TreeMap<String, ApplicationInfo> mMapAppInfo = null; private Map<String, PackageInfo> mMapPkgInfo = new HashMap<String, PackageInfo>(); // Cache private Boolean mInternet = null; private Boolean mFrozen = null; private long mInstallTime = -1; private long mUpdateTime = -1; public static final int STATE_ATTENTION = 0; public static final int STATE_CHANGED = 1; public static final int STATE_SHARED = 2; public ApplicationInfoEx(Context context, int uid) { mUid = uid; mMapAppInfo = new TreeMap<String, ApplicationInfo>(); PackageManager pm = context.getPackageManager(); String[] packages = pm.getPackagesForUid(uid); if (packages != null) for (String packageName : packages) try { ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0); mMapAppInfo.put(pm.getApplicationLabel(appInfo).toString(), appInfo); } catch (NameNotFoundException ignored) { } } public static List<ApplicationInfoEx> getXApplicationList(Context context, ProgressDialog dialog) { // Get references PackageManager pm = context.getPackageManager(); // Get app list SparseArray<ApplicationInfoEx> mapApp = new SparseArray<ApplicationInfoEx>(); List<ApplicationInfoEx> listApp = new ArrayList<ApplicationInfoEx>(); List<ApplicationInfo> listAppInfo = pm.getInstalledApplications(PackageManager.GET_META_DATA); if (dialog != null) dialog.setMax(listAppInfo.size()); for (int app = 0; app < listAppInfo.size(); app++) { if (dialog != null) dialog.setProgress(app + 1); ApplicationInfo appInfo = listAppInfo.get(app); Util.log(null, Log.INFO, "package=" + appInfo.packageName + " uid=" + appInfo.uid); ApplicationInfoEx appInfoEx = new ApplicationInfoEx(context, appInfo.uid); if (mapApp.get(appInfoEx.getUid()) == null) { mapApp.put(appInfoEx.getUid(), appInfoEx); listApp.add(appInfoEx); } } // Sort result Collections.sort(listApp); return listApp; } public ArrayList<String> getApplicationName() { return new ArrayList<String>(mMapAppInfo.navigableKeySet()); } public String getApplicationName(String packageName) { for (Entry<String, ApplicationInfo> entry : mMapAppInfo.entrySet()) if (entry.getValue().packageName.equals(packageName)) return entry.getKey(); return ""; } public List<String> getPackageName() { List<String> listPackageName = new ArrayList<String>(); for (ApplicationInfo appInfo : mMapAppInfo.values()) listPackageName.add(appInfo.packageName); return listPackageName; } private void getPackageInfo(Context context, String packageName) throws NameNotFoundException { PackageManager pm = context.getPackageManager(); mMapPkgInfo.put(packageName, pm.getPackageInfo(packageName, 0)); } public List<String> getPackageVersionName(Context context) { List<String> listVersionName = new ArrayList<String>(); for (String packageName : this.getPackageName()) try { getPackageInfo(context, packageName); String version = mMapPkgInfo.get(packageName).versionName; if (version == null) listVersionName.add("???"); else listVersionName.add(version); } catch (NameNotFoundException ex) { listVersionName.add(ex.getMessage()); } return listVersionName; } public String getPackageVersionName(Context context, String packageName) { try { getPackageInfo(context, packageName); String version = mMapPkgInfo.get(packageName).versionName; if (version == null) return "???"; else return version; } catch (NameNotFoundException ex) { return ex.getMessage(); } } public List<Integer> getPackageVersionCode(Context context) { List<Integer> listVersionCode = new ArrayList<Integer>(); for (String packageName : this.getPackageName()) try { getPackageInfo(context, packageName); listVersionCode.add(mMapPkgInfo.get(packageName).versionCode); } catch (NameNotFoundException ex) { listVersionCode.add(0); } return listVersionCode; } public Drawable getIcon(Context context) { // Pick first icon if (mMapAppInfo.size() > 0) return mMapAppInfo.firstEntry().getValue().loadIcon(context.getPackageManager()); else return new ColorDrawable(Color.TRANSPARENT); } public Bitmap getIconBitmap(Context context) { if (mMapAppInfo.size() > 0) { try { final ApplicationInfo appInfo = mMapAppInfo.firstEntry().getValue(); if (appInfo.icon == 0) appInfo.icon = android.R.drawable.sym_def_app_icon; final Resources resources = context.getPackageManager().getResourcesForApplication(appInfo); final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(resources, appInfo.icon, options); final int pixels = Math.round(Util.dipToPixels(context, 48)); options.inSampleSize = Util.calculateInSampleSize(options, pixels, pixels); options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(resources, appInfo.icon, options); } catch (NameNotFoundException ex) { Util.bug(null, ex); return null; } } else return null; } public boolean hasInternet(Context context) { if (mInternet == null) { mInternet = false; PackageManager pm = context.getPackageManager(); for (ApplicationInfo appInfo : mMapAppInfo.values()) if (pm.checkPermission("android.permission.INTERNET", appInfo.packageName) == PackageManager.PERMISSION_GRANTED) { mInternet = true; break; } } return mInternet; } public boolean isFrozen(Context context) { if (mFrozen == null) { PackageManager pm = context.getPackageManager(); boolean enabled = false; for (ApplicationInfo appInfo : mMapAppInfo.values()) try { int setting = pm.getApplicationEnabledSetting(appInfo.packageName); enabled = (enabled || setting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); enabled = (enabled || setting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED); if (enabled) break; } catch (IllegalArgumentException ignored) { } mFrozen = !enabled; } return mFrozen; } public int getUid() { return mUid; } @SuppressLint("FieldGetter") public int getState(Context context) { return Integer.parseInt(PrivacyManager.getSetting(-getUid(), PrivacyManager.cSettingState, Integer.toString(STATE_CHANGED))); } public long getInstallTime(Context context) { if (mInstallTime == -1) { long now = System.currentTimeMillis(); mInstallTime = now; for (String packageName : this.getPackageName()) try { getPackageInfo(context, packageName); long time = mMapPkgInfo.get(packageName).firstInstallTime; if (time < mInstallTime) mInstallTime = time; } catch (NameNotFoundException ex) { } if (mInstallTime == now) // no install time, so assume it is old mInstallTime = 0; } return mInstallTime; } public long getUpdateTime(Context context) { if (mUpdateTime == -1) { mUpdateTime = 0; for (String packageName : this.getPackageName()) try { getPackageInfo(context, packageName); long time = mMapPkgInfo.get(packageName).lastUpdateTime; if (time > mUpdateTime) mUpdateTime = time; } catch (NameNotFoundException ex) { } } return mUpdateTime; } @SuppressLint("FieldGetter") public long getModificationTime(Context context) { return Long.parseLong(PrivacyManager.getSetting(-getUid(), PrivacyManager.cSettingModifyTime, "0")); } public boolean isSystem() { boolean mSystem = false; for (ApplicationInfo appInfo : mMapAppInfo.values()) { mSystem = ((appInfo.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0); mSystem = mSystem || appInfo.packageName.equals(this.getClass().getPackage().getName()); mSystem = mSystem || appInfo.packageName.equals(this.getClass().getPackage().getName() + ".pro"); mSystem = mSystem || appInfo.packageName.equals("de.robv.android.xposed.installer"); } return mSystem; } public boolean isShared() { for (ApplicationInfo appInfo : mMapAppInfo.values()) if (PrivacyManager.isShared(appInfo.uid)) return true; return false; } public boolean isIsolated() { for (ApplicationInfo appInfo : mMapAppInfo.values()) if (PrivacyManager.isIsolated(appInfo.uid)) return true; return false; } @Override @SuppressLint("FieldGetter") public String toString() { return String.format("%d %s", getUid(), TextUtils.join(", ", getApplicationName())); } @Override public int compareTo(ApplicationInfoEx other) { // Locale respecting sorter Collator collator = Collator.getInstance(Locale.getDefault()); return collator.compare(TextUtils.join(", ", getApplicationName()), TextUtils.join(", ", other.getApplicationName())); } }