blob: 34d463eaf724e49c7f753d34edcb261f5b9186a2 [file] [log] [blame]
package com.cooliris.media;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
import android.util.Log;
import com.cooliris.cache.CacheService;
public final class LocalDataSource implements DataSource {
private static final String TAG = "LocalDataSource";
public static final DiskCache sThumbnailCache = new DiskCache("local-image-thumbs");
public static final DiskCache sThumbnailCacheVideo = new DiskCache("local-video-thumbs");
public static final String CAMERA_STRING = "Camera";
public static final String DOWNLOAD_STRING = "download";
public static final String CAMERA_BUCKET_NAME = Environment.getExternalStorageDirectory().toString() + "/DCIM/" + CAMERA_STRING;
public static final String DOWNLOAD_BUCKET_NAME = Environment.getExternalStorageDirectory().toString() + "/" + DOWNLOAD_STRING;
public static final int CAMERA_BUCKET_ID = getBucketId(CAMERA_BUCKET_NAME);
public static final int DOWNLOAD_BUCKET_ID = getBucketId(DOWNLOAD_BUCKET_NAME);
public static boolean sObserverActive = false;
private boolean mDisableImages;
private boolean mDisableVideos;
/**
* Matches code in MediaProvider.computeBucketValues. Should be a common
* function.
*/
public static int getBucketId(String path) {
return (path.toLowerCase().hashCode());
}
private Context mContext;
private ContentObserver mObserver;
public LocalDataSource(Context context) {
mContext = context;
}
public void setMimeFilter(boolean disableImages, boolean disableVideos) {
mDisableImages = disableImages;
mDisableVideos = disableVideos;
}
public void loadMediaSets(final MediaFeed feed) {
if (mContext == null) {
return;
}
stopListeners();
CacheService.loadMediaSets(feed, this, !mDisableImages, !mDisableVideos);
Handler handler = ((Gallery) mContext).getHandler();
ContentObserver observer = new ContentObserver(handler) {
public void onChange(boolean selfChange) {
final boolean isPaused = ((Gallery) mContext).isPaused();
if (isPaused) {
MediaSet mediaSet = feed.getCurrentSet();
if (mediaSet != null) {
CacheService.markDirtyImmediate(mediaSet.mId);
refreshUI(feed, mediaSet.mId);
}
}
CacheService.senseDirty(mContext, new CacheService.Observer() {
public void onChange(long[] ids) {
if (!isPaused)
return;
if (ids != null) {
int numLongs = ids.length;
for (int i = 0; i < numLongs; ++i) {
refreshUI(feed, ids[i]);
}
}
}
});
}
};
// Start listening.
Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
ContentResolver cr = mContext.getContentResolver();
mObserver = observer;
cr.registerContentObserver(uriImages, true, observer);
cr.registerContentObserver(uriVideos, true, observer);
sObserverActive = true;
}
public void shutdown() {
stopListeners();
}
private void stopListeners() {
ContentResolver cr = mContext.getContentResolver();
if (mObserver != null) {
cr.unregisterContentObserver(mObserver);
}
sObserverActive = false;
}
protected void refreshUI(MediaFeed feed, long setIdToUse) {
if (setIdToUse == Shared.INVALID) {
return;
}
if (feed.getMediaSet(setIdToUse) == null) {
MediaSet mediaSet = feed.addMediaSet(setIdToUse, this);
if (setIdToUse == CAMERA_BUCKET_ID) {
mediaSet.mName = CAMERA_STRING;
} else if (setIdToUse == DOWNLOAD_BUCKET_ID) {
mediaSet.mName = DOWNLOAD_STRING;
}
mediaSet.generateTitle(true);
} else {
MediaSet mediaSet = feed.replaceMediaSet(setIdToUse, this);
Log.i(TAG, "Replacing mediaset " + mediaSet.mName + " id " + setIdToUse + " current Id " + mediaSet.mId);
if (setIdToUse == CAMERA_BUCKET_ID) {
mediaSet.mName = CAMERA_STRING;
} else if (setIdToUse == DOWNLOAD_BUCKET_ID) {
mediaSet.mName = DOWNLOAD_STRING;
}
mediaSet.generateTitle(true);
}
}
public void loadItemsForSet(final MediaFeed feed, final MediaSet parentSet, int rangeStart, int rangeEnd) {
// Quick load from the cache.
if (mContext == null || parentSet == null) {
return;
}
loadMediaItemsIntoMediaFeed(feed, parentSet, rangeStart, rangeEnd);
}
private void loadMediaItemsIntoMediaFeed(final MediaFeed mediaFeed, final MediaSet set, int rangeStart, int rangeEnd) {
if (rangeEnd - rangeStart < 0) {
return;
}
CacheService.loadMediaItemsIntoMediaFeed(mediaFeed, set, rangeStart, rangeEnd, !mDisableImages, !mDisableVideos);
if (set.mId == CAMERA_BUCKET_ID) {
mediaFeed.moveSetToFront(set);
}
}
public boolean performOperation(final int operation, final ArrayList<MediaBucket> mediaBuckets, final Object data) {
int numBuckets = mediaBuckets.size();
ContentResolver cr = mContext.getContentResolver();
switch (operation) {
case MediaFeed.OPERATION_DELETE:
for (int i = 0; i < numBuckets; ++i) {
MediaBucket bucket = mediaBuckets.get(i);
MediaSet set = bucket.mediaSet;
ArrayList<MediaItem> items = bucket.mediaItems;
if (set != null && items == null) {
// Remove the entire bucket.
final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
final String whereImages = Images.ImageColumns.BUCKET_ID + "=" + Long.toString(set.mId);
final String whereVideos = Video.VideoColumns.BUCKET_ID + "=" + Long.toString(set.mId);
cr.delete(uriImages, whereImages, null);
cr.delete(uriVideos, whereVideos, null);
CacheService.markDirty(mContext);
}
if (set != null && items != null) {
// We need to remove these items from the set.
int numItems = items.size();
try {
for (int j = 0; j < numItems; ++j) {
MediaItem item = items.get(j);
cr.delete(Uri.parse(item.mContentUri), null, null);
}
} catch (Exception e) {
// If the database operation failed for any reason.
;
}
set.updateNumExpectedItems();
set.generateTitle(true);
CacheService.markDirty(mContext, set.mId);
}
}
break;
case MediaFeed.OPERATION_ROTATE:
for (int i = 0; i < numBuckets; ++i) {
MediaBucket bucket = mediaBuckets.get(i);
ArrayList<MediaItem> items = bucket.mediaItems;
if (items == null) {
continue;
}
float angleToRotate = ((Float) data).floatValue();
if (angleToRotate == 0) {
return true;
}
int numItems = items.size();
for (int j = 0; j < numItems; ++j) {
rotateItem(items.get(j), angleToRotate);
}
}
break;
}
return true;
}
private void rotateItem(final MediaItem item, float angleToRotate) {
ContentResolver cr = mContext.getContentResolver();
try {
int currentOrientation = (int) item.mRotation;
angleToRotate += currentOrientation;
float rotation = Shared.normalizePositive(angleToRotate);
String rotationString = Integer.toString((int) rotation);
// Update the database entry.
ContentValues values = new ContentValues();
values.put(Images.ImageColumns.ORIENTATION, rotationString);
try {
cr.update(Uri.parse(item.mContentUri), values, null, null);
} catch (Exception e) {
// If the database operation fails for any reason.
;
}
// Update the file EXIF information.
Uri uri = Uri.parse(item.mContentUri);
String uriScheme = uri.getScheme();
if (uriScheme.equals("file")) {
ExifInterface exif = new ExifInterface(uri.getPath());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, Integer.toString(Shared.degreesToExifOrientation(rotation)));
exif.saveAttributes();
}
// Invalidate the cache entry.
CacheService.markDirty(mContext, item.mParentMediaSet.mId);
// Update the object representation of the item.
item.mRotation = rotation;
} catch (Exception e) {
// System.out.println("Apparently not a JPEG");
}
}
public DiskCache getThumbnailCache() {
return sThumbnailCache;
}
public static MediaItem createMediaItemFromUri(Context context, Uri target) {
MediaItem item = null;
long id = ContentUris.parseId(target);
ContentResolver cr = context.getContentResolver();
String whereClause = Images.ImageColumns._ID + "=" + Long.toString(id);
try {
Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
item = new MediaItem();
CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
}
cursor.close();
cursor = null;
}
} catch (Exception e) {
// If the database operation failed for any reason.
;
}
return item;
}
public static MediaItem createMediaItemFromFileUri(Context context, String fileUri) {
MediaItem item = null;
String filepath = new File(URI.create(fileUri)).toString();
ContentResolver cr = context.getContentResolver();
long bucketId = SingleDataSource.parseBucketIdFromFileUri(fileUri);
String whereClause = Images.ImageColumns.BUCKET_ID + "=" + bucketId + " AND " + Images.ImageColumns.DATA + "='" + filepath
+ "'";
try {
Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
item = new MediaItem();
CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
}
cursor.close();
cursor = null;
}
} catch (Exception e) {
// If the database operation failed for any reason.
;
}
return item;
}
}