package com.letsvote.provider.base;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import android.content.ContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.provider.BaseColumns;
import android.support.annotation.NonNull;
import android.util.Log;
public abstract class BaseContentProvider extends ContentProvider {
public static final String QUERY_NOTIFY = "QUERY_NOTIFY";
public static final String QUERY_GROUP_BY = "QUERY_GROUP_BY";
public static final String QUERY_HAVING = "QUERY_HAVING";
public static final String QUERY_LIMIT = "QUERY_LIMIT";
public static class QueryParams {
public String table;
public String tablesWithJoins;
public String idColumn;
public String selection;
public String orderBy;
}
protected abstract QueryParams getQueryParams(Uri uri, String selection, String[] projection);
protected abstract boolean hasDebug();
protected abstract SQLiteOpenHelper createSqLiteOpenHelper();
protected SQLiteOpenHelper mSqLiteOpenHelper;
@Override
public final boolean onCreate() {
if (hasDebug()) {
// Enable logging of SQL statements as they are executed.
try {
Class<?> sqliteDebugClass = Class.forName("android.database.sqlite.SQLiteDebug");
Field field = sqliteDebugClass.getDeclaredField("DEBUG_SQL_STATEMENTS");
field.setAccessible(true);
field.set(null, true);
// Uncomment the following block if you also want logging of execution time (more verbose)
// field = sqliteDebugClass.getDeclaredField("DEBUG_SQL_TIME");
// field.setAccessible(true);
// field.set(null, true);
} catch (Throwable t) {
if (hasDebug()) Log.w(getClass().getSimpleName(), "Could not enable SQLiteDebug logging", t);
}
}
mSqLiteOpenHelper = createSqLiteOpenHelper();
return false;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
String table = uri.getLastPathSegment();
long rowId = mSqLiteOpenHelper.getWritableDatabase().insertOrThrow(table, null, values);
if (rowId == -1) return null;
String notify;
if (((notify = uri.getQueryParameter(QUERY_NOTIFY)) == null || "true".equals(notify))) {
getContext().getContentResolver().notifyChange(uri, null);
}
return uri.buildUpon().appendEncodedPath(String.valueOf(rowId)).build();
}
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
String table = uri.getLastPathSegment();
SQLiteDatabase db = mSqLiteOpenHelper.getWritableDatabase();
int res = 0;
db.beginTransaction();
try {
for (ContentValues v : values) {
long id = db.insert(table, null, v);
db.yieldIfContendedSafely();
if (id != -1) {
res++;
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
String notify;
if (res != 0 && ((notify = uri.getQueryParameter(QUERY_NOTIFY)) == null || "true".equals(notify))) {
getContext().getContentResolver().notifyChange(uri, null);
}
return res;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
QueryParams queryParams = getQueryParams(uri, selection, null);
int res = mSqLiteOpenHelper.getWritableDatabase().update(queryParams.table, values, queryParams.selection, selectionArgs);
String notify;
if (res != 0 && ((notify = uri.getQueryParameter(QUERY_NOTIFY)) == null || "true".equals(notify))) {
getContext().getContentResolver().notifyChange(uri, null);
}
return res;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
QueryParams queryParams = getQueryParams(uri, selection, null);
int res = mSqLiteOpenHelper.getWritableDatabase().delete(queryParams.table, queryParams.selection, selectionArgs);
String notify;
if (res != 0 && ((notify = uri.getQueryParameter(QUERY_NOTIFY)) == null || "true".equals(notify))) {
getContext().getContentResolver().notifyChange(uri, null);
}
return res;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
String groupBy = uri.getQueryParameter(QUERY_GROUP_BY);
String having = uri.getQueryParameter(QUERY_HAVING);
String limit = uri.getQueryParameter(QUERY_LIMIT);
QueryParams queryParams = getQueryParams(uri, selection, projection);
projection = ensureIdIsFullyQualified(projection, queryParams.table, queryParams.idColumn);
Cursor res = mSqLiteOpenHelper.getReadableDatabase().query(queryParams.tablesWithJoins, projection, queryParams.selection, selectionArgs, groupBy,
having, sortOrder == null ? queryParams.orderBy : sortOrder, limit);
res.setNotificationUri(getContext().getContentResolver(), uri);
return res;
}
private String[] ensureIdIsFullyQualified(String[] projection, String tableName, String idColumn) {
if (projection == null) return null;
String[] res = new String[projection.length];
for (int i = 0; i < projection.length; i++) {
if (projection[i].equals(idColumn)) {
res[i] = tableName + "." + idColumn + " AS " + BaseColumns._ID;
} else {
res[i] = projection[i];
}
}
return res;
}
@Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException {
HashSet<Uri> urisToNotify = new HashSet<Uri>(operations.size());
for (ContentProviderOperation operation : operations) {
urisToNotify.add(operation.getUri());
}
SQLiteDatabase db = mSqLiteOpenHelper.getWritableDatabase();
db.beginTransaction();
try {
int numOperations = operations.size();
ContentProviderResult[] results = new ContentProviderResult[numOperations];
int i = 0;
for (ContentProviderOperation operation : operations) {
results[i] = operation.apply(this, results, i);
if (operation.isYieldAllowed()) {
db.yieldIfContendedSafely();
}
i++;
}
db.setTransactionSuccessful();
for (Uri uri : urisToNotify) {
getContext().getContentResolver().notifyChange(uri, null);
}
return results;
} finally {
db.endTransaction();
}
}
public static Uri notify(Uri uri, boolean notify) {
return uri.buildUpon().appendQueryParameter(QUERY_NOTIFY, String.valueOf(notify)).build();
}
public static Uri groupBy(Uri uri, String groupBy) {
return uri.buildUpon().appendQueryParameter(QUERY_GROUP_BY, groupBy).build();
}
public static Uri having(Uri uri, String having) {
return uri.buildUpon().appendQueryParameter(QUERY_HAVING, having).build();
}
public static Uri limit(Uri uri, String limit) {
return uri.buildUpon().appendQueryParameter(QUERY_LIMIT, limit).build();
}
}