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 static final boolean IN_MEMORY_CACHE = false;
20 
21     private final String mTableName;
22     private final MySQLiteOpenHelper mOpenHelper;
23 
24     private boolean mIgnoreWrites;
25 
SQLiteCacheHelper(Context context, String name, int version, String tableName)26     public SQLiteCacheHelper(Context context, String name, int version, String tableName) {
27         if (IN_MEMORY_CACHE) {
28             name = null;
29         }
30         mTableName = tableName;
31         mOpenHelper = new MySQLiteOpenHelper(context, name, version);
32 
33         mIgnoreWrites = false;
34     }
35 
36     /**
37      * @see SQLiteDatabase#delete(String, String, String[])
38      */
delete(String whereClause, String[] whereArgs)39     public void delete(String whereClause, String[] whereArgs) {
40         if (mIgnoreWrites) {
41             return;
42         }
43         try {
44             mOpenHelper.getWritableDatabase().delete(mTableName, whereClause, whereArgs);
45         } catch (SQLiteFullException e) {
46             onDiskFull(e);
47         } catch (SQLiteException e) {
48             Log.d(TAG, "Ignoring sqlite exception", e);
49         }
50     }
51 
52     /**
53      * @see SQLiteDatabase#insertWithOnConflict(String, String, ContentValues, int)
54      */
insertOrReplace(ContentValues values)55     public void insertOrReplace(ContentValues values) {
56         if (mIgnoreWrites) {
57             return;
58         }
59         try {
60             mOpenHelper.getWritableDatabase().insertWithOnConflict(
61                     mTableName, null, values, SQLiteDatabase.CONFLICT_REPLACE);
62         } catch (SQLiteFullException e) {
63             onDiskFull(e);
64         } catch (SQLiteException e) {
65             Log.d(TAG, "Ignoring sqlite exception", e);
66         }
67     }
68 
onDiskFull(SQLiteFullException e)69     private void onDiskFull(SQLiteFullException e) {
70         Log.e(TAG, "Disk full, all write operations will be ignored", e);
71         mIgnoreWrites = true;
72     }
73 
74     /**
75      * @see SQLiteDatabase#query(String, String[], String, String[], String, String, String)
76      */
query(String[] columns, String selection, String[] selectionArgs)77     public Cursor query(String[] columns, String selection, String[] selectionArgs) {
78         return mOpenHelper.getReadableDatabase().query(
79                 mTableName, columns, selection, selectionArgs, null, null, null);
80     }
81 
clear()82     public void clear() {
83         mOpenHelper.clearDB(mOpenHelper.getWritableDatabase());
84     }
85 
close()86     public void close() {
87         mOpenHelper.close();
88     }
89 
onCreateTable(SQLiteDatabase db)90     protected abstract void onCreateTable(SQLiteDatabase db);
91 
92     /**
93      * A private inner class to prevent direct DB access.
94      */
95     private class MySQLiteOpenHelper extends NoLocaleSQLiteHelper {
96 
MySQLiteOpenHelper(Context context, String name, int version)97         public MySQLiteOpenHelper(Context context, String name, int version) {
98             super(context, name, version);
99         }
100 
101         @Override
onCreate(SQLiteDatabase db)102         public void onCreate(SQLiteDatabase db) {
103             onCreateTable(db);
104         }
105 
106         @Override
onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)107         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
108             if (oldVersion != newVersion) {
109                 clearDB(db);
110             }
111         }
112 
113         @Override
onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion)114         public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
115             if (oldVersion != newVersion) {
116                 clearDB(db);
117             }
118         }
119 
clearDB(SQLiteDatabase db)120         private void clearDB(SQLiteDatabase db) {
121             db.execSQL("DROP TABLE IF EXISTS " + mTableName);
122             onCreate(db);
123         }
124     }
125 }
126