/** * */ package gilday.android.powerhour.provider; import gilday.android.powerhour.data.CurrentPlaylistDatabaseHelper; import gilday.android.powerhour.data.PowerHour; import gilday.android.powerhour.data.PowerHour.NowPlaying; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.DatabaseUtils.InsertHelper; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.text.TextUtils; /** * ContentProvider for Power Hour data. Currently provides access to the power hour playlist stored in SQLite * @author jgilday * */ public class CurrentPlaylistProvider extends ContentProvider { private static final UriMatcher URI_MATCHER; private static final int NOW_PLAYING = 1; private static final int NOW_PLAYING_ID = 2; private CurrentPlaylistDatabaseHelper dbHelper; static { // Establish the UriMatcher in the static block since it is a static variable. // Just copying android developer documentation here. Not sure what the rationale is for making the // UriMatcher a static variable URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); URI_MATCHER.addURI("com.johnathangilday.powerhour.provider", NowPlaying.TABLE, NOW_PLAYING); URI_MATCHER.addURI("com.johnathangilday.powerhour.provider", NowPlaying.TABLE + "/#", NOW_PLAYING_ID); } /* (non-Javadoc) * @see android.content.ContentProvider#onCreate() */ @Override public boolean onCreate() { dbHelper = new CurrentPlaylistDatabaseHelper(getContext()); return true; } /* (non-Javadoc) * @see android.content.ContentProvider#query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) */ @Override public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { switch(URI_MATCHER.match(uri)) { case NOW_PLAYING: // Going to list playlist items. Initialize sortOrder if not set // Android didn't implement String.isEmpty() until Gingerbread... if(TextUtils.isEmpty(sortOrder)) sortOrder = PowerHour.NowPlaying.DEFAULT_SORT_ORDER; break; case NOW_PLAYING_ID: // This uri is for a single playlist item so set selection arg selection += "_ID = " + uri.getLastPathSegment(); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } SQLiteDatabase readableDb = dbHelper.getReadableDatabase(); Cursor cursor = readableDb.query(PowerHour.NowPlaying.TABLE, projection, selection, selectionArgs, null, null, sortOrder); // Following example on this next line cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } /** * InsertHelper, a fast way to make bulk inserts to a SQLite table, has been deprecated in API 17. * It has not been replaced by anything so I will continue to use the deprecated API until next version to * see if Android introduces a new way to do bulk inserts */ @Override public int bulkInsert(Uri uri, ContentValues[] values) { // Argument checking if(URI_MATCHER.match(uri) != NOW_PLAYING) { throw new IllegalArgumentException("Unknown URI " + uri); } if(values == null) { throw new IllegalArgumentException("Cannot bulk insert null list"); } SQLiteDatabase writableDb = dbHelper.getWritableDatabase(); InsertHelper ih = new InsertHelper(writableDb, NowPlaying.TABLE); int insertedCount = 0; final int idColumn = ih.getColumnIndex(NowPlaying._ID); final int artistColumn = ih.getColumnIndex(NowPlaying.ARTIST); final int albumColumn = ih.getColumnIndex(NowPlaying.ALBUM); final int titleColumn = ih.getColumnIndex(NowPlaying.TITLE); final int omitColumn = ih.getColumnIndex(NowPlaying.OMIT); final int playedColumn = ih.getColumnIndex(NowPlaying.PLAYED); final int positionColumn = ih.getColumnIndex(NowPlaying.POSITION); final int shufflePositionColumn = ih.getColumnIndex(NowPlaying.SHUFFLE_POSITION); writableDb.beginTransaction(); try { for (ContentValues value : values) { ih.prepareForInsert(); ih.bind(idColumn, value.getAsString(NowPlaying._ID)); ih.bind(artistColumn, value.getAsString(NowPlaying.ARTIST)); ih.bind(albumColumn, value.getAsString(NowPlaying.ALBUM)); ih.bind(titleColumn, value.getAsString(NowPlaying.TITLE)); ih.bind(omitColumn, ((Number) value.get(NowPlaying.OMIT)).intValue()); ih.bind(playedColumn, ((Number) value.get(NowPlaying.PLAYED)).intValue()); ih.bind(positionColumn, ((Number) value.get(NowPlaying.POSITION)).intValue()); ih.bind(shufflePositionColumn, ((Number) value.get(NowPlaying.SHUFFLE_POSITION)).intValue()); ih.execute(); } writableDb.setTransactionSuccessful(); insertedCount = values.length; } finally { ih.close(); writableDb.endTransaction(); } getContext().getContentResolver().notifyChange(uri, null); return insertedCount; } /* (non-Javadoc) * @see android.content.ContentProvider#insert(android.net.Uri, android.content.ContentValues) */ @Override public Uri insert(Uri uri, ContentValues initialValues) { // Validate uri if(URI_MATCHER.match(uri) != NOW_PLAYING) { throw new IllegalArgumentException("Unknown URI " + uri); } if(initialValues == null) { throw new IllegalArgumentException("Must include comprehensive set of initial values"); } // Hold the values to be inserted in the new row ContentValues values = new ContentValues(initialValues); // Not yet sure how insert will be used. Perhaps do more input checking // or automatically retrieve values from android music provider here SQLiteDatabase writableDb = dbHelper.getWritableDatabase(); long rowId = writableDb.insert(PowerHour.NowPlaying.TABLE, null, values); if(rowId <= 0) { throw new SQLException("Failed to insert row into " + uri); } Uri playlistItemUri = ContentUris.withAppendedId(PowerHour.NowPlaying.CONTENT_URI, rowId); getContext().getContentResolver().notifyChange(playlistItemUri, null); return playlistItemUri; } /* (non-Javadoc) * @see android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) */ @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); int count; switch(URI_MATCHER.match(uri)) { case NOW_PLAYING: count = db.update(NowPlaying.TABLE, values, where, whereArgs); break; case NOW_PLAYING_ID: String playlistItemId = uri.getLastPathSegment(); count = db.update(NowPlaying.TABLE, values, NowPlaying._ID + "=" + playlistItemId, whereArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; } /* (non-Javadoc) * @see android.content.ContentProvider#delete(android.net.Uri, java.lang.String, java.lang.String[]) */ @Override public int delete(Uri uri, String where, String[] whereArgs) { SQLiteDatabase writableDb = dbHelper.getWritableDatabase(); int count; switch(URI_MATCHER.match(uri)) { case NOW_PLAYING: count = writableDb.delete(NowPlaying.TABLE, where, whereArgs); break; case NOW_PLAYING_ID: String playlistItemId = uri.getLastPathSegment(); count = writableDb.delete( NowPlaying.TABLE, NowPlaying._ID + "=" + playlistItemId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; } /* (non-Javadoc) * @see android.content.ContentProvider#getType(android.net.Uri) */ @Override public String getType(Uri uri) { switch(URI_MATCHER.match(uri)){ case NOW_PLAYING: return NowPlaying.CONTENT_TYPE; case NOW_PLAYING_ID: return NowPlaying.CONTENT_ITEM_TYPE; default: throw new IllegalArgumentException("Unknown URI " + uri); } } }