package com.fastaccess.provider.icon;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
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.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.support.v4.content.res.ResourcesCompat;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import com.fastaccess.data.dao.AppsModel;
import com.fastaccess.helper.IconPackHelper;
import com.fastaccess.helper.PrefConstant;
import com.fastaccess.helper.PrefHelper;
import java.util.HashMap;
/**
* Cache of application icons. Icons can be made from any thread.
*/
public class IconCache {
private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
private static class CacheEntry {
public Bitmap icon;
public String title;
}
private final Bitmap mDefaultIcon;
private final Context mContext;
private final PackageManager mPackageManager;
private final HashMap<ComponentName, CacheEntry> mCache = new HashMap<>(INITIAL_ICON_CACHE_CAPACITY);
private int mIconDpi;
private static int sIconWidth = -1;
private static int sIconHeight = -1;
public static int sIconTextureWidth = -1;
public static int sIconTextureHeight = -1;
private static final Paint sBlurPaint = new Paint();
private static final Paint sGlowColorPressedPaint = new Paint();
private static final Paint sGlowColorFocusedPaint = new Paint();
private static final Paint sDisabledPaint = new Paint();
private static final Rect sOldBounds = new Rect();
private static final Canvas sCanvas = new Canvas();
private IconPackHelper mIconPackHelper;
static {
sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, Paint.FILTER_BITMAP_FLAG));
}
public IconCache(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
mContext = context;
mPackageManager = context.getPackageManager();
mIconDpi = activityManager.getLauncherLargeIconDensity();
mDefaultIcon = makeDefaultIcon();
mIconPackHelper = new IconPackHelper(context);
loadIconPack();
}
public void getTitleAndIcon(AppsModel application, ResolveInfo info, HashMap<Object, CharSequence> labelCache) {
synchronized (mCache) {
CacheEntry entry = cacheLocked(application.getComponentName(), info, labelCache);
application.setAppName(entry.title);
application.setBitmap(entry.icon);
}
}
private void loadIconPack() {
mIconPackHelper.unloadIconPack();
String iconPack = PrefHelper.getString(PrefConstant.ICON_PACK);
if (!TextUtils.isEmpty(iconPack) && !mIconPackHelper.loadIconPack(iconPack)) {
PrefHelper.set(PrefConstant.ICON_PACK, "");
}
}
public Drawable getFullResDefaultActivityIcon() {
return getFullResIcon(Resources.getSystem(),
android.R.mipmap.sym_def_app_icon);
}
public Drawable getFullResIcon(Resources resources, int iconId) {
Drawable d;
try {
d = ResourcesCompat.getDrawableForDensity(resources, iconId, mIconDpi, mContext.getTheme());
} catch (Resources.NotFoundException e) {
d = null;
}
return (d != null) ? d : getFullResDefaultActivityIcon();
}
public Drawable getFullResIcon(String packageName, int iconId) {
Resources resources;
try {
resources = mPackageManager.getResourcesForApplication(packageName);
} catch (PackageManager.NameNotFoundException e) {
resources = null;
}
if (resources != null) {
if (iconId != 0) {
return getFullResIcon(resources, iconId);
}
}
return getFullResDefaultActivityIcon();
}
public Drawable getFullResIcon(ResolveInfo info) {
return getFullResIcon(info.activityInfo);
}
public Drawable getFullResIcon(ActivityInfo info) {
Resources resources;
try {
resources = mPackageManager.getResourcesForApplication(info.applicationInfo);
} catch (PackageManager.NameNotFoundException e) {
resources = null;
}
if (resources != null) {
int iconId = 0;
if (mIconPackHelper != null && mIconPackHelper.isIconPackLoaded()) {
iconId = mIconPackHelper.getResourceIdForActivityIcon(info);
if (iconId != 0) {
return getFullResIcon(mIconPackHelper.getIconPackResources(), iconId);
}
}
iconId = info.getIconResource();
if (iconId != 0) {
return getFullResIcon(resources, iconId);
}
}
return getFullResDefaultActivityIcon();
}
private Bitmap makeDefaultIcon() {
Drawable d = getFullResDefaultActivityIcon();
Bitmap b = Bitmap.createBitmap(Math.max(d.getIntrinsicWidth(), 1),
Math.max(d.getIntrinsicHeight(), 1),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
d.setBounds(0, 0, b.getWidth(), b.getHeight());
d.draw(c);
c.setBitmap(null);
return b;
}
public void remove(ComponentName componentName) {
synchronized (mCache) {
mCache.remove(componentName);
}
}
public void flush() {
synchronized (mCache) {
mCache.clear();
}
}
public Bitmap getIcon(Intent intent) {
synchronized (mCache) {
final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0);
ComponentName component = intent.getComponent();
if (resolveInfo == null || component == null) {
return mDefaultIcon;
}
CacheEntry entry = cacheLocked(component, resolveInfo, null);
return entry.icon;
}
}
public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo, HashMap<Object, CharSequence> labelCache) {
synchronized (mCache) {
if (resolveInfo == null || component == null) {
return null;
}
CacheEntry entry = cacheLocked(component, resolveInfo, labelCache);
return entry.icon;
}
}
public boolean isDefaultIcon(Bitmap icon) {
return mDefaultIcon == icon;
}
private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info, HashMap<Object, CharSequence> labelCache) {
CacheEntry entry = mCache.get(componentName);
if (entry == null) {
entry = new CacheEntry();
mCache.put(componentName, entry);
ComponentName key;
if (info.activityInfo != null) {
key = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
} else {
key = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
}
if (labelCache != null && labelCache.containsKey(key)) {
entry.title = labelCache.get(key).toString();
} else {
entry.title = info.loadLabel(mPackageManager).toString();
if (labelCache != null) {
labelCache.put(key, entry.title);
}
}
if (entry.title == null) {
entry.title = info.activityInfo.name;
}
Drawable icon = getFullResIcon(info);
if (mIconPackHelper.isIconPackLoaded() && (mIconPackHelper.getResourceIdForActivityIcon(info.activityInfo) == 0)) {
entry.icon = createIconBitmap(icon, mContext, mIconPackHelper.getIconBack(), mIconPackHelper.getIconMask(), mIconPackHelper
.getIconUpon(), mIconPackHelper.getIconScale());
} else {
entry.icon = createIconBitmap(icon, mContext);
}
}
return entry;
}
public Bitmap getIcon(String packageName, String activityInfoName) {
ComponentName componentName = new ComponentName(packageName, activityInfoName);
if (mCache.get(componentName) != null) {
return mCache.get(componentName).icon;
} else {
Intent intent = new Intent();
intent.setComponent(new ComponentName(packageName, activityInfoName));
return getIcon(intent);
}
}
public HashMap<ComponentName, Bitmap> getAllIcons() {
synchronized (mCache) {
HashMap<ComponentName, Bitmap> set = new HashMap<>();
for (ComponentName cn : mCache.keySet()) {
final CacheEntry e = mCache.get(cn);
set.put(cn, e.icon);
}
return set;
}
}
public static Bitmap createIconBitmap(Bitmap icon, Context context) {
int textureWidth = sIconTextureWidth;
int textureHeight = sIconTextureHeight;
int sourceWidth = icon.getWidth();
int sourceHeight = icon.getHeight();
if (sourceWidth > textureWidth && sourceHeight > textureHeight) {
// Icon is bigger than it should be; clip it (solves the GB->ICS migration case)
return Bitmap.createBitmap(icon,
(sourceWidth - textureWidth) / 2,
(sourceHeight - textureHeight) / 2,
textureWidth, textureHeight);
} else if (sourceWidth == textureWidth && sourceHeight == textureHeight) {
// Icon is the right size, no need to change it
return icon;
} else {
// Icon is too small, render to a larger bitmap
final Resources resources = context.getResources();
return createIconBitmap(new BitmapDrawable(resources, icon), context);
}
}
public static Bitmap createIconBitmap(Drawable icon, Context context) {
synchronized (sCanvas) { // we share the statics :-(
if (sIconWidth == -1) {
initStatics(context);
}
int width = sIconWidth;
int height = sIconHeight;
if (icon instanceof PaintDrawable) {
PaintDrawable painter = (PaintDrawable) icon;
painter.setIntrinsicWidth(width);
painter.setIntrinsicHeight(height);
} else if (icon instanceof BitmapDrawable) {
// Ensure the bitmap has a density.
BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
Bitmap bitmap = bitmapDrawable.getBitmap();
if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
}
}
int sourceWidth = icon.getIntrinsicWidth();
int sourceHeight = icon.getIntrinsicHeight();
if (sourceWidth > 0 && sourceHeight > 0) {
// Scale the icon proportionally to the icon dimensions
final float ratio = (float) sourceWidth / sourceHeight;
if (sourceWidth > sourceHeight) {
height = (int) (width / ratio);
} else if (sourceHeight > sourceWidth) {
width = (int) (height * ratio);
}
}
// no intrinsic size --> use default size
int textureWidth = sIconTextureWidth;
int textureHeight = sIconTextureHeight;
final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight, Bitmap.Config.ARGB_8888);
final Canvas canvas = sCanvas;
canvas.setBitmap(bitmap);
final int left = (textureWidth - width) / 2;
final int top = (textureHeight - height) / 2;
sOldBounds.set(icon.getBounds());
icon.setBounds(left, top, left + width, top + height);
icon.draw(canvas);
icon.setBounds(sOldBounds);
canvas.setBitmap(null);
return bitmap;
}
}
public static Bitmap createIconBitmap(Drawable icon, Context context, Drawable iconBack, Drawable iconMask, Drawable iconUpon, float scale) {
synchronized (sCanvas) { // we share the statics :-(
if (sIconWidth == -1) {
initStatics(context);
}
int width = sIconWidth;
int height = sIconHeight;
if (icon instanceof PaintDrawable) {
PaintDrawable painter = (PaintDrawable) icon;
painter.setIntrinsicWidth(width);
painter.setIntrinsicHeight(height);
} else if (icon instanceof BitmapDrawable) {
// Ensure the bitmap has a density.
BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
Bitmap bitmap = bitmapDrawable.getBitmap();
if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
}
}
int sourceWidth = icon.getIntrinsicWidth();
int sourceHeight = icon.getIntrinsicHeight();
if (sourceWidth > 0 && sourceHeight > 0) {
// Scale the icon proportionally to the icon dimensions
final float ratio = (float) sourceWidth / sourceHeight;
if (sourceWidth > sourceHeight) {
height = (int) (width / ratio);
} else if (sourceHeight > sourceWidth) {
width = (int) (height * ratio);
}
}
// no intrinsic size --> use default size
int textureWidth = sIconTextureWidth;
int textureHeight = sIconTextureHeight;
Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
Bitmap.Config.ARGB_8888);
final Canvas canvas = sCanvas;
canvas.setBitmap(bitmap);
final int left = (textureWidth - width) / 2;
final int top = (textureHeight - height) / 2;
sOldBounds.set(icon.getBounds());
icon.setBounds(left, top, left + width, top + height);
canvas.save();
canvas.scale(scale, scale, width / 2, height / 2);
icon.draw(canvas);
canvas.restore();
if (iconMask != null) {
iconMask.setBounds(icon.getBounds());
((BitmapDrawable) iconMask).getPaint().setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
iconMask.draw(canvas);
}
if (iconBack != null) {
canvas.setBitmap(null);
Bitmap finalBitmap = Bitmap.createBitmap(textureWidth, textureHeight, Bitmap.Config.ARGB_8888);
canvas.setBitmap(finalBitmap);
iconBack.setBounds(icon.getBounds());
iconBack.draw(canvas);
canvas.drawBitmap(bitmap, null, icon.getBounds(), null);
bitmap = finalBitmap;
}
if (iconUpon != null) {
iconUpon.draw(canvas);
}
icon.setBounds(sOldBounds);
canvas.setBitmap(null);
return bitmap;
}
}
private static void initStatics(Context context) {
final Resources resources = context.getResources();
final DisplayMetrics metrics = resources.getDisplayMetrics();
final float density = metrics.density;
sIconWidth = sIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
sIconTextureWidth = sIconTextureHeight = sIconWidth;
sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
sGlowColorPressedPaint.setColor(0xffffc300);
sGlowColorFocusedPaint.setColor(0xffff8e00);
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0.2f);
sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm));
sDisabledPaint.setAlpha(0x88);
}
}