Skip to content

Instantly share code, notes, and snippets.

@d4rken
Created October 24, 2015 20:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d4rken/35838889b3d6994cea2f to your computer and use it in GitHub Desktop.
Save d4rken/35838889b3d6994cea2f to your computer and use it in GitHub Desktop.
A set of classes that was used to load previews in SD Maid during development. Inspired by Picasso, removed in favor of Glide.
package eu.thedarken.sdm.preview.loader;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Build;
import java.io.File;
import java.util.Locale;
import eu.thedarken.sdm.SDMContext;
import eu.thedarken.sdm.SDMaid;
import eu.thedarken.sdm.preview.BitmapRequest;
import eu.thedarken.sdm.preview.PreviewHelper;
public class ApkPreviewLoader extends PreviewLoader {
private static final String TAG = SDMaid.LOG_PREFIX + ":Preview:ApkPreviewLoader";
public ApkPreviewLoader(Context context) {
super(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private Bitmap buildAppPreview(File file, float[] size) {
String filePath = file.getAbsolutePath();
PackageInfo packageInfo = SDMContext.getInstance(getContext()).getIPCFunnel().getPackageArchiveInfo(file, PackageManager.GET_ACTIVITIES);
if (packageInfo != null) {
ApplicationInfo appInfo = packageInfo.applicationInfo;
// http://stackoverflow.com/questions/5674683/how-to-show-icon-of-apk-in-my-file-manager
if (Build.VERSION.SDK_INT >= 8) {
appInfo.sourceDir = filePath;
appInfo.publicSourceDir = filePath;
}
Drawable icon = null;
try {
icon = appInfo.loadIcon(getContext().getPackageManager());
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
if (icon != null) {
if (size[0] == 0 || size[1] == 0) {
size[0] = icon.getIntrinsicWidth();
size[1] = icon.getIntrinsicHeight();
}
return PreviewHelper.getBitmapFromDrawable(icon, (int) size[0], (int) size[1]);
}
}
return null;
}
@Override
public Bitmap build(BitmapRequest request) {
return buildAppPreview(new File(request.getUri().getPath()), request.getSize());
}
private final static String[] app_extensions = {".apk"};
@Override
public boolean isCompatible(BitmapRequest request) {
if (!request.getUri().toString().startsWith("file://"))
return false;
File file = new File(request.getUri().getPath());
int cutoff = file.getName().lastIndexOf(".");
if (cutoff != -1) {
String extension = file.getName().substring(cutoff);
for (String app : app_extensions) {
if (extension.toLowerCase(Locale.getDefault()).equals(app.toLowerCase(Locale.getDefault())))
return true;
}
}
return false;
}
}
package eu.thedarken.sdm.preview;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v4.util.LruCache;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class BitmapCache {
private LruCache<String, Bitmap> cache;
private Context mContext;
public BitmapCache(Context context) {
mContext = context;
int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
if (memClass == 0)
memClass = 16;
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 32;
cache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number
// of items.
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
}
public synchronized void addBitmapToCache(String key, Bitmap bitmap) {
addBitmapToCache(key, bitmap, false);
}
public synchronized void addBitmapToCache(String key, Bitmap bitmap, boolean cacheExternal) {
if (getBitmapFromCache(key, true) == null && key != null && bitmap != null) {
cache.put(key, bitmap);
if (cacheExternal) {
File cachefile = getExternalCacheFile(key);
if (cachefile.exists())
cachefile.delete();
if (cachefile.isFile()) {
FileOutputStream out;
try {
out = new FileOutputStream(cachefile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public Bitmap getBitmapFromCache(String key) {
return getBitmapFromCache(key, false);
}
public Bitmap getBitmapFromCache(String key, boolean tryExternal) {
if (cache.get(key) == null) {
if (tryExternal) {
File img = getExternalCacheFile(key);
if (img.exists()) {
Bitmap image = BitmapFactory.decodeFile(img.getAbsolutePath());
// Don't cache the image if it is null, i.e. there was a decoding error
if (image != null)
addBitmapToCache(key, image, false);
return image;
}
}
}
return cache.get(key);
}
public void evictAll() {
cache.evictAll();
}
private File getExternalCacheFile(String tag) {
File cacheDir = new File(mContext.getExternalCacheDir() + "/bitmapcache/");
if (!cacheDir.exists())
cacheDir.mkdirs();
return new File(cacheDir.getAbsolutePath() + File.separator + tag);
}
}
package eu.thedarken.sdm.preview;
import android.net.Uri;
import android.support.annotation.NonNull;
import java.util.Arrays;
public class BitmapRequest {
final boolean mCacheExternal;
final String mAlias;
final float[] mSize;
private final Uri mUri;
public BitmapRequest(@NonNull Uri uri, boolean cacheExternal, @NonNull String alias, @NonNull float[] size) {
mCacheExternal = cacheExternal;
mAlias = alias;
mSize = size;
mUri = uri;
}
public boolean isCacheExternal() {
return mCacheExternal;
}
public String getAlias() {
return mAlias;
}
public float[] getSize() {
return mSize;
}
@NonNull
public Uri getUri() {
return mUri;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof BitmapRequest))
return false;
BitmapRequest foo = (BitmapRequest) o;
// if (mCacheExternal != foo.mCacheExternal
// || !Arrays.equals(mSize, foo.mSize)
// || !mAlias.equals(foo.mAlias)
// || !mUri.equals(foo.mUri))
// return false;
if(!mAlias.equals(foo.mAlias))
return false;
return true;
}
@Override
public int hashCode() {
int hash = 17;
// hash = hash * 31 + Boolean.valueOf(mCacheExternal).hashCode();
// hash = hash * 31 + Arrays.hashCode(mSize);
hash = hash * 31 + mAlias.hashCode();
// hash = hash * 31 + mUri.hashCode();
return hash;
}
@Override
public String toString() {
return getUri().toString() + " | alias:" + getAlias();
}
}
package eu.thedarken.sdm.preview;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import java.lang.ref.WeakReference;
public class DeferredRequestBuilder implements ViewTreeObserver.OnPreDrawListener {
private static final String TAG = Preview.LOG_PREFIX + "DeferredRequestBuilder";
final RequestBuilder mRequestBuilder;
final WeakReference<ImageView> mDestination;
public DeferredRequestBuilder(RequestBuilder requestBuilder, ImageView destination) {
mRequestBuilder = requestBuilder;
destination.getViewTreeObserver().addOnPreDrawListener(this);
mDestination = new WeakReference<>(destination);
if (destination.getVisibility() == View.GONE)
destination.setVisibility(View.INVISIBLE);
}
@Override
public boolean onPreDraw() {
View destination = mDestination.get();
if (destination == null)
return true;
ViewTreeObserver observer = destination.getViewTreeObserver();
if (!observer.isAlive())
return true;
int width = destination.getWidth();
int height = destination.getHeight();
if (width <= 0 || height <= 0)
return true;
observer.removeOnPreDrawListener(this);
mRequestBuilder.go();
return true;
}
void cancel() {
View destination = mDestination.get();
if (destination == null)
return;
ViewTreeObserver observer = destination.getViewTreeObserver();
if (!observer.isAlive())
return;
observer.removeOnPreDrawListener(this);
}
}
package eu.thedarken.sdm.preview.loader;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.File;
import java.util.Locale;
import eu.thedarken.sdm.preview.BitmapRequest;
public class ImagePreviewLoader extends PreviewLoader {
private final static String[] image_extensions = {".jpg", ".jpeg", ".gif", ".bmp", ".png", ".raw"};
public ImagePreviewLoader(Context context) {
super(context);
}
@Override
public boolean isCompatible(BitmapRequest request) {
if (!request.getUri().toString().startsWith("file://"))
return false;
File file = new File(request.getUri().getPath());
int cutoff = file.getName().lastIndexOf(".");
if (cutoff != -1) {
String extension = file.getName().substring(cutoff);
for (String img : image_extensions) {
if (extension.toLowerCase(Locale.getDefault()).equals(img.toLowerCase(Locale.getDefault())))
return true;
}
}
return false;
}
@Override
public Bitmap build(BitmapRequest request) {
File file = new File(request.getUri().getPath());
return buildImagePreview(file, request.getSize());
}
private Bitmap buildImagePreview(File file, float size[]) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
if (size[0] == 0 || size[1] == 0) {
size[0] = options.outWidth;
size[1] = options.outHeight;
}
options.inSampleSize = calculateInSampleSize(options, (int) size[0], (int) size[1]);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(file.getAbsolutePath(), options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
}
package eu.thedarken.sdm.preview;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.ImageView;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import eu.thedarken.sdm.SDMaid;
import eu.thedarken.sdm.tools.Logy;
public class Preview implements PreviewCallback {
private static final String TAG = SDMaid.LOG_PREFIX + "Preview";
public static final String LOG_PREFIX = TAG + ":";
private final Object mAccessLock = new Object();
private Context mContext;
private final BitmapCache mCache;
private final PreviewWorker mWorker;
private volatile static Preview sInstance;
private final Map<ImageView, PreviewTask> mImageTargetMap = new WeakHashMap<>();
private final HashMap<BitmapRequest, Set<PreviewTask>> mBitMapRequestMap = new HashMap<>();
private final Map<ImageView, DeferredRequestBuilder> mDeferredRequestMap = new WeakHashMap<>();
public static Preview with(Context c) {
if (sInstance == null) {
synchronized (Preview.class) {
if (sInstance == null)
sInstance = new Preview(c.getApplicationContext());
}
}
return sInstance;
}
private Preview(Context m) {
mContext = m;
mCache = new BitmapCache(m);
mWorker = new PreviewWorker(mContext, mCache, this);
}
Context getContext() {
return mContext;
}
BitmapCache getCache() {
return mCache;
}
public RequestBuilder load(File file) {
return load(Uri.fromFile(file));
}
public RequestBuilder load(String pkg) {
return load(Uri.parse("package://" + pkg));
}
public RequestBuilder load(Uri uri) {
RequestBuilder builder = new RequestBuilder(this, uri);
return builder;
}
public boolean isLoading() {
return mWorker.isRunning();
}
public void clearCache() {
Logy.d(TAG, "Clearing data...");
mCache.evictAll();
}
public void stopLoading() {
Logy.d(TAG, "Stopping loaders...");
synchronized (mAccessLock) {
mWorker.stop();
mImageTargetMap.clear();
mImageTargetMap.clear();
for (DeferredRequestBuilder deferredRequestBuilder : mDeferredRequestMap.values())
deferredRequestBuilder.cancel();
mDeferredRequestMap.clear();
}
}
void submit(PreviewTask previewTask) {
ensureUIThread();
BitmapRequest newBitmapRequest = previewTask.getBitmapRequest();
ImageView destination = previewTask.getDestination();
synchronized (mAccessLock) {
if (destination != null) {
cancelRequest(destination);
mImageTargetMap.put(destination, previewTask);
}
Set<PreviewTask> tasksForThisBitmap = mBitMapRequestMap.get(newBitmapRequest);
if (tasksForThisBitmap == null)
tasksForThisBitmap = new HashSet<>();
tasksForThisBitmap.add(previewTask);
mBitMapRequestMap.put(newBitmapRequest, tasksForThisBitmap);
Logy.v(TAG, "Submitted: " + previewTask.getDestination().toString() + " | " + newBitmapRequest.toString());
}
mWorker.submit(newBitmapRequest);
}
public void cancelRequest(@NonNull ImageView destination) {
ensureUIThread();
synchronized (mAccessLock) {
PreviewTask obsoleteTask = mImageTargetMap.remove(destination);
if (obsoleteTask != null) {
BitmapRequest possiblyObsoleteBitmapRequest = obsoleteTask.getBitmapRequest();
final Set<PreviewTask> previewTasks = mBitMapRequestMap.get(possiblyObsoleteBitmapRequest);
if (previewTasks != null) {
if (previewTasks.remove(obsoleteTask))
Logy.v(TAG, "Removed obsolete task.");
if (previewTasks.isEmpty()) {
Logy.v(TAG, "BitmapRequest has no associated tasks. Canceling it.");
mBitMapRequestMap.remove(possiblyObsoleteBitmapRequest);
mWorker.cancel(possiblyObsoleteBitmapRequest);
}
}
}
DeferredRequestBuilder deferredBuilder = mDeferredRequestMap.remove(destination);
if (deferredBuilder != null)
deferredBuilder.cancel();
}
}
protected void deferRequest(DeferredRequestBuilder deferred) {
ensureUIThread();
synchronized (mAccessLock) {
ImageView destination = deferred.mDestination.get();
if (mDeferredRequestMap.containsKey(destination))
cancelRequest(destination);
mDeferredRequestMap.put(destination, deferred);
Logy.v(TAG, "Deferred:" + deferred);
}
}
@Override
public void onBitmapRequestDone(final BitmapRequest request, final Bitmap bitmap) {
Logy.v(TAG, "Postprocessing:" + request.toString());
Set<PreviewTask> previewTasks;
synchronized (mAccessLock) {
previewTasks = mBitMapRequestMap.remove(request);
if (previewTasks == null) {
Logy.v(TAG, "Preview tasks were invalidated for this bitmap:" + request.toString());
return;
}
for (PreviewTask task : previewTasks) {
mImageTargetMap.remove(task.getDestination());
}
}
if (previewTasks.isEmpty())
Logy.v(TAG, "previewtasks were empty for:" + request.toString());
Handler handler = new Handler(Looper.getMainLooper());
for (final PreviewTask task : previewTasks) {
final ImageView destination = task.getDestination();
if (destination != null) {
if (handler.post(new Runnable() {
@Override
public void run() {
Logy.v(TAG, "detination:" + destination.toString() + " request:" + request.getAlias());
destination.setImageBitmap(bitmap);
destination.setVisibility(View.VISIBLE);
}
})) {
Logy.v(TAG, "destination posted:" + destination.toString());
if (destination.getHandler() == null)
Logy.v(TAG, "destination handler null:" + destination.toString());
} else {
Logy.v(TAG, "destination failed:" + destination.toString());
}
} else {
Logy.v(TAG, "detination was null, request:" + request.getAlias());
}
final View placeHolder = task.getPlaceHolder();
if (placeHolder != null) {
if (handler.post(new Runnable() {
@Override
public void run() {
Logy.v(TAG, "placeHolder:" + placeHolder.toString() + " request:" + request.getAlias());
placeHolder.setVisibility(View.INVISIBLE);
}
})) {
Logy.v(TAG, "placeHolder posted:" + placeHolder.toString());
} else {
Logy.v(TAG, "placeHolder failed:" + placeHolder.toString());
}
} else {
Logy.v(TAG, "placeHolder was null, request:" + request.getAlias());
}
Logy.v(TAG, "Preview tasks completed:" + task.toString());
}
}
static void ensureUIThread() {
if (Looper.getMainLooper().getThread() != Thread.currentThread())
throw new IllegalStateException("Not called from UI thread!");
}
}
package eu.thedarken.sdm.preview;
import android.graphics.Bitmap;
public interface PreviewCallback {
void onBitmapRequestDone(BitmapRequest bitmapRequest, Bitmap bitmap);
}
package eu.thedarken.sdm.preview;
import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.DrawableContainer;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.VectorDrawable;
import android.os.Build;
import eu.thedarken.sdm.tools.ApiHelper;
public class PreviewHelper {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static Bitmap getBitmapFromDrawable(Drawable drawable, int width, int height) {
if (drawable instanceof BitmapDrawable) {
return Bitmap.createScaledBitmap(((BitmapDrawable) drawable).getBitmap(), width, height, true);
} else if (drawable instanceof StateListDrawable) {
StateListDrawable stateDrwbl = (StateListDrawable) drawable;
stateDrwbl.mutate();
Drawable.ConstantState constantState = stateDrwbl.getConstantState();
if (constantState instanceof DrawableContainer.DrawableContainerState) {
DrawableContainer.DrawableContainerState drwblContainerState = (DrawableContainer.DrawableContainerState) constantState;
final Drawable[] drawables = drwblContainerState.getChildren();
for (Drawable drwbl : drawables) {
if (drwbl instanceof BitmapDrawable)
return Bitmap.createScaledBitmap(((BitmapDrawable) drwbl).getBitmap(), width, height, true);
}
}
} else if (ApiHelper.hasLolliPop() && drawable instanceof VectorDrawable) {
VectorDrawable vIcon = (VectorDrawable) drawable;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
vIcon.setBounds(0, 0, width, height);
vIcon.draw(canvas);
return bitmap;
}
return null;
}
}
package eu.thedarken.sdm.preview;
import android.view.View;
import android.widget.ImageView;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
class PreviewTask {
private final BitmapRequest mBitmapRequest;
private final WeakReference<ImageView> mDestination;
private final WeakReference<View> mPlaceHolder;
private final long mTimeStamp;
PreviewTask(BitmapRequest bitmapRequest, ImageView destination, View placeHolder) {
mTimeStamp = System.nanoTime();
mBitmapRequest = bitmapRequest;
if (destination != null) {
mDestination = new WeakReference<>(destination);
} else {
mDestination = null;
}
if (placeHolder != null) {
mPlaceHolder = new WeakReference<>(placeHolder);
} else {
mPlaceHolder = null;
}
}
public long getTimeStamp() {
return mTimeStamp;
}
public BitmapRequest getBitmapRequest() {
return mBitmapRequest;
}
public ImageView getDestination() {
return mDestination == null ? null : mDestination.get();
}
public View getPlaceHolder() {
return mPlaceHolder == null ? null : mPlaceHolder.get();
}
}
package eu.thedarken.sdm.preview;
import android.content.Context;
import android.graphics.Bitmap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import eu.thedarken.sdm.SDMaid;
import eu.thedarken.sdm.preview.loader.ApkPreviewLoader;
import eu.thedarken.sdm.preview.loader.AppPreviewLoader;
import eu.thedarken.sdm.preview.loader.FallbackPreviewLoader;
import eu.thedarken.sdm.preview.loader.ImagePreviewLoader;
import eu.thedarken.sdm.preview.loader.PreviewLoader;
import eu.thedarken.sdm.tools.Logy;
public class PreviewWorker {
private static final String TAG = SDMaid.LOG_PREFIX + "PreviewWorker";
private final List<PreviewLoader> mPreviewLoaders = new ArrayList<>();
private final Context mContext;
private final PreviewCallback mListener;
private final BitmapCache mCache;
private final AtomicInteger mRunningWorkers = new AtomicInteger(0);
private final Stack<BitmapRequest> mRequestOrder = new Stack<>();
private final Set<BitmapRequest> mActiveRequests = new HashSet<>();
private final Object mRequestLock = new Object();
private final ExecutorService mThreadPool = Executors.newFixedThreadPool(MAXWORKERS);
private static final int MAXWORKERS = 3;
public PreviewWorker(Context context, BitmapCache cache, PreviewCallback listener) {
mContext = context;
mListener = listener;
mCache = cache;
mPreviewLoaders.add(new ImagePreviewLoader(mContext));
mPreviewLoaders.add(new ApkPreviewLoader(mContext));
mPreviewLoaders.add(new AppPreviewLoader(mContext));
mPreviewLoaders.add(new FallbackPreviewLoader(mContext));
}
private PreviewLoader determineLoader(BitmapRequest request) {
for (PreviewLoader loader : mPreviewLoaders)
if (loader.isCompatible(request))
return loader;
return null;
}
public boolean isRunning() {
return mRunningWorkers.get() > 0;
}
public void stop() {
mRequestOrder.clear();
}
public Set<BitmapRequest> getActiveRequests() {
return mActiveRequests;
}
public void submit(BitmapRequest bitmapRequest) {
Bitmap bitmap = mCache.getBitmapFromCache(bitmapRequest.getAlias());
if (bitmap != null) {
Logy.v(TAG, "Quick return:" + bitmapRequest.toString());
mListener.onBitmapRequestDone(bitmapRequest, bitmap);
return;
}
synchronized (mRequestLock) {
if (mActiveRequests.contains(bitmapRequest))
return;
if (mRequestOrder.contains(bitmapRequest))
mRequestOrder.remove(bitmapRequest);
mRequestOrder.push(bitmapRequest);
if (mRunningWorkers.get() < MAXWORKERS) {
mRunningWorkers.incrementAndGet();
mThreadPool.submit(new WorkerLoop());
}
}
}
public void cancel(BitmapRequest request) {
synchronized (mRequestLock) {
if (mRequestOrder.remove(request))
Logy.v(TAG, "Removed request:" + request.toString());
}
}
private class WorkerLoop implements Runnable {
@Override
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LOWEST);
while (true) {
BitmapRequest bitmapRequest;
synchronized (mRequestLock) {
if (mRequestOrder.isEmpty()) {
break;
} else {
bitmapRequest = mRequestOrder.pop();
mActiveRequests.add(bitmapRequest);
}
}
String targetTag = bitmapRequest.getAlias();
boolean cacheExternal = bitmapRequest.isCacheExternal();
Bitmap previewBitmap = mCache.getBitmapFromCache(targetTag, cacheExternal);
if (previewBitmap == null) {
Logy.v(TAG, "Loading new bitmap for " + bitmapRequest.toString());
PreviewLoader loader = determineLoader(bitmapRequest);
if (loader != null) {
previewBitmap = loader.build(bitmapRequest);
if (previewBitmap != null)
mCache.addBitmapToCache(targetTag, previewBitmap, cacheExternal);
}
} else {
Logy.v(TAG, "Using cached bitmap of " + bitmapRequest.toString());
}
synchronized (mRequestLock) {
mActiveRequests.remove(bitmapRequest);
}
Logy.v(TAG, "Processed: " + bitmapRequest.getAlias() + ", source " + bitmapRequest.getUri());
mListener.onBitmapRequestDone(bitmapRequest, previewBitmap);
}
mRunningWorkers.decrementAndGet();
}
}
}
package eu.thedarken.sdm.preview;
import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
import android.support.annotation.DimenRes;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.ImageView;
import java.lang.ref.WeakReference;
import eu.thedarken.sdm.SDMaid;
public class RequestBuilder {
private static final String TAG = SDMaid.LOG_PREFIX + "RequestBuilder";
private final Context mContext;
private final Preview mPreviewInstance;
private final Uri mTargetUri;
private String mTargetAlias;
private float[] mDesiredTargetSize;
private WeakReference<ImageView> mDestination;
private WeakReference<View> mPlaceHolder;
public RequestBuilder(Preview loader, @NonNull Uri uri) {
mPreviewInstance = loader;
mContext = loader.getContext();
mTargetUri = uri;
}
public RequestBuilder withCustomAlias(String alias) {
mTargetAlias = alias;
return this;
}
public RequestBuilder inSize(@DimenRes int sizeRes) {
Resources r = mContext.getResources();
float calcDpi = r.getDimension(sizeRes);
mDesiredTargetSize = new float[]{calcDpi, calcDpi};
return this;
}
public RequestBuilder into(ImageView destination) {
mDestination = new WeakReference<>(destination);
return this;
}
public RequestBuilder withPlaceholder(View placeholder) {
mPlaceHolder = new WeakReference<>(placeholder);
return this;
}
private boolean ensureSize() {
if (mDesiredTargetSize == null) {
float[] size = null;
ImageView dest = mDestination.get();
if (dest != null) {
int width = dest.getWidth();
int height = dest.getHeight();
if (width != 0 && height != 0) {
size = new float[]{
width, height
};
}
if (size != null) {
mDesiredTargetSize = size;
} else {
mPreviewInstance.deferRequest(new DeferredRequestBuilder(this, dest));
return false;
}
} else {
mDesiredTargetSize = new float[]{0, 0};
}
}
return true;
}
public void go() {
final ImageView destination = mDestination.get();
if (destination != null) {
Preview.ensureUIThread();
destination.setImageBitmap(null);
destination.setVisibility(View.INVISIBLE);
}
final View placeHolder = mPlaceHolder.get();
if (placeHolder != null) {
Preview.ensureUIThread();
placeHolder.setVisibility(View.VISIBLE);
}
if (!ensureSize())
return;
if (mTargetAlias == null) {
mTargetAlias = mTargetUri.toString() + ":" + mDesiredTargetSize[0] + "x" + mDesiredTargetSize[1];
}
BitmapRequest bitmapRequest = new BitmapRequest(mTargetUri, false, mTargetAlias, mDesiredTargetSize);
PreviewTask previewTask = new PreviewTask(bitmapRequest, destination, placeHolder);
mPreviewInstance.submit(previewTask);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment