package com.fastaccess.helper; import android.app.Activity; import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.v4.app.Fragment; import android.text.TextUtils; import android.widget.Toast; import com.fastaccess.App; import com.fastaccess.R; import com.fastaccess.data.dao.events.ThemePackEventModel; import com.fastaccess.ui.adapter.IconPackAdapter; import com.fastaccess.data.dao.IconPackInfo; import org.greenrobot.eventbus.EventBus; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class IconPackHelper { public final static int PICK_ICON = 2001; static final String ICON_MASK_TAG = "iconmask"; static final String ICON_BACK_TAG = "iconback"; static final String ICON_UPON_TAG = "iconupon"; static final String ICON_SCALE_TAG = "scale"; final static String PLAY_STORE_PACKAGENAME = "com.android.vending"; final static String PLAY_STORE_SEARCH_URI = "market://search?q=icon+pack"; public final static String[] sSupportedActions = new String[]{ "org.adw.launcher.THEMES", "com.gau.go.launcherex.theme" }; public static final String[] sSupportedCategories = new String[]{ "com.fede.launcher.THEME_ICONPACK", "com.anddoes.launcher.THEME", "com.teslacoilsw.launcher.THEME" }; private Map<String, String> mIconPackResources; private final Context mContext; private String mLoadedIconPackName; private Resources mLoadedIconPackResource; private Drawable mIconBack, mIconUpon, mIconMask; private float mIconScale; public Drawable getIconBack() { return mIconBack; } public Drawable getIconMask() { return mIconMask; } public Drawable getIconUpon() { return mIconUpon; } public float getIconScale() { return mIconScale; } public IconPackHelper(Context context) { mContext = context; mIconPackResources = new HashMap<>(); } private Drawable getDrawableForName(String name) { if (isIconPackLoaded()) { String item = mIconPackResources.get(name); if (!TextUtils.isEmpty(item)) { int id = getResourceIdForDrawable(item); if (id != 0) { return mLoadedIconPackResource.getDrawable(id); } } } return null; } public static Map<String, IconPackInfo> getSupportedPackages(Context context) { Intent i = new Intent(); Map<String, IconPackInfo> packages = new HashMap<>(); PackageManager packageManager = context.getPackageManager(); for (String action : sSupportedActions) { i.setAction(action); for (ResolveInfo r : packageManager.queryIntentActivities(i, 0)) { IconPackInfo info = new IconPackInfo(r, packageManager); packages.put(r.activityInfo.packageName, info); } } i = new Intent(Intent.ACTION_MAIN); for (String category : sSupportedCategories) { i.addCategory(category); for (ResolveInfo r : packageManager.queryIntentActivities(i, 0)) { IconPackInfo info = new IconPackInfo(r, packageManager); packages.put(r.activityInfo.packageName, info); } i.removeCategory(category); } return packages; } private static void loadResourcesFromXmlParser(XmlPullParser parser, Map<String, String> iconPackResources) throws XmlPullParserException, IOException { int eventType = parser.getEventType(); do { if (eventType != XmlPullParser.START_TAG) { continue; } if (parser.getName().equalsIgnoreCase(ICON_MASK_TAG) || parser.getName().equalsIgnoreCase(ICON_BACK_TAG) || parser.getName().equalsIgnoreCase(ICON_UPON_TAG)) { List<String> icons = new ArrayList<>(); icons.add(parser.getAttributeValue(null, "img")); for (int i = 0; i < 10; i++) { icons.add(parser.getAttributeValue(null, "img" + i)); } for (String icon : icons) { if (icon == null) { if (parser.getAttributeCount() > 0) { for (int count = 0; count < parser.getAttributeCount(); count++) { icon = parser.getAttributeValue(count); iconPackResources.put(parser.getName().toLowerCase(), icon); } } } } continue; } if (parser.getName().equalsIgnoreCase(ICON_SCALE_TAG)) { String factor = parser.getAttributeValue(null, "factor"); if (factor == null) { if (parser.getAttributeCount() == 1) { factor = parser.getAttributeValue(0); } } iconPackResources.put(parser.getName().toLowerCase(), factor); continue; } if (!parser.getName().equalsIgnoreCase("item")) { continue; } String component = parser.getAttributeValue(null, "component"); String drawable = parser.getAttributeValue(null, "drawable"); // Validate component/drawable exist if (TextUtils.isEmpty(component) || TextUtils.isEmpty(drawable)) { continue; } // Validate format/length of component if (!component.startsWith("ComponentInfo{") || !component.endsWith("}") || component.length() < 16) { continue; } // Sanitize stored value component = component.substring(14, component.length() - 1).toLowerCase(); ComponentName name = null; if (!component.contains("/")) { // Package icon reference iconPackResources.put(component, drawable); } else { name = ComponentName.unflattenFromString(component); if (name != null) { iconPackResources.put(name.getPackageName(), drawable); iconPackResources.put(name.getPackageName() + "." + name.getClassName(), drawable); } } } while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT); } private static void loadApplicationResources(Context context, Map<String, String> iconPackResources, String packageName) { Field[] drawableItems = null; try { Context appContext = context.createPackageContext(packageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); drawableItems = Class.forName(packageName + ".R$drawable", true, appContext.getClassLoader()).getFields(); } catch (Exception e) { return; } for (Field f : drawableItems) { String name = f.getName(); String icon = name.toLowerCase(); name = name.replaceAll("_", "."); iconPackResources.put(name, icon); int activityIndex = name.lastIndexOf("."); if (activityIndex <= 0 || activityIndex == name.length() - 1) { continue; } String iconPackage = name.substring(0, activityIndex); if (TextUtils.isEmpty(iconPackage)) { continue; } iconPackResources.put(iconPackage, icon); String iconActivity = name.substring(activityIndex + 1); if (TextUtils.isEmpty(iconActivity)) { continue; } iconPackResources.put(iconPackage + "." + iconActivity, icon); } } public boolean loadIconPack(String packageName) { mIconPackResources = getIconPackResources(mContext, packageName); Resources res; try { res = mContext.getPackageManager().getResourcesForApplication(packageName); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return false; } mLoadedIconPackResource = res; mLoadedIconPackName = packageName; mIconBack = getDrawableForName(ICON_BACK_TAG); mIconMask = getDrawableForName(ICON_MASK_TAG); mIconUpon = getDrawableForName(ICON_UPON_TAG); String scale = mIconPackResources.get(ICON_SCALE_TAG); if (scale != null) { try { mIconScale = Float.valueOf(scale); } catch (NumberFormatException ignored) {} } return true; } public static Map<String, String> getIconPackResources(Context context, String packageName) { if (TextUtils.isEmpty(packageName)) { return null; } Resources res = null; try { res = context.getPackageManager().getResourcesForApplication(packageName); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return null; } XmlPullParser parser = null; InputStream inputStream = null; Map<String, String> iconPackResources = new HashMap<>(); try { inputStream = res.getAssets().open("appfilter.xml"); XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); parser = factory.newPullParser(); parser.setInput(inputStream, "UTF-8"); } catch (Exception e) { // Catch any exception since we want to fall back to parsing the xml/ // resource in all cases int resId = res.getIdentifier("appfilter", "xml", packageName); if (resId != 0) { parser = res.getXml(resId); } } if (parser != null) { try { loadResourcesFromXmlParser(parser, iconPackResources); return iconPackResources; } catch (XmlPullParserException | IOException e) { e.printStackTrace(); } finally { // Cleanup resources if (parser instanceof XmlResourceParser) { ((XmlResourceParser) parser).close(); } if (inputStream != null) { try { inputStream.close(); } catch (IOException ignored) {} } } } // Application uses a different theme format (most likely launcher pro) int arrayId = res.getIdentifier("theme_iconpack", "array", packageName); if (arrayId == 0) { arrayId = res.getIdentifier("icon_pack", "array", packageName); } if (arrayId != 0) { String[] iconPack = res.getStringArray(arrayId); for (String entry : iconPack) { if (TextUtils.isEmpty(entry)) { continue; } String icon = entry.toLowerCase(); entry = entry.replaceAll("_", "."); iconPackResources.put(entry, icon); int activityIndex = entry.lastIndexOf("."); if (activityIndex <= 0 || activityIndex == entry.length() - 1) { continue; } String iconPackage = entry.substring(0, activityIndex); if (TextUtils.isEmpty(iconPackage)) { continue; } iconPackResources.put(iconPackage, icon); String iconActivity = entry.substring(activityIndex + 1); if (TextUtils.isEmpty(iconActivity)) { continue; } iconPackResources.put(iconPackage + "." + iconActivity, icon); } } else { loadApplicationResources(context, iconPackResources, packageName); } return iconPackResources; } public void unloadIconPack() { mLoadedIconPackResource = null; mLoadedIconPackName = null; mIconPackResources = null; mIconMask = null; mIconBack = null; mIconUpon = null; mIconScale = 1f; } public static void pickIconPack(final Fragment context, final boolean pickIcon) { Map<String, IconPackInfo> supportedPackages = getSupportedPackages(context.getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(context.getContext(), R.style.AlertDialogStyle); if (supportedPackages.isEmpty()) { builder.setTitle(context.getString(R.string.get_themes)); builder.setMessage(R.string.no_icon_packs) .setPositiveButton(R.string.get_themes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(PLAY_STORE_SEARCH_URI)); context.startActivity(intent); } }).setNegativeButton(R.string.cancel, null) .show(); return; } final IconPackAdapter adapter = new IconPackAdapter(context.getContext(), supportedPackages, pickIcon); if (!pickIcon) { builder.setTitle(R.string.choose_theme_pack); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int position) { if (adapter.isCurrentIconPack(position)) { return; } String selectedPackage = adapter.getItem(position); PrefHelper.set(PrefConstant.ICON_PACK, selectedPackage); App.getInstance().flushIconPack(); EventBus.getDefault().post(new ThemePackEventModel()); } }).setPositiveButton(context.getString(R.string.get_themes), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { try { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(PLAY_STORE_SEARCH_URI)); context.startActivity(intent); } catch (Exception e) { e.printStackTrace(); } } }); } else { builder.setTitle(R.string.choose_icon); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == 0) { Intent intent = new Intent(); intent.putExtra("default", true); context.onActivityResult(PICK_ICON, Activity.RESULT_CANCELED, intent); } else { String selectedPackage = adapter.getItem(which); try { Intent i = new Intent(); i.setPackage(selectedPackage); i.setAction("org.adw.launcher.icons.ACTION_PICK_ICON"); i.putExtra("package", selectedPackage); context.startActivityForResult(i, PICK_ICON); } catch (Exception e) { Toast.makeText(context.getContext(), context.getString(R.string.not_support_icon_theme), Toast.LENGTH_LONG).show(); } } } }); } builder.show(); } public boolean isIconPackLoaded() { return mLoadedIconPackResource != null && mLoadedIconPackName != null && mIconPackResources != null; } private int getResourceIdForDrawable(String resource) { return mLoadedIconPackResource.getIdentifier(resource, "drawable", mLoadedIconPackName); } public Resources getIconPackResources() { return mLoadedIconPackResource; } public int getResourceIdForActivityIcon(ActivityInfo info) { String drawable = mIconPackResources.get(info.packageName.toLowerCase() + "." + info.name.toLowerCase()); if (drawable == null) { // Icon pack doesn't have an icon for the activity, fallback to package icon drawable = mIconPackResources.get(info.packageName.toLowerCase()); if (drawable == null) { return 0; } } return getResourceIdForDrawable(drawable); } }