package com.nutiteq.cache; import java.util.ArrayList; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; public class CacheIndexDatabaseHelper { private static final int DATABASE_VERSION = 1; private static final String CACHE_INDEX_TABLE = "cache_index"; private static final String CREATE_CACHE_INDEX_TABLE = "CREATE TABLE " + CACHE_INDEX_TABLE + " (id INTEGER PRIMARY KEY AUTOINCREMENT, cache_key TEXT NOT NULL, " + "resource_path TEXT_NOT_NULL, resource_size INTEGER NOT NULL, used_timestamp INTEGER NOT NULL)"; private final Context ctx; private DatabaseHelper databaseHelper; private final String databaseName; private SQLiteDatabase database; private static final String KEY_ID = "id"; private static final String KEY_CACHE_KEY = "cache_key"; private static final String KEY_RESOURCE_PATH = "resource_path"; private static final String KEY_RESOURCE_SIZE = "resource_size"; private static final String KEY_USED_TIMESTAMP = "used_timestamp"; private static final String LOG_TAG = "CacheIndexDatabaseHelper"; private static class DatabaseHelper extends SQLiteOpenHelper { public DatabaseHelper(final Context context, final String databaseName) { super(context, databaseName, null, DATABASE_VERSION); } @Override public void onCreate(final SQLiteDatabase db) { db.execSQL(CREATE_CACHE_INDEX_TABLE); } @Override public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { onCreate(db); } } public CacheIndexDatabaseHelper(final Context ctx, final String databaseName) { this.ctx = ctx; this.databaseName = databaseName; } public void open() { databaseHelper = new DatabaseHelper(ctx, databaseName); database = databaseHelper.getWritableDatabase(); } public void close() { databaseHelper.close(); } public boolean containsKey(final String cacheKey) { final long start = System.currentTimeMillis(); final Cursor c = database.query(CACHE_INDEX_TABLE, new String[] { KEY_ID }, "cache_key = ?", new String[] { cacheKey }, null, null, null); final boolean hasKey = c.moveToFirst(); c.close(); Log.d(LOG_TAG, "execution time " + (System.currentTimeMillis() - start)); return hasKey; } public List<String> addToIndex(final String cacheKey, final String resourcePath, final int resourceSize, final int cacheSize) { final ContentValues values = new ContentValues(); values.put(KEY_CACHE_KEY, cacheKey); values.put(KEY_RESOURCE_PATH, resourcePath); values.put(KEY_RESOURCE_SIZE, resourceSize); values.put(KEY_USED_TIMESTAMP, System.currentTimeMillis()); database.insert(CACHE_INDEX_TABLE, null, values); final Cursor c = database.rawQuery("SELECT SUM(resource_size) FROM cache_index", null); int totalSize = 0; if (c.moveToFirst()) { totalSize = c.getInt(0); } c.close(); Log.d(LOG_TAG, "maxSize = " + cacheSize + " currentSize = " + totalSize); if (totalSize < cacheSize) { return new ArrayList<String>(); } else { return reduceCacheSize(totalSize - cacheSize); } } private List<String> reduceCacheSize(final int bytesNeededToFree) { final Cursor c = database.query(CACHE_INDEX_TABLE, new String[] { KEY_RESOURCE_PATH, KEY_RESOURCE_SIZE }, null, null, null, null, "used_timestamp ASC"); final List<String> removedFiles = new ArrayList<String>(); int moreBytesNeeded = bytesNeededToFree; while (c.moveToNext() && moreBytesNeeded > 0) { removedFiles.add(c.getString(0)); moreBytesNeeded -= c.getInt(1); } c.close(); deleteFilesFromIndex(removedFiles); return removedFiles; } private void deleteFilesFromIndex(final List<String> removedFiles) { final String[] files = removedFiles.toArray(new String[removedFiles.size()]); final StringBuffer whereClause = new StringBuffer(); for (int i = 0; i < files.length; i++) { whereClause.append(KEY_RESOURCE_PATH).append(" = ?"); if (i != files.length - 1) { whereClause.append(" OR "); } } database.beginTransaction(); final int affectedRows = database.delete(CACHE_INDEX_TABLE, whereClause.toString(), files); database.setTransactionSuccessful(); database.endTransaction(); Log.d(LOG_TAG, "Needed to delete " + removedFiles.size() + ", deleted " + affectedRows); } public String getRespourcePathForKey(final String cacheKey) { final Cursor c = database.query(CACHE_INDEX_TABLE, new String[] { KEY_RESOURCE_PATH }, KEY_CACHE_KEY + " = ?", new String[] { cacheKey }, null, null, null); String resourcePath = ""; if (c.moveToFirst()) { resourcePath = c.getString(0); } c.close(); return resourcePath; } }