Split utility functions from Song into Playlist and MediaUtils

This commit is contained in:
Christopher Eby 2010-05-18 19:07:08 -05:00
parent 7c082f4856
commit 8459c71b4e
8 changed files with 311 additions and 260 deletions

View File

@ -56,7 +56,7 @@ import android.widget.FilterQueryProvider;
public class MediaAdapter extends CursorAdapter implements FilterQueryProvider {
/**
* The type of media represented by this adapter. Must be one of the
* Song.FIELD_* constants. Determines which content provider to query for
* MediaUtils.FIELD_* constants. Determines which content provider to query for
* media and what fields to display.
*/
int mType;
@ -117,23 +117,23 @@ public class MediaAdapter extends CursorAdapter implements FilterQueryProvider {
mExpandable = expandable;
switch (type) {
case Song.TYPE_ARTIST:
case MediaUtils.TYPE_ARTIST:
mStore = MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI;
mFields = new String[] { MediaStore.Audio.Artists.ARTIST };
mFieldKeys = new String[] { MediaStore.Audio.Artists.ARTIST_KEY };
break;
case Song.TYPE_ALBUM:
case MediaUtils.TYPE_ALBUM:
mStore = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;
mFields = new String[] { MediaStore.Audio.Albums.ARTIST, MediaStore.Audio.Albums.ALBUM };
// Why is there no artist_key column constant in the album MediaStore? The column does seem to exist.
mFieldKeys = new String[] { "artist_key", MediaStore.Audio.Albums.ALBUM_KEY };
break;
case Song.TYPE_SONG:
case MediaUtils.TYPE_SONG:
mStore = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
mFields = new String[] { MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.TITLE };
mFieldKeys = new String[] { MediaStore.Audio.Media.ARTIST_KEY, MediaStore.Audio.Media.ALBUM_KEY, MediaStore.Audio.Media.TITLE_KEY };
break;
case Song.TYPE_PLAYLIST:
case MediaUtils.TYPE_PLAYLIST:
mStore = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
mFields = new String[] { MediaStore.Audio.Playlists.NAME };
mFieldKeys = null;

View File

@ -0,0 +1,132 @@
/*
* Copyright (C) 2010 Christopher Eby <kreed@kreed.org>
*
* This file is part of Vanilla Music Player.
*
* Vanilla Music Player is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Vanilla Music Player is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kreed.vanilla;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
public class MediaUtils {
/**
* Type indicating an id represents an artist.
*/
public static final int TYPE_ARTIST = 1;
/**
* Type indicating an id represents an album.
*/
public static final int TYPE_ALBUM = 2;
/**
* Type indicating an id represents a song.
*/
public static final int TYPE_SONG = 3;
/**
* Type indicating an id represents a playlist.
*/
public static final int TYPE_PLAYLIST = 4;
/**
* Return a cursor containing the ids of all the songs with artist or
* album of the specified id.
*
* @param type TYPE_ARTIST or TYPE_ALBUM, indicating the the id represents
* an artist or album
* @param id The MediaStore id of the artist or album
*/
private static Cursor getMediaCursor(int type, long id)
{
String selection = "=" + id + " AND " + MediaStore.Audio.Media.IS_MUSIC + "!=0";
switch (type) {
case TYPE_ARTIST:
selection = MediaStore.Audio.Media.ARTIST_ID + selection;
break;
case TYPE_ALBUM:
selection = MediaStore.Audio.Media.ALBUM_ID + selection;
break;
default:
throw new IllegalArgumentException("Invalid type specified: " + type);
}
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Audio.Media._ID };
String sort = MediaStore.Audio.Media.ARTIST_KEY + ',' + MediaStore.Audio.Media.ALBUM_KEY + ',' + MediaStore.Audio.Media.TRACK;
return resolver.query(media, projection, selection, null, sort);
}
/**
* Return a cursor containing the ids of all the songs in the playlist
* with the given id.
*
* @param id The id of the playlist in MediaStore.Audio.Playlists.
*/
private static Cursor getPlaylistCursor(long id)
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", id);
String[] projection = new String[] { MediaStore.Audio.Playlists.Members.AUDIO_ID };
String sort = MediaStore.Audio.Playlists.Members.PLAY_ORDER;
return resolver.query(uri, projection, null, null, sort);
}
/**
* Return an array containing all the song ids that match the specified parameters
*
* @param type Type the id represents. Must be one of the Song.TYPE_*
* constants.
* @param id The id of the element in the MediaStore content provider for
* the given type.
*/
public static long[] getAllSongIdsWith(int type, long id)
{
Cursor cursor;
switch (type) {
case TYPE_SONG:
return new long[] { id };
case TYPE_ARTIST:
case TYPE_ALBUM:
cursor = getMediaCursor(type, id);
break;
case TYPE_PLAYLIST:
cursor = getPlaylistCursor(id);
break;
default:
throw new IllegalArgumentException("Specified type not valid: " + type);
}
if (cursor == null)
return null;
int count = cursor.getCount();
if (count == 0)
return null;
long[] songs = new long[count];
for (int i = 0; i != count; ++i) {
if (!cursor.moveToNext())
return null;
songs[i] = cursor.getLong(0);
}
cursor.close();
return songs;
}
}

View File

@ -92,7 +92,7 @@ public class NewPlaylistDialog extends Dialog implements TextWatcher, View.OnCli
{
// Update the action button based on whether there is an
// existing playlist with the given name.
int res = Song.getPlaylist(s.toString()) == -1 ? R.string.create : R.string.overwrite;
int res = Playlist.getPlaylist(s.toString()) == -1 ? R.string.create : R.string.overwrite;
mPositiveButton.setText(res);
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (C) 2010 Christopher Eby <kreed@kreed.org>
*
* This file is part of Vanilla Music Player.
*
* Vanilla Music Player is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Vanilla Music Player is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kreed.vanilla;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
/**
* Instances of this class simply provide a basic representation of a playlist
* (currently only the id and name). The class also provides various playlist-
* related static utility functions.
*/
public class Playlist {
/**
* Create a Playlist with the given id and name.
*/
public Playlist(long id, String name)
{
this.id = id;
this.name = name;
}
/**
* The MediaStore.Audio.Playlists id of the playlist.
*/
public long id;
/**
* The name of the playlist.
*/
public String name;
/**
* Queries all the playlists known to the MediaStore.
*
* @return An array of Playlists
*/
public static Playlist[] getPlaylists()
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Uri media = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Audio.Playlists._ID, MediaStore.Audio.Playlists.NAME };
String sort = MediaStore.Audio.Playlists.NAME;
Cursor cursor = resolver.query(media, projection, null, null, sort);
if (cursor == null)
return null;
int count = cursor.getCount();
if (count == 0)
return null;
Playlist[] playlists = new Playlist[count];
for (int i = 0; i != count; ++i) {
if (!cursor.moveToNext())
return null;
playlists[i] = new Playlist(cursor.getLong(0), cursor.getString(1));
}
cursor.close();
return playlists;
}
/**
* Retrieves the id for a playlist with the given name.
*
* @param name The name of the playlist.
* @return The id of the playlist, or -1 if there is no playlist with the
* given name.
*/
public static long getPlaylist(String name)
{
long id = -1;
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Cursor cursor = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Audio.Playlists._ID },
MediaStore.Audio.Playlists.NAME + "=?",
new String[] { name }, null);
if (cursor != null) {
if (cursor.moveToNext())
id = cursor.getLong(0);
cursor.close();
}
return id;
}
/**
* Create a new playlist with the given name. If a playlist with the given
* name already exists, it will be overwritten.
*
* @param name The name of the playlist.
* @return The id of the new playlist.
*/
public static long createPlaylist(String name)
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
long id = getPlaylist(name);
if (id == -1) {
// We need to create a new playlist.
ContentValues values = new ContentValues(1);
values.put(MediaStore.Audio.Playlists.NAME, name);
Uri uri = resolver.insert(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, values);
id = Long.parseLong(uri.getLastPathSegment());
} else {
// We are overwriting an existing playlist. Clear existing songs.
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", id);
resolver.delete(uri, null, null);
}
return id;
}
/**
* Add the given set of song ids to the playlist with the given id.
*
* @param playlistId The MediaStore.Audio.Playlist id of the playlist to
* modify.
* @param toAdd The MediaStore ids of all the songs to be added to the
* playlist.
*/
public static void addToPlaylist(long playlistId, long[] toAdd)
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
String[] projection = new String[] { MediaStore.Audio.Playlists.Members.PLAY_ORDER };
Cursor cursor = resolver.query(uri, projection, null, null, null);
int base = 0;
if (cursor.moveToLast())
base = cursor.getInt(0) + 1;
cursor.close();
ContentValues[] values = new ContentValues[toAdd.length];
for (int i = 0; i != values.length; ++i) {
values[i] = new ContentValues(1);
values[i].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(base + i));
values[i].put(MediaStore.Audio.Playlists.Members.AUDIO_ID, toAdd[i]);
}
resolver.bulkInsert(uri, values);
}
}

View File

@ -19,7 +19,6 @@
package org.kreed.vanilla;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
@ -46,23 +45,6 @@ public class Song implements Parcelable {
*/
public static final int FLAG_RANDOM = 0x1;
/**
* Type indicating an id represents an artist.
*/
public static final int TYPE_ARTIST = 1;
/**
* Type indicating an id represents an album.
*/
public static final int TYPE_ALBUM = 2;
/**
* Type indicating an id represents a song.
*/
public static final int TYPE_SONG = 3;
/**
* Type indicating an id represents a playlist.
*/
public static final int TYPE_PLAYLIST = 4;
private static final String[] FILLED_PROJECTION = {
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DATA,
@ -197,231 +179,6 @@ public class Song implements Parcelable {
}
}
/**
* Return a cursor containing the ids of all the songs with artist or
* album of the specified id.
*
* @param type TYPE_ARTIST or TYPE_ALBUM, indicating the the id represents
* an artist or album
* @param id The MediaStore id of the artist or album
*/
private static Cursor getMediaCursor(int type, long id)
{
String selection = "=" + id + " AND " + MediaStore.Audio.Media.IS_MUSIC + "!=0";
switch (type) {
case TYPE_ARTIST:
selection = MediaStore.Audio.Media.ARTIST_ID + selection;
break;
case TYPE_ALBUM:
selection = MediaStore.Audio.Media.ALBUM_ID + selection;
break;
default:
throw new IllegalArgumentException("Invalid type specified: " + type);
}
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Audio.Media._ID };
String sort = MediaStore.Audio.Media.ARTIST_KEY + ',' + MediaStore.Audio.Media.ALBUM_KEY + ',' + MediaStore.Audio.Media.TRACK;
return resolver.query(media, projection, selection, null, sort);
}
/**
* Return a cursor containing the ids of all the songs in the playlist
* with the given id.
*
* @param id The id of the playlist in MediaStore.Audio.Playlists.
*/
private static Cursor getPlaylistCursor(long id)
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", id);
String[] projection = new String[] { MediaStore.Audio.Playlists.Members.AUDIO_ID };
String sort = MediaStore.Audio.Playlists.Members.PLAY_ORDER;
return resolver.query(uri, projection, null, null, sort);
}
/**
* Class simply containing metadata about a playlist.
*/
public static class Playlist {
/**
* Create a Playlist with the given id and name.
*/
public Playlist(long id, String name)
{
this.id = id;
this.name = name;
}
/**
* The MediaStore.Audio.Playlists id of the playlist.
*/
public long id;
/**
* The name of the playlist.
*/
public String name;
}
/**
* Queries all the playlists known to the MediaStore.
*
* @return An array of Playlists
* @see Playlist
*/
public static Playlist[] getPlaylists()
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Uri media = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Audio.Playlists._ID, MediaStore.Audio.Playlists.NAME };
String sort = MediaStore.Audio.Playlists.NAME;
Cursor cursor = resolver.query(media, projection, null, null, sort);
if (cursor == null)
return null;
int count = cursor.getCount();
if (count == 0)
return null;
Playlist[] playlists = new Playlist[count];
for (int i = 0; i != count; ++i) {
if (!cursor.moveToNext())
return null;
playlists[i] = new Playlist(cursor.getLong(0), cursor.getString(1));
}
cursor.close();
return playlists;
}
/**
* Retrieves the id for a playlist with the given name.
*
* @param name The name of the playlist.
* @return The id of the playlist, or -1 if there is no playlist with the
* given name.
*/
public static long getPlaylist(String name)
{
long id = -1;
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Cursor cursor = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Audio.Playlists._ID },
MediaStore.Audio.Playlists.NAME + "=?",
new String[] { name }, null);
if (cursor != null) {
if (cursor.moveToNext())
id = cursor.getLong(0);
cursor.close();
}
return id;
}
/**
* Create a new playlist with the given name. If a playlist with the given
* name already exists, it will be overwritten.
*
* @param name The name of the playlist.
* @return The id of the new playlist.
*/
public static long createPlaylist(String name)
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
long id = getPlaylist(name);
if (id == -1) {
// We need to create a new playlist.
ContentValues values = new ContentValues(1);
values.put(MediaStore.Audio.Playlists.NAME, name);
Uri uri = resolver.insert(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, values);
id = Long.parseLong(uri.getLastPathSegment());
} else {
// We are overwriting an existing playlist. Clear existing songs.
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", id);
resolver.delete(uri, null, null);
}
return id;
}
/**
* Add the given set of song ids to the playlist with the given id.
*
* @param playlistId The MediaStore.Audio.Playlist id of the playlist to
* modify.
* @param toAdd The MediaStore ids of all the songs to be added to the
* playlist.
*/
public static void addToPlaylist(long playlistId, long[] toAdd)
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
String[] projection = new String[] { MediaStore.Audio.Playlists.Members.PLAY_ORDER };
Cursor cursor = resolver.query(uri, projection, null, null, null);
int base = 0;
if (cursor.moveToLast())
base = cursor.getInt(0) + 1;
cursor.close();
ContentValues[] values = new ContentValues[toAdd.length];
for (int i = 0; i != values.length; ++i) {
values[i] = new ContentValues(1);
values[i].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(base + i));
values[i].put(MediaStore.Audio.Playlists.Members.AUDIO_ID, toAdd[i]);
}
resolver.bulkInsert(uri, values);
}
/**
* Return an array containing all the song ids that match the specified parameters
*
* @param type Type the id represents. Must be one of the Song.TYPE_*
* constants.
* @param id The id of the element in the MediaStore content provider for
* the given type.
*/
public static long[] getAllSongIdsWith(int type, long id)
{
Cursor cursor;
switch (type) {
case TYPE_SONG:
return new long[] { id };
case TYPE_ARTIST:
case TYPE_ALBUM:
cursor = getMediaCursor(type, id);
break;
case TYPE_PLAYLIST:
cursor = getPlaylistCursor(id);
break;
default:
throw new IllegalArgumentException("Specified type not valid: " + type);
}
if (cursor == null)
return null;
int count = cursor.getCount();
if (count == 0)
return null;
long[] songs = new long[count];
for (int i = 0; i != count; ++i) {
if (!cursor.moveToNext())
return null;
songs[i] = cursor.getLong(0);
}
cursor.close();
return songs;
}
public boolean equals(Song other)
{
if (other == null)
@ -518,7 +275,7 @@ public class Song implements Parcelable {
ParcelFileDescriptor parcelFileDescriptor = resolver.openFileDescriptor(uri, "r");
if (parcelFileDescriptor != null) {
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
cover = BitmapFactory.decodeFileDescriptor(fileDescriptor);
cover = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, BITMAP_OPTIONS);
}
} catch (IllegalStateException e) {
} catch (FileNotFoundException e) {

View File

@ -38,7 +38,7 @@ public class SongMediaAdapter extends MediaAdapter {
*/
public SongMediaAdapter(Context context, boolean expandable, boolean requery)
{
super(context, Song.TYPE_SONG, expandable, requery);
super(context, MediaUtils.TYPE_SONG, expandable, requery);
}
@Override

View File

@ -103,10 +103,10 @@ public class SongSelector extends PlaybackActivity implements AdapterView.OnItem
mLimiterViews = (ViewGroup)findViewById(R.id.limiter_layout);
setupView(R.id.artist_list, new MediaAdapter(this, Song.TYPE_ARTIST, true, false));
setupView(R.id.album_list, new MediaAdapter(this, Song.TYPE_ALBUM, true, false));
setupView(R.id.artist_list, new MediaAdapter(this, MediaUtils.TYPE_ARTIST, true, false));
setupView(R.id.album_list, new MediaAdapter(this, MediaUtils.TYPE_ALBUM, true, false));
setupView(R.id.song_list, new SongMediaAdapter(this, false, false));
setupView(R.id.playlist_list, new MediaAdapter(this, Song.TYPE_PLAYLIST, false, true));
setupView(R.id.playlist_list, new MediaAdapter(this, MediaUtils.TYPE_PLAYLIST, false, true));
mHandler.sendEmptyMessage(MSG_INIT);
}
@ -345,7 +345,7 @@ public class SongSelector extends PlaybackActivity implements AdapterView.OnItem
menu.add(0, MENU_EXPAND, 0, R.string.expand);
playlistMenu.add(type, MENU_NEW_PLAYLIST, id, R.string.new_playlist);
Song.Playlist[] playlists = Song.getPlaylists();
Playlist[] playlists = Playlist.getPlaylists();
for (int i = 0; i != playlists.length; ++i)
playlistMenu.add(type, (int)playlists[i].id + 100, id, playlists[i].name);
}
@ -365,8 +365,8 @@ public class SongSelector extends PlaybackActivity implements AdapterView.OnItem
*/
private void addToPlaylist(long playlistId, int type, long mediaId, CharSequence title)
{
long[] ids = Song.getAllSongIdsWith(type, mediaId);
Song.addToPlaylist(playlistId, ids);
long[] ids = MediaUtils.getAllSongIdsWith(type, mediaId);
Playlist.addToPlaylist(playlistId, ids);
String message = getResources().getQuantityString(R.plurals.added_to_playlist, ids.length, ids.length, title);
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
@ -481,7 +481,7 @@ public class SongSelector extends PlaybackActivity implements AdapterView.OnItem
NewPlaylistDialog dialog = (NewPlaylistDialog)message.obj;
if (dialog.isAccepted()) {
String name = dialog.getText();
long playlistId = Song.createPlaylist(name);
long playlistId = Playlist.createPlaylist(name);
addToPlaylist(playlistId, message.arg1, message.arg2, name);
}
break;

View File

@ -353,13 +353,13 @@ public final class SongTimeline {
*
* @param enqueue If true, enqueue the set. If false, play the set.
* @param type The type represented by the id. Must be one of the
* Song.FIELD_* constants.
* MediaUtils.FIELD_* constants.
* @param id The id of the element in the MediaStore content provider for
* the given type.
*/
public void chooseSongs(boolean enqueue, int type, long id)
{
long[] songs = Song.getAllSongIdsWith(type, id);
long[] songs = MediaUtils.getAllSongIdsWith(type, id);
if (songs == null || songs.length == 0)
return;