I'm working on playlist in my audio player. I have return a code to add songs to playlist. The code works fine, but i have a small problem though. The problem is if I add a single song to playlist, two copies of the same song are added. It is like, if I add song A to playlist and then I open the playlist to which I added song A, I can see two copies of song A in there.
Code:
public static void AddSongToPlaylist(long songID, long pID, Context context ){
Uri pUri = MediaStore.Audio.Playlists.Members.getContentUri("external", pID);
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
String[] cols = new String[] {
"count(*)"
};
Cursor cur = resolver.query(pUri, cols, null, null, null);
cur.moveToFirst();
final int base = cur.getInt(0)+1;
cur.close();
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER,base);
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, songID);
resolver.insert(pUri,values);
resolver.notifyChange(Uri.parse("content://media"), null);
Log.i("URI:",resolver.insert(pUri, values)+"");
Toast.makeText(context, "Song Added", Toast.LENGTH_SHORT).show();
Log.i("Song ID:", String.valueOf(songID));
}
Stop calling resolver.insert() again through Log.i().
Related
I want to retrieve all song playlists in an Android device. I have searched online for code samples but the query playlistResolver.query(playlists, null, null, null, null) always gives me size 0. The do loop that prints out the names of the playlists never gets executed. I have tried a few solutions online but all didn't work. Appreciate any help. Thanks!
public void getSongList() {
//retrieve song info
ContentResolver musicResolver = getContentResolver();
//retrieve playlists
ContentResolver playlistResolver = getApplicationContext().getContentResolver();
Uri playlists = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
Cursor c = playlistResolver.query(playlists, null, null, null, null);
long playlistId = 0;
if(c!=null && c.moveToFirst()) {
do {
String plName = c.getString(c.getColumnIndex(MediaStore.Audio.Playlists.NAME));
playlistId = c.getLong(c.getColumnIndex(MediaStore.Audio.Playlists._ID));
Log.d("PLAYLIST NAME", "PLAYLIST NAME " + plName);
} while (c.moveToNext());
}
c.close();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String isMusic = MediaStore.Audio.Media.IS_MUSIC + "!= 0";//only get music tracks
Cursor musicCursor = musicResolver.query(musicUri, null, isMusic, null, null);
if(musicCursor!=null){
musicCursor.moveToFirst();
//get columns
int titleColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.TITLE);
int idColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media._ID);
int artistColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.ARTIST);
int durationColumn = musicCursor.getColumnIndex
(MediaStore.Audio.AudioColumns.DURATION);
//add songs to list
do {
long thisId = musicCursor.getLong(idColumn);
String thisTitle = musicCursor.getString(titleColumn);
String thisArtist = musicCursor.getString(artistColumn);
int thisDuration = musicCursor.getInt(durationColumn);
//String thisPlaylist = musicCursor.getString(playlistColumn);
//Log.d("SONG IN PLAYLIST", "SONG " + thisTitle + " IN PLAYLIST " + thisPlaylist);
songList.add(new Song(thisId, thisTitle, thisArtist, thisDuration));
}
while (musicCursor.moveToNext());
}
}
I stumbled against the same issue today. The global storage for playlists would normally be Phone\Internal storage\Playlists. The code quoted in the question can retrieve playlists only from that global storage. If a music app creates playlists in its local storage then you can't access those playlists.
I installed two different music apps X and Y.
Both could create playlists but none of the playlist would go into
the default storage place
Each app displayed playlists created by itself. None of the apps
displayed the playlist created by the other app.
Then I installed a third app Z. It created its playlist in the global storage and I was able to retrieve it using the code in the question. One of the first apps was able to display the playlists crated by Z but it continued to create new playlists in its local storage only.
I have 2 separate methods for retrieving songs using the content resolver. One i use to get all the songs on the phone and one i use to retrieve all playlists from my phone and then, for each playlist i get the songs on it and add it to the playlist object. I do this by searching through the list of all the songs for the ids that match the ids in the playlist. The problem is that the ids don't match. I know for sure for ex. that one playlist has 3 songs on it but the ids it finds are totally different from the one of the songs.
This is the method i use for retrieving all the songs:
public ArrayList<Song> getSongList(){
ArrayList<Song> songs = new ArrayList<Song>();
//query external audio
ContentResolver musicResolver = getContentResolver();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
//iterate over results if valid
if(musicCursor!=null && musicCursor.moveToFirst()){
//get columns
int titleColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
int idColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
int artistColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.ARTIST);
int albumColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.ALBUM);
int durationColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.DURATION);
int dataColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.DATA);
int displayNameColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.DISPLAY_NAME);
//add songs to list
do {
String name;
if(musicCursor.getString(titleColumn)==null || musicCursor.getString(titleColumn).isEmpty()) name=musicCursor.getString(displayNameColumn);
else name=musicCursor.getString(titleColumn);
songs.add(new Song(musicCursor.getLong(idColumn), name, musicCursor.getString(albumColumn), musicCursor.getString(artistColumn), musicCursor.getString(durationColumn), musicCursor.getString(dataColumn)));
}
while (musicCursor.moveToNext());
}
And this is the one for playlists:
public void getPlayists() {
playlists = new ArrayList<Playlist>();
// query external audio
String[] projection = {
android.provider.MediaStore.Audio.Playlists._ID,
android.provider.MediaStore.Audio.Playlists.NAME };
String[] projectionPl = {
android.provider.MediaStore.Audio.Media._ID,
android.provider.MediaStore.Audio.Media.TITLE };
ContentResolver resolver = context.getContentResolver();
Uri playlistsUri = android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
Cursor playlistsCursor = resolver.query(playlistsUri, projection, null,
null, null);
// iterate over results if valid
if (playlistsCursor != null && playlistsCursor.moveToFirst()) {
// get columns
int idColumn = playlistsCursor
.getColumnIndex(android.provider.MediaStore.Audio.Playlists._ID);
int nameColumn = playlistsCursor
.getColumnIndex(android.provider.MediaStore.Audio.Playlists.NAME);
// add songs to list
do {
long id = playlistsCursor.getLong(idColumn);
Playlist pl = new Playlist(
playlistsCursor.getString(nameColumn), id);
Cursor plCursor = resolver.query(
android.provider.MediaStore.Audio.Playlists.Members
.getContentUri("external", id), projectionPl,
null, null, null);
if (plCursor != null && plCursor.moveToFirst()) {
// get columns
int idColumna = plCursor
.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
int nameColumna = plCursor
.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
// add songs to list
do {
long ida = plCursor.getLong(idColumna);
String title = plCursor.getString(nameColumna);
for (Song song : songs) {
if (song.id == ida) {
pl.addSong(song);
}
}
} while (plCursor.moveToNext());
}
playlists.add(pl);
} while (playlistsCursor.moveToNext());
}
Can someone explain exactly how the song ids work or how can i modify my methods to make them work? Thanks.
Your playlistsCursor is against android.provider.MediaStore.Audio.Playlists.Members whereas you then proceed to get values from playlistsCursor but against android.provider.MediaStore.Audio.Media
The returned structure for a playlist is:
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, playorder);
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audio_id);
so if you are looking for the audio Id then change
int idColumn = playlistsCursor
.getColumnIndex(android.provider.MediaStore.Audio.Playlists._ID);
to
int idColumn = playlistsCursor
.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID);
ps: I have previously posted code to create playlists etc.
Look at my app Playlist Manager on Google Play or Amazon App Store for additional functionality
I want to make an mp3 app in which the user gives a text and then it plays that song. So far, I have this function in mind:
public void searchSong(String x) {
mp = MediaPlayer.create(MainActivity.this, R.raw.x);
mp.start();
}
where x is the name stored, But ofcourse this gives an error saying "x cannot be resolved or is not a field". How can I fix that? Thanks a lot
If your songs have already stored in a specific location of sdcard,you can get the uri of song file ,then use mp.setDataSource() to bind what will be played.
If you want to search songs by specific song name, you can use android.provider.MediaStore.The Media provider contains meta data for all available media on both internal and external storage devices include song name.
A simple query code snippet is like this:
public void searchSong(String songName) {
final String[] projections = new String[] {
android.provider.MediaStore.Audio.Media.ARTIST,
android.provider.MediaStore.Audio.Media.DATA };
final String selection = Media.TITLE + " = ?";
final String[] selectionArgs = new String[] { songName };
Cursor cursor = mContentResolver
.query(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projections, selection, selectionArgs,
Media.DEFAULT_SORT_ORDER);
if (cursor != null) {
int indexFilePath = cursor.getColumnIndex(Media.DATA);
int indexArtist = cursor.getColumnIndex(Media.ARTIST);
while (cursor.moveToNext()) {
// Get the informations of the song
cursor.getString(indexArtist);
cursor.getString(indexFilePath);
// Then do what you want
}
cursor.close();
}
}
I'm working with Android on a Media Player app, when creating a playlist in the database and then try to modify it, like removing songs from the playlist or moving song to other position(the app has a reordering feature, drag and drop), it simply doesn't work. I'm using these two codes for removing and reordering:
public boolean movePlaylistSong(int playlistId, int from, int to){
try{
return MediaStore.Audio.Playlists.Members.moveItem(context.getContentResolver(), playlistId, from, to);
}catch(Exception e){
Logger.e(TAG, e.getMessage());
}
return false;
}
public boolean removeFromPlaylist(int playlistId, int audioId) {
try{
ContentResolver resolver = context.getContentResolver();
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
return resolver.delete(uri, MediaStore.Audio.Playlists.Members.AUDIO_ID +"=?", new String[]{String.valueOf(audioId)}) != 0;
}catch(Exception e){
e.printStackTrace();
}
return false;
}
They both return true that it was successful but when reloading the playlist from the database(The external content uri of the playlists) again it returns the original one with NO CHANGES applied. It returns success result but it actually didn't work.
Thanks in advance.
Calling moveItem will change the PLAY_ORDER value, but you need to sort by the PLAY_ORDER on your cursor to see the change. Otherwise the cursor will sort by _ID, which doesn't get edited.
Uri uriPlaylistTracks = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistID);
String sortOrder = MediaStore.Audio.Playlists.Members.PLAY_ORDER;
cursor = resolver.query(uriPlaylistTracks, STAR, null, null, sortOrder);
To change the PLAY_ORDER, I did this:
//get the PLAY_ORDER values for song
cursor.moveToPosition(fromPosition);
int from = (int) cursor.getLong(cursor.getColumnIndex(Audio.Playlists.Members.PLAY_ORDER));
cursor.moveToPosition(toPosition); //position in list
int to = (int) cursor.getLong(cursor.getColumnIndex(Audio.Playlists.Members.PLAY_ORDER));
//update the PLAY_ORDER values using moveItem
boolean result = MediaStore.Audio.Playlists.Members.moveItem(resolver,
playlistID, from, to);
//get new cursor with the updated PLAY_ORDERs
cursor = resolver.query(uriPlaylistTracks, STAR, null, null, sortOrder);
//change the cursor for a listview adapter
adapter.changeCursor(cursor);
adapter.notifyDataSetChanged();
Struggling with same issue. Behaves as successful but no change. I did note however that your playlistid is of type int yet the documentation states long.
public static final boolean moveItem (ContentResolver res, long playlistId, int from, int to)
I also found this answer on the forum
Alternative to MediaStore.Playlists.Members.moveItem
I found that it does move the PLAY_ORDER but not the AUDIO_ID.
I am trying to create an app which simply offers an edittext and imagebutton. If the butten gets clicked, the idea is that an album is added to the Playlist, named in the edittext box. Albums should be selected randomly. Goes without saying that the album tracks should be in the correct order.
I can add more functionality later eg. save, overwrite, delete etc.
I have the interface but am struggling with the code. I sort of get the concept of ContentProviders.
so the code needs to:
access the Playlists, which I believe is achieved by using MediaStore.Audio.Playlists
access the Albums, which I believe is achieved by using MediaStore.Audio.Albums
add to the Playlist
I have the following code (most bits obtained from this site. Thanks btw) to access the Playlist but it crashes with a Null Exception error.
public void checkforplaylists()
{
//Get a cursor over all playlists.
final ContentResolver resolver= MediaProvider.mContentResolver;
final Uri uri=MediaStore.Audio.Playlists.INTERNAL_CONTENT_URI;
final String id=MediaStore.Audio.Playlists._ID;
final String name=MediaStore.Audio.Playlists.NAME;
final String[]columns={id,name};
final Cursor playlists= resolver.query(uri, columns, null, null, null);
if(playlists==null)
{
Log.e(TAG,"Found no playlists.");
return;
}
return;
}
Anyone who can help?
I think you mean NullPointerException, which means one of your assignments is null and then you try to access a member of the object you intended it to be. Most likely it is resolver, but to be sure you need the line number reported and/or to step through that with a debugger.
This works. When using the ContentResolver, the Context (this) is required.
public void checkforplaylists(Context context)
{
ContentResolver cr = context.getContentResolver();
final Uri uri=MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
final String id=MediaStore.Audio.Playlists._ID;
final String name=MediaStore.Audio.Playlists.NAME;
final String[]columns={id,name};
final Cursor playlists= cr.query(uri, columns, null, null, null);
if(playlists==null)
{
Log.e(TAG,"Found no playlists.");
return;
}
Log.e(TAG,"Found playlists.");
return;
}
use this code, will work
public boolean addPlaylist(String pname) {
Uri playlists = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
Cursor c = resolver.query(playlists, new String[] { "*" }, null, null,
null);
long playlistId = 0;
c.moveToFirst();
do {
String plname = c.getString(c
.getColumnIndex(MediaStore.Audio.Playlists.NAME));
if (plname.equalsIgnoreCase(pname)) {
playlistId = c.getLong(c
.getColumnIndex(MediaStore.Audio.Playlists._ID));
break;
}
} while (c.moveToNext());
c.close();
if (playlistId != 0) {
Uri deleteUri = ContentUris.withAppendedId(playlists, playlistId);
Log.d(TAG, "REMOVING Existing Playlist: " + playlistId);
// delete the playlist
resolver.delete(deleteUri, null, null);
}
Log.d(TAG, "CREATING PLAYLIST: " + pname);
ContentValues v1 = new ContentValues();
v1.put(MediaStore.Audio.Playlists.NAME, pname);
v1.put(MediaStore.Audio.Playlists.DATE_MODIFIED,
System.currentTimeMillis());
Uri newpl = resolver.insert(playlists, v1);
Log.d(TAG, "Added PlayLIst: " + newpl);
flag=true;
return flag;
}