optimize icon pack loading with laziness

This commit is contained in:
f43nd1r 2019-06-24 18:26:47 +02:00
parent 87d16ab200
commit 57a5da4901

View file

@ -13,17 +13,14 @@ import android.graphics.drawable.Drawable;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import android.util.Xml; import android.util.Xml;
import net.pierrox.lightning_launcher.configuration.ShortcutConfig; import net.pierrox.lightning_launcher.configuration.ShortcutConfig;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
public class IconPack { public class IconPack {
@ -82,6 +79,214 @@ public class IconPack {
page.reload(); page.reload();
} }
private static class LegacyIconPackResIdFetcher {
private final Resources resources;
private final String packageName;
private List<String> iconNames;
private final Map<ComponentName, Integer> cache = new HashMap<>();
private LegacyIconPackResIdFetcher(Resources resources, String packageName) {
this.resources = resources;
this.packageName = packageName;
}
private List<String> 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<String, String> items = new TreeMap<>();
private final List<String> 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<Bitmap> iconBackCache;
private Bitmap iconUponCache;
private Bitmap iconMaskCache;
private final Map<ComponentName, Integer> 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<Bitmap> 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") @SuppressLint("DefaultLocale")
private static boolean doApplyIconPackInBackground(final Context context, final String package_name, final Page page, final int item_id) { private static boolean doApplyIconPackInBackground(final Context context, final String package_name, final Page page, final int item_id) {
Context icon_pack; Context icon_pack;
@ -92,110 +297,8 @@ public class IconPack {
} }
Resources res = icon_pack.getResources(); Resources res = icon_pack.getResources();
int icon_pack_res_id = res.getIdentifier("icon_pack", "array", package_name); LegacyIconPackResIdFetcher legacyIconPackResIdFetcher = new LegacyIconPackResIdFetcher(res, package_name);
AppFilterIconPackResIdFetcher appFilterIconPackResIdFetcher = new AppFilterIconPackResIdFetcher(icon_pack, package_name);
// build the cache of icon name -> drawable id (legacy way)
HashMap<String, Integer> icon_name_ids = new HashMap<String, Integer>();
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<String, Integer> component_name_ids = new HashMap<String, Integer>();
ArrayList<Bitmap> icon_effect_back = new ArrayList<Bitmap>();
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) {}
}
// File pages_dir = FileUtils.getPagesDir(Customize.this); // File pages_dir = FileUtils.getPagesDir(Customize.this);
// String[] pages = pages_dir.list(); // String[] pages = pages_dir.list();
@ -224,6 +327,7 @@ public class IconPack {
// } catch (Exception e) { // } catch (Exception e) {
// // pass // // pass
// } // }
List<Bitmap> icon_effect_back = appFilterIconPackResIdFetcher.getIconBacks();
File icon_dir = page.getAndCreateIconDir(); File icon_dir = page.getAndCreateIconDir();
icon_dir.mkdirs(); icon_dir.mkdirs();
@ -231,8 +335,10 @@ public class IconPack {
File icon_effect_back_file = new File(icon_dir, "b"); 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(); 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"); 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(); 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"); 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(); if (icon_effect_mask != null) saveBitmapToFile(icon_effect_mask, icon_effect_mask_file); else icon_effect_mask_file.delete();
page.setModified(); page.setModified();
@ -251,21 +357,9 @@ public class IconPack {
ComponentName cn = s.getIntent().getComponent(); ComponentName cn = s.getIntent().getComponent();
if(cn != null) { if(cn != null) {
// try to get an id through the appfilter way // 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) { 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) drawable_id = legacyIconPackResIdFetcher.tryFindDrawableIdForComponent(cn);
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);
}
}
} }
if(drawable_id != null) { if(drawable_id != null) {
@ -304,7 +398,7 @@ public class IconPack {
} else if(icon_effect_back.size() > 1) { } else if(icon_effect_back.size() > 1) {
Bitmap bitmap = icon_effect_back.get((n++)%icon_effect_back.size()); Bitmap bitmap = icon_effect_back.get((n++)%icon_effect_back.size());
saveBitmapToFile(bitmap, ShortcutConfig.getIconBackFile(icon_dir, s.getId())); saveBitmapToFile(bitmap, ShortcutConfig.getIconBackFile(icon_dir, s.getId()));
s.modifyShortcutConfig().iconEffectScale = icon_effect_scale; s.modifyShortcutConfig().iconEffectScale = appFilterIconPackResIdFetcher.getScale();
} }
} }
} }