/*
* Copyright (C) 2014 Fastboot Mobile, LLC.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, see <http://www.gnu.org/licenses>.
*/
package com.fastbootmobile.encore.art;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Build;
import android.support.annotation.NonNull;
import com.fastbootmobile.encore.model.BoundEntity;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Helper class allowing to easily download and fetch an album art or artist art
*/
public class AlbumArtHelper {
private static final String TAG = "AlbumArtHelper";
private static final int CORE_POOL_SIZE = 2;
private static final int PRI_CORE_POOL_SIZE = 2;
private static final int MAXIMUM_POOL_SIZE = 6;
private static final int PRI_MAXIMUM_POOL_SIZE = 3;
private static final int KEEP_ALIVE = 10;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(@NonNull Runnable r) {
return new Thread(r, "Art AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<>(64);
private static final BlockingQueue<Runnable> sPriorityPoolWorkQueue =
new LinkedBlockingQueue<>(32);
static final Executor ART_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
static final Executor PRIORITY_ART_POOL_EXECUTOR
= new ThreadPoolExecutor(PRI_CORE_POOL_SIZE, PRI_MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPriorityPoolWorkQueue, sThreadFactory);
public interface AlbumArtListener {
void onArtLoaded(RecyclingBitmapDrawable output, BoundEntity request);
}
public static class BackgroundResult {
public BoundEntity request;
public RecyclingBitmapDrawable bitmap;
public boolean retry;
public AlbumArtListener listener;
public int size;
}
public static AlbumArtTask retrieveAlbumArt(Resources res, AlbumArtListener listener,
BoundEntity request, int size, boolean immediate) {
AlbumArtRequest requestStructure = new AlbumArtRequest();
requestStructure.entity = request;
requestStructure.listener = listener;
requestStructure.requestedSize = size;
requestStructure.res = res;
AlbumArtTask task = new AlbumArtTask();
// On Android 4.2+, we use our custom executor. Android 4.1 and below uses the predefined
// pool, as the custom one causes the app to just crash without any kind of error message
// for no reason (at least in the emulator).
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (immediate) {
if (sPriorityPoolWorkQueue.remainingCapacity() == 0) {
// Release a previous work to free up space in the queue
sPriorityPoolWorkQueue.remove(sPriorityPoolWorkQueue.iterator().next());
}
task.executeOnExecutor(PRIORITY_ART_POOL_EXECUTOR, requestStructure);
} else {
if (sPoolWorkQueue.remainingCapacity() == 0) {
// Release a previous work to free up space in the queue
sPoolWorkQueue.remove(sPoolWorkQueue.iterator().next());
}
task.executeOnExecutor(ART_POOL_EXECUTOR, requestStructure);
}
} else {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, requestStructure);
}
return task;
}
public static void clearAlbumArtRequests() {
sPriorityPoolWorkQueue.clear();
sPoolWorkQueue.clear();
}
static class AlbumArtRequest {
Resources res;
AlbumArtHelper.AlbumArtListener listener;
int requestedSize;
BoundEntity entity;
}
}