安卓P,mtk的文件管理器中的apk,不显示apk的图标;这个其实是原来的设计,所有的apk都用安卓机器人表示,但是为了让apk看起来更直观,因此需要显示图标。同时,不能因为获取图标导致异常的卡顿。
原来的逻辑是注释掉的那行代码,下面的那句是改过的
alps/vendor/mediatek/proprietary/packages/apps/FileManager/src/com/mediatek/filemanager/FileInfoAdapter.java
private void setIcon(FileViewHolder viewHolder, FileInfo fileInfo, int viewDirection) {
// Modify start ^_^
// Bitmap icon = IconManager.getInstance().getIcon(mResources, fileInfo, mService, viewDirection);
Bitmap icon = IconManager.getInstance().getIcon(mContext, mResources, fileInfo, mService, viewDirection);
// Modify end ^_^
viewHolder.mIcon.setImageBitmap(icon);
viewHolder.mIcon.setAlpha(DEFAULT_ICON_ALPHA);
if (FileInfoManager.PASTE_MODE_CUT == mFileInfoManager.getPasteType()) {
if (mFileInfoManager.isPasteItem(fileInfo)) {
viewHolder.mIcon.setAlpha(CUT_ICON_ALPHA);
}
}
....
}
alps/vendor/mediatek/proprietary/packages/apps/FileManager/src/com/mediatek/filemanager/IconManager.java中添加方法
// Add start ^_^
public Bitmap getIcon(Context context, Resources res, FileInfo fileInfo, FileManagerService service, int viewDirection) {
if (mCurrentDirection != viewDirection) {
mDirectionChanged = true;
mCurrentDirection = viewDirection;
}
Bitmap icon = null;
boolean isExternal = MountPointManager.getInstance().isExternalFile(fileInfo);
//LogUtils.d(TAG, "getIcon,isExternal =" + isExternal);
if (fileInfo.isDirectory()) {
icon = getFolderIcon(fileInfo, isExternal);
} else {
String mimeType = fileInfo.getFileMimeType(service);
// Add by zhiheng.huang on 2019/3/12 for start ^_^
if (mimeType.startsWith("application/vnd.android.package-archive")) {
Bitmap bitmap = DiskCacheUtil.getInstance(context).getBitmap(fileInfo.getFileAbsolutePath());
if (bitmap != null) {
return bitmap;
}
return getApkIcon(context, fileInfo.getFileAbsolutePath());
}
// Add by zhiheng.huang on 2019/3/12 for end ^_^
LogUtils.d(TAG, "getIcon imimeType =" + mimeType);
int iconId = getDrawableId(service, mimeType);
if (fileInfo.isDrmFile()) {
// try to get the DRM file icon.
icon = DrmManager.getInstance().overlayDrmIconSkew(res,
fileInfo.getFileAbsolutePath(), iconId);
if (icon != null && isExternal) {
icon = createExternalIcon(icon);
}
}
if (icon == null) {
icon = getFileIcon(iconId, isExternal);
}
}
return icon;
}
private Bitmap getApkIcon(Context context, String apkPath) {
PackageManager pm = context.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
appInfo.sourceDir = apkPath;
appInfo.publicSourceDir = apkPath;
try {
Bitmap bitmap = DiskCacheUtil.drawable2Bitmap(appInfo.loadIcon(pm));
DiskCacheUtil.getInstance(context).put(apkPath, bitmap);
return bitmap;
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
}
return null;
}
// Add end ^_^
获取apk的图标并显示并不难,但是为了保证流畅,我才用的是DiskLruCache来缓存获取的图片,下次进来的时候直接去缓存读取,就不需要再次解析包名获取了,下面是缓存的代码文件
package com.mediatek.filemanager.utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* Add by HZH on 2019/3/13
*/
public class DiskCacheUtil {
private static final long DEFAULT_MAX_SIZE = Long.MAX_VALUE;
private static final int DEFAULT_MAX_COUNT = Integer.MAX_VALUE;
private static final String CACHE_PREFIX = "cdu";
private static final Map CACHE_MAP = new HashMap<>();
private final String mCacheKey;
private final File mCacheDir;
private final long mMaxSize;
private final int mMaxCount;
private DiskCacheManager mDiskCacheManager;
private static Context mContext;
/**
* Return the single {@link DiskCacheUtil} instance.
* cache directory: /data/data/package/cache/cacheUtils
* cache size: unlimited
* cache count: unlimited
*
* @return the single {@link DiskCacheUtil} instance
*/
public static DiskCacheUtil getInstance(Context context) {
mContext = context;
return getInstance(context, "", DEFAULT_MAX_SIZE, DEFAULT_MAX_COUNT);
}
/**
* Return the single {@link DiskCacheUtil} instance.
* cache directory: /data/data/package/cache/cacheName
*
* @param cacheName The name of cache.
* @param maxSize The max size of cache, in bytes.
* @param maxCount The max count of cache.
* @return the single {@link DiskCacheUtil} instance
*/
public static DiskCacheUtil getInstance(Context context, String cacheName, final long maxSize, final int maxCount) {
mContext = context;
if (isSpace(cacheName)) cacheName = "cacheUtils";
File file = new File(context.getCacheDir(), cacheName);
return getInstance(file, maxSize, maxCount);
}
/**
* Return the single {@link DiskCacheUtil} instance.
* cache size: unlimited
* cache count: unlimited
*
* @param cacheDir The directory of cache.
* @return the single {@link DiskCacheUtil} instance
*/
public static DiskCacheUtil getInstance(final File cacheDir) {
return getInstance(cacheDir, DEFAULT_MAX_SIZE, DEFAULT_MAX_COUNT);
}
/**
* Return the single {@link DiskCacheUtil} instance.
*
* @param cacheDir The directory of cache.
* @param maxSize The max size of cache, in bytes.
* @param maxCount The max count of cache.
* @return the single {@link DiskCacheUtil} instance
*/
public static DiskCacheUtil getInstance(final File cacheDir,
final long maxSize,
final int maxCount) {
final String cacheKey = cacheDir.getAbsoluteFile() + "_" + maxSize + "_" + maxCount;
DiskCacheUtil cache = CACHE_MAP.get(cacheKey);
if (cache == null) {
synchronized (DiskCacheUtil.class) {
cache = CACHE_MAP.get(cacheKey);
if (cache == null) {
cache = new DiskCacheUtil(cacheKey, cacheDir, maxSize, maxCount);
CACHE_MAP.put(cacheKey, cache);
}
}
}
return cache;
}
private DiskCacheUtil(final String cacheKey,
final File cacheDir,
final long maxSize,
final int maxCount) {
mCacheKey = cacheKey;
mCacheDir = cacheDir;
mMaxSize = maxSize;
mMaxCount = maxCount;
}
private DiskCacheManager getDiskCacheManager() {
if (mCacheDir.exists()) {
if (mDiskCacheManager == null) {
mDiskCacheManager = new DiskCacheManager(mCacheDir, mMaxSize, mMaxCount);
}
} else {
if (mCacheDir.mkdirs()) {
mDiskCacheManager = new DiskCacheManager(mCacheDir, mMaxSize, mMaxCount);
} else {
Log.e("DiskCacheUtil", "can't make dirs in " + mCacheDir.getAbsolutePath());
}
}
return mDiskCacheManager;
}
@Override
public String toString() {
return mCacheKey + "@" + Integer.toHexString(hashCode());
}
///
// about bytes
///
/**
* Put bytes in cache.
*
* @param key The key of cache.
* @param value The value of cache.
*/
public void put(final String key, final byte[] value) {
put(key, value, -1);
}
/**
* Put bytes in cache.
*
* @param key The key of cache.
* @param value The value of cache.
* @param saveTime The save time of cache, in seconds.
*/
public void put(final String key, byte[] value, final int saveTime) {
if (value == null) return;
DiskCacheManager diskCacheManager = getDiskCacheManager();
if (diskCacheManager == null) return;
if (saveTime >= 0) value = DiskCacheHelper.newByteArrayWithTime(saveTime, value);
File file = diskCacheManager.getFileBeforePut(key);
writeFileFromBytes(file, value);
diskCacheManager.updateModify(file);
diskCacheManager.put(file);
}
/**
* Return the bytes in cache.
*
* @param key The key of cache.
* @return the bytes if cache exists or null otherwise
*/
public byte[] getBytes(final String key) {
return getBytes(key, null);
}
/**
* Return the bytes in cache.
*
* @param key The key of cache.
* @param defaultValue The default value if the cache doesn't exist.
* @return the bytes if cache exists or defaultValue otherwise
*/
public byte[] getBytes(final String key, final byte[] defaultValue) {
DiskCacheManager diskCacheManager = getDiskCacheManager();
if (diskCacheManager == null) return defaultValue;
final File file = diskCacheManager.getFileIfExists(key);
if (file == null) return defaultValue;
byte[] data = readFile2Bytes(file);
if (DiskCacheHelper.isDue(data)) {
diskCacheManager.removeByKey(key);
return defaultValue;
}
diskCacheManager.updateModify(file);
return DiskCacheHelper.getDataWithoutDueTime(data);
}
///
// about Bitmap
///
/**
* Put bitmap in cache.
*
* @param key The key of cache.
* @param value The value of cache.
*/
public void put(final String key, final Bitmap value) {
put(key, value, -1);
}
/**
* Put bitmap in cache.
*
* @param key The key of cache.
* @param value The value of cache.
* @param saveTime The save time of cache, in seconds.
*/
public void put(final String key, final Bitmap value, final int saveTime) {
put(key, bitmap2Bytes(value), saveTime);
}
/**
* Return the bitmap in cache.
*
* @param key The key of cache.
* @return the bitmap if cache exists or null otherwise
*/
public Bitmap getBitmap(final String key) {
return getBitmap(key, null);
}
/**
* Return the bitmap in cache.
*
* @param key The key of cache.
* @param defaultValue The default value if the cache doesn't exist.
* @return the bitmap if cache exists or defaultValue otherwise
*/
public Bitmap getBitmap(final String key, final Bitmap defaultValue) {
byte[] bytes = getBytes(key);
if (bytes == null) return defaultValue;
return bytes2Bitmap(bytes);
}
///
// about Drawable
///
/**
* Put drawable in cache.
*
* @param key The key of cache.
* @param value The value of cache.
*/
public void put(final String key, final Drawable value) {
put(key, value, -1);
}
/**
* Put drawable in cache.
*
* @param key The key of cache.
* @param value The value of cache.
* @param saveTime The save time of cache, in seconds.
*/
public void put(final String key, final Drawable value, final int saveTime) {
put(key, drawable2Bytes(value), saveTime);
}
/**
* Return the drawable in cache.
*
* @param key The key of cache.
* @return the drawable if cache exists or null otherwise
*/
public Drawable getDrawable(final String key) {
return getDrawable(key, null);
}
/**
* Return the drawable in cache.
*
* @param key The key of cache.
* @param defaultValue The default value if the cache doesn't exist.
* @return the drawable if cache exists or defaultValue otherwise
*/
public Drawable getDrawable(final String key, final Drawable defaultValue) {
byte[] bytes = getBytes(key);
if (bytes == null) return defaultValue;
return bytes2Drawable(bytes);
}
/**
* Return the size of cache, in bytes.
*
* @return the size of cache, in bytes
*/
public long getCacheSize() {
DiskCacheManager diskCacheManager = getDiskCacheManager();
if (diskCacheManager == null) return 0;
return diskCacheManager.getCacheSize();
}
/**
* Return the count of cache.
*
* @return the count of cache
*/
public int getCacheCount() {
DiskCacheManager diskCacheManager = getDiskCacheManager();
if (diskCacheManager == null) return 0;
return diskCacheManager.getCacheCount();
}
/**
* Remove the cache by key.
*
* @param key The key of cache.
* @return {@code true}: success
{@code false}: fail
*/
public boolean remove(final String key) {
DiskCacheManager diskCacheManager = getDiskCacheManager();
if (diskCacheManager == null) return true;
return diskCacheManager.removeByKey(key);
}
/**
* Clear all of the cache.
*
* @return {@code true}: success
{@code false}: fail
*/
public boolean clear() {
DiskCacheManager diskCacheManager = getDiskCacheManager();
if (diskCacheManager == null) return true;
return diskCacheManager.clear();
}
private static final class DiskCacheManager {
private final AtomicLong cacheSize;
private final AtomicInteger cacheCount;
private final long sizeLimit;
private final int countLimit;
private final Map lastUsageDates
= Collections.synchronizedMap(new HashMap());
private final File cacheDir;
private final Thread mThread;
private DiskCacheManager(final File cacheDir, final long sizeLimit, final int countLimit) {
this.cacheDir = cacheDir;
this.sizeLimit = sizeLimit;
this.countLimit = countLimit;
cacheSize = new AtomicLong();
cacheCount = new AtomicInteger();
mThread = new Thread(new Runnable() {
@Override
public void run() {
int size = 0;
int count = 0;
final File[] cachedFiles = cacheDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith(CACHE_PREFIX);
}
});
if (cachedFiles != null) {
for (File cachedFile : cachedFiles) {
size += cachedFile.length();
count += 1;
lastUsageDates.put(cachedFile, cachedFile.lastModified());
}
cacheSize.getAndAdd(size);
cacheCount.getAndAdd(count);
}
}
});
mThread.start();
}
private long getCacheSize() {
try {
mThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return cacheSize.get();
}
private int getCacheCount() {
try {
mThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return cacheCount.get();
}
private File getFileBeforePut(final String key) {
File file = new File(cacheDir, CACHE_PREFIX + String.valueOf(key.hashCode()));
if (file.exists()) {
cacheCount.addAndGet(-1);
cacheSize.addAndGet(-file.length());
}
return file;
}
private File getFileIfExists(final String key) {
File file = new File(cacheDir, CACHE_PREFIX + String.valueOf(key.hashCode()));
if (!file.exists()) return null;
return file;
}
private void put(final File file) {
cacheCount.addAndGet(1);
cacheSize.addAndGet(file.length());
while (cacheCount.get() > countLimit || cacheSize.get() > sizeLimit) {
cacheSize.addAndGet(-removeOldest());
cacheCount.addAndGet(-1);
}
}
private void updateModify(final File file) {
Long millis = System.currentTimeMillis();
file.setLastModified(millis);
lastUsageDates.put(file, millis);
}
private boolean removeByKey(final String key) {
File file = getFileIfExists(key);
if (file == null) return true;
if (!file.delete()) return false;
cacheSize.addAndGet(-file.length());
cacheCount.addAndGet(-1);
lastUsageDates.remove(file);
return true;
}
private boolean clear() {
File[] files = cacheDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith(CACHE_PREFIX);
}
});
if (files == null || files.length <= 0) return true;
boolean flag = true;
for (File file : files) {
if (!file.delete()) {
flag = false;
continue;
}
cacheSize.addAndGet(-file.length());
cacheCount.addAndGet(-1);
lastUsageDates.remove(file);
}
if (flag) {
lastUsageDates.clear();
cacheSize.set(0);
cacheCount.set(0);
}
return flag;
}
/**
* Remove the oldest files.
*
* @return the size of oldest files, in bytes
*/
private long removeOldest() {
if (lastUsageDates.isEmpty()) return 0;
Long oldestUsage = Long.MAX_VALUE;
File oldestFile = null;
Set> entries = lastUsageDates.entrySet();
synchronized (lastUsageDates) {
for (Map.Entry entry : entries) {
Long lastValueUsage = entry.getValue();
if (lastValueUsage < oldestUsage) {
oldestUsage = lastValueUsage;
oldestFile = entry.getKey();
}
}
}
if (oldestFile == null) return 0;
long fileSize = oldestFile.length();
if (oldestFile.delete()) {
lastUsageDates.remove(oldestFile);
return fileSize;
}
return 0;
}
}
private static final class DiskCacheHelper {
static final int TIME_INFO_LEN = 14;
private static byte[] newByteArrayWithTime(final int second, final byte[] data) {
byte[] time = createDueTime(second).getBytes();
byte[] content = new byte[time.length + data.length];
System.arraycopy(time, 0, content, 0, time.length);
System.arraycopy(data, 0, content, time.length, data.length);
return content;
}
/**
* Return the string of due time.
*
* @param seconds The seconds.
* @return the string of due time
*/
private static String createDueTime(final int seconds) {
return String.format(
Locale.getDefault(), "_$%010d$_",
System.currentTimeMillis() / 1000 + seconds
);
}
private static boolean isDue(final byte[] data) {
long millis = getDueTime(data);
return millis != -1 && System.currentTimeMillis() > millis;
}
private static long getDueTime(final byte[] data) {
if (hasTimeInfo(data)) {
String millis = new String(copyOfRange(data, 2, 12));
try {
return Long.parseLong(millis) * 1000;
} catch (NumberFormatException e) {
return -1;
}
}
return -1;
}
private static byte[] getDataWithoutDueTime(final byte[] data) {
if (hasTimeInfo(data)) {
return copyOfRange(data, TIME_INFO_LEN, data.length);
}
return data;
}
private static byte[] copyOfRange(final byte[] original, final int from, final int to) {
int newLength = to - from;
if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
byte[] copy = new byte[newLength];
System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
return copy;
}
private static boolean hasTimeInfo(final byte[] data) {
return data != null
&& data.length >= TIME_INFO_LEN
&& data[0] == '_'
&& data[1] == '$'
&& data[12] == '$'
&& data[13] == '_';
}
}
///
// other utils methods
///
private static byte[] string2Bytes(final String string) {
if (string == null) return null;
return string.getBytes();
}
private static String bytes2String(final byte[] bytes) {
if (bytes == null) return null;
return new String(bytes);
}
private static Object bytes2Object(final byte[] bytes) {
if (bytes == null) return null;
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
if (ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static byte[] bitmap2Bytes(final Bitmap bitmap) {
if (bitmap == null) return null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
return baos.toByteArray();
}
private static Bitmap bytes2Bitmap(final byte[] bytes) {
return (bytes == null || bytes.length <= 0)
? null
: BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
private static byte[] drawable2Bytes(final Drawable drawable) {
return drawable == null ? null : bitmap2Bytes(drawable2Bitmap(drawable));
}
private static Drawable bytes2Drawable(final byte[] bytes) {
return bytes == null ? null : bitmap2Drawable(bytes2Bitmap(bytes));
}
public static Bitmap drawable2Bitmap(final Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
Bitmap bitmap;
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(
1,
1,
drawable.getOpacity() != PixelFormat.OPAQUE
? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565
);
} else {
bitmap = Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE
? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565
);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
private static Drawable bitmap2Drawable(final Bitmap bitmap) {
return bitmap == null
? null
: new BitmapDrawable(mContext.getResources(), bitmap);
}
private static void writeFileFromBytes(final File file, final byte[] bytes) {
FileChannel fc = null;
try {
fc = new FileOutputStream(file, false).getChannel();
fc.write(ByteBuffer.wrap(bytes));
fc.force(true);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fc != null) {
fc.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static byte[] readFile2Bytes(final File file) {
FileChannel fc = null;
try {
fc = new RandomAccessFile(file, "r").getChannel();
int size = (int) fc.size();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, size).load();
byte[] data = new byte[size];
mbb.get(data, 0, size);
return data;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
if (fc != null) {
fc.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static boolean isSpace(final String s) {
if (s == null) return true;
for (int i = 0, len = s.length(); i < len; ++i) {
if (!Character.isWhitespace(s.charAt(i))) {
return false;
}
}
return true;
}
}