Hello guys i am trying to get the absolute path of audio file in android api level 29 i.e, Q but the problem is that DATA is deprecated so how to resolve this problem and also using the absolute path (e.x : storage/sdcard/music.mp3) we can get the embedded picture to that audio but in content uri (content://) that we can get using the _ID Column by appending the id of the file.But if we are not able to to get the absolute path then how to play an audio file using content:// Uri ?
The previous codes that i am using is :
public ArrayList<Song> FolderFilesList(Context context, String FolderPath) {
//folder-exclude-sub-folders
ArrayList<Song> songs = new ArrayList<>();
String[] columns = {
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.TRACK,
MediaStore.Audio.Media.ARTIST_ID,
MediaStore.Audio.Media.DISPLAY_NAME,
};
String selection = MediaStore.Audio.Media.DATA + " LIKE ? AND " + MediaStore.Audio.Media.DATA + " NOT LIKE ? ";
String[] selectionArgs = new String[]{
"%" + FolderPath + "%",
"%" + FolderPath + "/%/%"
};
Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
columns(), selection, selectionArgs, null);
if (cursor.moveToFirst()) {
do {
Song song = new Song(
cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media._ID)),
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE)),
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM)),
cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)),
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)),
cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST_ID)),
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA)),
cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.TRACK)),
cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION))
);
//File f = new File(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA)));
// if (f.isFile() && f.exists()) {
songs.add(song);
//}
} while (cursor.moveToNext());
}
if (cursor != null) {
cursor.close();
}
return songs;
}
You won't be able to get the absolute path now but you can get content uri and using that content uri means (content://) and use it to write file in your cache directory of your package folder using the below code :
String filePath = new File(resolver.openFileDescriptor(contentUri, "r");
And then use InputStream and OutputStream to store it in cache directory and use this filePath to as a File.
Use this line in application in the Manifest file
android:requestLegacyExternalStorage="true"
Related
I got a MP4 File (MIME_TYPE = audio/x-m4a) which I can't find quering mediastore.
I don't know if it's a video or an audio file, so I try to query File table of mediastore (also checke video and audio table with same result).
The file is stored in Music/MP4TestFiles Folder on internal storage (not on an SD-Card, not stored in internal app storage).
Testing on Android 13.
Uri uri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
String audiodir = "%MP4TestFiles%";
String[] projection = new String[] {
MediaStore.Files.FileColumns.MIME_TYPE,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.DISPLAY_NAME,
MediaStore.Files.FileColumns.DATE_ADDED,
MediaStore.Files.FileColumns._ID};
String selection = MediaStore.Files.FileColumns.RELATIVE_PATH+ " like ? ";
String[] selectionArgs = new String[] {audiodir};
String sortOrder = MediaStore.Files.FileColumns.DATE_ADDED + " ASC";
Cursor cur = getContentResolver().query(uri, projection, selection, selectionArgs,sortOrder);
if (cur == null) {
Log.e(TAG, "mp4...no file found in Directory: "+audiodir);
} else if (!cur.moveToFirst()) {
Log.e(TAG, "mp4 Failed to move cursor to first row (no query results). 1");
} else {
Log.d(TAG, "mp4 files found")
}
Permission is set in Manifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage"/>
If I rename the file into m4b, I got a result.
Any suggestions what's going wrong?
Thanks,
GGK
I developed an app which saves photos inside the app folder (/android/data/[app-folder]/files/Report/[directory]) with some data saved into DESCRIPTION field, here is my code to save image:
ContentValues image = new ContentValues();
image.put(Images.Media.TITLE, directory);
image.put(Images.Media.DISPLAY_NAME, FOTOC_PREFIX_NAME + "_" + directory + "_" + data + ".jpg");
image.put(Images.Media.DESCRIPTION, "EXAMPLE DESC");
image.put(Images.Media.DATE_ADDED, System.currentTimeMillis());
image.put(Images.Media.MIME_TYPE, "image/jpg");
image.put(Images.Media.ORIENTATION, 0);
File parent = imagePath.getParentFile();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
image.put(MediaStore.Images.ImageColumns.RELATIVE_PATH, parent.getAbsolutePath());
}
image.put(Images.ImageColumns.BUCKET_ID, parent.toString().toLowerCase().hashCode());
image.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, parent.getName().toLowerCase());
image.put(Images.Media.SIZE, imagePath.length());
image.put(Images.Media.DATA, imagePath.getAbsolutePath());
Uri result = getContentResolver().insert(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY), image);
And then i read data with:
String whereCause = MediaStore.Images.Media.DISPLAY_NAME + " LIKE '%" + UsefullThings.getNameWithoutExtension(photofile.getName()) + "%'";
String[] projection = new String[] {MediaStore.Images.Media.DISPLAY_NAME,MediaStore.Images.Media.DESCRIPTION,MediaStore.Images.Media.TITLE,MediaStore.Images.Media._ID};
Cursor cursor = getContentResolver().query(MediaStore.Images.Media
.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY), projection, whereCause, null, MediaStore.Images.Media._ID);
if (cursor.getCount() == 1) {
cursor.moveToFirst();
}
String descstring = "";
try {
descstring =cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DESCRIPTION));
}catch(Exception e){
....
}
where photofile is the image.
Everything is working fine, but if i reboot my tablet then the same query returns empty cursor.
Can anyone help me?
Thanks
app which saves photos inside the app folder (/android/data/[app-folder]/files/Report/[directory])
You mean /storage/emulated/0/Android/data/[app-folder]/files/Report/[directory] ?
That is impossible to begin with if you use the MediaStore.
That is an app specific directory and the MediaStore will not give you insert() uries for that location.
image.put(MediaStore.Images.ImageColumns.RELATIVE_PATH, parent.getAbsolutePath());
You should put a relative path in .RELATIVE_PATH. Not a full absolute path as you do now. Also we cannot see what exactly you put in there. Please tell value of parent.getAbsolutePath().
I recently upgraded the app's target version to API 29. Due to the scoped storage in Android 10, i used MediaStore API to store and retrieve images from app external storage. Earlier, i used getExternalStoragePublicDirectory to store images taken through camera, now i use MediaStore.Images.Media.EXTERNAL_CONTENT_URI to write file to an external storage location.
Issue i am facing now is,
When i open my app and take pictures, it stores under a folder name that i gave 'myapp' and i can retrieve my images through Mediastore cursor and show them in a custom gallery. And when i uninstall my app 'myapp' folder still exists. And when i install my app again and try to read the images from the gallery, cursor is not returning any image. But if i take picture again, then i could load them to my custom gallery. Custom gallery view is just a row of images at the bottom of the screen, so that user doesn't have to browse through the photos folder to load the image to the app.
This is how i store my images in the MediaStore
Content values:
String RELATIVE_PATH = Environment.DIRECTORY_PICTURES + File.separator + "myApp";
final ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, generateImageName(new Date()));
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, RELATIVE_PATH);
Generate Name method:
int sameSecondCount;
protected String generateName(Date now)
{
String result = formatter.format(now);
long nowMillis = now.getTime();
if (nowMillis / 1000 == lastMillis / 1000)
{
sameSecondCount++;
result += "_" + sameSecondCount;
}
else
sameSecondCount = 0;
lastMillis = nowMillis;
return result + PICTURE_EXTENSION_JPG;
}
#WorkerThread
private Uri writePictureToFile(ContentValues contentValues, byte[] bitmapBytes) throws IOException
{
final ContentResolver resolver = getApplication().getContentResolver();
Uri uri = null;
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
try
{
uri = resolver.insert(contentUri, contentValues);
if (uri == null)
throw new IOException("Failed to create new MediaStore record.");
OutputStream stream = resolver.openOutputStream(uri);
if (stream == null)
{
throw new IOException("Failed to get output stream.");
}
stream.write(bitmapBytes);
}
catch (IOException e)
{
// Delete the content from the media store
if (uri != null)
resolver.delete(uri, null, null);
throw e;
}
return uri;
}
Reading images
{
String selectionMimeType = MediaStore.Files.FileColumns.MIME_TYPE + " in (?,?,?)";
String[] args = new String[]{
MimeTypeMap.getSingleton().getMimeTypeFromExtension("jpg"),
MimeTypeMap.getSingleton().getMimeTypeFromExtension("png")};
Cursor cursor = context.getContentResolver()
.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, selectionMimeType, selectionArgs,
orderBy + " DESC");
if (cursor != null)
{
int idColumnIndex = imageCursor.getColumnIndex(MediaStore.Images.Media._ID);
imageCursor.moveToFirst();
int imageCount = imageCursor.getCount();
for (int i = 0; i < imageCount && i < totalCount; i++)
{
final long imageId = imageCursor.getLong(idColumnIndex);
Uri uriImage = Uri.withAppendedPath(uriExternal, "" + imageId);
GalleryData galleryImageData = new GalleryImageData(imageId, uriImage); // Custom class with id and Uri
galleryViewModelList.add(galleryImageData);
imageCursor.moveToNext();
}
imageCursor.close();
}
Why the images that i stored in the folder in Mediastore is not being returned by the above code when i reinstall my App. Is it by design or am i missing something?
These are the columns i am retrieving,
final String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID, MediaStore.Images.Media.MIME_TYPE };
final String orderBy = MediaStore.Images.Media.DATE_TAKEN; ```
For unclear reasons, Android 10 considers two app installations separated by time to be separate apps, no different than if those were two completely different apps.
As a result, once your app is uninstalled, it loses access to all files that it created... even if the same app is later reinstalled.
So, you need to treat files from a previous installation of your app the same way as you would treat files from completely unrelated apps: request READ_EXTERNAL_STORAGE to be able to query for them and read their contents. The "read their contents" part requires android:requestLegacyExternalStorage="true" on the <application> in the manifest.
I want to load the cover art of a Audio/Music file which is present in Internal Storage of the device.
I Only have the path to the file.
This is what I have tried till now-
I have referred this Issue which show the solution.
But I don't know how to exactly create an new Module, as from what information I could gather online is we have to register the Module first then use them
Any one who could guide me on how to register the Module and then load the cover art would be really helpful.
Also I have tried loading the cover art the normal way like but it does not load the cover art.
GlideApp
.with(myFragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.into(myImageView);
If this is the path you are having :
/storage/emulated/0/Download/mysong.mp3
Then you can use following function :
public void getAudioAlbumImageContentUri(Context context, String filePath) {
Uri audioUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Audio.Media.DATA + "=? ";
String[] projection = new String[] { MediaStore.Audio.Media._ID , MediaStore.Audio.Media.ALBUM_ID};
Cursor cursor = context.getContentResolver().query(
audioUri,
projection,
selection,
new String[] { filePath }, null);
if (cursor != null && cursor.moveToFirst()) {
long albumId = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri imgUri = ContentUris.withAppendedId(sArtworkUri,
albumId);
Log.d(TAG,"AudioCoverImgUri = "+ imgUri.toString());
Glide.with(this)
.load(imgUri)
.into(((ImageView)findViewById(R.id.button)));
cursor.close();
}
}
I want to my application to scan for music files only in those folders which I have specified in preferences. So that other music files like audio books do not get included.
Currently, I've written this code, that scans all music files:
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()) {
columnIndex = cursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
result[position] = cursor.getString(columnIndex);
position++;
}
return result;
}
Check out the answer to a similar question (although it is for images, the same idea should apply to audio):
Get filename and path from URI from mediastore
Looks like DATA stores the file path. I think if you use the MediaStore.Audio.Media.DATA column as part of your where clause, you can return only audio files from the directory you want.