/** 扫描类型, 并将Song与Genre关联 */ public static ArrayList<Genre> scanGenres(Context context) { LogUtils.v(TAG, "scanGenres() called"); ArrayList<Genre> genres = new ArrayList<>(); Cursor cursor = context .getContentResolver() .query( MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI, genreProjection, null, null, MediaStore.Audio.Genres.NAME + " ASC"); LogUtils.v(TAG, cursor.getCount() + ""); for (int i = 0; i < cursor.getCount(); i++) { cursor.moveToPosition(i); int genreId = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Genres._ID)); String genreName = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Genres.NAME)); // LogUtils.v(TAG, "get genres : id = " + genreId + " name = " + genreName); Genre genre = new Genre(genreId, genreName); genres.add(genre); // 将歌曲与类型关联 Cursor genreCursor = context .getContentResolver() .query( MediaStore.Audio.Genres.Members.getContentUri("external", genreId), new String[] {MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.IS_MUSIC + " != 0 ", null, null); genreCursor.moveToFirst(); for (int j = 0; j < genreCursor.getCount(); j++) { genreCursor.moveToPosition(j); int index = genreCursor.getColumnIndex(MediaStore.Audio.Media._ID); final Song song = findSongById(genreCursor.getInt(index)); if (song != null) { song.setmGenreId(genreId); } } genreCursor.close(); } cursor.close(); return genres; }
/** * Builds a query that will return all the songs in the genre with the given id. * * @param id The id of the genre in MediaStore.Audio.Genres. * @param projection The columns to query. * @param selection The selection to pass to the query, or null. * @param selectionArgs The arguments to substitute into the selection. * @param sort The sort order. * @param type The media type to query and return * @param returnSongs returns matching songs instead of `type' if true */ public static QueryTask buildGenreQuery( long id, String[] projection, String selection, String[] selectionArgs, String sort, int type, boolean returnSongs) { // Note: This function works on a raw sql query with way too much internal // knowledge about the mediaProvider SQL table layout. Yes: it's ugly. // The reason for this mess is that android has a very crippled genre implementation // and does, for example, not allow us to query the albumbs beloging to a genre. Uri uri = MediaStore.Audio.Genres.Members.getContentUri("external", id); String[] clonedProjection = projection .clone(); // we modify the projection, but this should not be visible to the caller String sql = ""; String authority = "audio"; if (type == TYPE_ARTIST) authority = "artist_info"; if (type == TYPE_ALBUM) authority = "album_info"; // Our raw SQL query includes the album_info table (well: it's actually a view) // which shares some columns with audio. // This regexp should matche duplicate column names and forces them to use // the audio table as a source final String _FORCE_AUDIO_SRC = "(^|[ |,\\(])(_id|album(_\\w+)?|artist(_\\w+)?)"; // Prefix the SELECTed rows with the current table authority name for (int i = 0; i < clonedProjection.length; i++) { if (clonedProjection[i].equals("0") == false) // do not prefix fake rows clonedProjection[i] = (returnSongs ? "audio" : authority) + "." + clonedProjection[i]; } sql += TextUtils.join(", ", clonedProjection); sql += " FROM audio_genres_map_noid, audio" + (authority.equals("audio") ? "" : ", " + authority); sql += " WHERE(audio._id = audio_id AND genre_id=?)"; if (selection != null && selection.length() > 0) sql += " AND(" + selection.replaceAll(_FORCE_AUDIO_SRC, "$1audio.$2") + ")"; if (type == TYPE_ARTIST) sql += " AND(artist_info._id = audio.artist_id)" + (returnSongs ? "" : " GROUP BY artist_info._id"); if (type == TYPE_ALBUM) sql += " AND(album_info._id = audio.album_id)" + (returnSongs ? "" : " GROUP BY album_info._id"); if (sort != null && sort.length() > 0) sql += " ORDER BY " + sort.replaceAll(_FORCE_AUDIO_SRC, "$1audio.$2"); // We are now turning this into an sql injection. Fun times. clonedProjection[0] = sql + " --"; QueryTask result = new QueryTask(uri, clonedProjection, selection, selectionArgs, sort); result.type = TYPE_GENRE; return result; }