summaryrefslogtreecommitdiffstats
path: root/src/com/android/photos/data/MediaCacheDatabase.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/photos/data/MediaCacheDatabase.java')
-rw-r--r--src/com/android/photos/data/MediaCacheDatabase.java286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/com/android/photos/data/MediaCacheDatabase.java b/src/com/android/photos/data/MediaCacheDatabase.java
new file mode 100644
index 000000000..c92ac0fdf
--- /dev/null
+++ b/src/com/android/photos/data/MediaCacheDatabase.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.photos.data;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+import com.android.photos.data.MediaRetriever.MediaSize;
+
+import java.io.File;
+
+class MediaCacheDatabase extends SQLiteOpenHelper {
+ public static final int DB_VERSION = 1;
+ public static final String DB_NAME = "mediacache.db";
+
+ /** Internal database table used for the media cache */
+ public static final String TABLE = "media_cache";
+
+ private static interface Columns extends BaseColumns {
+ /** The Content URI of the original image. */
+ public static final String URI = "uri";
+ /** MediaSize.getValue() values. */
+ public static final String MEDIA_SIZE = "media_size";
+ /** The last time this image was queried. */
+ public static final String LAST_ACCESS = "last_access";
+ /** The image size in bytes. */
+ public static final String SIZE_IN_BYTES = "size";
+ }
+
+ static interface Action {
+ void execute(Uri uri, long id, MediaSize size, Object parameter);
+ }
+
+ private static final String[] PROJECTION_ID = {
+ Columns._ID,
+ };
+
+ private static final String[] PROJECTION_CACHED = {
+ Columns._ID, Columns.MEDIA_SIZE, Columns.SIZE_IN_BYTES,
+ };
+
+ private static final String[] PROJECTION_CACHE_SIZE = {
+ "SUM(" + Columns.SIZE_IN_BYTES + ")"
+ };
+
+ private static final String[] PROJECTION_DELETE_OLD = {
+ Columns._ID, Columns.URI, Columns.MEDIA_SIZE, Columns.SIZE_IN_BYTES, Columns.LAST_ACCESS,
+ };
+
+ public static final String CREATE_TABLE = "CREATE TABLE " + TABLE + "("
+ + Columns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + Columns.URI + " TEXT NOT NULL,"
+ + Columns.MEDIA_SIZE + " INTEGER NOT NULL,"
+ + Columns.LAST_ACCESS + " INTEGER NOT NULL,"
+ + Columns.SIZE_IN_BYTES + " INTEGER NOT NULL,"
+ + "UNIQUE(" + Columns.URI + ", " + Columns.MEDIA_SIZE + "))";
+
+ public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLE;
+
+ public static final String WHERE_THUMBNAIL = Columns.MEDIA_SIZE + " = "
+ + MediaSize.Thumbnail.getValue();
+
+ public static final String WHERE_NOT_THUMBNAIL = Columns.MEDIA_SIZE + " <> "
+ + MediaSize.Thumbnail.getValue();
+
+ public static final String WHERE_CLEAR_CACHE = Columns.LAST_ACCESS + " <= ?";
+
+ public static final String WHERE_CLEAR_CACHE_LARGE = WHERE_CLEAR_CACHE + " AND "
+ + WHERE_NOT_THUMBNAIL;
+
+ static class QueryCacheResults {
+ public QueryCacheResults(long id, int sizeVal) {
+ this.id = id;
+ this.size = MediaSize.fromInteger(sizeVal);
+ }
+ public long id;
+ public MediaSize size;
+ }
+
+ public MediaCacheDatabase(Context context) {
+ super(context, DB_NAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(CREATE_TABLE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL(DROP_TABLE);
+ onCreate(db);
+ MediaCache.getInstance().clearCacheDir();
+ }
+
+ public Long getCached(Uri uri, MediaSize size) {
+ String where = Columns.URI + " = ? AND " + Columns.MEDIA_SIZE + " = ?";
+ SQLiteDatabase db = getWritableDatabase();
+ String[] whereArgs = {
+ uri.toString(), String.valueOf(size.getValue()),
+ };
+ Cursor cursor = db.query(TABLE, PROJECTION_ID, where, whereArgs, null, null, null);
+ Long id = null;
+ if (cursor.moveToNext()) {
+ id = cursor.getLong(0);
+ }
+ cursor.close();
+ if (id != null) {
+ String[] updateArgs = {
+ id.toString()
+ };
+ ContentValues values = new ContentValues();
+ values.put(Columns.LAST_ACCESS, System.currentTimeMillis());
+ db.beginTransaction();
+ try {
+ db.update(TABLE, values, Columns._ID + " = ?", updateArgs);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+ return id;
+ }
+
+ 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();
+ String[] whereArgs = {
+ uri.toString(), String.valueOf(size.getValue()),
+ };
+ Cursor cursor = db.query(TABLE, PROJECTION_CACHED, where, whereArgs, null, null, orderBy);
+ MediaSize bestSize = null;
+ if (cursor.moveToNext()) {
+ long id = cursor.getLong(0);
+ bestSize = MediaSize.fromInteger(cursor.getInt(1));
+ long fileSize = cursor.getLong(2);
+ action.execute(uri, id, bestSize, fileSize);
+ }
+ cursor.close();
+ return bestSize;
+ }
+
+ public long insert(Uri uri, MediaSize size, Action action, File tempFile) {
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+ try {
+ ContentValues values = new ContentValues();
+ values.put(Columns.LAST_ACCESS, System.currentTimeMillis());
+ values.put(Columns.MEDIA_SIZE, size.getValue());
+ values.put(Columns.URI, uri.toString());
+ values.put(Columns.SIZE_IN_BYTES, tempFile.length());
+ long id = db.insert(TABLE, null, values);
+ if (id != -1) {
+ action.execute(uri, id, size, tempFile);
+ db.setTransactionSuccessful();
+ }
+ return id;
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public void updateLength(long id, long fileSize) {
+ ContentValues values = new ContentValues();
+ values.put(Columns.SIZE_IN_BYTES, fileSize);
+ String[] whereArgs = {
+ String.valueOf(id)
+ };
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+ try {
+ db.update(TABLE, values, Columns._ID + " = ?", whereArgs);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ 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) {
+ 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);
+ MediaSize size = MediaSize.fromInteger(cursor.getInt(1));
+ long length = cursor.getLong(2);
+ action.execute(uri, id, size, length);
+ }
+ cursor.close();
+ try {
+ db.delete(TABLE, where, whereArgs);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public void deleteOldCached(boolean includeThumbnails, long deleteSize, Action action) {
+ String where = includeThumbnails ? null : WHERE_NOT_THUMBNAIL;
+ long lastAccess = 0;
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+ try {
+ Cursor cursor = db.query(TABLE, PROJECTION_DELETE_OLD, where, null, null, null,
+ Columns.LAST_ACCESS);
+ while (cursor.moveToNext()) {
+ long id = cursor.getLong(0);
+ String uri = cursor.getString(1);
+ MediaSize size = MediaSize.fromInteger(cursor.getInt(2));
+ long length = cursor.getLong(3);
+ long imageLastAccess = cursor.getLong(4);
+
+ if (imageLastAccess != lastAccess && deleteSize < 0) {
+ break; // We've deleted enough.
+ }
+ lastAccess = imageLastAccess;
+ action.execute(Uri.parse(uri), id, size, length);
+ deleteSize -= length;
+ }
+ cursor.close();
+ String[] whereArgs = {
+ String.valueOf(lastAccess),
+ };
+ String whereDelete = includeThumbnails ? WHERE_CLEAR_CACHE : WHERE_CLEAR_CACHE_LARGE;
+ db.delete(TABLE, whereDelete, whereArgs);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public long getCacheSize() {
+ return getCacheSize(null);
+ }
+
+ public long getThumbnailCacheSize() {
+ return getCacheSize(WHERE_THUMBNAIL);
+ }
+
+ private long getCacheSize(String where) {
+ SQLiteDatabase db = getReadableDatabase();
+ Cursor cursor = db.query(TABLE, PROJECTION_CACHE_SIZE, where, null, null, null, null);
+ long size = -1;
+ if (cursor.moveToNext()) {
+ size = cursor.getLong(0);
+ }
+ cursor.close();
+ return size;
+ }
+}