package com.cooliris.cache;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicReference;
import android.app.IntentService;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.MergeCursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
import android.os.Process;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
import android.util.Log;
import com.cooliris.media.DataSource;
import com.cooliris.media.DiskCache;
import com.cooliris.media.Gallery;
import com.cooliris.media.LocalDataSource;
import com.cooliris.media.LongSparseArray;
import com.cooliris.media.MediaFeed;
import com.cooliris.media.MediaItem;
import com.cooliris.media.MediaSet;
import com.cooliris.media.R;
import com.cooliris.media.Shared;
import com.cooliris.media.SortCursor;
import com.cooliris.media.UriTexture;
import com.cooliris.media.Utils;
public final class CacheService extends IntentService {
public static final String ACTION_CACHE = "com.cooliris.cache.action.CACHE";
public static final DiskCache sAlbumCache = new DiskCache("local-album-cache");
public static final DiskCache sMetaAlbumCache = new DiskCache("local-meta-cache");
public static final DiskCache sSkipThumbnailIds = new DiskCache("local-skip-cache");
private static final String TAG = "CacheService";
private static ImageList sList = null;
// Wait 2 seconds to start the thumbnailer so that the application can load
// without any overheads.
private static final int THUMBNAILER_WAIT_IN_MS = 2000;
private static final int DEFAULT_THUMBNAIL_WIDTH = 128;
private static final int DEFAULT_THUMBNAIL_HEIGHT = 96;
public static final String DEFAULT_IMAGE_SORT_ORDER = Images.ImageColumns.DATE_TAKEN + " ASC";
public static final String DEFAULT_VIDEO_SORT_ORDER = Video.VideoColumns.DATE_TAKEN + " ASC";
public static final String DEFAULT_BUCKET_SORT_ORDER = "upper(" + Images.ImageColumns.BUCKET_DISPLAY_NAME + ") ASC";
// Must preserve order between these indices and the order of the terms in
// BUCKET_PROJECTION_IMAGES, BUCKET_PROJECTION_VIDEOS.
// Not using SortedHashMap for efficieny reasons.
public static final int BUCKET_ID_INDEX = 0;
public static final int BUCKET_NAME_INDEX = 1;
public static final String[] BUCKET_PROJECTION_IMAGES = new String[] { Images.ImageColumns.BUCKET_ID,
Images.ImageColumns.BUCKET_DISPLAY_NAME };
public static final String[] BUCKET_PROJECTION_VIDEOS = new String[] { Video.VideoColumns.BUCKET_ID,
Video.VideoColumns.BUCKET_DISPLAY_NAME };
// Must preserve order between these indices and the order of the terms in
// THUMBNAIL_PROJECTION.
public static final int THUMBNAIL_ID_INDEX = 0;
public static final int THUMBNAIL_DATE_MODIFIED_INDEX = 1;
public static final int THUMBNAIL_DATA_INDEX = 2;
public static final int THUMBNAIL_ORIENTATION_INDEX = 2;
public static final String[] THUMBNAIL_PROJECTION = new String[] { Images.ImageColumns._ID, Images.ImageColumns.DATE_MODIFIED,
Images.ImageColumns.DATA, Images.ImageColumns.ORIENTATION };
public static final String[] SENSE_PROJECTION = new String[] { Images.ImageColumns.BUCKET_ID,
"MAX(" + Images.ImageColumns.DATE_ADDED + "), COUNT(*)" };
// Must preserve order between these indices and the order of the terms in
// INITIAL_PROJECTION_IMAGES and
// INITIAL_PROJECTION_VIDEOS.
public static final int MEDIA_ID_INDEX = 0;
public static final int MEDIA_CAPTION_INDEX = 1;
public static final int MEDIA_MIME_TYPE_INDEX = 2;
public static final int MEDIA_LATITUDE_INDEX = 3;
public static final int MEDIA_LONGITUDE_INDEX = 4;
public static final int MEDIA_DATE_TAKEN_INDEX = 5;
public static final int MEDIA_DATE_ADDED_INDEX = 6;
public static final int MEDIA_DATE_MODIFIED_INDEX = 7;
public static final int MEDIA_DATA_INDEX = 8;
public static final int MEDIA_ORIENTATION_OR_DURATION_INDEX = 9;
public static final int MEDIA_BUCKET_ID_INDEX = 10;
public static final String[] PROJECTION_IMAGES = new String[] { Images.ImageColumns._ID, Images.ImageColumns.TITLE,
Images.ImageColumns.MIME_TYPE, Images.ImageColumns.LATITUDE, Images.ImageColumns.LONGITUDE,
Images.ImageColumns.DATE_TAKEN, Images.ImageColumns.DATE_ADDED, Images.ImageColumns.DATE_MODIFIED,
Images.ImageColumns.DATA, Images.ImageColumns.ORIENTATION, Images.ImageColumns.BUCKET_ID };
private static final String[] PROJECTION_VIDEOS = new String[] { Video.VideoColumns._ID, Video.VideoColumns.TITLE,
Video.VideoColumns.MIME_TYPE, Video.VideoColumns.LATITUDE, Video.VideoColumns.LONGITUDE, Video.VideoColumns.DATE_TAKEN,
Video.VideoColumns.DATE_ADDED, Video.VideoColumns.DATE_MODIFIED, Video.VideoColumns.DATA, Video.VideoColumns.DURATION,
Video.VideoColumns.BUCKET_ID };
public static final String BASE_CONTENT_STRING_IMAGES = (Images.Media.EXTERNAL_CONTENT_URI).toString() + "/";
public static final String BASE_CONTENT_STRING_VIDEOS = (Video.Media.EXTERNAL_CONTENT_URI).toString() + "/";
private static final AtomicReference<Thread> CACHE_THREAD = new AtomicReference<Thread>();
private static final AtomicReference<Thread> THUMBNAIL_THREAD = new AtomicReference<Thread>();
// Special indices in the Albumcache.
private static final int ALBUM_CACHE_METADATA_INDEX = -1;
private static final int ALBUM_CACHE_DIRTY_INDEX = -2;
private static final int ALBUM_CACHE_INCOMPLETE_INDEX = -3;
private static final int ALBUM_CACHE_DIRTY_BUCKET_INDEX = -4;
private static final int ALBUM_CACHE_LOCALE_INDEX = -5;
private static final DateFormat mDateFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
private static final DateFormat mAltDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
private static final byte[] sDummyData = new byte[] { 1 };
private static boolean QUEUE_DIRTY_SET;
private static boolean QUEUE_DIRTY_ALL;
private static boolean QUEUE_DIRTY_SENSE;
public interface Observer {
void onChange(long[] bucketIds);
}
public static final String getCachePath(final String subFolderName) {
return Environment.getExternalStorageDirectory() + "/Android/data/com.cooliris.media/cache/" + subFolderName;
}
public static final void startCache(final Context context, final boolean checkthumbnails) {
final Locale locale = getLocaleForAlbumCache();
final Locale defaultLocale = Locale.getDefault();
if (locale == null || !locale.equals(defaultLocale)) {
sAlbumCache.deleteAll();
putLocaleForAlbumCache(defaultLocale);
}
final Intent intent = new Intent(ACTION_CACHE, null, context, CacheService.class);
intent.putExtra("checkthumbnails", checkthumbnails);
context.startService(intent);
}
public static final boolean isCacheReady(final boolean onlyMediaSets) {
if (onlyMediaSets) {
return (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null && sAlbumCac