diff --git a/xl-image_utils-test_suite/lint.xml b/xl-image_utils-test_suite/lint.xml deleted file mode 100644 index ee0eead..0000000 --- a/xl-image_utils-test_suite/lint.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/AdvancedMemoryCacherTests.java b/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/AdvancedMemoryCacherTests.java index a12e165..d00560a 100644 --- a/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/AdvancedMemoryCacherTests.java +++ b/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/AdvancedMemoryCacherTests.java @@ -19,9 +19,11 @@ import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; +import android.os.Build; import android.test.AndroidTestCase; public class AdvancedMemoryCacherTests extends AndroidTestCase { + private static final boolean SHOULD_RUN = Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT; private AdvancedMemoryLRUCacher mMemCache; private Bitmap.Config mBitmapConfig; @@ -29,10 +31,16 @@ public class AdvancedMemoryCacherTests extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); - mMemCache = new AdvancedMemoryLRUCacher(); + if (SHOULD_RUN) { + mMemCache = new AdvancedMemoryLRUCacher(); + } } public void testClearingCache() { + if (!SHOULD_RUN) { + return; + } + assertEquals(0, mMemCache.getNumImagesInCache()); mMemCache.cacheBitmap(getBitmap(), new DecodeSignature("url1", 1, mBitmapConfig)); assertEquals(1, mMemCache.getNumImagesInCache()); @@ -44,6 +52,10 @@ public void testClearingCache() { @SuppressLint("NewApi") public void testGetBitmapAndLru() { + if (!SHOULD_RUN) { + return; + } + Bitmap bitmap = getBitmap(); mMemCache.cacheBitmap(bitmap, new DecodeSignature("url1", 1, mBitmapConfig)); mMemCache.cacheBitmap(bitmap, new DecodeSignature("url1", 2, mBitmapConfig)); diff --git a/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/DiskCacheTests.java b/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/DiskCacheTests.java index 653a6eb..71e4026 100644 --- a/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/DiskCacheTests.java +++ b/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/DiskCacheTests.java @@ -1,78 +1,219 @@ package com.xtremelabs.imageutils; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.net.URL; + import android.graphics.Bitmap; +import android.graphics.Point; import android.test.AndroidTestCase; +import android.test.MoreAsserts; +import android.widget.ImageView; + +import com.xtremelabs.imageutils.DiskLRUCacher.FileFormatException; +import com.xtremelabs.imageutils.ImageLoader.Options; +import com.xtremelabs.imageutils.ImageLoader.Options.ScalingPreference; +import com.xtremelabs.imageutils.NetworkToDiskInterface.ImageDownloadResult; +import com.xtremelabs.imageutils.NetworkToDiskInterface.ImageDownloadResult.Result; public class DiskCacheTests extends AndroidTestCase { - private ImageSystemDiskCache mDiskCache; + private static final String IMAGE_URL = "http://placekitten.com/400/600"; + + private static final CacheRequest CACHE_REQUEST = new CacheRequest(IMAGE_URL); + + private DiskCache mDiskCache; @Override protected void setUp() throws Exception { super.setUp(); - mDiskCache = new DiskCache(getContext(), mImageDiskObserver) { - }; + if (mDiskCache == null) + mDiskCache = new DiskCache(getContext(), mImageDiskObserver); + + mDiskCache.init(); } - + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + mDiskCache.clear(); + } + public void testDownloadImageFromInputStream() { - fail(); + downloadImage(); } public void testIsCached() { - fail(); - } + assertFalse(mDiskCache.isCached(CACHE_REQUEST)); - public void testGetSampleSize() { - fail(); - } + downloadImage(); - public void testBumpOnDisk() { - fail(); + assertTrue(mDiskCache.isCached(CACHE_REQUEST)); } public void testSetDiskCacheSize() { - fail(); + assertFalse(mDiskCache.isCached(CACHE_REQUEST)); + + downloadImage(); + populateImageDetails(); + + assertTrue(mDiskCache.isCached(CACHE_REQUEST)); + + mDiskCache.setDiskCacheSize(1); + + assertFalse(mDiskCache.isCached(CACHE_REQUEST)); + + downloadImage(); + populateImageDetails(); + + assertFalse(mDiskCache.isCached(CACHE_REQUEST)); + + mDiskCache.setDiskCacheSize(1 * 1024 * 1024); + + downloadImage(); + populateImageDetails(); + + assertTrue(mDiskCache.isCached(CACHE_REQUEST)); } public void testGetImageDimensions() { - fail(); + assertNull(mDiskCache.getImageDimensions(CACHE_REQUEST)); + + downloadImage(); + populateImageDetails(); + + assertNotNull(mDiskCache.getImageDimensions(CACHE_REQUEST)); } public void testInvalidateUri() { fail(); } - public void testGetBitmapSynchronouslyFromDisk() { - fail(); + public void testJournalingLruEvictions() { + assertFalse(mDiskCache.isCached(CACHE_REQUEST)); + + downloadImage(); + populateImageDetails(); + + assertTrue(mDiskCache.isCached(CACHE_REQUEST)); + + mDiskCache = new DiskCache(mContext, mImageDiskObserver); + mDiskCache.setDiskCacheSizeWithoutClearing(1); + mDiskCache.init(); + + assertFalse(mDiskCache.isCached(CACHE_REQUEST)); + } + + public void testGetSampleSize() { + assertEquals(-1, mDiskCache.getSampleSize(CACHE_REQUEST)); + + downloadImage(); + populateImageDetails(); + + MoreAsserts.assertNotEqual(-1, mDiskCache.getSampleSize(CACHE_REQUEST)); + } + + public void testGetSampleSizeWithNoDetailsSaved() { + assertFalse(mDiskCache.isCached(CACHE_REQUEST)); + + downloadImage(); + + Options options = new Options(); + options.heightBounds = 300; + options.widthBounds = 200; + options.scalingPreference = ScalingPreference.MATCH_TO_SMALLER_DIMENSION; + CacheRequest cacheRequest = new CacheRequest(IMAGE_URL, getScalingInfo(null, options)); + assertEquals(2, mDiskCache.getSampleSize(cacheRequest)); + + fail(); // TODO read comment in getSampleSize + } + + public void testGetBitmapSynchronouslyFromDisk() throws FileNotFoundException, FileFormatException { + downloadImage(); + populateImageDetails(); + + DecodeSignature decodeSignature = new DecodeSignature(IMAGE_URL, 1, null); + Bitmap bitmap = mDiskCache.getBitmapSynchronouslyFromDisk(CACHE_REQUEST, decodeSignature); + assertNotNull(bitmap); } public void testCalculateAndSaveImageDetails() { - fail(); + assertFalse(mDiskCache.isCached(CACHE_REQUEST)); + + downloadImage(); + + assertEquals(1, mDiskCache.getSampleSize(CACHE_REQUEST)); + + populateImageDetails(); + + Options options = new Options(); + options.heightBounds = 300; + options.widthBounds = 200; + options.scalingPreference = ScalingPreference.MATCH_TO_SMALLER_DIMENSION; + CacheRequest cacheRequest = new CacheRequest(IMAGE_URL, getScalingInfo(null, options)); + assertEquals(2, mDiskCache.getSampleSize(cacheRequest)); } - public void testGetDetailsPrioritizable() { - fail(); + ScalingInfo getScalingInfo(ImageView imageView, final Options options) { + ScalingInfo scalingInfo = new ScalingInfo(); + if (options.overrideSampleSize != null) { + scalingInfo.sampleSize = options.overrideSampleSize; + return scalingInfo; + } + + Integer width = options.widthBounds; + Integer height = options.heightBounds; + + if (options.autoDetectBounds && imageView != null) { + Point viewBounds = ViewDimensionsUtil.getImageViewDimensions(imageView); + + width = getBounds(width, viewBounds.x); + height = getBounds(height, viewBounds.y); + } + + scalingInfo.width = width; + scalingInfo.height = height; + return scalingInfo; } - public void testGetDecodePrioritizable() { - fail(); + private static Integer getBounds(Integer currentDimension, int viewDimension) { + if (viewDimension != -1) { + if (currentDimension == null) { + currentDimension = viewDimension; + } else { + currentDimension = Math.min(currentDimension, viewDimension); + } + } + return currentDimension; + } + + private InputStream getInputStream() { + try { + return new URL(IMAGE_URL).openStream(); + } catch (Exception e) {} + return null; + } + + private void downloadImage() { + ImageDownloadResult result = mDiskCache.downloadImageFromInputStream(IMAGE_URL, getInputStream()); + assertEquals(result.getResult(), Result.SUCCESS); + } + + private void populateImageDetails() { + mDiskCache.cacheImageDetails(CACHE_REQUEST); } private final ImageDiskObserver mImageDiskObserver = new ImageDiskObserver() { @Override - public void onImageDetailsRetrieved(String uri) { - } + public void onImageDetailsRetrieved(String uri) {} @Override - public void onImageDetailsRequestFailed(String uri, String errorMessage) { - } + public void onImageDetailsRequestFailed(String uri, String errorMessage) {} @Override - public void onImageDecoded(DecodeSignature decodeSignature, Bitmap bitmap, ImageReturnedFrom returnedFrom) { - } + public void onImageDecoded(DecodeSignature decodeSignature, Bitmap bitmap, ImageReturnedFrom returnedFrom) {} @Override - public void onImageDecodeFailed(DecodeSignature decodeSignature, String error) { - } + public void onImageDecodeFailed(DecodeSignature decodeSignature, String error) {} }; } diff --git a/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/ImageSystemDatabaseTests.java b/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/ImageSystemDatabaseTests.java index cfa002a..25aebd8 100644 --- a/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/ImageSystemDatabaseTests.java +++ b/xl-image_utils-test_suite/src/com/xtremelabs/imageutils/ImageSystemDatabaseTests.java @@ -1,6 +1,8 @@ package com.xtremelabs.imageutils; +import android.os.SystemClock; import android.test.AndroidTestCase; +import android.test.MoreAsserts; import com.xtremelabs.imageutils.ImageSystemDatabase.ImageSystemDatabaseObserver; @@ -15,8 +17,13 @@ protected void setUp() throws Exception { super.setUp(); mDatabase = new ImageSystemDatabase(mDatabaseObserver); - mDatabase.init(getContext()); + mDatabase.init(mContext); + } + + @Override + protected void tearDown() throws Exception { mDatabase.clear(); + super.tearDown(); } public void testBeginWrite() { @@ -39,6 +46,20 @@ public void testEndWrite() { assertFalse(entry.hasDetails()); } + public void testBump() { + mDatabase.beginWrite(TEST_URI_1); + mDatabase.endWrite(TEST_URI_1); + + ImageEntry entry = mDatabase.getEntry(TEST_URI_1); + long lastAccessedTime = entry.lastAccessedTime; + + SystemClock.sleep(10); + + mDatabase.bump(TEST_URI_1); + + MoreAsserts.assertNotEqual(lastAccessedTime, entry.lastAccessedTime); + } + public void testWriteFailed() { mDatabase.beginWrite(TEST_URI_1); ImageEntry entry = mDatabase.getEntry(TEST_URI_1); @@ -56,9 +77,13 @@ public void testHasDetails() { int testSizeY = 10; mDatabase.beginWrite(TEST_URI_1); mDatabase.endWrite(TEST_URI_1); - mDatabase.submitDetails(TEST_URI_1, new Dimensions(testSizeX, testSizeY)); ImageEntry entry = mDatabase.getEntry(TEST_URI_1); + assertFalse(entry.hasDetails()); + + mDatabase.submitDetails(TEST_URI_1, new Dimensions(testSizeX, testSizeY), 100L); + + entry = mDatabase.getEntry(TEST_URI_1); assertNotNull(entry); assertTrue(entry.onDisk); @@ -76,7 +101,11 @@ public void testClear() { mDatabase.endWrite(TEST_URI_2); mDatabase.endWrite(TEST_URI_3); - mDatabase.submitDetails(TEST_URI_3, new Dimensions(0, 0)); + mDatabase.submitDetails(TEST_URI_3, new Dimensions(0, 0), 100L); + + assertNotNull(mDatabase.getEntry(TEST_URI_1)); + assertNotNull(mDatabase.getEntry(TEST_URI_2)); + assertNotNull(mDatabase.getEntry(TEST_URI_3)); mDatabase.clear(); @@ -85,12 +114,84 @@ public void testClear() { assertNull(mDatabase.getEntry(TEST_URI_3)); } - public void testStartupDataRecovery() { + public void testFileSize() { + mDatabase.beginWrite(TEST_URI_1); + mDatabase.beginWrite(TEST_URI_2); + mDatabase.beginWrite(TEST_URI_3); + mDatabase.endWrite(TEST_URI_1); + mDatabase.endWrite(TEST_URI_2); + mDatabase.endWrite(TEST_URI_3); + + assertEquals(0, mDatabase.getTotalFileSize()); + + mDatabase.submitDetails(TEST_URI_1, new Dimensions(0, 0), 100L); + mDatabase.submitDetails(TEST_URI_2, new Dimensions(0, 0), 100L); + mDatabase.submitDetails(TEST_URI_3, new Dimensions(0, 0), 100L); + + assertEquals(300, mDatabase.getTotalFileSize()); + + mDatabase.submitDetails(TEST_URI_3, new Dimensions(0, 0), 200L); + + assertEquals(400, mDatabase.getTotalFileSize()); + } + + public void testNoImageOnDiskTriggerDownload() { fail(); + // should probably be somewhere else + + /* + * 1. Stub out getBitmapSynchronouslyFromDisk to throw a FileNotFoundException. + * + * 2. Stub out the DiskCache interface with a method for "restart image load" + * + * 3. Put an entry in the database for the "fake" image we are decoding. + * + * 4. Create a decode prioritizable and synchronously call "execute" on it. + * + * 5. Assert true that the database has removed the row for our image. + * + * 6. Assert true that the "restart image load" method was called. -- This is not built out yet and may not be 100% correct. + */ } public void testStartupDataRecoveryOrdering() { - fail(); + mDatabase.beginWrite(TEST_URI_1); + mDatabase.beginWrite(TEST_URI_2); + mDatabase.beginWrite(TEST_URI_3); + + mDatabase.endWrite(TEST_URI_1); + mDatabase.endWrite(TEST_URI_2); + mDatabase.endWrite(TEST_URI_3); + + mDatabase.close(); + + mDatabase = new ImageSystemDatabase(mDatabaseObserver); + mDatabase.init(mContext); + + assertEquals(mDatabase.removeLRU().uri, TEST_URI_1); + assertEquals(mDatabase.removeLRU().uri, TEST_URI_2); + assertEquals(mDatabase.removeLRU().uri, TEST_URI_3); + assertNull(mDatabase.removeLRU()); + + mDatabase.beginWrite(TEST_URI_1); + mDatabase.beginWrite(TEST_URI_2); + mDatabase.beginWrite(TEST_URI_3); + + mDatabase.endWrite(TEST_URI_1); + mDatabase.endWrite(TEST_URI_2); + mDatabase.endWrite(TEST_URI_3); + + mDatabase.bump(TEST_URI_1); + + mDatabase.close(); + + mDatabase = new ImageSystemDatabase(mDatabaseObserver); + mDatabase.init(mContext); + + assertEquals(mDatabase.removeLRU().uri, TEST_URI_2); + assertEquals(mDatabase.removeLRU().uri, TEST_URI_3); + assertEquals(mDatabase.removeLRU().uri, TEST_URI_1); + assertNull(mDatabase.removeLRU()); } public void testJournalingEvictionWithNoWrite() { @@ -102,11 +203,17 @@ public void testJournalingEvictionWithNoWrite() { assertFalse(entry.hasDetails()); assertEquals(TEST_URI_1, entry.uri); + mDatabase.close(); + ImageSystemDatabase database = new ImageSystemDatabase(mDatabaseObserver); entry = database.getEntry(TEST_URI_1); assertNull(entry); } + public void testJournalingData() { + fail(); // TODO make sure that data written is same as data read after re-start (seen it fail) + } + public void testJournalingEvictionsWithNoWrite() { mDatabase.beginWrite(TEST_URI_1); mDatabase.beginWrite(TEST_URI_2); @@ -114,45 +221,75 @@ public void testJournalingEvictionsWithNoWrite() { mDatabase.endWrite(TEST_URI_2); + ImageEntry entry1 = mDatabase.getEntry(TEST_URI_1); + ImageEntry entry2 = mDatabase.getEntry(TEST_URI_2); + ImageEntry entry3 = mDatabase.getEntry(TEST_URI_3); + + assertNotNull(entry1); + assertNotNull(entry2); + assertNotNull(entry3); + mDatabase.close(); ImageSystemDatabase database = new ImageSystemDatabase(mDatabaseObserver); - ImageEntry entry1 = database.getEntry(TEST_URI_1); - ImageEntry entry2 = database.getEntry(TEST_URI_2); - ImageEntry entry3 = database.getEntry(TEST_URI_3); + database.init(mContext); + entry1 = database.getEntry(TEST_URI_1); + entry2 = database.getEntry(TEST_URI_2); + entry3 = database.getEntry(TEST_URI_3); assertNull(entry1); assertNotNull(entry2); assertNull(entry3); } - public void testJournalingWithDetailsRequest() { - fail(); - } + public void testRemoveLRU() { + mDatabase.beginWrite(TEST_URI_1); + mDatabase.beginWrite(TEST_URI_2); + mDatabase.beginWrite(TEST_URI_3); - public void testJournalingWithDetailsRequests() { - fail(); - } + mDatabase.endWrite(TEST_URI_1); + mDatabase.endWrite(TEST_URI_2); + mDatabase.endWrite(TEST_URI_3); - public void testJournalingLruEvictions() { - fail(); - } + assertEquals(mDatabase.removeLRU().uri, TEST_URI_1); + assertEquals(mDatabase.removeLRU().uri, TEST_URI_2); + assertEquals(mDatabase.removeLRU().uri, TEST_URI_3); + assertNull(mDatabase.removeLRU()); - public void testDetailsOnDatabaseRecovery() { - fail(); + mDatabase.beginWrite(TEST_URI_1); + mDatabase.beginWrite(TEST_URI_2); + mDatabase.beginWrite(TEST_URI_3); + + mDatabase.endWrite(TEST_URI_1); + mDatabase.endWrite(TEST_URI_2); + mDatabase.endWrite(TEST_URI_3); + + mDatabase.bump(TEST_URI_1); + + assertEquals(mDatabase.removeLRU().uri, TEST_URI_2); + assertEquals(mDatabase.removeLRU().uri, TEST_URI_3); + assertEquals(mDatabase.removeLRU().uri, TEST_URI_1); + assertNull(mDatabase.removeLRU()); } - public void testNoEvictionsForIncompleteDownloads() { - fail(); + public void testNoLruEvictionsForIncompleteDownloads() { + mDatabase.beginWrite(TEST_URI_1); + mDatabase.beginWrite(TEST_URI_2); + mDatabase.beginWrite(TEST_URI_3); + + mDatabase.endWrite(TEST_URI_2); + mDatabase.endWrite(TEST_URI_3); + + assertEquals(mDatabase.removeLRU().uri, TEST_URI_2); + assertEquals(mDatabase.removeLRU().uri, TEST_URI_3); + assertNull(mDatabase.removeLRU()); } private final ImageSystemDatabaseObserver mDatabaseObserver = new ImageSystemDatabaseObserver() { @Override - public void onDetailsRequired(String filename) { - } + public void onDetailsRequired(String filename) {} @Override - public void onBadJournalEntry(String filename) { - } + public void onBadJournalEntry(ImageEntry entry) {} }; } diff --git a/xl_image_utils_lib/project.properties b/xl_image_utils_lib/project.properties index 36f1594..484dab0 100644 --- a/xl_image_utils_lib/project.properties +++ b/xl_image_utils_lib/project.properties @@ -11,5 +11,5 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-15 +target=android-17 android.library=true diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/AsyncOperationsMaps.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/AsyncOperationsMaps.java index 59592b6..5015841 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/AsyncOperationsMaps.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/AsyncOperationsMaps.java @@ -214,7 +214,7 @@ public void transferOperation(String uri, RequestParameters requestParameters, I case DEFAULT: CacheRequest cacheRequest = requestParameters.cacheRequest; int sampleSize = mObserver.getSampleSize(cacheRequest); - DecodeSignature decodeSignature = new DecodeSignature(uri, sampleSize, requestParameters.cacheRequest.getOptions().preferedConfig); + DecodeSignature decodeSignature = new DecodeSignature(uri, sampleSize, requestParameters.cacheRequest.getOptions().preferredConfig); registerDecodeRequest(cacheRequest, decodeSignature, imageCacherListener, requestParameters.imageReturnedFrom); break; @@ -396,7 +396,7 @@ private void cancelDecodePrioritizable(ImageCacherListener imageCacherListener) private synchronized DecodeSignature getDecodeSignature(CacheRequest cacheRequest) { int sampleSize = mObserver.getSampleSize(cacheRequest); - return new DecodeSignature(cacheRequest.getUri(), sampleSize, cacheRequest.getOptions().preferedConfig); + return new DecodeSignature(cacheRequest.getUri(), sampleSize, cacheRequest.getOptions().preferredConfig); } static interface OperationsObserver { diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/DiskCache.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/DiskCache.java index 63599b8..c9ec117 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/DiskCache.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/DiskCache.java @@ -1,29 +1,45 @@ package com.xtremelabs.imageutils; +import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.net.URISyntaxException; +import java.util.Map; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import com.xtremelabs.imageutils.DiskLRUCacher.FileFormatException; +import com.xtremelabs.imageutils.ImageSystemDatabase.ImageSystemDatabaseObserver; import com.xtremelabs.imageutils.NetworkToDiskInterface.ImageDownloadResult.Result; class DiskCache implements ImageSystemDiskCache { + private static final int MAX_PERMANENT_STORAGE_IMAGE_DIMENSIONS_CACHED = 25; private final Context mContext; private final ImageDiskObserver mImageDiskObserver; + private final Map mPermanentStorageMap = new LRUMap(34, MAX_PERMANENT_STORAGE_IMAGE_DIMENSIONS_CACHED); private ImageSystemDatabase mImageSystemDatabase; private FileSystemManager mFileSystemManager; + private long mMaxCacheSize = 50 * 1024 * 1024; DiskCache(Context context, ImageDiskObserver imageDiskObserver) { - mContext = context; + mContext = context.getApplicationContext(); mImageDiskObserver = imageDiskObserver; + mFileSystemManager = new FileSystemManager("img", mContext); + mImageSystemDatabase = new ImageSystemDatabase(mImageSystemDatabaseObserver); } - + + void init() { + mImageSystemDatabase.init(mContext); + clearLRUFiles(); + } + @Override public ImageDownloadResult downloadImageFromInputStream(String uri, InputStream inputStream) { ImageDownloadResult result; @@ -34,6 +50,7 @@ public ImageDownloadResult downloadImageFromInputStream(String uri, InputStream mFileSystemManager.loadStreamToFile(inputStream, imageEntry.getFileName()); mImageSystemDatabase.endWrite(uri); result = new ImageDownloadResult(Result.SUCCESS); + } catch (IOException e) { mImageSystemDatabase.writeFailed(uri); result = new ImageDownloadResult(Result.FAILURE, "Failed to download image to disk! IOException caught. Error message: " + e.getMessage()); @@ -44,62 +61,232 @@ public ImageDownloadResult downloadImageFromInputStream(String uri, InputStream @Override public boolean isCached(CacheRequest cacheRequest) { - // TODO Auto-generated method stub - return false; + boolean isCached; + String uri = cacheRequest.getUri(); + if (cacheRequest.isFileSystemRequest()) { + isCached = mPermanentStorageMap.get(uri) != null; + } else { + ImageEntry entry = mImageSystemDatabase.getEntry(uri); + isCached = entry != null && entry.onDisk; + } + + return isCached; } @Override - public int getSampleSize(CacheRequest imageRequest) { - // TODO Auto-generated method stub - return 0; + public int getSampleSize(CacheRequest cacheRequest) { + Dimensions dimensions = getImageDimensions(cacheRequest); + if (dimensions == null) { + return -1; + } + + return SampleSizeCalculationUtility.calculateSampleSize(cacheRequest, dimensions); } @Override public void bumpOnDisk(String uri) { - // TODO Auto-generated method stub - + mImageSystemDatabase.bump(uri); } @Override public void setDiskCacheSize(long sizeInBytes) { - // TODO Auto-generated method stub - + mMaxCacheSize = sizeInBytes; + clearLRUFiles(); } @Override public Dimensions getImageDimensions(CacheRequest cacheRequest) { - // TODO Auto-generated method stub - return null; + String uri = cacheRequest.getUri(); + Dimensions dimensions; + if (cacheRequest.isFileSystemRequest()) { + dimensions = mPermanentStorageMap.get(uri); + } else { + ImageEntry entry = mImageSystemDatabase.getEntry(uri); + dimensions = entry != null && entry.hasDetails() ? new Dimensions(entry.sizeX, entry.sizeY) : null; + } + return dimensions; } @Override public void invalidateFileSystemUri(String uri) { - // TODO Auto-generated method stub - + // TODO WATCH OUT FOR SYNCHRONIZATION ISSUES, probably should go through same flow that for 2 identical requests + mPermanentStorageMap.remove(uri); } @Override public Bitmap getBitmapSynchronouslyFromDisk(CacheRequest cacheRequest, DecodeSignature decodeSignature) throws FileNotFoundException, FileFormatException { - // TODO Auto-generated method stub - return null; + int sampleSize = decodeSignature.sampleSize; + Bitmap.Config bitmapConfig = decodeSignature.bitmapConfig; + + File file = getFile(cacheRequest); + FileInputStream fileInputStream = new FileInputStream(file); + + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inSampleSize = sampleSize; + opts.inPreferredConfig = bitmapConfig; + + Bitmap bitmap = BitmapFactory.decodeStream(fileInputStream, null, opts); + if (fileInputStream != null) { + try { + fileInputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (bitmap == null) { + file.delete(); + throw new FileFormatException(); + } + return bitmap; } @Override public void calculateAndSaveImageDetails(CacheRequest cacheRequest) throws URISyntaxException, FileNotFoundException { - // TODO Auto-generated method stub + String uri = cacheRequest.getUri(); + File file = getFile(cacheRequest); + Dimensions dimensions = getImageDimensionsFromDisk(file); + + if (cacheRequest.isFileSystemRequest()) { + mPermanentStorageMap.put(uri, dimensions); + } else { + mImageSystemDatabase.submitDetails(uri, dimensions, file.length()); + clearLRUFiles(); + } + } + + private void clearLRUFiles() { + while (mImageSystemDatabase.getTotalFileSize() > mMaxCacheSize) { + ImageEntry entry = mImageSystemDatabase.removeLRU(); + mFileSystemManager.deleteFile(entry.getFileName()); + } + } + + private File getFile(CacheRequest cacheRequest) throws FileNotFoundException { + String uri = cacheRequest.getUri(); + File file; + if (cacheRequest.isFileSystemRequest()) { + try { + file = new File(new URI(uri.replace(" ", "%20")).getPath()); + } catch (URISyntaxException e) { + e.printStackTrace(); + throw new FileNotFoundException(); + } + } else { + ImageEntry entry = mImageSystemDatabase.getEntry(uri); + if (entry == null) + throw new FileNotFoundException(); + file = mFileSystemManager.getFile(entry.getFileName()); + } + return file; + } + + private static Dimensions getImageDimensionsFromDisk(File file) throws FileNotFoundException { + FileInputStream fileInputStream = null; + try { + fileInputStream = new FileInputStream(file); + BitmapFactory.Options o = new BitmapFactory.Options(); + o.inJustDecodeBounds = true; + BitmapFactory.decodeStream(fileInputStream, null, o); + return new Dimensions(o.outWidth, o.outHeight); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + throw e; + + } finally { + if (fileInputStream != null) { + try { + fileInputStream.close(); + } catch (IOException e) {} + } + } } @Override - public Prioritizable getDetailsPrioritizable(CacheRequest imageRequest) { - // TODO Auto-generated method stub - return null; + public Prioritizable getDetailsPrioritizable(final CacheRequest cacheRequest) { + return new DefaultPrioritizable(cacheRequest, new Request(cacheRequest.getUri())) { + @Override + public void execute() { + cacheImageDetails(cacheRequest); + } + }; + } + + void cacheImageDetails(CacheRequest cacheRequest) { + String uri = cacheRequest.getUri(); + try { + calculateAndSaveImageDetails(cacheRequest); + mImageDiskObserver.onImageDetailsRetrieved(uri); + + } catch (URISyntaxException e) { + mImageDiskObserver.onImageDetailsRequestFailed(uri, "URISyntaxException caught when attempting to retrieve image details. URI: " + uri); + } catch (FileNotFoundException e) { + mImageDiskObserver.onImageDetailsRequestFailed(uri, "Image file not found. URI: " + uri); + } } @Override - public Prioritizable getDecodePrioritizable(CacheRequest cacheRequest, DecodeSignature decodeSignature, ImageReturnedFrom imageReturnedFrom) { - // TODO Auto-generated method stub - return null; + public Prioritizable getDecodePrioritizable(final CacheRequest cacheRequest, final DecodeSignature decodeSignature, final ImageReturnedFrom imageReturnedFrom) { + return new DefaultPrioritizable(cacheRequest, new Request(decodeSignature)) { + @Override + public void execute() { + boolean failed = false; + String errorMessage = null; + Bitmap bitmap = null; + try { + bitmap = getBitmapSynchronouslyFromDisk(cacheRequest, decodeSignature); + + } catch (FileNotFoundException e) { + failed = true; + errorMessage = "FileNotFoundException -- Disk decode failed with error message: " + e.getMessage(); + + } catch (FileFormatException e) { + failed = true; + errorMessage = "FileFormatException -- Disk decode failed with error message: " + e.getMessage(); + } + + if (!failed) { + mImageDiskObserver.onImageDecoded(decodeSignature, bitmap, imageReturnedFrom); + + } else if (cacheRequest.isFileSystemRequest()) { + mPermanentStorageMap.remove(decodeSignature.uri); + mImageDiskObserver.onImageDecodeFailed(decodeSignature, errorMessage); + + } else { + try { + mFileSystemManager.deleteFile(getFile(cacheRequest)); + } catch (FileNotFoundException e) {} + mImageSystemDatabase.deleteEntry(decodeSignature.uri); + mImageDiskObserver.onImageDecodeFailed(decodeSignature, errorMessage); + } + // TODO need to re-start entire process if image was supposed to be on disk but wasn't + } + }; + } + + private final ImageSystemDatabaseObserver mImageSystemDatabaseObserver = new ImageSystemDatabaseObserver() { + + @Override + public void onDetailsRequired(String filename) { + cacheImageDetails(new CacheRequest(filename)); + } + + @Override + public void onBadJournalEntry(ImageEntry entry) { + mFileSystemManager.deleteFile(entry.getFileName()); + } + }; + + /** ALL THE METHODS BELOW ARE FOR TESTING PURPOSES ONLY!!!! */ + + void clear() { + mImageSystemDatabase.clear(); + mFileSystemManager.clearDirectory(); + } + + void setDiskCacheSizeWithoutClearing(long bytes) { + mMaxCacheSize = bytes; } } diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/DiskLRUCacher.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/DiskLRUCacher.java index ddfeb30..ffd38f8 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/DiskLRUCacher.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/DiskLRUCacher.java @@ -280,9 +280,6 @@ private static Dimensions getImageDimensionsFromDisk(File file) throws FileNotFo } public static class FileFormatException extends Exception { - /** - * - */ private static final long serialVersionUID = -2180782787028503586L; } diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/DisplayUtility.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/DisplayUtility.java index 02c4b42..ff34dea 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/DisplayUtility.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/DisplayUtility.java @@ -16,35 +16,18 @@ package com.xtremelabs.imageutils; -import android.annotation.SuppressLint; import android.content.Context; -import android.graphics.Point; -import android.os.Build; -import android.view.Display; -import android.view.WindowManager; +import android.util.DisplayMetrics; class DisplayUtility { - private volatile Dimensions displaySize; + private Dimensions dimensions; - @SuppressLint("NewApi") - @SuppressWarnings("deprecation") public Dimensions getDisplaySize(Context applicationContext) { - if (displaySize == null) { - Display display = ((WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); - - if (Build.VERSION.SDK_INT < 13) { - // These method calls are used before API level 13. - displaySize = new Dimensions(display.getWidth(), display.getHeight()); - } else { - Point size = new Point(); - display.getSize(size); - displaySize = new Dimensions(size.x, size.y); - } + if (dimensions == null) { + DisplayMetrics metrics = applicationContext.getResources().getDisplayMetrics(); + dimensions = new Dimensions(metrics.widthPixels, metrics.heightPixels); } - return displaySize; - } - public void notifyConfigurationChanged() { - displaySize = null; + return dimensions; } } diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/FileSystemManager.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/FileSystemManager.java index c48610c..81982a7 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/FileSystemManager.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/FileSystemManager.java @@ -134,6 +134,10 @@ private void deleteDirectory(File directory) { public void deleteFile(String name) { File file = getFile(name); + deleteFile(file); + } + + public void deleteFile(File file) { if (!file.isDirectory()) { file.delete(); } else { diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageCacher.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageCacher.java index 930c651..c4e03c9 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageCacher.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageCacher.java @@ -80,7 +80,7 @@ public ImageResponse getBitmap(CacheRequest cacheRequest, ImageCacherListener im boolean isCached = mDiskCache.isCached(cacheRequest); if (isCached && sampleSize != -1) { Bitmap bitmap; - DecodeSignature decodeSignature = new DecodeSignature(uri, sampleSize, cacheRequest.getOptions().preferedConfig); + DecodeSignature decodeSignature = new DecodeSignature(uri, sampleSize, cacheRequest.getOptions().preferredConfig); bitmap = mMemoryCache.getBitmap(decodeSignature); if (bitmap != null) return new ImageResponse(bitmap, ImageReturnedFrom.MEMORY, ImageResponseStatus.SUCCESS); @@ -118,7 +118,7 @@ public ImageResponse getBitmapSynchronouslyFromDiskOrMemory(CacheRequest cacheRe try { if (isCached && sampleSize != -1) { - DecodeSignature decodeSignature = new DecodeSignature(uri, sampleSize, cacheRequest.getOptions().preferedConfig); + DecodeSignature decodeSignature = new DecodeSignature(uri, sampleSize, cacheRequest.getOptions().preferredConfig); Bitmap bitmap; if ((bitmap = mMemoryCache.getBitmap(decodeSignature)) != null) { return new ImageResponse(bitmap, ImageReturnedFrom.MEMORY, ImageResponseStatus.SUCCESS); @@ -129,7 +129,7 @@ public ImageResponse getBitmapSynchronouslyFromDiskOrMemory(CacheRequest cacheRe mDiskCache.calculateAndSaveImageDetails(cacheRequest); sampleSize = getSampleSize(cacheRequest); if (sampleSize != -1) { - DecodeSignature decodeSignature = new DecodeSignature(uri, sampleSize, cacheRequest.getOptions().preferedConfig); + DecodeSignature decodeSignature = new DecodeSignature(uri, sampleSize, cacheRequest.getOptions().preferredConfig); return getBitmapSynchronouslyFromDisk(cacheRequest, decodeSignature); } } @@ -342,14 +342,14 @@ protected Void doInBackground(Void... params) { return null; } - DecodeSignature decodeSignature = new DecodeSignature(cacheRequest.getUri(), sampleSize, cacheRequest.getOptions().preferedConfig); + DecodeSignature decodeSignature = new DecodeSignature(cacheRequest.getUri(), sampleSize, cacheRequest.getOptions().preferredConfig); Bitmap bitmap; if ((bitmap = mMemoryCache.getBitmap(decodeSignature)) != null) { imageCacherListener.onImageAvailable(new ImageResponse(bitmap, ImageReturnedFrom.DISK, ImageResponseStatus.SUCCESS)); } else { decodeBitmapFromDisk(cacheRequest, decodeSignature, imageCacherListener); } - } else if (cacheRequest.isFileSystemRequest()) { + } else if (cacheRequest.isFileSystemRequest() || isCached) { retrieveImageDetails(cacheRequest, imageCacherListener); } else { downloadImageFromNetwork(cacheRequest, imageCacherListener); diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageEntry.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageEntry.java index 21ed1f0..0d9a494 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageEntry.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageEntry.java @@ -8,12 +8,14 @@ class ImageEntry { public long lastAccessedTime = creationTime; public int sizeX = -1; public int sizeY = -1; + public long fileSize; + public long expiry = Long.MAX_VALUE; String getFileName() { return Long.toString(id); } public boolean hasDetails() { - return sizeX != -1 || sizeY != -1; + return sizeX != -1 || sizeY != -1 || fileSize != 0; } } diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageLoader.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageLoader.java index dcdf277..0517c63 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageLoader.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageLoader.java @@ -174,10 +174,6 @@ public void destroy() { } } - public void notifyConfigurationChanged() { - mDisplayUtility.notifyConfigurationChanged(); - } - /** * The ImageLoader will default to the options provided here if no other options are provided. * @@ -614,7 +610,7 @@ public void precacheImageToDiskAndMemory(String uri, Dimensions bounds, Options Options o = new Options(); o.autoDetectBounds = options.autoDetectBounds; o.overrideSampleSize = options.overrideSampleSize; - o.preferedConfig = options.preferedConfig; + o.preferredConfig = options.preferredConfig; o.scalingPreference = options.scalingPreference; o.useScreenSizeAsBounds = options.useScreenSizeAsBounds; o.widthBounds = bounds.width; @@ -921,6 +917,6 @@ public static enum ScalingPreference { *
* Default value: null. */ - public Bitmap.Config preferedConfig = null; + public Bitmap.Config preferredConfig = null; } } diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageSystemDatabase.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageSystemDatabase.java index 946d576..c14fbf8 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageSystemDatabase.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImageSystemDatabase.java @@ -5,16 +5,13 @@ import android.content.Context; import android.database.Cursor; -import android.database.sqlite.SQLiteCursor; -import android.database.sqlite.SQLiteCursorDriver; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteQuery; import android.util.Log; +import com.xtremelabs.imageutils.ImagesTable.Columns; import com.xtremelabs.imageutils.db.Database; import com.xtremelabs.imageutils.db.Table; -class ImageSystemDatabase { +class ImageSystemDatabase { // TODO should this be implementing an interface? private final ImagesTable mImagesTable = ImagesTable.getInstance(); private final ImageSystemDatabaseObserver mObserver; private Database mDatabase; @@ -28,14 +25,7 @@ public void init(Context context) { List> tables = new ArrayList>(); tables.add(mImagesTable); - mDatabase = new Database(context, new SQLiteDatabase.CursorFactory() { - @SuppressWarnings("deprecation") - @Override - public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, SQLiteQuery query) { - return new SQLiteCursor(db, masterQuery, editTable, query); - } - }, tables); - + mDatabase = new Database(context, tables); populateCache(); performBadFileCheck(); } @@ -43,76 +33,84 @@ public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, Strin public void beginWrite(String uri) { ImageEntry entry = new ImageEntry(); entry.uri = uri; - mImagesTable.insert(entry, mDatabase.getWritableDatabase()); + entry.id = mImagesTable.insert(mDatabase.getWritableDatabase(), entry); mCache.putEntry(entry); } public void endWrite(String uri) { ImageEntry entry = mCache.getEntry(uri); entry.onDisk = true; + mImagesTable.insert(mDatabase.getWritableDatabase(), entry); + } + + public void bump(String uri) { + ImageEntry entry = mCache.getEntry(uri); entry.lastAccessedTime = System.currentTimeMillis(); - mImagesTable.insert(entry, mDatabase.getWritableDatabase()); + mImagesTable.insert(mDatabase.getWritableDatabase(), entry); } public void writeFailed(String uri) { - ImageEntry entry = mCache.removeEntry(uri); - String whereClause = ImagesTable.Columns.ID.getColumnName() + "=?"; - String[] whereArgs = new String[] { Long.toString(entry.id) }; - mImagesTable.delete(mDatabase.getWritableDatabase(), whereClause, whereArgs); + deleteEntry(uri); + } + + public void deleteEntry(String uri) { + mCache.removeEntry(uri); + deleteRow(uri); } ImageEntry getEntry(String uri) { return mCache.getEntry(uri); } + long getTotalFileSize() { + String[] columns = new String[] { "SUM(" + Columns.FILE_SIZE.getName() + ")" }; + Cursor cursor = mImagesTable.selectFromTable(mDatabase.getReadableDatabase(), columns, null, null, null, null, null, null); + cursor.moveToFirst(); + long total = cursor.getLong(0); + cursor.close(); + return total; + } + void clear() { mCache.clear(); mImagesTable.onClear(mDatabase.getWritableDatabase()); } - void submitDetails(String uri, Dimensions dimensions) { + void submitDetails(String uri, Dimensions dimensions, long fileSize) { ImageEntry entry = mCache.getEntry(uri); entry.sizeX = dimensions.width; entry.sizeY = dimensions.height; - mImagesTable.insert(entry, mDatabase.getWritableDatabase()); + entry.fileSize = fileSize; + mImagesTable.insert(mDatabase.getWritableDatabase(), entry); } private void populateCache() { Cursor allEntries = mImagesTable.selectAllFromTable(mDatabase.getReadableDatabase()); Log.d("JAMIE", "Entries in database: " + allEntries.getCount()); while (allEntries.moveToNext()) { - ImageEntry entry = new ImageEntry(); - entry.id = allEntries.getLong(allEntries.getColumnIndex(ImagesTable.Columns.ID.getColumnName())); - entry.uri = allEntries.getString(allEntries.getColumnIndex(ImagesTable.Columns.URI.getColumnName())); - entry.creationTime = allEntries.getLong(allEntries.getColumnIndex(ImagesTable.Columns.CREATION_TIME.getColumnName())); - entry.lastAccessedTime = allEntries.getLong(allEntries.getColumnIndex(ImagesTable.Columns.LAST_ACCESSED_TIME.getColumnName())); - entry.onDisk = allEntries.getInt(allEntries.getColumnIndex(ImagesTable.Columns.ON_DISK.getColumnName())) == 1; - entry.sizeX = allEntries.getInt(allEntries.getColumnIndex(ImagesTable.Columns.SIZE_X.getColumnName())); - entry.sizeY = allEntries.getInt(allEntries.getColumnIndex(ImagesTable.Columns.SIZE_Y.getColumnName())); - + ImageEntry entry = ImagesTable.getEntryFromCursor(allEntries); mCache.putEntry(entry); - Log.d("JAMIE", "Recovered URI: " + entry.uri + ", ONDISK: " + entry.onDisk); } } private void performBadFileCheck() { - String onDiskColumn = ImagesTable.Columns.ON_DISK.getColumnName(); + String onDiskColumn = ImagesTable.Columns.ON_DISK.getName(); Cursor cursor = mImagesTable.selectFromTable(mDatabase.getReadableDatabase(), onDiskColumn + "=?", new String[] { "0" }); while (cursor.moveToNext()) { - Log.d("JAMIE", "Deleting an item. URI: " + cursor.getString(cursor.getColumnIndex(ImagesTable.Columns.URI.getColumnName()))); - int columnIndex = cursor.getColumnIndex(ImagesTable.Columns.ID.getColumnName()); - int badImageEntryId = cursor.getInt(columnIndex); - String filename = Integer.toString(badImageEntryId); - - mObserver.onBadJournalEntry(filename); - deleteRow(badImageEntryId); + ImageEntry entry = ImagesTable.getEntryFromCursor(cursor); + Log.d("JAMIE", "Deleting an item. URI: " + entry.uri); + deleteEntry(entry.uri); + mObserver.onBadJournalEntry(entry); } + cursor.close(); } - private void deleteRow(int badImageEntryId) { - mImagesTable.delete(mDatabase.getWritableDatabase(), ImagesTable.Columns.ID.getColumnName() + "=?", new String[] { Integer.toString(badImageEntryId) }); + private void deleteRow(String uri) { + String whereClause = ImagesTable.Columns.URI.getName() + "=?"; + String[] whereArgs = new String[] { uri }; + mImagesTable.delete(mDatabase.getWritableDatabase(), whereClause, whereArgs); } /** @@ -123,8 +121,23 @@ void close() { } interface ImageSystemDatabaseObserver { - void onBadJournalEntry(String filename); + void onBadJournalEntry(ImageEntry entry); void onDetailsRequired(String filename); } + + public ImageEntry removeLRU() { + String orderBy = Columns.LAST_ACCESSED_TIME + " ASC"; + String selection = Columns.ON_DISK.getName() + "=?"; + Cursor cursor = mImagesTable.selectFromTable(mDatabase.getReadableDatabase(), null, selection, new String[] { "1" }, null, null, orderBy, Integer.toString(1)); + + ImageEntry entry = null; + if (cursor.moveToFirst()) { + entry = ImagesTable.getEntryFromCursor(cursor); + deleteEntry(entry.uri); + } + + return entry; + } + } diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImagesTable.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImagesTable.java index 4dbce47..172dec6 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImagesTable.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ImagesTable.java @@ -3,104 +3,116 @@ import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import android.util.Log; +import android.provider.BaseColumns; import com.xtremelabs.imageutils.db.Table; class ImagesTable extends Table { - enum Columns { - ID(0), URI(1), ON_DISK(2), CREATION_TIME(3), LAST_ACCESSED_TIME(4), SIZE_X(5), SIZE_Y(6); - - private final int mIndex; + private static final String TABLE_NAMES = "images"; - private Columns(int index) { - mIndex = index; - } + // must remain in same order as Columns enum + private static final String[] COLUMNS = { + BaseColumns._ID, + "uri", + "on_disk", + "creation_time", + "last_accessed_time", + "size_x", + "size_y", + "fileSize", + "expiry"}; - String getColumnName() { - return mColumns[mIndex]; + enum Columns { + ID, + URI, + ON_DISK, + CREATION_TIME, + LAST_ACCESSED_TIME, + SIZE_X, + SIZE_Y, + FILE_SIZE, + EXPIRY; + + String getName() { + int index = ordinal(); + return COLUMNS[index]; } } - private static class InstanceHolder { - private static ImagesTable sInstance = new ImagesTable(); - } - - private final static String[] mColumns = { "_id", "uri", "on_disk", "creation_time", "last_accessed_time", "size_x", "size_y" }; - private final String mTableName = "images"; + private static final ImagesTable sInstance = new ImagesTable(); static ImagesTable getInstance() { - return InstanceHolder.sInstance; + return sInstance; } @Override public String[] getColumns() { - return mColumns; + return COLUMNS; } @Override public String getTableName() { - return mTableName; - } - - @Override - public void insert(ImageEntry item, SQLiteDatabase db) { - ContentValues contentValues = new ContentValues(); - contentValues.put(mColumns[1], item.uri); - contentValues.put(mColumns[2], item.onDisk); - contentValues.put(mColumns[3], item.creationTime); - contentValues.put(mColumns[4], item.lastAccessedTime); - contentValues.put(mColumns[5], item.sizeX); - contentValues.put(mColumns[6], item.sizeY); - Log.d("JAMIE", "Insertion result: " + db.insertWithOnConflict(mTableName, null, contentValues, SQLiteDatabase.CONFLICT_REPLACE)); + return TABLE_NAMES; } @Override protected String getColumnsForCreation() { - StringBuilder builder = new StringBuilder(); - builder.append(mColumns[0] + " INTEGER PRIMARY KEY AUTOINCREMENT, "); - builder.append(mColumns[1] + " TEXT, "); - builder.append(mColumns[2] + " INTEGER, "); - builder.append(mColumns[3] + " BIGINT, "); - builder.append(mColumns[4] + " BIGINT, "); - builder.append(mColumns[5] + " INTEGER, "); - builder.append(mColumns[6] + " INTEGER, "); - return builder.toString(); + String columns = + COLUMNS[0] + " INTEGER PRIMARY KEY, " + + COLUMNS[1] + " TEXT, " + + COLUMNS[2] + " INTEGER, " + + COLUMNS[3] + " INTEGER, " + + COLUMNS[4] + " INTEGER, " + + COLUMNS[5] + " INTEGER, " + + COLUMNS[6] + " INTEGER, " + + COLUMNS[7] + " INTEGER, " + + COLUMNS[8] + " INTEGER, "; + return columns; } @Override protected String getUniqueString() { - return mColumns[0] + ", " + mColumns[1]; + return COLUMNS[1]; } @Override protected ContentValues toContentValues(ImageEntry item) { ContentValues contentValues = new ContentValues(); - contentValues.put(mColumns[0], item.id); - contentValues.put(mColumns[1], item.uri); - contentValues.put(mColumns[2], item.onDisk); - contentValues.put(mColumns[3], item.creationTime); - contentValues.put(mColumns[4], item.lastAccessedTime); - contentValues.put(mColumns[5], item.sizeX); - contentValues.put(mColumns[6], item.sizeY); + // id is generated by DB, not model + contentValues.put(COLUMNS[1], item.uri); + contentValues.put(COLUMNS[2], item.onDisk ? 1 : 0); + contentValues.put(COLUMNS[3], item.creationTime); + contentValues.put(COLUMNS[4], item.lastAccessedTime); + contentValues.put(COLUMNS[5], item.sizeX); + contentValues.put(COLUMNS[6], item.sizeY); + contentValues.put(COLUMNS[7], item.fileSize); + contentValues.put(COLUMNS[8], item.expiry); return contentValues; } - public ImageEntry getEntry(String uri, SQLiteDatabase db) { + public ImageEntry getEntry(SQLiteDatabase db, String uri) { ImageEntry entry = null; - Cursor cursor = selectFromTable(db, Columns.URI.getColumnName() + "=?", new String[] { uri }); - if (cursor.getCount() == 1) { - entry = new ImageEntry(); - entry.id = cursor.getLong(cursor.getColumnIndex(Columns.ID.getColumnName())); - entry.uri = cursor.getString(cursor.getColumnIndex(Columns.URI.getColumnName())); - entry.creationTime = cursor.getLong(cursor.getColumnIndex(Columns.CREATION_TIME.getColumnName())); - entry.lastAccessedTime = cursor.getLong(cursor.getColumnIndex(Columns.LAST_ACCESSED_TIME.getColumnName())); - entry.onDisk = cursor.getInt(cursor.getColumnIndex(Columns.ON_DISK.getColumnName())) == 1; - entry.sizeX = cursor.getInt(cursor.getColumnIndex(Columns.SIZE_X.getColumnName())); - entry.sizeY = cursor.getInt(cursor.getColumnIndex(Columns.SIZE_Y.getColumnName())); + Cursor cursor = selectFromTable(db, Columns.URI.getName() + "=?", new String[] { uri }); + if (cursor.moveToFirst()) { + entry = getEntryFromCursor(cursor); } return entry; } + + public static ImageEntry getEntryFromCursor(Cursor cursor) { + ImageEntry entry = new ImageEntry(); + entry.id = cursor.getLong(0); + entry.uri = cursor.getString(1); + entry.onDisk = cursor.getInt(2) == 1; + entry.creationTime = cursor.getLong(3); + entry.lastAccessedTime = cursor.getLong(4); + entry.sizeX = cursor.getInt(5); + entry.sizeY = cursor.getInt(6); + entry.fileSize = cursor.getLong(7); + entry.expiry = cursor.getLong(8); + return entry; + } + } diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ViewDimensionsUtil.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ViewDimensionsUtil.java index b4d56aa..53939e7 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/ViewDimensionsUtil.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/ViewDimensionsUtil.java @@ -17,15 +17,15 @@ package com.xtremelabs.imageutils; import android.graphics.Point; -import android.view.ViewGroup; +import android.view.View; import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; class ViewDimensionsUtil { public static Point getImageViewDimensions(ImageView imageView) { Point dimensions = new Point(); - dimensions.x = getDimensions(imageView, true); - dimensions.y = getDimensions(imageView, false); + dimensions.x = getDimension(imageView, true); + dimensions.y = getDimension(imageView, false); if (dimensions.x <= 0) { dimensions.x = -1; } @@ -35,41 +35,25 @@ public static Point getImageViewDimensions(ImageView imageView) { return dimensions; } - private static int getDimensions(ImageView imageView, boolean isWidth) { - LayoutParams params = imageView.getLayoutParams(); - if (params == null) { - return -1; - } - int length = isWidth ? params.width : params.height; - if (length == LayoutParams.WRAP_CONTENT) { - return -1; - } else if (length == LayoutParams.MATCH_PARENT) { - try { - return getParentDimensions((ViewGroup) imageView.getParent(), isWidth); - } catch (ClassCastException e) { - return -1; - } - } else { - return length; - } - } - - private static int getParentDimensions(ViewGroup parent, boolean isWidth) { + private static int getDimension(View view, boolean isWidth) { LayoutParams params; - if (parent == null || (params = parent.getLayoutParams()) == null) { - return -1; - } - int length = isWidth ? params.width : params.height; - if (length == LayoutParams.WRAP_CONTENT) { - return -1; - } else if (length == LayoutParams.MATCH_PARENT) { - try { - return getParentDimensions((ViewGroup) parent.getParent(), isWidth); - } catch (ClassCastException e) { + while (view != null && (params = view.getLayoutParams()) != null) { + int length = isWidth ? params.width : params.height; + if (length == LayoutParams.WRAP_CONTENT) { return -1; + + } else if (length == LayoutParams.MATCH_PARENT) { + try { + view = (View) view.getParent(); + } catch (ClassCastException e) { + return -1; + } + + } else { + return length; } - } else { - return length; } + + return -1; } } diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/db/Database.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/db/Database.java index 041db3e..2e18cf8 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/db/Database.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/db/Database.java @@ -14,10 +14,14 @@ public class Database extends SQLiteOpenHelper { private final List> mTables; + public Database(Context context, List> tables) { + this(context, null, tables); + } + public Database(Context context, CursorFactory factory, List> tables) { super(context, DatabaseConfig.NAME, factory, DatabaseConfig.VERSION); - if (tables == null) - throw new IllegalArgumentException("The list of tables cannot be null!"); + if (tables == null || tables.isEmpty()) + throw new IllegalArgumentException("The list of tables cannot be null or empty!"); mTables = tables; } diff --git a/xl_image_utils_lib/src/com/xtremelabs/imageutils/db/Table.java b/xl_image_utils_lib/src/com/xtremelabs/imageutils/db/Table.java index a8eac9f..256b62c 100644 --- a/xl_image_utils_lib/src/com/xtremelabs/imageutils/db/Table.java +++ b/xl_image_utils_lib/src/com/xtremelabs/imageutils/db/Table.java @@ -55,27 +55,40 @@ public Cursor selectAllFromTable(SQLiteDatabase db) { return db.query(getTableName(), getColumns(), null, null, null, null, null); } + public Cursor selectFromTable(SQLiteDatabase db, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) { + return db.query(getTableName(), columns, selection, selectionArgs, groupBy, having, orderBy, limit); + } + public Cursor selectFromTable(SQLiteDatabase db, String selection, String[] selectArgs) { return db.query(getTableName(), getColumns(), selection, selectArgs, null, null, null); } - public void insert(List items, SQLiteDatabase db) { + public void insert(SQLiteDatabase db, List items) { for (T item : items) { - insert(item, db); + insert(db, item); } } - public void insert(T item, SQLiteDatabase db) { + /** + * {@link SQLiteDatabase#insert(String, String, ContentValues)} + */ + public long insert(SQLiteDatabase db, T item) { ContentValues values = toContentValues(item); - db.insertWithOnConflict(getTableName(), null, values, SQLiteDatabase.CONFLICT_REPLACE); + return db.insert(getTableName(), null, values); } - public void update(T item, String where, String[] whereArgs, SQLiteDatabase db) { + /** + * {@link SQLiteDatabase#update(String, ContentValues, String, String[])} + */ + public int update(SQLiteDatabase db, T item, String where, String[] whereArgs) { ContentValues values = toContentValues(item); - db.updateWithOnConflict(getTableName(), values, where, whereArgs, SQLiteDatabase.CONFLICT_REPLACE); + return db.update(getTableName(), values, where, whereArgs); } - public void delete(SQLiteDatabase db, String whereClause, String[] whereArgs) { - db.delete(getTableName(), whereClause, whereArgs); + /** + * {@link SQLiteDatabase#delete(String, String, String[])} + */ + public int delete(SQLiteDatabase db, String whereClause, String[] whereArgs) { + return db.delete(getTableName(), whereClause, whereArgs); } }