In my Android application, I want the user to be able to select Albums, Artists and Playlists and then send an intent for their default media player to play them.
I fetch the ID in the standard way:
final Uri exAudioUri = Uri.parse("content://com.google.android.music.MusicContent/playlists");
final String[] proj = { MediaStore.Audio.Playlists._ID, MediaStore.Audio.Playlists.NAME };
final Cursor musiccursor = ctx.getContentResolver().query(exAudioUri, proj, null, null, null);
String name = null;
String id = null;
if (musiccursor != null && musiccursor.getCount() > 0) {
while (musiccursor.moveToNext()) {
name = musiccursor.getString(musiccursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.NAME));
id = musiccursor.getString(musiccursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists._ID));
For Playlists I'm using the following intent:
Intent playMediaIntent = new Intent(Intent.ACTION_VIEW);
playMediaIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
playMediaIntent.setType(MediaStore.Audio.Playlists.CONTENT_TYPE);
playMediaIntent.putExtra("playlist", playlistID);
The Google Play Music app intercepts this and plays the playlist successfully.
Trying to do the same for albums gives me an activity not found exception:
Intent playMediaIntent = new Intent(Intent.ACTION_VIEW);
playMediaIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//playMediaIntent.setType("vnd.android.cursor.dir/track");
playMediaIntent.setType(MediaStore.Audio.Albums.CONTENT_TYPE);
//playMediaIntent.setData(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
playMediaIntent.putExtra("album", albumID);
I know these are undocumented methods and subject to change, but I don't want to have to implement an entire media player of my own, when a user will already have chosen their favourite....
Can anyone suggest any 'standard' code that media players will intercept?
Alternatively, is there a way to get all of the songs from the album (or artist) and send an intent with data containing an array of track URIs to play or queue up??
Been to the depths of Google/Stackoverflow on this one and drawn a blank...
Please help! I thank you in advance.
Related
Ok, this question is pretty straightforward, how can I get all the Songs on a device (or If on the entire device is not possible at least in one folder, for example, the music one) in a map containing all the songs with their respective path in something like this:
var song= {
// Key: Value
'title': 'All Star',
'author': 'Smash Mouth', //Optional but would like to get this too
'album': 'All Star', //Optional but would like to get this too
'path': 'storage/emulated/0/Music'
};
How Could I do it?
Android has a mediaplayer class, which scans all media files and generates corresponding database information when booting and plugging and unplugging sd cards. You can get information about music files in the following way.
private List<SingListBean> getAllSing(Context context) {
int flag = 1;
List<SingListBean> listBeans = new ArrayList<>();
Cursor cursor = context.getContentResolver().query
(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
while (cursor.moveToNext()) {
String singName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
String singAlbum = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
Long _size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
listBeans.add(new SingListBean(flag++, singName, singAlbum, _size, duration, url));
}
return listBeans;
}
I've been attempting to look for a solution with regards to the problem as stated in the title above but to no avail.
I'm trying to find a way to check if an Audio file has or does not have an album art, so in the case when there is no album art, I'll be able to set my own drawable for it.
Here's the code I'm running to initialize my song list.
ContentResolver cr = getActivity().getContentResolver();
Uri songsUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String songsSelection = MediaStore.Audio.Media.IS_MUSIC + "!= 0";
String songsSortOrder = MediaStore.Audio.Media.TITLE + " ASC";
Cursor songCur = cr.query(songsUri, null, songsSelection, null, songsSortOrder);
int songCount = 0;
if(songCur != null)
{
songCount = songCur.getCount();
if(songCount > 0)
{
while(songCur.moveToNext())
{
//String data = songCur.getString(songCur.getColumnIndex(MediaStore.Audio.Media.DATA));
// Debug
//Log.e("Song Path", data);
// (long _id, long _albumId, long _artistId, String _title,
// String _artistName, String _albumName, int _duration)
//Log.e("Music ID", songCur.getString(cur.getColumnIndex(MediaStore.Audio.Media._ID)));
//Log.e("Music Album ID", songCur.getString(songCur.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)));
//Log.e("Music Artist ID", songCur.getString(cur.getColumnIndex(MediaStore.Audio.Media.ARTIST_ID)));
//Log.e("Music Title", songCur.getString(cur.getColumnIndex(MediaStore.Audio.Media.TITLE)));
//Log.e("Music Artist Name", songCur.getString(cur.getColumnIndex(MediaStore.Audio.Media.ARTIST)));
//Log.e("Music Album Name", songCur.getString(songCur.getColumnIndex(MediaStore.Audio.Media.ALBUM)));
//Log.e("Music Duration", songCur.getString(cur.getColumnIndex(MediaStore.Audio.Media.DURATION)));
mediaManager.songFiles.add(new Song(
songCur.getString(songCur.getColumnIndex(MediaStore.Audio.Media.DATA)),
songCur.getLong(songCur.getColumnIndex(MediaStore.Audio.Media._ID)),
songCur.getLong(songCur.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)),
songCur.getLong(songCur.getColumnIndex(MediaStore.Audio.Media.ARTIST_ID)),
songCur.getString(songCur.getColumnIndex(MediaStore.Audio.Media.TITLE)),
songCur.getString(songCur.getColumnIndex(MediaStore.Audio.Media.ARTIST)),
songCur.getString(songCur.getColumnIndex(MediaStore.Audio.Media.ALBUM)),
songCur.getInt(songCur.getColumnIndex(MediaStore.Audio.Media.DURATION))));
}
}
songCur.close();
}
Let me know if you require any further explanation on my question.
I noticed in your code that you're getting retrieving the album_id of a particular song so a while back I discovered a simple way to fetch album art by appending the album_id to a particular URI, checkout the following code
public Uri getAlbumArtUri(long albumID) {
return ContentUris.withAppendedId(Uri.parse("content://media/external/audio/albumart"), albumID);
}
I then use an Image Loading library like Universal Image Loader or Glide to load the image into an ImageView, like so:
ImageLoader.getInstance().displayImage
(getAlbumArtUri(song.albumId).toString(),
holder.albumArt, new DisplayImageOptions.Builder().cacheInMemory(true).
showImageOnFail(R.drawable.albumart_mp_unknown).resetViewBeforeLoading(true).
build());
showImageOnFail() takes in a drawable that would be displayed incase of error.(This means the song doesn't have album artwork)
P.S I also found the solution discussed on this Stack Overflow Post Quite useful:
Most robust way to fetch Album Art in Android
Hope this helps!
I am developing an application where i need all the ringtone title and uri. I just need the title but not the Ringtone object. A well known way to get ringtone uri and title is following
rm = new RingtoneManager(getActivity());
rm.setType(RingtoneManager.TYPE_RINGTONE);
Cursor cursor = rm.getCursor();
if(cursor.moveToFirst()){
do{
try{
Uri uri= rm.getRingtoneUri(cursor.getPosition());
Ringtone rtone = rm.getRingtone(cursor.getPosition());
System.out.printf("URI: " + uri.toString());
System.out.printf("Title: " + rtone.getTitle(this));
}
catch(Exception ee){}
}while(cursor.moveToNext());
}
My problem is Ringtone object. It's costly to create Ringtone object each time. Ringtone object also create media player. So when i load all the list it's takes little bit time. I have also tested the code without creating the Ringtone object and it's fair enough.
I want to open Contacts pick activity from my application with search field should be filled programmatically.
Can anyone suggest what URI shoud i use or anything to put in intent's extra?
private static final int PICK_CONTACT_SUBACTIVITY = 2;
private void startContactActivity() {
Uri uri = Uri.parse("content://contacts/people");
// Here in this normally we pass number e.g. Uri.encode("987") but i want to pass name as filter is it possible?
// I have also tried
//uri = Uri.withAppendedPath(android.provider.ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode("pra"));
//uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode("pra"));
uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode("pra"));
Intent intent = new Intent(Intent.ACTION_PICK, uri);
startActivityForResult(intent, PICK_CONTACT_SUBACTIVITY);
}
Can anyone suggest how can i achieve this?
You can follow :
how-to-pick-contact-number-from-phone-book-of-android-in-to-my-application
or
developer.android.com/training/contacts-provider/modify-data
It seems that it is not possible to specify a filter programmatically.
The Android SDK documentation states (in the chapter "Retrieval and modification with intents") that for ACTION_PICK you can only use one of
Contacts.CONTENT_URI, Phone.CONTENT_URI, StructuredPostal.CONTENT_URI, Email.CONTENT_URI. This is indirectly a filter (all contacts, all with phone numbers, all with postal address, or all with email), but it is limited to this.
I am currently making an app which works with images. I need to implement functionality where the user picks a file stored on the SD card. Once they pick the picture (using the Android gallery), the the file-location of the image will be sent to another Activity, where other work will be done upon it.
I have seen similar posts here on SO, but none to answer my question specifically. Basically this is the code I am doing when the user clicks the "Load a Picture" button:
// Create a new Intent to open the picture selector:
Intent loadPicture = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// To start it, run the startActivityForResult() method:
startActivityForResult(loadPicture, SELECT_IMAGE);
From that code, I then have a onActivityResult() method to listen to the call-back:
// If the user tried to select an image:
if(requestCode == SELECT_IMAGE)
{
// Check if the user actually selected an image:
if(resultCode == Activity.RESULT_OK)
{
// This gets the URI of the image the user selected:
Uri selectedImage = data.getData();
// Create a new Intent to send to the next Activity:
Intent i = new Intent(currentActivty.this, nextActivity.class);
// ----------------- Problem Area -----------------
// I would like to send the filename to the Intent object, and send it over.
// However, the selectedImage.toString() method will return a
// "content://" string instead of a file location. How do I get a file
// location from that URI object?
i.putExtra("PICTURE_LOCATION", selectedImage.toString());
// Start the activity outlined with the Intent above:
startActivity(i);
As the code above states, the uri.toString() will return a content:// string instead of the file location of the selected picture. How do I obtain the file location?
Note: Another possible solution is to send over the content:// string and convert that into a Bitmap (which is what happens in the next Activity). However, I don't know how to do that.
I have found the answer to my own question. After doing some more searching, I finally stumbled upon a post here on SO which asks the same question here: android get real path by Uri.getPath().
Unfortunately, the answer has a broken link. After some Google searching, I found the correct link to the site here: http://www.androidsnippets.org/snippets/130/ (I have verified that this code does indeed work.)
However, I decided to take a different route. Since my next Activity is using an ImageView to display the picture, I am instead going to use the Uri content string for all methods that link to the next Activity.
In the next Activity, I am using the ImageView.setImageUri() method.
Here is the code I am doing in the next Activity to display the picture from the content:// string:
// Get the content string from the previous Activity:
picLocation = getIntent().getStringExtra("PICTURE_LOCATION");
// Instantiate the ImageView object:
ImageView imageViewer = (ImageView)findViewById(R.id.ImageViewer);
// Convert the Uri string into a usable Uri:
Uri temp = Uri.parse(picLocation);
imageViewer.setImageURI(temp);
I hope that this question and answer will be helpful to future Android developers.
Here's another answer that I hope someone finds useful:
You can do this for any content in the MediaStore. In my app, I have to get the path from URIs and get the URI from paths. The former:
/**
* Gets the corresponding path to a file from the given content:// URI
* #param selectedVideoUri The content:// URI to find the file path from
* #param contentResolver The content resolver to use to perform the query.
* #return the file path as a string
*/
private String getFilePathFromContentUri(Uri selectedVideoUri,
ContentResolver contentResolver) {
String filePath;
String[] filePathColumn = {MediaColumns.DATA};
Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
}
The latter (which I do for videos, but can also be used for Audio or Files or other types of stored content by substituting MediaStore.Audio (etc) for MediaStore.Video:
/**
* Gets the MediaStore video ID of a given file on external storage
* #param filePath The path (on external storage) of the file to resolve the ID of
* #param contentResolver The content resolver to use to perform the query.
* #return the video ID as a long
*/
private long getVideoIdFromFilePath(String filePath,
ContentResolver contentResolver) {
long videoId;
Log.d(TAG,"Loading file " + filePath);
// This returns us content://media/external/videos/media (or something like that)
// I pass in "external" because that's the MediaStore's name for the external
// storage on my device (the other possibility is "internal")
Uri videosUri = MediaStore.Video.Media.getContentUri("external");
Log.d(TAG,"videosUri = " + videosUri.toString());
String[] projection = {MediaStore.Video.VideoColumns._ID};
// TODO This will break if we have no matching item in the MediaStore.
Cursor cursor = contentResolver.query(videosUri, projection, MediaStore.Video.VideoColumns.DATA + " LIKE ?", new String[] { filePath }, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(projection[0]);
videoId = cursor.getLong(columnIndex);
Log.d(TAG,"Video ID is " + videoId);
cursor.close();
return videoId;
}
Basically, the DATA column of MediaStore (or whichever sub-section of it you're querying) stores the file path, so you use what you know to look up the DATA, or you query on the DATA field to select the content you care about.