/*
* Copyright (C) 2005-2009 Team XBMC
* http://xbmc.org
*
* 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 2, 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 XBMC Remote; see the file license. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
package org.xbmc.android.remote.business;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import org.xbmc.api.business.DataResponse;
import org.xbmc.api.object.ICoverArt;
import org.xbmc.api.presentation.INotifiableController;
import org.xbmc.api.type.ThumbSize;
import android.graphics.Bitmap;
import android.util.Log;
/**
* This thread asynchronously delivers memory-cached bitmaps.
*
* The memory cache keeps small-size thumb bitmaps in a soft-referenced list.
* This thread is directly accessed by the original HttpApi thread, through one
* of its wrappers.
*
* @author Team XBMC
*/
class MemCacheThread extends AbstractThread {
private final static String TAG = "MemCacheThread";
private final static boolean DEBUG = AbstractManager.DEBUG;
/**
* Singleton instance of this thread
*/
protected static MemCacheThread sHttpApiThread;
/**
* The actual cache variable. Here are the thumbs stored.
*/
private static final HashMap<Long, SoftReference<Bitmap>> sCacheSmall = new HashMap<Long, SoftReference<Bitmap>>();
private static final HashMap<Long, SoftReference<Bitmap>> sCacheMedium = new HashMap<Long, SoftReference<Bitmap>>();
private static final HashMap<Long, Boolean> sNotAvailable = new HashMap<Long, Boolean>();
/**
* Constructor is protected, use get().
*/
protected MemCacheThread() {
super("HTTP API Mem Cache Thread");
}
/**
* Asynchronously returns a thumb from the mem cache, or null if
* not available.
*
* @param response Response object
* @param cover Which cover to return
*/
public void getCover(final DataResponse<Bitmap> response, final ICoverArt cover, final int thumbSize, final INotifiableController controller, final Bitmap defaultCover) {
if (controller == null) {
Log.w(TAG, "[" + cover.getId() + "] Controller is null.");
}
mHandler.post(new Runnable() {
public void run() {
if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Checking if cover in cache..");
if (cover != null) {
final long crc = cover.getCrc();
final SoftReference<Bitmap> ref = getCache(thumbSize).get(crc);
if (ref != null) {
if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] -> In cache.");
response.value = ref.get();
if (DEBUG && response.value == null) Log.w(TAG, "[" + cover.getId() + "] -> GC'd from cache.");
} else if (sNotAvailable.containsKey(crc)) {
if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] -> Marked as not-in-cache (" + crc + ").");
response.value = defaultCover;
} else {
if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] -> Not in cache.");
}
}
done(controller, response);
}
});
}
private static HashMap<Long, SoftReference<Bitmap>> getCache(int thumbSize) {
return (thumbSize == ThumbSize.MEDIUM) ? sCacheMedium : sCacheSmall;
}
/**
* Synchronously returns a thumb from the mem cache, or null
* if not available.
*
* @param cover Which cover to return
* @return Bitmap or null if not available.
*/
public static Bitmap getCover(ICoverArt cover, int thumbSize) {
Bitmap cache = getCache(thumbSize).get(cover.getCrc()).get();
return cache;
}
/**
* Checks if a thumb is in the mem cache.
* @param cover
* @return True if thumb is in mem cache, false otherwise.
*/
public static boolean isInCache(ICoverArt cover, int thumbSize) {
return (thumbSize == ThumbSize.SMALL || thumbSize == ThumbSize.MEDIUM) &&
getCache(thumbSize).containsKey(cover.getCrc()) &&
getCache(thumbSize).get(cover.getCrc()) != null &&
getCache(thumbSize).get(cover.getCrc()).get() != null;
}
/**
* Adds a cover to the mem cache
* @param cover Which cover to add
* @param bitmap Bitmap data
*/
public static void addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSize) {
// if bitmap is null, add an entry to the sNotAvailable table so we can return the default bitmap later directly.
if (bitmap == null) {
sNotAvailable.put(cover.getCrc(), true);
} else if (thumbSize == ThumbSize.SMALL || thumbSize == ThumbSize.MEDIUM) {
getCache(thumbSize).put(cover.getCrc(), new SoftReference<Bitmap>(bitmap));
}
}
/**
* Returns an instance of this thread. Spawns if necessary.
* @return
*/
public static MemCacheThread get() {
if (sHttpApiThread == null) {
sHttpApiThread = new MemCacheThread();
sHttpApiThread.start();
// thread must be entirely started
waitForStartup(sHttpApiThread);
}
return sHttpApiThread;
}
public synchronized static void quit() {
if (sHttpApiThread != null) {
sHttpApiThread.mHandler.getLooper().quit();
sHttpApiThread = null;
}
}
public static void purgeCache() {
sCacheMedium.clear();
sCacheSmall.clear();
sNotAvailable.clear();
}
}