/* * Copyright 2015 Synced Synapse. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xbmc.kore.provider; import android.content.ContentProvider; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.provider.BaseColumns; import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.SelectionBuilder; import java.util.Arrays; /** * Provider for {@link MediaContract} data. */ public class MediaProvider extends ContentProvider { private static final String TAG = LogUtils.makeLogTag(MediaProvider.class); private MediaDatabase mOpenHelper; private Context context; private static final UriMatcher sUriMatcher = buildUriMatcher(); private static final int HOSTS_LIST = 100; private static final int HOSTS_ID = 101; private static final int MOVIES_ALL = 200; private static final int MOVIES_LIST = 201; private static final int MOVIES_ID = 202; private static final int MOVIE_CAST_ALL = 210; private static final int MOVIE_CAST_LIST = 211; private static final int TVSHOWS_ALL = 300; private static final int TVSHOWS_LIST = 302; private static final int TVSHOWS_ID = 303; private static final int TVSHOWS_CAST_ALL = 310; private static final int TVSHOWS_CAST_LIST = 311; private static final int SEASONS_ALL = 400; private static final int TVSHOW_SEASONS_LIST = 401; private static final int TVSHOW_SEASONS_ID = 402; private static final int EPISODES_ALL = 500; private static final int TVSHOW_EPISODES_LIST = 501; private static final int TVSHOW_EPISODES_ID = 502; private static final int TVSHOW_SEASON_EPISODES_LIST = 503; private static final int TVSHOW_SEASON_EPISODES_ID = 504; private static final int ARTISTS_ALL = 600; private static final int ARTISTS_LIST = 601; private static final int ARTISTS_ID = 602; private static final int ARTIST_ALBUMS_LIST = 610; private static final int ARTIST_SONGS_LIST = 611; private static final int ALBUMS_ALL = 700; private static final int ALBUMS_LIST = 701; private static final int ALBUMS_ID = 702; private static final int ALBUM_ARTISTS_LIST = 710; private static final int ALBUM_GENRES_LIST = 711; private static final int SONGS_ALL = 800; private static final int SONGS_ALBUM = 802; private static final int SONGS_ID = 803; private static final int SONGS_LIST = 804; private static final int AUDIO_GENRES_ALL = 900; private static final int AUDIO_GENRES_LIST = 901; private static final int AUDIO_GENRES_ID = 902; private static final int AUDIO_GENRE_ALBUMS_LIST = 910; private static final int ALBUM_ARTISTS_ALL = 1000; private static final int ALBUM_GENRES_ALL = 1001; private static final int SONG_ARTISTS_ALL = 1002; private static final int MUSIC_VIDEOS_ALL = 1100; private static final int MUSIC_VIDEOS_LIST = 1101; private static final int MUSIC_VIDEOS_ID = 1102; /** * 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 = MediaContract.CONTENT_AUTHORITY; // Hosts matcher.addURI(authority, MediaContract.PATH_HOSTS, HOSTS_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*", HOSTS_ID); // Movies and cast matcher.addURI(authority, MediaContract.PATH_MOVIES, MOVIES_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_MOVIES, MOVIES_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_MOVIES + "/*", MOVIES_ID); matcher.addURI(authority, MediaContract.PATH_MOVIE_CAST, MOVIE_CAST_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_MOVIES + "/*/" + MediaContract.PATH_MOVIE_CAST, MOVIE_CAST_LIST); // TV Shows and cast matcher.addURI(authority, MediaContract.PATH_TVSHOWS, TVSHOWS_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_TVSHOWS, TVSHOWS_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_TVSHOWS + "/*", TVSHOWS_ID); matcher.addURI(authority, MediaContract.PATH_TVSHOW_CAST, TVSHOWS_CAST_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_TVSHOWS + "/*/" + MediaContract.PATH_TVSHOW_CAST, TVSHOWS_CAST_LIST); // Seasons matcher.addURI(authority, MediaContract.PATH_SEASONS, SEASONS_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_TVSHOWS + "/*/" + MediaContract.PATH_SEASONS, TVSHOW_SEASONS_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_TVSHOWS + "/*/" + MediaContract.PATH_SEASONS + "/*", TVSHOW_SEASONS_ID); // Episodes matcher.addURI(authority, MediaContract.PATH_EPISODES, EPISODES_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_TVSHOWS + "/*/" + MediaContract.PATH_EPISODES, TVSHOW_EPISODES_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_TVSHOWS + "/*/" + MediaContract.PATH_EPISODES + "/*", TVSHOW_EPISODES_ID); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_TVSHOWS + "/*/" + MediaContract.PATH_SEASONS + "/*/" + MediaContract.PATH_EPISODES, TVSHOW_SEASON_EPISODES_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_TVSHOWS + "/*/" + MediaContract.PATH_SEASONS + "/*/" + MediaContract.PATH_EPISODES + "/*", TVSHOW_SEASON_EPISODES_ID); // Artists matcher.addURI(authority, MediaContract.PATH_ARTISTS, ARTISTS_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ARTISTS, ARTISTS_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ARTISTS + "/*", ARTISTS_ID); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ARTISTS + "/*/" + MediaContract.PATH_ALBUMS, ARTIST_ALBUMS_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ARTISTS + "/*/" + MediaContract.PATH_SONGS, ARTIST_SONGS_LIST); // Albums matcher.addURI(authority, MediaContract.PATH_ALBUMS, ALBUMS_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ALBUMS, ALBUMS_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ALBUMS + "/*", ALBUMS_ID); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ALBUMS + "/*/" + MediaContract.PATH_ARTISTS, ALBUM_ARTISTS_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ALBUMS + "/*/" + MediaContract.PATH_AUDIO_GENRES, ALBUM_GENRES_LIST); // Songs matcher.addURI(authority, MediaContract.PATH_SONGS, SONGS_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_SONGS, SONGS_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ALBUMS + "/*/" + MediaContract.PATH_SONGS, SONGS_ALBUM); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_ALBUMS + "/*/" + MediaContract.PATH_SONGS + "/*", SONGS_ID); // Genres matcher.addURI(authority, MediaContract.PATH_AUDIO_GENRES, AUDIO_GENRES_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_AUDIO_GENRES, AUDIO_GENRES_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_AUDIO_GENRES + "/*", AUDIO_GENRES_ID); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_AUDIO_GENRES + "/*/" + MediaContract.PATH_ALBUMS, AUDIO_GENRE_ALBUMS_LIST); // AlbumArtists matcher.addURI(authority, MediaContract.PATH_ALBUM_ARTISTS, ALBUM_ARTISTS_ALL); // AlbumGenres matcher.addURI(authority, MediaContract.PATH_ALBUM_GENRES, ALBUM_GENRES_ALL); // SongArtists matcher.addURI(authority, MediaContract.PATH_SONG_ARTISTS, SONG_ARTISTS_ALL); // Music Videos matcher.addURI(authority, MediaContract.PATH_MUSIC_VIDEOS, MUSIC_VIDEOS_ALL); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_MUSIC_VIDEOS, MUSIC_VIDEOS_LIST); matcher.addURI(authority, MediaContract.PATH_HOSTS + "/*/" + MediaContract.PATH_MUSIC_VIDEOS + "/*", MUSIC_VIDEOS_ID); return matcher; } public void setContext(Context context) { this.context = context; } @Override public boolean onCreate() { if (context == null) { context = getContext(); } mOpenHelper = new MediaDatabase(context); return true; } /** {@inheritDoc} */ @Override public String getType(Uri uri) { final int match = sUriMatcher.match(uri); switch (match) { case HOSTS_LIST: return MediaContract.Hosts.CONTENT_TYPE; case HOSTS_ID: return MediaContract.Hosts.CONTENT_ITEM_TYPE; case MOVIES_ALL: case MOVIES_LIST: return MediaContract.Movies.CONTENT_TYPE; case MOVIES_ID: return MediaContract.Movies.CONTENT_ITEM_TYPE; case MOVIE_CAST_ALL: case MOVIE_CAST_LIST: return MediaContract.MovieCast.CONTENT_TYPE; case TVSHOWS_ALL: case TVSHOWS_LIST: return MediaContract.TVShows.CONTENT_TYPE; case TVSHOWS_ID: return MediaContract.TVShows.CONTENT_ITEM_TYPE; case TVSHOWS_CAST_ALL: case TVSHOWS_CAST_LIST: return MediaContract.TVShowCast.CONTENT_TYPE; case SEASONS_ALL: case TVSHOW_SEASONS_LIST: return MediaContract.Seasons.CONTENT_TYPE; case TVSHOW_SEASONS_ID: return MediaContract.Seasons.CONTENT_ITEM_TYPE; case EPISODES_ALL: case TVSHOW_EPISODES_LIST: case TVSHOW_SEASON_EPISODES_LIST: return MediaContract.Episodes.CONTENT_TYPE; case TVSHOW_EPISODES_ID: case TVSHOW_SEASON_EPISODES_ID: return MediaContract.Episodes.CONTENT_ITEM_TYPE; case ARTISTS_ALL: case ARTISTS_LIST: case ALBUM_ARTISTS_LIST: return MediaContract.Artists.CONTENT_TYPE; case ARTISTS_ID: return MediaContract.Artists.CONTENT_ITEM_TYPE; case ALBUMS_ALL: case ALBUMS_LIST: case ARTIST_ALBUMS_LIST: case AUDIO_GENRE_ALBUMS_LIST: return MediaContract.Albums.CONTENT_TYPE; case ALBUMS_ID: return MediaContract.Albums.CONTENT_ITEM_TYPE; case SONGS_ALL: case SONGS_LIST: case ARTIST_SONGS_LIST: case SONGS_ALBUM: return MediaContract.Songs.CONTENT_TYPE; case SONGS_ID: return MediaContract.Songs.CONTENT_ITEM_TYPE; case AUDIO_GENRES_ALL: case AUDIO_GENRES_LIST: case ALBUM_GENRES_LIST: return MediaContract.AudioGenres.CONTENT_TYPE; case AUDIO_GENRES_ID: return MediaContract.AudioGenres.CONTENT_ITEM_TYPE; case ALBUM_ARTISTS_ALL: return MediaContract.AlbumArtists.CONTENT_TYPE; case ALBUM_GENRES_ALL: return MediaContract.AlbumGenres.CONTENT_TYPE; case SONG_ARTISTS_ALL: return MediaContract.SongArtists.CONTENT_TYPE; case MUSIC_VIDEOS_ALL: case MUSIC_VIDEOS_LIST: return MediaContract.MusicVideos.CONTENT_TYPE; case MUSIC_VIDEOS_ID: return MediaContract.MusicVideos.CONTENT_ITEM_TYPE; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } } /** {@inheritDoc} */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { LogUtils.LOGV(TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")"); final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); final int match = sUriMatcher.match(uri); Cursor cursor; switch (match) { default: { // Most cases are handled with simple SelectionBuilder final SelectionBuilder builder = buildQuerySelection(uri, match); String limit = uri.getQueryParameter(MediaContract.LIMIT_QUERY); cursor = builder.where(selection, selectionArgs) .query(db, projection, sortOrder, limit); } } return cursor; } /** {@inheritDoc} */ @Override public Uri insert(Uri uri, ContentValues values) { LogUtils.LOGV(TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")"); final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final int match = sUriMatcher.match(uri); Uri insertedUri; switch (match) { case HOSTS_LIST: { values.put(MediaContract.SyncColumns.UPDATED, System.currentTimeMillis()); long hostId = db.insertOrThrow(MediaDatabase.Tables.HOSTS, null, values); insertedUri = MediaContract.Hosts.buildHostUri(hostId); break; } default: { throw new UnsupportedOperationException("Unsuported uri: " + uri); } } context.getContentResolver().notifyChange(uri, null); return insertedUri; } /** {@inheritDoc} */ @Override public int bulkInsert(Uri uri, ContentValues[] values) { long startTime = System.currentTimeMillis(); final int match = sUriMatcher.match(uri); String table; switch (match) { case MOVIES_ALL: { table = MediaDatabase.Tables.MOVIES; break; } case MOVIE_CAST_ALL: { table = MediaDatabase.Tables.MOVIE_CAST; break; } case TVSHOWS_ALL: { table = MediaDatabase.Tables.TVSHOWS; break; } case TVSHOWS_CAST_ALL: { table = MediaDatabase.Tables.TVSHOWS_CAST; break; } case SEASONS_ALL: { table = MediaDatabase.Tables.SEASONS; break; } case EPISODES_ALL: { table = MediaDatabase.Tables.EPISODES; break; } case ARTISTS_ALL: { table = MediaDatabase.Tables.ARTISTS; break; } case ALBUMS_ALL: { table = MediaDatabase.Tables.ALBUMS; break; } case SONGS_ALL: { table = MediaDatabase.Tables.SONGS; break; } case AUDIO_GENRES_ALL: { table = MediaDatabase.Tables.AUDIO_GENRES; break; } case ALBUM_GENRES_ALL: { table = MediaDatabase.Tables.ALBUM_GENRES; break; } case ALBUM_ARTISTS_ALL: { table = MediaDatabase.Tables.ALBUM_ARTISTS; break; } case SONG_ARTISTS_ALL: { table = MediaDatabase.Tables.SONG_ARTISTS; break; } case MUSIC_VIDEOS_ALL: { table = MediaDatabase.Tables.MUSIC_VIDEOS; break; } default: { throw new UnsupportedOperationException("Unknown uri: " + uri); } } final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); db.beginTransaction(); long updateTime = System.currentTimeMillis(); try { for (ContentValues value : values) { switch (match) { case ALBUM_GENRES_ALL: case ALBUM_ARTISTS_ALL: case SONG_ARTISTS_ALL: // Nothing to add to these tables break; default: value.put(MediaContract.SyncColumns.UPDATED, updateTime); break; } db.insertOrThrow(table, null, value); } db.setTransactionSuccessful(); } catch (Exception e) { LogUtils.LOGD(TAG, "Couldn't bulk insert records. Exception: " + e.getMessage()); } finally { db.endTransaction(); } context.getContentResolver().notifyChange(uri, null); LogUtils.LOGD(TAG, "Bulk insert finished for uri (" + uri + ") in (ms): " + (System.currentTimeMillis() - startTime)); return values.length; } /** {@inheritDoc} */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { LogUtils.LOGD(TAG, "update(uri=" + uri + ", values=" + values.toString() + ")"); final int match = sUriMatcher.match(uri); switch (match) { case HOSTS_ID: case MOVIES_ID: case TVSHOWS_ID: case TVSHOW_SEASONS_ID: case TVSHOW_EPISODES_ID: case ARTISTS_ID: case ALBUMS_ID: case SONGS_ID: case AUDIO_GENRES_ID: case MUSIC_VIDEOS_ID: { // Add updated field values.put(MediaContract.SyncColumns.UPDATED, System.currentTimeMillis()); break; } default: { throw new UnsupportedOperationException("Unknown uri for update: " + uri); } } final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final SelectionBuilder builder = buildQuerySelection(uri, match); int result = builder.where(selection, selectionArgs) .update(db, values); context.getContentResolver().notifyChange(uri, null); return result; } /** {@inheritDoc} */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { final int match = sUriMatcher.match(uri); final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final SelectionBuilder builder = buildQuerySelection(uri, match); int result = builder.where(selection, selectionArgs) .delete(db); LogUtils.LOGD(TAG, "delete(uri=" + uri + "). Rows affected: " + result); context.getContentResolver().notifyChange(uri, null); return result; } /** * 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 buildQuerySelection(Uri uri, int match) { final SelectionBuilder builder = new SelectionBuilder(); switch (match) { case HOSTS_LIST: { return builder.table(MediaDatabase.Tables.HOSTS); } case HOSTS_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); return builder.table(MediaDatabase.Tables.HOSTS) .where(BaseColumns._ID + "=?", hostId); } case MOVIES_ALL: { return builder.table(MediaDatabase.Tables.MOVIES); } case MOVIES_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); return builder.table(MediaDatabase.Tables.MOVIES) .where(MediaContract.Movies.HOST_ID + "=?", hostId); } case MOVIES_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String movieId = MediaContract.Movies.getMovieId(uri); return builder.table(MediaDatabase.Tables.MOVIES) .where(MediaContract.Movies.HOST_ID + "=?", hostId) .where(MediaContract.Movies.MOVIEID + "=?", movieId); } case MOVIE_CAST_ALL: { return builder.table(MediaDatabase.Tables.MOVIE_CAST); } case MOVIE_CAST_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); final String movieId = MediaContract.Movies.getMovieId(uri); return builder.table(MediaDatabase.Tables.MOVIE_CAST) .where(MediaContract.MovieCast.HOST_ID + "=?", hostId) .where(MediaContract.MovieCast.MOVIEID + "=?", movieId); } case TVSHOWS_ALL: { return builder.table(MediaDatabase.Tables.TVSHOWS); } case TVSHOWS_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); return builder.table(MediaDatabase.Tables.TVSHOWS) .where(MediaContract.TVShows.HOST_ID + "=?", hostId); } case TVSHOWS_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String tvshowId = MediaContract.TVShows.getTVShowId(uri); return builder.table(MediaDatabase.Tables.TVSHOWS) .where(MediaContract.TVShows.HOST_ID + "=?", hostId) .where(MediaContract.TVShows.TVSHOWID + "=?", tvshowId); } case TVSHOWS_CAST_ALL: { return builder.table(MediaDatabase.Tables.TVSHOWS_CAST); } case TVSHOWS_CAST_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); final String tvshowId = MediaContract.TVShows.getTVShowId(uri); return builder.table(MediaDatabase.Tables.TVSHOWS_CAST) .where(MediaContract.TVShowCast.HOST_ID + "=?", hostId) .where(MediaContract.TVShowCast.TVSHOWID + "=?", tvshowId); } case SEASONS_ALL: { return builder.table(MediaDatabase.Tables.SEASONS); } case TVSHOW_SEASONS_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); final String tvshowId = MediaContract.TVShows.getTVShowId(uri); return builder.table(MediaDatabase.Tables.SEASONS) .where(MediaContract.Seasons.HOST_ID + "=?", hostId) .where(MediaContract.Seasons.TVSHOWID + "=?", tvshowId); } case TVSHOW_SEASONS_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String tvshowId = MediaContract.TVShows.getTVShowId(uri); final String season = MediaContract.Seasons.getTVShowSeasonId(uri); return builder.table(MediaDatabase.Tables.SEASONS) .where(MediaContract.Seasons.HOST_ID + "=?", hostId) .where(MediaContract.Seasons.TVSHOWID + "=?", tvshowId) .where(MediaContract.Seasons.SEASON + "=?", season); } case EPISODES_ALL: { return builder.table(MediaDatabase.Tables.EPISODES); } case TVSHOW_EPISODES_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); final String tvshowId = MediaContract.TVShows.getTVShowId(uri); return builder.table(MediaDatabase.Tables.EPISODES) .where(MediaContract.Episodes.HOST_ID + "=?", hostId) .where(MediaContract.Episodes.TVSHOWID + "=?", tvshowId); } case TVSHOW_EPISODES_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String tvshowId = MediaContract.TVShows.getTVShowId(uri); final String episodeId = MediaContract.Episodes.getTVShowEpisodeId(uri); return builder.table(MediaDatabase.Tables.EPISODES) .where(MediaContract.Episodes.HOST_ID + "=?", hostId) .where(MediaContract.Episodes.TVSHOWID + "=?", tvshowId) .where(MediaContract.Episodes.EPISODEID + "=?", episodeId); } case TVSHOW_SEASON_EPISODES_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); final String tvshowId = MediaContract.TVShows.getTVShowId(uri); final String season = MediaContract.Seasons.getTVShowSeasonId(uri); return builder.table(MediaDatabase.Tables.EPISODES) .where(MediaContract.Episodes.HOST_ID + "=?", hostId) .where(MediaContract.Episodes.TVSHOWID + "=?", tvshowId) .where(MediaContract.Episodes.SEASON + "=?", season); } case TVSHOW_SEASON_EPISODES_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String tvshowId = MediaContract.TVShows.getTVShowId(uri); final String season = MediaContract.Seasons.getTVShowSeasonId(uri); final String episodeId = MediaContract.Episodes.getTVShowSeasonEpisodeId(uri); return builder.table(MediaDatabase.Tables.EPISODES) .where(MediaContract.Episodes.HOST_ID + "=?", hostId) .where(MediaContract.Episodes.TVSHOWID + "=?", tvshowId) .where(MediaContract.Episodes.SEASON + "=?", season) .where(MediaContract.Episodes.EPISODEID + "=?", episodeId); } case ARTISTS_ALL: { return builder.table(MediaDatabase.Tables.ARTISTS); } case ARTISTS_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); return builder.table(MediaDatabase.Tables.ARTISTS) .where(MediaContract.Artists.HOST_ID + "=?", hostId); } case ARTISTS_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String artistId = MediaContract.Artists.getArtistId(uri); return builder.table(MediaDatabase.Tables.ARTISTS) .where(MediaContract.Artists.HOST_ID + "=?", hostId) .where(MediaContract.Artists.ARTISTID + "=?", artistId); } case ALBUMS_ALL: { return builder.table(MediaDatabase.Tables.ALBUMS); } case ALBUMS_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); return builder.table(MediaDatabase.Tables.ALBUMS) .where(MediaContract.Albums.HOST_ID + "=?", hostId); } case ALBUMS_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String albumId = MediaContract.Albums.getAlbumId(uri); return builder.table(MediaDatabase.Tables.ALBUMS) .where(MediaContract.Albums.HOST_ID + "=?", hostId) .where(MediaContract.Albums.ALBUMID + "=?", albumId); } case SONGS_ALL: { return builder.table(MediaDatabase.Tables.SONGS); } case SONGS_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); return builder.table(MediaDatabase.Tables.SONGS_FOR_ARTIST_AND_OR_ALBUM_JOIN) .mapToTable(MediaContract.Songs.SONGID, MediaDatabase.Tables.SONGS) .mapToTable(MediaContract.Songs.TITLE, MediaDatabase.Tables.SONGS) .mapToTable(MediaContract.Songs.ALBUMID, MediaDatabase.Tables.SONGS) .mapToTable(MediaContract.Songs.THUMBNAIL, MediaDatabase.Tables.SONGS) .mapToTable(MediaContract.Songs.DISPLAYARTIST, MediaDatabase.Tables.SONGS) .mapToTable(MediaContract.AlbumArtists.ARTISTID, MediaDatabase.Tables.ALBUM_ARTISTS) .mapToTable(MediaContract.SongArtists.ARTISTID, MediaDatabase.Tables.SONG_ARTISTS) .where(Qualified.SONGS_HOST_ID + "=?", hostId) .groupBy(Qualified.SONGS_SONGID); } case SONGS_ALBUM: { final String hostId = MediaContract.Hosts.getHostId(uri); final String albumId = MediaContract.Albums.getAlbumId(uri); return builder.table(MediaDatabase.Tables.SONGS) .where(Qualified.SONGS_HOST_ID + "=?", hostId) .where(Qualified.SONGS_ALBUMID + "=?", albumId); } case SONGS_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String albumId = MediaContract.Albums.getAlbumId(uri); final String songId = MediaContract.Songs.getSongId(uri); return builder.table(MediaDatabase.Tables.SONGS) .where(MediaContract.Songs.HOST_ID + "=?", hostId) .where(MediaContract.Songs.ALBUMID + "=?", albumId) .where(MediaContract.Songs.SONGID + "=?", songId); } case AUDIO_GENRES_ALL: { return builder.table(MediaDatabase.Tables.AUDIO_GENRES); } case AUDIO_GENRES_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); return builder.table(MediaDatabase.Tables.AUDIO_GENRES) .where(MediaContract.AudioGenres.HOST_ID + "=?", hostId); } case AUDIO_GENRES_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String audioGenreId = MediaContract.AudioGenres.getAudioGenreId(uri); return builder.table(MediaDatabase.Tables.AUDIO_GENRES) .where(MediaContract.AudioGenres.HOST_ID + "=?", hostId) .where(MediaContract.AudioGenres.GENREID + "=?", audioGenreId); } case ALBUM_ARTISTS_ALL: { return builder.table(MediaDatabase.Tables.ALBUM_ARTISTS); } case SONG_ARTISTS_ALL: { return builder.table(MediaDatabase.Tables.SONG_ARTISTS); } case ALBUM_GENRES_ALL: { return builder.table(MediaDatabase.Tables.ALBUM_GENRES); } case ARTIST_ALBUMS_LIST: { // Albums for Artists final String hostId = MediaContract.Hosts.getHostId(uri); final String artistId = MediaContract.Artists.getArtistId(uri); return builder.table(MediaDatabase.Tables.ALBUMS_FOR_ARTIST_JOIN) .mapToTable(MediaContract.Albums._ID, MediaDatabase.Tables.ALBUMS) .mapToTable(MediaContract.Albums.HOST_ID, MediaDatabase.Tables.ALBUMS) .mapToTable(MediaContract.Albums.ALBUMID, MediaDatabase.Tables.ALBUMS) .mapToTable(MediaContract.AlbumArtists.ARTISTID, MediaDatabase.Tables.ALBUM_ARTISTS) .where(Qualified.ALBUM_ARTISTS_HOST_ID + "=?", hostId) .where(Qualified.ALBUM_ARTISTS_ARTISTID + "=?", artistId); } case ARTIST_SONGS_LIST: { // Songs for Artists final String hostId = MediaContract.Hosts.getHostId(uri); final String artistId = MediaContract.Artists.getArtistId(uri); return builder.table(MediaDatabase.Tables.SONGS_FOR_ARTIST_AND_OR_ALBUM_JOIN) .mapToTable(MediaContract.Songs.SONGID, MediaDatabase.Tables.SONGS) .mapToTable(MediaContract.Songs.TITLE, MediaDatabase.Tables.SONGS) .mapToTable(MediaContract.Songs.ALBUMID, MediaDatabase.Tables.SONGS) .mapToTable(MediaContract.Songs.DISPLAYARTIST, MediaDatabase.Tables.SONGS) .mapToTable(MediaContract.AlbumArtists.ARTISTID, MediaDatabase.Tables.ALBUM_ARTISTS) .mapToTable(MediaContract.SongArtists.ARTISTID, MediaDatabase.Tables.SONG_ARTISTS) .where(Qualified.SONG_ARTISTS_HOST_ID + "=?", hostId) .where(Qualified.SONG_ARTISTS_ARTISTID + "=?" + " OR " + Qualified.ALBUM_ARTISTS_ARTISTID + "=?", artistId, artistId) .groupBy(Qualified.SONGS_ID); } case ALBUM_ARTISTS_LIST: { // Artists for Album final String hostId = MediaContract.Hosts.getHostId(uri); final String albumId = MediaContract.Albums.getAlbumId(uri); return builder.table(MediaDatabase.Tables.ARTISTS_FOR_ALBUM_JOIN) .mapToTable(MediaContract.Artists._ID, MediaDatabase.Tables.ARTISTS) .mapToTable(MediaContract.Artists.HOST_ID, MediaDatabase.Tables.ARTISTS) .mapToTable(MediaContract.Artists.ARTISTID, MediaDatabase.Tables.ARTISTS) .mapToTable(MediaContract.AlbumArtists.ALBUMID, MediaDatabase.Tables.ALBUM_ARTISTS) .where(Qualified.ALBUM_ARTISTS_HOST_ID + "=?", hostId) .where(Qualified.ALBUM_ARTISTS_ALBUMID + "=?", albumId); } case ALBUM_GENRES_LIST: { // Genres for Album final String hostId = MediaContract.Hosts.getHostId(uri); final String albumId = MediaContract.Albums.getAlbumId(uri); return builder.table(MediaDatabase.Tables.GENRES_FOR_ALBUM_JOIN) .mapToTable(MediaContract.AudioGenres._ID, MediaDatabase.Tables.AUDIO_GENRES) .mapToTable(MediaContract.AudioGenres.HOST_ID, MediaDatabase.Tables.AUDIO_GENRES) .mapToTable(MediaContract.AudioGenres.GENREID, MediaDatabase.Tables.AUDIO_GENRES) .mapToTable(MediaContract.AlbumGenres.ALBUMID, MediaDatabase.Tables.ALBUM_GENRES) .where(Qualified.ALBUM_GENRES_HOST_ID + "=?", hostId) .where(Qualified.ALBUM_GENRES_ALBUMID + "=?", albumId); } case AUDIO_GENRE_ALBUMS_LIST: { // Album for a Genre final String hostId = MediaContract.Hosts.getHostId(uri); final String genreId = MediaContract.AudioGenres.getAudioGenreId(uri); return builder.table(MediaDatabase.Tables.ALBUMS_FOR_GENRE_JOIN) .mapToTable(MediaContract.Albums._ID, MediaDatabase.Tables.ALBUMS) .mapToTable(MediaContract.Albums.HOST_ID, MediaDatabase.Tables.ALBUMS) .mapToTable(MediaContract.Albums.ALBUMID, MediaDatabase.Tables.ALBUMS) .mapToTable(MediaContract.AlbumGenres.GENREID, MediaDatabase.Tables.ALBUM_GENRES) .where(Qualified.ALBUM_GENRES_HOST_ID + "=?", hostId) .where(Qualified.ALBUM_GENRES_GENREID + "=?", genreId); } case MUSIC_VIDEOS_ALL: { return builder.table(MediaDatabase.Tables.MUSIC_VIDEOS); } case MUSIC_VIDEOS_LIST: { final String hostId = MediaContract.Hosts.getHostId(uri); return builder.table(MediaDatabase.Tables.MUSIC_VIDEOS) .where(MediaContract.MusicVideos.HOST_ID + "=?", hostId); } case MUSIC_VIDEOS_ID: { final String hostId = MediaContract.Hosts.getHostId(uri); final String musicVideoId = MediaContract.MusicVideos.getMusicVideoId(uri); return builder.table(MediaDatabase.Tables.MUSIC_VIDEOS) .where(MediaContract.MusicVideos.HOST_ID + "=?", hostId) .where(MediaContract.MusicVideos.MUSICVIDEOID + "=?", musicVideoId); } default: { throw new UnsupportedOperationException("Unknown uri: " + uri); } } } /** * {@link MediaContract} fields that are fully qualified with a specific * parent {@link MediaDatabase.Tables}. Used when needed to work around SQL ambiguity. */ public interface Qualified { String ALBUMS_TITLE = MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.TITLE; String ALBUMS_GENRE = MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.GENRE; String ALBUMS_YEAR = MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.YEAR; String ALBUMS_THUMBNAIL = MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.THUMBNAIL; String ALBUMS_DISPLAYARTIST = MediaDatabase.Tables.ALBUMS + "." + MediaContract.Albums.DISPLAYARTIST; String ALBUM_ARTISTS_HOST_ID = MediaDatabase.Tables.ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.HOST_ID; String ALBUM_ARTISTS_ARTISTID = MediaDatabase.Tables.ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.ARTISTID; String ALBUM_ARTISTS_ALBUMID = MediaDatabase.Tables.ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.ALBUMID; String ALBUM_GENRES_HOST_ID = MediaDatabase.Tables.ALBUM_GENRES + "." + MediaContract.AlbumGenres.HOST_ID; String ALBUM_GENRES_GENREID = MediaDatabase.Tables.ALBUM_GENRES + "." + MediaContract.AlbumGenres.GENREID; String ALBUM_GENRES_ALBUMID = MediaDatabase.Tables.ALBUM_GENRES + "." + MediaContract.AlbumGenres.ALBUMID; String SONGS_ID = MediaDatabase.Tables.SONGS + "." + MediaContract.Songs._ID; String SONGS_TRACK = MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.TRACK; String SONGS_DURATION = MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.DURATION; String SONGS_FILE = MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.FILE; String SONGS_HOST_ID = MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.HOST_ID; String SONGS_SONGID = MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.SONGID; String SONGS_DISPLAYARTIST = MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.DISPLAYARTIST; String SONGS_TITLE = MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.TITLE; String SONGS_ALBUMID = MediaDatabase.Tables.SONGS + "." + MediaContract.Songs.ALBUMID; String SONG_ARTISTS_HOST_ID = MediaDatabase.Tables.SONG_ARTISTS + "." + MediaContract.SongArtists.HOST_ID; String SONG_ARTISTS_ARTISTID = MediaDatabase.Tables.SONG_ARTISTS + "." + MediaContract.SongArtists.ARTISTID; } }