From b658ef4f610fcbafff4fa5e584cabe253e76d879 Mon Sep 17 00:00:00 2001 From: George Mount Date: Wed, 27 Mar 2013 16:53:41 -0700 Subject: Remove ImageCache from PhotoProvider in favor of MediaCache. Change-Id: I4e75a094d1dc033ac892c2b95bdc6b6a4a165304 --- src/com/android/photos/data/MediaCache.java | 19 ++++--- .../android/photos/data/MediaCacheDatabase.java | 38 ++++++++----- src/com/android/photos/data/MediaCacheUtils.java | 28 ++++++++++ src/com/android/photos/data/PhotoProvider.java | 63 +++------------------- .../com/android/photos/data/MediaCacheTest.java | 18 +++---- 5 files changed, 82 insertions(+), 84 deletions(-) diff --git a/src/com/android/photos/data/MediaCache.java b/src/com/android/photos/data/MediaCache.java index 7b5eca558..9cf69d643 100644 --- a/src/com/android/photos/data/MediaCache.java +++ b/src/com/android/photos/data/MediaCache.java @@ -276,7 +276,7 @@ public class MediaCache { mCacheDir = cacheDir; } - private File getCacheDir() { + public File getCacheDir() { synchronized (mContext) { if (mCacheDir == null) { String state = Environment.getExternalStorageState(); @@ -398,6 +398,10 @@ public class MediaCache { File file = null; if (cachedId != null) { file = createCacheImagePath(cachedId); + if (!file.exists()) { + mDatabaseHelper.delete(contentUri, size, mDeleteFile); + file = null; + } } return file; } @@ -479,9 +483,9 @@ public class MediaCache { } size = retriever.normalizeMediaSize(uri, size); - Long cachedId = mDatabaseHelper.getCached(uri, size); - if (cachedId != null) { - addNotification(complete, createCacheImagePath(cachedId)); + File cachedFile = getCachedFile(uri, size); + if (cachedFile != null) { + addNotification(complete, cachedFile); return; } String differentiator = getDifferentiator(uri.getScheme(), uri.getAuthority()); @@ -540,10 +544,9 @@ public class MediaCache { } private void processTask(ProcessingJob job) { - Long cachedId = mDatabaseHelper.getCached(job.contentUri, job.size); - if (cachedId != null) { - File file = createCacheImagePath(cachedId); - addNotification(job.complete, file); + File cachedFile = getCachedFile(job.contentUri, job.size); + if (cachedFile != null) { + addNotification(job.complete, cachedFile); return; } diff --git a/src/com/android/photos/data/MediaCacheDatabase.java b/src/com/android/photos/data/MediaCacheDatabase.java index 16265b574..c92ac0fdf 100644 --- a/src/com/android/photos/data/MediaCacheDatabase.java +++ b/src/com/android/photos/data/MediaCacheDatabase.java @@ -46,7 +46,7 @@ class MediaCacheDatabase extends SQLiteOpenHelper { } static interface Action { - void execute(Uri uri, long id, MediaRetriever.MediaSize size, Object parameter); + void execute(Uri uri, long id, MediaSize size, Object parameter); } private static final String[] PROJECTION_ID = { @@ -89,10 +89,10 @@ class MediaCacheDatabase extends SQLiteOpenHelper { static class QueryCacheResults { public QueryCacheResults(long id, int sizeVal) { this.id = id; - this.size = MediaRetriever.MediaSize.fromInteger(sizeVal); + this.size = MediaSize.fromInteger(sizeVal); } public long id; - public MediaRetriever.MediaSize size; + public MediaSize size; } public MediaCacheDatabase(Context context) { @@ -111,7 +111,7 @@ class MediaCacheDatabase extends SQLiteOpenHelper { MediaCache.getInstance().clearCacheDir(); } - public Long getCached(Uri uri, MediaRetriever.MediaSize size) { + public Long getCached(Uri uri, MediaSize size) { String where = Columns.URI + " = ? AND " + Columns.MEDIA_SIZE + " = ?"; SQLiteDatabase db = getWritableDatabase(); String[] whereArgs = { @@ -140,7 +140,7 @@ class MediaCacheDatabase extends SQLiteOpenHelper { return id; } - public MediaRetriever.MediaSize executeOnBestCached(Uri uri, MediaRetriever.MediaSize size, Action action) { + public MediaSize executeOnBestCached(Uri uri, MediaSize size, Action action) { String where = Columns.URI + " = ? AND " + Columns.MEDIA_SIZE + " < ?"; String orderBy = Columns.MEDIA_SIZE + " DESC"; SQLiteDatabase db = getReadableDatabase(); @@ -148,10 +148,10 @@ class MediaCacheDatabase extends SQLiteOpenHelper { uri.toString(), String.valueOf(size.getValue()), }; Cursor cursor = db.query(TABLE, PROJECTION_CACHED, where, whereArgs, null, null, orderBy); - MediaRetriever.MediaSize bestSize = null; + MediaSize bestSize = null; if (cursor.moveToNext()) { long id = cursor.getLong(0); - bestSize = MediaRetriever.MediaSize.fromInteger(cursor.getInt(1)); + bestSize = MediaSize.fromInteger(cursor.getInt(1)); long fileSize = cursor.getLong(2); action.execute(uri, id, bestSize, fileSize); } @@ -159,7 +159,7 @@ class MediaCacheDatabase extends SQLiteOpenHelper { return bestSize; } - public long insert(Uri uri, MediaRetriever.MediaSize size, Action action, File tempFile) { + public long insert(Uri uri, MediaSize size, Action action, File tempFile) { SQLiteDatabase db = getWritableDatabase(); db.beginTransaction(); try { @@ -195,20 +195,34 @@ class MediaCacheDatabase extends SQLiteOpenHelper { } } + public void delete(Uri uri, MediaSize size, Action action) { + String where = Columns.URI + " = ? AND " + Columns.MEDIA_SIZE + " = ?"; + String[] whereArgs = { + uri.toString(), String.valueOf(size.getValue()), + }; + deleteRows(uri, where, whereArgs, action); + } + public void delete(Uri uri, Action action) { - SQLiteDatabase db = getWritableDatabase(); String where = Columns.URI + " = ?"; String[] whereArgs = { uri.toString() }; + deleteRows(uri, where, whereArgs, action); + } + + private void deleteRows(Uri uri, String where, String[] whereArgs, Action action) { + SQLiteDatabase db = getWritableDatabase(); + // Make this an atomic operation + db.beginTransaction(); Cursor cursor = db.query(TABLE, PROJECTION_CACHED, where, whereArgs, null, null, null); while (cursor.moveToNext()) { long id = cursor.getLong(0); - MediaRetriever.MediaSize size = MediaRetriever.MediaSize.fromInteger(cursor.getInt(1)); - action.execute(uri, id, size, null); + MediaSize size = MediaSize.fromInteger(cursor.getInt(1)); + long length = cursor.getLong(2); + action.execute(uri, id, size, length); } cursor.close(); - db.beginTransaction(); try { db.delete(TABLE, where, whereArgs); db.setTransactionSuccessful(); diff --git a/src/com/android/photos/data/MediaCacheUtils.java b/src/com/android/photos/data/MediaCacheUtils.java index 1463d5241..e3ccd1402 100644 --- a/src/com/android/photos/data/MediaCacheUtils.java +++ b/src/com/android/photos/data/MediaCacheUtils.java @@ -21,9 +21,12 @@ import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.util.Log; +import android.util.Pools.SimplePool; +import android.util.Pools.SynchronizedPool; import com.android.gallery3d.R; import com.android.gallery3d.common.BitmapUtils; +import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.DecodeUtils; import com.android.gallery3d.data.MediaItem; import com.android.gallery3d.util.ThreadPool.CancelListener; @@ -33,10 +36,15 @@ import com.android.photos.data.MediaRetriever.MediaSize; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; public class MediaCacheUtils { private static final String TAG = MediaCacheUtils.class.getSimpleName(); private static int QUALITY = 80; + private static final int BUFFER_SIZE = 4096; + private static final SimplePool mBufferPool = new SynchronizedPool(5); + private static final JobContext sJobStub = new JobContext() { @Override @@ -136,4 +144,24 @@ public class MediaCacheUtils { } return success; } + + public static int copyStream(InputStream in, OutputStream out) throws IOException { + byte[] buffer = mBufferPool.acquire(); + if (buffer == null) { + buffer = new byte[BUFFER_SIZE]; + } + try { + int totalWritten = 0; + int bytesRead; + while ((bytesRead = in.read(buffer)) >= 0) { + out.write(buffer, 0, bytesRead); + totalWritten += bytesRead; + } + return totalWritten; + } finally { + Utils.closeSilently(in); + Utils.closeSilently(out); + mBufferPool.release(buffer); + } + } } diff --git a/src/com/android/photos/data/PhotoProvider.java b/src/com/android/photos/data/PhotoProvider.java index 880c67126..cffd1239e 100644 --- a/src/com/android/photos/data/PhotoProvider.java +++ b/src/com/android/photos/data/PhotoProvider.java @@ -85,6 +85,12 @@ public class PhotoProvider extends SQLiteContentProvider { * Contains columns that can be accessed via Photos.CONTENT_URI. */ public static interface Photos extends BaseColumns { + /** + * The image_type query parameter required for requesting a specific + * size of image. + */ + public static final String MEDIA_SIZE_QUERY_PARAMETER = "media_size"; + /** Internal database table used for basic photo information. */ public static final String TABLE = "photos"; /** Content URI for basic photo and video information. */ @@ -203,49 +209,6 @@ public class PhotoProvider extends SQLiteContentProvider { public static final String KEY_EXIF_ISO = ExifInterface.TAG_ISO; } - /** - * Contains columns and Uri for maintaining the image cache. - */ - public static interface ImageCache extends BaseColumns { - /** Internal database table used for the image cache */ - public static final String TABLE = "image_cache"; - - /** - * The image_type query parameter required for accessing a specific - * image - */ - public static final String IMAGE_TYPE_QUERY_PARAMETER = "image_type"; - - // ImageCache.IMAGE_TYPE values - public static final int IMAGE_TYPE_ALBUM_COVER = 1; - public static final int IMAGE_TYPE_THUMBNAIL = 2; - public static final int IMAGE_TYPE_PREVIEW = 3; - public static final int IMAGE_TYPE_ORIGINAL = 4; - - /** - * Content URI for retrieving image paths. The - * IMAGE_TYPE_QUERY_PARAMETER must be used in queries. - */ - public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE); - - /** - * Content URI for retrieving the album cover art. The album ID must be - * appended to the URI. - */ - public static final Uri ALBUM_COVER_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, - Albums.TABLE); - - /** - * An _ID from Albums or Photos, depending on whether IMAGE_TYPE is - * IMAGE_TYPE_ALBUM or not. Long value. - */ - public static final String REMOTE_ID = "remote_id"; - /** One of IMAGE_TYPE_* values. */ - public static final String IMAGE_TYPE = "image_type"; - /** The String path to the image. */ - public static final String PATH = "path"; - }; - // SQL used within this class. protected static final String WHERE_ID = BaseColumns._ID + " = ?"; protected static final String WHERE_METADATA_ID = Metadata.PHOTO_ID + " = ? AND " @@ -284,10 +247,8 @@ public class PhotoProvider extends SQLiteContentProvider { protected static final int MATCH_ALBUM_ID = 4; protected static final int MATCH_METADATA = 5; protected static final int MATCH_METADATA_ID = 6; - protected static final int MATCH_IMAGE = 7; - protected static final int MATCH_ALBUM_COVER = 8; - protected static final int MATCH_ACCOUNT = 9; - protected static final int MATCH_ACCOUNT_ID = 10; + protected static final int MATCH_ACCOUNT = 7; + protected static final int MATCH_ACCOUNT_ID = 8; static { sUriMatcher.addURI(AUTHORITY, Photos.TABLE, MATCH_PHOTO); @@ -299,11 +260,6 @@ public class PhotoProvider extends SQLiteContentProvider { sUriMatcher.addURI(AUTHORITY, Metadata.TABLE, MATCH_METADATA); // match against metadata/ sUriMatcher.addURI(AUTHORITY, Metadata.TABLE + "/#", MATCH_METADATA_ID); - // match against image_cache/ - sUriMatcher.addURI(AUTHORITY, ImageCache.TABLE + "/#", MATCH_IMAGE); - // match against image_cache/album/ - sUriMatcher.addURI(AUTHORITY, ImageCache.TABLE + "/" + Albums.TABLE + "/#", - MATCH_ALBUM_COVER); sUriMatcher.addURI(AUTHORITY, Accounts.TABLE, MATCH_ACCOUNT); // match against Accounts._ID sUriMatcher.addURI(AUTHORITY, Accounts.TABLE + "/#", MATCH_ACCOUNT_ID); @@ -476,9 +432,6 @@ public class PhotoProvider extends SQLiteContentProvider { if (match == UriMatcher.NO_MATCH) { throw unknownUri(uri); } - if (match == MATCH_IMAGE || match == MATCH_ALBUM_COVER) { - throw new IllegalArgumentException("Operation not allowed on image cache database"); - } return match; } diff --git a/tests/src/com/android/photos/data/MediaCacheTest.java b/tests/src/com/android/photos/data/MediaCacheTest.java index df990edb1..9e7112807 100644 --- a/tests/src/com/android/photos/data/MediaCacheTest.java +++ b/tests/src/com/android/photos/data/MediaCacheTest.java @@ -157,7 +157,7 @@ public class MediaCacheTest extends ProviderTestCase2 { public void testRetrieveOriginal() throws IOException { copyResourceToFile(R.raw.galaxy_nexus, mImage.getPath()); Uri uri = Uri.fromFile(mImage); - mMediaCache.retrieveOriginal(uri, mReady, mReady); + mMediaCache.retrieveOriginal(uri, mReady, null); assertTrue(mReady.waitForNotification()); assertNull(mReady.mInputStream); assertEquals(mImage, mReady.mOriginalFile); @@ -236,13 +236,13 @@ public class MediaCacheTest extends ProviderTestCase2 { copyResourceToFile(R.raw.android_lawn, mImage.getPath()); Uri uri = Uri.fromFile(mImage); - mMediaCache.retrieveOriginal(uri, mReady, mReady); + mMediaCache.retrieveOriginal(uri, mReady, null); assertTrue(mReady.waitForNotification()); assertNull(mReady.mInputStream); assertNotNull(mReady.mOriginalFile); mReady = new ReadyCollector(); - mMediaCache.retrievePreview(uri, mReady, mReady); + mMediaCache.retrievePreview(uri, mReady, null); assertTrue(mReady.waitForNotification()); assertNotNull(mReady.mInputStream); assertNull(mReady.mOriginalFile); @@ -254,7 +254,7 @@ public class MediaCacheTest extends ProviderTestCase2 { assertTrue(maxDimension < (targetSize * 2)); mReady = new ReadyCollector(); - mMediaCache.retrieveThumbnail(uri, mReady, mReady); + mMediaCache.retrieveThumbnail(uri, mReady, null); assertTrue(mReady.waitForNotification()); assertNotNull(mReady.mInputStream); assertNull(mReady.mOriginalFile); @@ -269,11 +269,11 @@ public class MediaCacheTest extends ProviderTestCase2 { public void testFastImage() throws IOException { copyResourceToFile(R.raw.galaxy_nexus, mImage.getPath()); Uri uri = Uri.fromFile(mImage); - mMediaCache.retrieveThumbnail(uri, mReady, mReady); + mMediaCache.retrieveThumbnail(uri, mReady, null); mReady.waitForNotification(); mReady.mInputStream.close(); - mMediaCache.retrieveOriginal(uri, mReady, mReady); + mMediaCache.retrieveOriginal(uri, mReady, null); assertTrue(mReady.waitForNotification()); assertNotNull(mReady.mInputStream); mReady.mInputStream.close(); @@ -282,7 +282,7 @@ public class MediaCacheTest extends ProviderTestCase2 { public void testBadRetriever() { Uri uri = Photos.CONTENT_URI; try { - mMediaCache.retrieveOriginal(uri, mReady, mReady); + mMediaCache.retrieveOriginal(uri, mReady, null); fail("Expected exception"); } catch (IllegalArgumentException e) { // expected @@ -295,7 +295,7 @@ public class MediaCacheTest extends ProviderTestCase2 { copyResourceToFile(R.raw.android_lawn, mImage.getPath()); Uri uri = Uri.fromFile(mImage); - mMediaCache.retrieveThumbnail(uri, mReady, mReady); + mMediaCache.retrieveThumbnail(uri, mReady, null); assertTrue(mReady.waitForNotification()); mReady.mInputStream.close(); assertNotNull(mMediaCache.getCachedFile(uri, MediaSize.Preview)); @@ -307,7 +307,7 @@ public class MediaCacheTest extends ProviderTestCase2 { mMediaCache.addRetriever(uri.getScheme(), uri.getAuthority(), retriever); retriever.setNullUri(); try { - mMediaCache.retrieveOriginal(uri, mReady, mReady); + mMediaCache.retrieveOriginal(uri, mReady, null); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { // expected -- cgit v1.2.3