In our app we want to get the music-files of one specific folder. We want to do this, to use the media store.
So we have a path /mnt/sd/music of this dir we will need all the files and not of the subdirs.
We tried to make a query with a substring, but it doesnt work.
public ArrayList<Song> getAudioFilesOfDir(String pathDirectory)
{
ArrayList<Song> songs = new ArrayList<Song>();
//Some audio may be explicitly marked as not being music
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0 AND " + android.provider.MediaStore.Audio.Media.DATA.substring(pathDirectory.length()).contains("/") ;
String[] projection = {
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.TRACK,
MediaStore.Audio.Media.YEAR,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_KEY,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.TITLE_KEY,
MediaStore.Audio.Media.ARTIST_ID,
MediaStore.Audio.Media.ARTIST
};
ContentResolver cr = CoreLib.Context().getContentResolver();
Cursor cursor = cr.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
MediaStore.Audio.Media._ID);
int _ID_Column = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
int DATA_Column = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
int TRACK_Column = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
int YEAR_Column = cursor.getColumnIndex(MediaStore.Audio.Media.YEAR);
int DURATION_Column = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
int ALBUM_ID_Column = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
int ALBUM_Column = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
//int ALBUM_KEY_Column = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_KEY);
//int TITLE_Column = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
//int TITLE_KEY_Column = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE_KEY);
//int ARTIST_ID_Column = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST_ID);
int ARTIST_Column = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
while(cursor.moveToNext())
{
Song song = new Song();
song.setTrackId(cursor.getInt(_ID_Column));
song.setPathAudioFile(cursor.getString(DATA_Column));
song.setTrackName(cursor.getString(TRACK_Column));
song.setYearTrack(cursor.getInt(YEAR_Column));
song.setDuration(cursor.getString(DURATION_Column));
song.setAlbumId(cursor.getInt(ALBUM_ID_Column));
song.setAlbumName(cursor.getString(ALBUM_Column));
song.setArtist(cursor.getString(ARTIST_Column));
songs.add(song);
}
return songs;
}
I can tell that this won't work:
android.provider.MediaStore.Audio.Media.DATA.substring(pathDirectory.length()).contains("/")
MediaStore.Audio.Media.DATA just contains a constant for database column and operating on that is just wrong.
You might find your solution in these answers.
Related
I tried other solutions on Stack Overflow, but they are not working with my problem. The below code is working perfectly before Android Q versions, but did not work with Android Q.
Here are the functions which are used to fetch albums and images.
First for fetching AlbumImages:
public static ArrayList<ImageFolder> getPicturePaths(Context context){
ArrayList<ImageFolder> picFolders = new ArrayList<>();
ArrayList<String> picPaths = new ArrayList<>();
Uri allImagesuri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String[] projection = {MediaStore.Images.ImageColumns.DATA, MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.BUCKET_ID};
Cursor cursor = context.getContentResolver().query(allImagesuri, projection, null, null, null);
try {
if (cursor != null) {
cursor.moveToFirst();
}
do {
ImageFolder folds = new ImageFolder();
String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME));
String folder = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME));
String datapath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
//String folderpaths = datapath.replace(name,"");
String folderpaths = datapath.substring(0, datapath.lastIndexOf(folder + "/"));
folderpaths = folderpaths + folder + "/";
if (!picPaths.contains(folderpaths)) {
picPaths.add(folderpaths);
folds.setPath(folderpaths);
folds.setFolderName(folder);
folds.setFirstPic(datapath);//if the folder has only one picture this line helps to set it as first so as to avoid blank image in itemview
folds.addpics();
picFolders.add(folds);
} else {
for (int i = 0; i < picFolders.size(); i++) {
if (picFolders.get(i).getPath().equals(folderpaths)) {
picFolders.get(i).setFirstPic(datapath);
picFolders.get(i).addpics();
}
}
}
} while (cursor.moveToNext());
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
return picFolders;
}
And here is the method to fetch images from albums:
public static ArrayList<PhotoItemModel> getAllImagesByFolder(Context context, String path){
ArrayList<PhotoItemModel> images = new ArrayList<>();
Uri allImagesuri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Images.ImageColumns.DATA ,MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.SIZE};
Cursor cursor = context.getContentResolver().query( allImagesuri, projection, MediaStore.Images.Media.DATA + " like ? ", new String[] {"%"+path+"%"}, null);
try {
cursor.moveToFirst();
do{
PhotoItemModel pic = new PhotoItemModel();
pic.setPicturName(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)));
pic.setPicturePath(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)));
pic.setPictureSize(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)));
images.add(pic);
}while(cursor.moveToNext());
cursor.close();
ArrayList<PhotoItemModel> reSelection = new ArrayList<>();
for(int i = images.size()-1;i > -1;i--){
reSelection.add(images.get(i));
}
images = reSelection;
} catch (Exception e) {
e.printStackTrace();
}
return images;
}
How can I fix this?
First check whether the Android Q is getting some problem (permission related) to reach Folder path
String folderpaths = datapath.substring(0, datapath.lastIndexOf(folder + "/"));
folderpaths = folderpaths + folder + "/";
Under Android Q you cannot use the .DATA column.
Instead use .RELATIVE_PATH.
Read the threads tagged mediastore.
I search about read song in android and I see a code from you:
private static ArrayList<SongModel> LoadSongsFromCard() {
ArrayList<SongModel> songs = new ArrayList<SongModel>();
// Filter only mp3s, only those marked by the MediaStore to be music and longer than 1 minute
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0"
+ " AND " + MediaStore.Audio.Media.MIME_TYPE + "= 'audio/mpeg'"
+ " AND " + MediaStore.Audio.Media.DURATION + " > 60000";
final String[] projection = new String[] {
MediaStore.Audio.Media._ID, //0
MediaStore.Audio.Media.TITLE, //1
MediaStore.Audio.Media.ARTIST, //2
MediaStore.Audio.Media.DATA, //3
MediaStore.Audio.Media.DISPLAY_NAME
};
final String sortOrder = MediaStore.Audio.AudioColumns.TITLE
+ " COLLATE LOCALIZED ASC";
Cursor cursor = null;
try {
// the uri of the table that we want to query
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; //getContentUriForPath("");
// query the db
cursor = _context.getContentResolver().query(uri,
projection, selection, null, sortOrder);
if (cursor != null) {
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
//if (cursor.getString(3).contains("AwesomePlaylists")) {
SongModel GSC = new SongModel();
GSC.ID = cursor.getLong(0);
GSC.songTitle = cursor.getString(1);
GSC.songArtist = cursor.getString(2);
GSC.path = cursor.getString(3);
// This code assumes genre is stored in the first letter of the song file name
String genreCodeString = cursor.getString(4).substring(0, 1);
if (!genreCodeString.isEmpty()) {
try {
GSC.genre = Short.parseShort(genreCodeString);
} catch (NumberFormatException ex) {
Random r = new Random();
GSC.genre = (short) r.nextInt(4);
} finally {
songs.add(GSC);
}
}
//}
cursor.moveToNext();
}
}
} catch (Exception ex) {
} finally {
if (cursor != null) {
cursor.close();
}
}
return songs;
}
I'm really learning to program for Android, and modify your code for what I needed , but I have trouble understanding when you assign cursor
cursor = _context.getContentResolver () query ( uri , projection , selection , null, sortOrder ) . ;
Part of _context not understand you kindly explain it please.
If your class extends activity you can use this for _context. If not, you need to pass the context from your activity. The first case mentioned would look like this:
// query the db
cursor = this.getContentResolver().query(uri, projection, selection, null, sortOrder);
__
What is Context in Android?
I'm looking to export the contacts that are stored in the native database.
I'm having trouble retrieving contacts from native database.
Here is the query I would like to use :
Get all the contacts that have at least a phone number or an email.
Here is the query I am using :
String dataWhere = ContactsContract.Data.MIMETYPE + "=? OR " + ContactsContract.Data.MIMETYPE + "=?";
String[] dataWhereValues = new String[]{ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE};
String[] dataProjection = new String[]{ContactsContract.Data.CONTACT_ID, ContactsContract.Data.LOOKUP_KEY, ContactsContract.Data.DISPLAY_NAME_PRIMARY, ContactsContract.Data.STARRED, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA_VERSION};
Cursor data = getContentResolver().query(ContactsContract.Data.CONTENT_URI, dataProjection, dataWhere, dataWhereValues, ContactsContract.Data.CONTACT_ID);
But this query gives me lots of weird contacts, and some of my contacts are also missing...
Can anyone help me please ?
this may help you for getting phone numbers and display names...
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, null);
// importing phone contacts
while (phones.moveToNext())
{
listMobileNo.add(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
listName.add(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
}
phones.close();
Here is the query I ended up with
String where = ContactsContract.Data.MIMETYPE + "=? OR " + ContactsContract.Data.MIMETYPE + "=?";
String[] whereValues = new String[]{ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE};
String[] dataProjection = new String[]{ContactsContract.Data.CONTACT_ID, ContactsContract.Data.LOOKUP_KEY, ContactsContract.Data.DISPLAY_NAME_PRIMARY, ContactsContract.Data.STARRED, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA_VERSION};
Cursor cursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, dataProjection, dataWhere, dataWhereValues, ContactsContract.Data.CONTACT_ID + " ASC");
int cidIndex = cursor.getColumnIndexOrThrow(ContactsContract.Data.CONTACT_ID);
int nameIndex = cursor.getColumnIndexOrThrow(ContactsContract.Data.DISPLAY_NAME_PRIMARY);
int starredIndex = cursor.getColumnIndexOrThrow(ContactsContract.Data.STARRED);
int typeIndex = cursor.getColumnIndexOrThrow(ContactsContract.Data.MIMETYPE);
int data1Index = cursor.getColumnIndexOrThrow(ContactsContract.Data.DATA1);
int data2Index = cursor.getColumnIndexOrThrow(ContactsContract.Data.DATA2);
int lookupKeyIndex = cursor.getColumnIndexOrThrow(ContactsContract.Data.LOOKUP_KEY);
int versionIndex = cursor.getColumnIndexOrThrow(ContactsContract.Data.DATA_VERSION);
boolean hasData = cursor.moveToNext();
while (hasData){
contactId = cursor.getLong(cidIndex);
nativeLookupKey = cursor.getString(lookupKeyIndex);
fullName = cursor.getString(nameIndex);
starred = cursor.getInt(starredIndex);
version = cursor.getLong(versionIndex);
while (currentContactId <= contactId && hasData) {
if (currentContactId == contactId) {
String type = cursor.getString(typeIndex);
if (type.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
String email = cursor.getString(data1Index);
} else if (type.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
String number = cursor.getString(data1Index);
}
}
hasData = cursor.moveToNext();
if (hasData) {
currentContactId = cursor.getLong(cidIndex);
}
}
}
I was trying to build a music player application , and I wanted to add a feature in order to add a song to a playlist.Here is the code:
public static void addToPlaylist(ContentResolver resolver,SongDetails songDetails,int playlistId) {
String[] cols = new String[] {
"count(*)"
};
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
Cursor cur = resolver.query(uri, cols, null, null, null);
cur.moveToFirst();
final int base = cur.getInt(0);
cur.close();
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(base + songDetails.getId()));
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, songDetails.getId());
values.put(MediaStore.Audio.Playlists.Members.DISPLAY_NAME, songDetails.getSongTitle());
values.put(MediaStore.Audio.Playlists.Members.ARTIST, songDetails.getArtistName());
values.put(MediaStore.Audio.Playlists.Members.DATA, songDetails.getSongData());
Log.i("URI:",resolver.insert(uri, values)+"");
}
and in the logs I always get:
URI: null
which means that the song is not added to the playlist.Does anybody have any idea why the song is not added?
I've been using this method and it worked for me.
public static String addTracksToPlaylist(final long id, List<MediaData> tracks, final Context context) {
int count = getPlaylistSize(id, context);
ContentValues[] values = new ContentValues[tracks.size()];
for (int i = 0; i < tracks.size(); i++) {
values[i] = new ContentValues();
values[i].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, i + count + 1);
values[i].put(MediaStore.Audio.Playlists.Members.AUDIO_ID, tracks.get(i).getId());
}
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", id);
ContentResolver resolver = context.getContentResolver();
int num = resolver.bulkInsert(uri, values);
resolver.notifyChange(Uri.parse("content://media"), null);
return String.format(context.getString(R.string.ADDED_TO_PLAYLIST), num, context.getString(R.string.CURRENT));
}
Retrieving tracks from playlist:
public static Cursor getTrackListFromPlaylist(Context context, long plid) {
String[] MEDIA_COLUMNS = new String[] {
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ARTIST_ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Playlists.Members.AUDIO_ID,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.DATA,
MINUTES + "||':'||" + SECONDS + " as " + FORMATTED_DURATION,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media._ID
};
return query(context, MediaStore.Audio.Playlists.Members.getContentUri("external", plid),
MEDIA_COLUMNS, null, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER);
}
I'm trying to scan all the music files from a specified folder and I am encountering a performance problem combined with an app close.
My approach is to first get all the music files from the phone using:
String[] projection = {
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.TITLE
};
String selection = MediaStore.Audio.Media.IS_MUSIC + "!=" + 0;
cursor = managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
MediaStore.Audio.Media.TITLE + " ASC");
Then I get the location for each of the fetched files using:
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
If the file location is within a specified folder, I add it to the list that will be displayed on screen.
The problem with this approach is that it is not performing well.
It hangs for 4-5 seconds.
If I scroll the list the app closes.
Below is the full code I'm using right now:
private String[] getTrackList() {
String[] result = null;
String[] projection = {
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.TITLE
};
String selection = MediaStore.Audio.Media.IS_MUSIC + "!=" + 0;
cursor = managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
MediaStore.Audio.Media.TITLE + " ASC");
result = new String[cursor.getCount()];
int position = 0;
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
getSearchableDir("/mnt/sdcard/Music/"); //See below
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
String currentDir = cursor.getString(columnIndex).substring(0,
cursor.getString(columnIndex).lastIndexOf("/") + 1);
if (searchableDir.contains(currentDir)) {
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
result[position] = cursor.getString(columnIndex);
position++;
}
}
return result;
}
// Function for recursively fetching all the sub-directories
private void getSearchableDir(String path) {
searchableDir.add(path);
File root = new File(path);
File[] list = root.listFiles();
for (File f : list) {
if (f.isDirectory()) {
searchableDir.add(f.getAbsolutePath());
getSearchableDir(f.getAbsolutePath());
}
}
}
I think it's safe to say that getSearchableDir is the performance hog here.
Re-factor the code so that this function is not called.