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); } }