From 57a5da4901ca28aa47bba9c6b846719d3d2e6ce0 Mon Sep 17 00:00:00 2001 From: f43nd1r Date: Mon, 24 Jun 2019 18:26:47 +0200 Subject: [PATCH] optimize icon pack loading with laziness --- .../lightning_launcher/data/IconPack.java | 340 +++++++++++------- 1 file changed, 217 insertions(+), 123 deletions(-) diff --git a/app/llx/core/src/main/java/net/pierrox/lightning_launcher/data/IconPack.java b/app/llx/core/src/main/java/net/pierrox/lightning_launcher/data/IconPack.java index bbe3541..7b83da3 100644 --- a/app/llx/core/src/main/java/net/pierrox/lightning_launcher/data/IconPack.java +++ b/app/llx/core/src/main/java/net/pierrox/lightning_launcher/data/IconPack.java @@ -13,17 +13,14 @@ import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.util.Log; import android.util.Xml; - import net.pierrox.lightning_launcher.configuration.ShortcutConfig; - import org.xmlpull.v1.XmlPullParser; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; +import java.util.*; public class IconPack { @@ -82,6 +79,214 @@ public class IconPack { page.reload(); } + private static class LegacyIconPackResIdFetcher { + private final Resources resources; + private final String packageName; + private List iconNames; + private final Map cache = new HashMap<>(); + + private LegacyIconPackResIdFetcher(Resources resources, String packageName) { + this.resources = resources; + this.packageName = packageName; + } + + private List getIconNames() { + if (iconNames == null) { + int iconPackResId = resources.getIdentifier("icon_pack", "array", packageName); + if (iconPackResId != 0) { + iconNames = Arrays.asList(resources.getStringArray(iconPackResId)); + } else { + iconNames = new ArrayList<>(); + } + } + return iconNames; + } + + public Integer tryFindDrawableIdForComponent(ComponentName cn) { + if (cache.containsKey(cn)) { + return cache.get(cn); + } + // try to find an id, either with or without the activity name (try with the activity name first, otherwise try only the package) + String className = cn.getClassName(); + String iconName = className.replace('.', '_').toLowerCase(); + Integer drawableId = getDrawableIdForName(iconName); + if (drawableId == null) { + int pos = className.lastIndexOf('.') + 1; // if not found will produce 0 which is fine + iconName = (cn.getPackageName() + "_" + className.substring(pos)).replace('.', '_').toLowerCase(); + drawableId = getDrawableIdForName(iconName); + if (drawableId == null) { + iconName = cn.getPackageName().replace('.', '_').toLowerCase(); + drawableId = getDrawableIdForName(iconName); + } + } + if (drawableId != null) { + cache.put(cn, drawableId); + } + return drawableId; + } + + private Integer getDrawableIdForName(String iconName) { + if (getIconNames().contains(iconName)) { + try { + return resources.getIdentifier(iconName, "drawable", packageName); + } catch (Resources.NotFoundException e) { + // pass, error in input array + } + } + return null; + } + + + } + + private static class AppFilterIconPackResIdFetcher { + private final Map items = new TreeMap<>(); + private final List iconBacks = new ArrayList<>(); + private final Resources resources; + private final String packageName; + private String iconUpon = null; + private String iconMask = null; + private float scale = 1; + private List iconBackCache; + private Bitmap iconUponCache; + private Bitmap iconMaskCache; + private final Map itemCache = new TreeMap<>(); + + public AppFilterIconPackResIdFetcher(Context iconPack, String packageName) { + this.resources = iconPack.getResources(); + this.packageName = packageName; + InputStream appfilterStream = null; + try { + XmlPullParser parser; + int appfilter_id = resources.getIdentifier("appfilter", "xml", packageName); + if(appfilter_id != 0) { + parser = resources.getXml(appfilter_id); + } else { + try { + appfilterStream = iconPack.getAssets().open("appfilter.xml"); + parser = Xml.newPullParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); + parser.setInput(appfilterStream, null); + } catch(IOException e) { + parser = null; + } + } + if(parser != null) { + int eventType = parser.next(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + String name = parser.getName(); + switch (name) { + case "iconback": { + String n = parser.getAttributeValue(null, "img"); + if (n == null) { + for (int i = 1; i < 30; i++) { + n = parser.getAttributeValue(null, "img" + i); + if (n == null) { + break; + } + iconBacks.add(n); + } + } else { + iconBacks.add(n); + } + break; + } + case "iconupon": { + String n = parser.getAttributeValue(null, "img"); + if (n == null) { + n = parser.getAttributeValue(null, "img1"); + } + iconUpon = n; + break; + } + case "iconmask": { + String n = parser.getAttributeValue(null, "img"); + if (n == null) { + n = parser.getAttributeValue(null, "img1"); + } + iconMask = n; + break; + } + case "scale": + scale = Float.parseFloat(parser.getAttributeValue(null, "factor")); + break; + case "item": + String component = parser.getAttributeValue(null, "component"); + String drawable = parser.getAttributeValue(null, "drawable"); + try { + int start = component.indexOf('{') + 1; + String componentName = component.substring(start, component.lastIndexOf('}')); + if (componentName.indexOf('/', start) == -1) { + componentName = componentName.substring(0, componentName.lastIndexOf('.') - 1) + "/" + componentName; + } + items.put(componentName, drawable); + } catch (Exception e) { + Log.i("LL", "unable to decode " + component); + // pass, error in input array + } + break; + } + } + eventType = parser.next(); + } + } + } catch (Exception e1) { + e1.printStackTrace(); + } finally { + if(appfilterStream != null) try { appfilterStream.close(); } catch (IOException e) {} + } + } + + public List getIconBacks() { + if(iconBackCache == null) { + iconBackCache = new ArrayList<>(); + for (String iconBack : iconBacks) { + Bitmap b = loadBitmapFromDrawable(resources, packageName, iconBack); + if(b != null) { + iconBackCache.add(b); + } + } + } + return iconBackCache; + } + + public Bitmap getIconUpon() { + if(iconUponCache == null && iconUpon != null) { + iconUponCache = loadBitmapFromDrawable(resources, packageName, iconUpon); + } + return iconUponCache; + } + + public Bitmap getIconMask() { + if(iconMaskCache == null && iconMask != null) { + iconMaskCache = loadBitmapFromDrawable(resources, packageName, iconMask); + } + return iconMaskCache; + } + + public float getScale() { + return scale; + } + + public Integer tryFindDrawableIdForComponent(ComponentName cn) { + if(itemCache.containsKey(cn)) { + return itemCache.get(cn); + } + Integer drawableId = null; + String flatten = cn.flattenToString(); + if(items.containsKey(flatten)) { + drawableId = resources.getIdentifier(items.get(flatten), "drawable", packageName); + } + if(drawableId != null) { + itemCache.put(cn, drawableId); + } + return drawableId; + } + + + } + @SuppressLint("DefaultLocale") private static boolean doApplyIconPackInBackground(final Context context, final String package_name, final Page page, final int item_id) { Context icon_pack; @@ -92,110 +297,8 @@ public class IconPack { } Resources res = icon_pack.getResources(); - int icon_pack_res_id = res.getIdentifier("icon_pack", "array", package_name); - - // build the cache of icon name -> drawable id (legacy way) - HashMap icon_name_ids = new HashMap(); - if(icon_pack_res_id != 0) { - String[] icon_names = res.getStringArray(icon_pack_res_id); - for(String icon_name : icon_names) { - try { - int drawable_res_id = res.getIdentifier(icon_name, "drawable", package_name); - if(drawable_res_id != 0) icon_name_ids.put(icon_name, Integer.valueOf(drawable_res_id)); - } catch(Resources.NotFoundException e) { - // pass, error in input array - } - } - } - - // build the cache of componentname -> drawable id and load icon layers if available - HashMap component_name_ids = new HashMap(); - ArrayList icon_effect_back = new ArrayList(); - Bitmap icon_effect_over=null, icon_effect_mask=null; - float icon_effect_scale = 1; - InputStream appfilter_is = null; - try { - XmlPullParser parser; - int appfilter_id = icon_pack.getResources().getIdentifier("appfilter", "xml", package_name); - if(appfilter_id != 0) { - parser = icon_pack.getResources().getXml(appfilter_id); - } else { - try { - appfilter_is = icon_pack.getAssets().open("appfilter.xml"); - parser = Xml.newPullParser(); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); - parser.setInput(appfilter_is, null); - } catch(IOException e) { - parser = null; - } - } - - if(parser == null) { - return false; - } - - int eventType = parser.next(); - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG) { - String name = parser.getName(); - if (name.equals("iconback")) { - String n = parser.getAttributeValue(null, "img"); - if(n == null) { - for(int i=1; i<30; i++) { - n = parser.getAttributeValue(null, "img"+i); - if(n == null) { - break; - } - Bitmap b = loadBitmapFromDrawable(res, package_name, n); - if(b != null) { - icon_effect_back.add(b); - } - } - } else { - Bitmap b = loadBitmapFromDrawable(res, package_name, n); - if(b != null) { - icon_effect_back.add(b); - } - } - } else if (name.equals("iconupon")) { - String n = parser.getAttributeValue(null, "img"); - if(n == null) { - n = parser.getAttributeValue(null, "img1"); - } - icon_effect_over = loadBitmapFromDrawable(res, package_name, n); - } else if (name.equals("iconmask")) { - String n = parser.getAttributeValue(null, "img"); - if(n == null) { - n = parser.getAttributeValue(null, "img1"); - } - icon_effect_mask = loadBitmapFromDrawable(res, package_name, n); - } else if (name.equals("scale")) { - icon_effect_scale = Float.parseFloat(parser.getAttributeValue(null, "factor")); - } else if (name.equals("item")) { - String component = parser.getAttributeValue(null, "component"); - String drawable = parser.getAttributeValue(null, "drawable"); - try { - String component_name = component.substring(component.indexOf('{')+1, component.indexOf('}')); - if(component_name.indexOf('/') == -1) { - component_name = component_name.substring(0, component_name.lastIndexOf('.')-1) + "/" + component_name; - } - ComponentName cn = ComponentName.unflattenFromString(component_name); - - int drawable_res_id = res.getIdentifier(drawable, "drawable", package_name); - if(drawable_res_id != 0) component_name_ids.put(cn.flattenToString(), Integer.valueOf(drawable_res_id)); - } catch(Exception e) { - Log.i("LL", "unable to decode " + component); - // pass, error in input array - } - } - } - eventType = parser.next(); - } - } catch (Exception e1) { - e1.printStackTrace(); - } finally { - if(appfilter_is != null) try { appfilter_is.close(); } catch (IOException e) {} - } + LegacyIconPackResIdFetcher legacyIconPackResIdFetcher = new LegacyIconPackResIdFetcher(res, package_name); + AppFilterIconPackResIdFetcher appFilterIconPackResIdFetcher = new AppFilterIconPackResIdFetcher(icon_pack, package_name); // File pages_dir = FileUtils.getPagesDir(Customize.this); // String[] pages = pages_dir.list(); @@ -224,6 +327,7 @@ public class IconPack { // } catch (Exception e) { // // pass // } + List icon_effect_back = appFilterIconPackResIdFetcher.getIconBacks(); File icon_dir = page.getAndCreateIconDir(); icon_dir.mkdirs(); @@ -231,8 +335,10 @@ public class IconPack { File icon_effect_back_file = new File(icon_dir, "b"); if (icon_effect_back.size() > 0) saveBitmapToFile(icon_effect_back.get(0), icon_effect_back_file); else icon_effect_back_file.delete(); File icon_effect_over_file = new File(icon_dir, "o"); + Bitmap icon_effect_over = appFilterIconPackResIdFetcher.getIconUpon(); if (icon_effect_over != null) saveBitmapToFile(icon_effect_over, icon_effect_over_file); else icon_effect_over_file.delete(); File icon_effect_mask_file = new File(icon_dir, "m"); + Bitmap icon_effect_mask = appFilterIconPackResIdFetcher.getIconMask(); if (icon_effect_mask != null) saveBitmapToFile(icon_effect_mask, icon_effect_mask_file); else icon_effect_mask_file.delete(); page.setModified(); @@ -251,21 +357,9 @@ public class IconPack { ComponentName cn = s.getIntent().getComponent(); if(cn != null) { // try to get an id through the appfilter way - Integer drawable_id = component_name_ids.get(cn.flattenToString()); + Integer drawable_id = appFilterIconPackResIdFetcher.tryFindDrawableIdForComponent(cn); if(drawable_id == null) { - // try to find an id, either with or without the activity name (try with the activty name first, otherwise try only the package) - String class_name = cn.getClassName(); - String icon_name = class_name.replace('.', '_').toLowerCase(); - drawable_id = icon_name_ids.get(icon_name); - if(drawable_id == null) { - int pos = class_name.lastIndexOf('.')+1; // if not found will produce 0 which is fine - icon_name = (cn.getPackageName()+"_"+class_name.substring(pos)).replace('.', '_').toLowerCase(); - drawable_id = icon_name_ids.get(icon_name); - if(drawable_id == null) { - icon_name = cn.getPackageName().replace('.', '_').toLowerCase(); - drawable_id = icon_name_ids.get(icon_name); - } - } + drawable_id = legacyIconPackResIdFetcher.tryFindDrawableIdForComponent(cn); } if(drawable_id != null) { @@ -304,7 +398,7 @@ public class IconPack { } else if(icon_effect_back.size() > 1) { Bitmap bitmap = icon_effect_back.get((n++)%icon_effect_back.size()); saveBitmapToFile(bitmap, ShortcutConfig.getIconBackFile(icon_dir, s.getId())); - s.modifyShortcutConfig().iconEffectScale = icon_effect_scale; + s.modifyShortcutConfig().iconEffectScale = appFilterIconPackResIdFetcher.getScale(); } } }