Example #1
0
  /** 扫描类型, 并将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;
  }