1 package com.android.launcher3.util; 2 3 import android.content.ContentValues; 4 import android.content.Context; 5 import android.database.Cursor; 6 import android.database.sqlite.SQLiteDatabase; 7 import android.database.sqlite.SQLiteException; 8 import android.database.sqlite.SQLiteFullException; 9 import android.database.sqlite.SQLiteOpenHelper; 10 import android.util.Log; 11 12 /** 13 * An extension of {@link SQLiteOpenHelper} with utility methods for a single table cache DB. 14 * Any exception during write operations are ignored, and any version change causes a DB reset. 15 */ 16 public abstract class SQLiteCacheHelper { 17 private static final String TAG = "SQLiteCacheHelper"; 18 19 private final String mTableName; 20 private final MySQLiteOpenHelper mOpenHelper; 21 22 private boolean mIgnoreWrites; 23 24 public SQLiteCacheHelper(Context context, String name, int version, String tableName) { 25 mTableName = tableName; 26 mOpenHelper = new MySQLiteOpenHelper(context, name, version); 27 28 mIgnoreWrites = false; 29 } 30 31 /** 32 * @see SQLiteDatabase#update(String, ContentValues, String, String[]) 33 */ 34 public void update(ContentValues values, String whereClause, String[] whereArgs) { 35 if (mIgnoreWrites) { 36 return; 37 } 38 try { 39 mOpenHelper.getWritableDatabase().update(mTableName, values, whereClause, whereArgs); 40 } catch (SQLiteFullException e) { 41 onDiskFull(e); 42 } catch (SQLiteException e) { 43 Log.d(TAG, "Ignoring sqlite exception", e); 44 } 45 } 46 47 /** 48 * @see SQLiteDatabase#delete(String, String, String[]) 49 */ 50 public void delete(String whereClause, String[] whereArgs) { 51 if (mIgnoreWrites) { 52 return; 53 } 54 try { 55 mOpenHelper.getWritableDatabase().delete(mTableName, whereClause, whereArgs); 56 } catch (SQLiteFullException e) { 57 onDiskFull(e); 58 } catch (SQLiteException e) { 59 Log.d(TAG, "Ignoring sqlite exception", e); 60 } 61 } 62 63 /** 64 * @see SQLiteDatabase#insertWithOnConflict(String, String, ContentValues, int) 65 */ 66 public void insertOrReplace(ContentValues values) { 67 if (mIgnoreWrites) { 68 return; 69 } 70 try { 71 mOpenHelper.getWritableDatabase().insertWithOnConflict( 72 mTableName, null, values, SQLiteDatabase.CONFLICT_REPLACE); 73 } catch (SQLiteFullException e) { 74 onDiskFull(e); 75 } catch (SQLiteException e) { 76 Log.d(TAG, "Ignoring sqlite exception", e); 77 } 78 } 79 80 private void onDiskFull(SQLiteFullException e) { 81 Log.e(TAG, "Disk full, all write operations will be ignored", e); 82 mIgnoreWrites = true; 83 } 84 85 /** 86 * @see SQLiteDatabase#query(String, String[], String, String[], String, String, String) 87 */ 88 public Cursor query(String[] columns, String selection, String[] selectionArgs) { 89 return mOpenHelper.getReadableDatabase().query( 90 mTableName, columns, selection, selectionArgs, null, null, null); 91 } 92 93 protected abstract void onCreateTable(SQLiteDatabase db); 94 95 /** 96 * A private inner class to prevent direct DB access. 97 */ 98 private class MySQLiteOpenHelper extends SQLiteOpenHelper { 99 100 public MySQLiteOpenHelper(Context context, String name, int version) { 101 super(context, name, null, version); 102 } 103 104 @Override 105 public void onCreate(SQLiteDatabase db) { 106 onCreateTable(db); 107 } 108 109 @Override 110 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 111 if (oldVersion != newVersion) { 112 clearDB(db); 113 } 114 } 115 116 @Override 117 public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 118 if (oldVersion != newVersion) { 119 clearDB(db); 120 } 121 } 122 123 private void clearDB(SQLiteDatabase db) { 124 db.execSQL("DROP TABLE IF EXISTS " + mTableName); 125 onCreate(db); 126 } 127 } 128 } 129