package oraculum.droid.provider; import java.util.ArrayList; import java.util.Arrays; import oraculum.droid.provider.DroidHDContract.Clientes; import oraculum.droid.provider.DroidHDContract.Clientes.SearchSuggest; import oraculum.droid.provider.DroidHDContract.ClientesColumns; import oraculum.droid.provider.DroidHDDatabase.Tables; import oraculum.droid.util.SelectionBuilder; import android.app.SearchManager; import android.content.ContentProvider; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentValues; import android.content.Context; import android.content.OperationApplicationException; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.provider.BaseColumns; import android.util.Log; public class DroidHDProvider extends ContentProvider { private static final String TAG = "DroidHDProvider"; private static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); private DroidHDDatabase mOpenHelper; private static UriMatcher sUriMatcher = buildUriMatcher(); private static final int CLIENTES = 100; private static final int CLIENTES_ID = 101; private static final int CLIENTES_SEARCH = 102; private static final int SEARCH_SUGGEST = 800; /** * Build and return a {@link UriMatcher} that catches all {@link Uri} * variations supported by this {@link ContentProvider}. */ private static UriMatcher buildUriMatcher() { final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); final String authority = DroidHDContract.CONTENT_AUTHORITY; matcher.addURI(authority, "clientes", CLIENTES); matcher.addURI(authority, "clientes/search/*", CLIENTES_SEARCH); matcher.addURI(authority, "clientes/*", CLIENTES_ID); matcher.addURI(authority, "search_suggest_query", SEARCH_SUGGEST); return matcher; } @Override public boolean onCreate() { final Context context = getContext(); mOpenHelper = new DroidHDDatabase(context); return true; } /** {@inheritDoc} */ @Override public String getType(Uri uri) { final int match = sUriMatcher.match(uri); switch (match) { case CLIENTES: return Clientes.CONTENT_TYPE; case CLIENTES_ID: return Clientes.CONTENT_ITEM_TYPE; case CLIENTES_SEARCH: return Clientes.CONTENT_TYPE; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } } /** {@inheritDoc} */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { if (LOGV) Log.v(TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")"); final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); sUriMatcher = buildUriMatcher(); final int match = sUriMatcher.match(uri); switch (match) { default: { // Most cases are handled with simple SelectionBuilder final SelectionBuilder builder = buildExpandedSelection(uri, match); return builder.where(selection, selectionArgs).query(db, projection, sortOrder); } case SEARCH_SUGGEST: { final SelectionBuilder builder = new SelectionBuilder(); // Adjust incoming query to become SQL text match selectionArgs[0] = selectionArgs[0] + "%"; builder.table(Tables.SEARCH_SUGGEST); builder.where(selection, selectionArgs); builder.map(SearchManager.SUGGEST_COLUMN_QUERY, SearchManager.SUGGEST_COLUMN_TEXT_1); projection = new String[] { BaseColumns._ID, SearchManager.SUGGEST_COLUMN_TEXT_1, SearchManager.SUGGEST_COLUMN_QUERY }; final String limit = uri.getQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT); return builder.query(db, projection, null, null, SearchSuggest.DEFAULT_SORT, limit); } } } /** {@inheritDoc} */ @Override public Uri insert(Uri uri, ContentValues values) { if (LOGV) Log.v(TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")"); final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final int match = sUriMatcher.match(uri); switch (match) { case CLIENTES: { db.insertOrThrow(Tables.CLIENTES, null, values); getContext().getContentResolver().notifyChange(uri, null); return Clientes.buildClienteUri(values.getAsString(Clientes.cliente_id)); } case CLIENTES_ID: { db.insertOrThrow(Tables.CLIENTES, null, values); getContext().getContentResolver().notifyChange(uri, null); return Clientes.buildClienteUri(values.getAsString(Clientes.cliente_id)); } case SEARCH_SUGGEST: { db.insertOrThrow(Tables.SEARCH_SUGGEST, null, values); getContext().getContentResolver().notifyChange(uri, null); return SearchSuggest.CONTENT_URI; } default: { throw new UnsupportedOperationException("Unknown uri: " + uri); } } } /** {@inheritDoc} */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { if (LOGV) Log.v(TAG, "update(uri=" + uri + ", values=" + values.toString() + ")"); final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final SelectionBuilder builder = buildSimpleSelection(uri); int retVal = builder.where(selection, selectionArgs).update(db, values); getContext().getContentResolver().notifyChange(uri, null); return retVal; } /** {@inheritDoc} */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { if (LOGV) Log.v(TAG, "delete(uri=" + uri + ")"); final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final SelectionBuilder builder = buildSimpleSelection(uri); int retVal = builder.where(selection, selectionArgs).delete(db); getContext().getContentResolver().notifyChange(uri, null); return retVal; } /** * Apply the given set of {@link ContentProviderOperation}, executing inside * a {@link SQLiteDatabase} transaction. All changes will be rolled back if * any single one fails. */ @Override public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); db.beginTransaction(); try { final int numOperations = operations.size(); final ContentProviderResult[] results = new ContentProviderResult[numOperations]; for (int i = 0; i < numOperations; i++) { results[i] = operations.get(i).apply(this, results, i); } db.setTransactionSuccessful(); return results; } finally { db.endTransaction(); } } /** * Build a simple {@link SelectionBuilder} to match the requested * {@link Uri}. This is usually enough to support {@link #insert}, * {@link #update}, and {@link #delete} operations. */ private SelectionBuilder buildSimpleSelection(Uri uri) { final SelectionBuilder builder = new SelectionBuilder(); final int match = sUriMatcher.match(uri); switch (match) { case CLIENTES: { return builder.table(Tables.CLIENTES); } case CLIENTES_ID: { final String clienteId = Clientes.getClienteId(uri); return builder.table(Tables.CLIENTES) .where(Clientes.cliente_id + "=?", clienteId); } case SEARCH_SUGGEST: { return builder.table(Tables.SEARCH_SUGGEST); } default: { throw new UnsupportedOperationException("Unknown uri: " + uri); } } } /** * Build an advanced {@link SelectionBuilder} to match the requested * {@link Uri}. This is usually only used by {@link #query}, since it * performs table joins useful for {@link Cursor} data. */ private SelectionBuilder buildExpandedSelection(Uri uri, int match) { final SelectionBuilder builder = new SelectionBuilder(); switch (match) { case CLIENTES: { return builder.table(Tables.CLIENTES); } case CLIENTES_ID: { final String clienteId = Clientes.getClienteId(uri); return builder.table(Tables.CLIENTES) .where(Clientes.cliente_id + "=?", clienteId); } case CLIENTES_SEARCH: { final String query = Clientes.getSearchQuery(uri); return builder.table(Tables.CLIENTES) .where(ClientesColumns.cliente_nome + " LIKE '" + query + "%'"); } default: { throw new UnsupportedOperationException("Unknown uri: " + uri); } } } }