Android media provider does not get recently added images - java

I want to fetch all the images in android device. Therefore I used this code to fetch images-
private fun getAllShownImagesPath(activity: Activity): ArrayList<String>
{
val uri: Uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val listOfAllImages = ArrayList<String>()
var absolutePathOfImage : String
val projection = arrayOf(MediaStore.MediaColumns.DATA, MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
val orderBy = MediaStore.Images.Media.DATE_ADDED
val cursor = activity.contentResolver.query(uri, projection, null, null, orderBy)
val indexData = cursor!!.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
cursor.moveToLast()
while (cursor.moveToPrevious())
{
absolutePathOfImage = cursor.getString(indexData)
listOfAllImages.add(absolutePathOfImage)
}
cursor.close()
return listOfAllImages
}
But this does not returns recently added images like if you downloaded it few hours ago.
This is somehow fixed when you reboot the device or the image you want to access is like one day old.
Note- you can also provide solution in java.
Thanks

Forcefully send broadcast then media cursor will be updated. call this before access media cursor
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.parse("file://" + Environment.getExternalStorageDirectory())));

Related

How to retrieve list of all local audio files and its parameters properly?

For now, I'm doing this with content resolver. Code:
private fun loadMedia(): List<LocalMusic> {
val list = mutableListOf<LocalMusic>()
val contentResolver = context.contentResolver
val uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val selection = "${MediaStore.Audio.Media.IS_MUSIC}!= 0"
val sortOrder = "${MediaStore.Audio.Media.TITLE} ASC"
var i = 0
contentResolver.query(uri, null, selection, null, sortOrder).use {
if (it != null && it.count > 0) {
while (it.moveToNext()) {
val title = it.getString(it.getColumnIndex(MediaStore.MediaColumns.TITLE))
// Android Studio shows a lint, which tells that MediaStore.MediaColumns.ARTIST
//requires API 30. But in Android Pie it works.
val artist = it.getString(it.getColumnIndex(MediaStore.MediaColumns.ARTIST))
//the same lint as described above(required api 29)
val album = it.getString(it.getColumnIndex(MediaStore.MediaColumns.ALBUM))
// This one is deprecated(fantastic, what to do?).
val source = it.getString(it.getColumnIndex(MediaStore.MediaColumns.DATA))
val duration = it.getLong(it.getColumnIndex(MediaStore.MediaColumns.DURATION))
list.add(LocalMusic(id = "$i", artist = artist, title = title, source = source,
album = album, duration = duration, image = "some uri"))
i++
}
}
}
return list.toList()
}
So, there are some questions:
The main one. Should I use MediaStore.MediaColumns.DATA to get URI anyway? I know that Google tells "sometimes you don't have permissions to work with storage, blah-blah, that's why it's deprecated", but is there a better way(I always have needed permissions)?
About "MediaStore.MediaColumns.ARTIST" and "MediaStore.MediaColumns.ALBUM". Why it requires API 30, if I found its usages in tutorials 5-6 years ago, though there was no API 30 at all? Because of support libraries, migrations, etc? Should I keep using it?

Get ringtone - english name

I want to get the ringtones of a phone, but see only the english (non-localized version).
My theory, was using a ContextWrapper, and set that context locale to en_US and pass that new locale to RingtoneManager.getRingtone() (code based from Set Locale programmatically ):
ContextWrapper cw = new ContextWrapper(context);
Context cc = setContextLocale(cw, "en_US"); // This method was copied from the StackOverflow question above ^^
Ringtone defaultRingtone = RingtoneManager.getRingtone(cc, Settings.System.DEFAULT_RINGTONE_URI);
String sss = defaultRingtone.getTitle(cc);
So, yes, this does not work as expected. Any ideas?
Hope you find what you are looking for with following code snippet:
data class Ringtone(
val _id: String,
val title: String
)
val cursor = RingtoneManager(this).cursor
cursor.moveToFirst()
val list = ArrayList<Ringtone>()
do {
list.add(Ringtone(
cursor.getString(0),
cursor.getString(1)
))
} while (cursor.moveToNext())
Log.i(TAG, "ringtones list=$list")

How to get MediaStore.Images.ImageColumns.TITLE of an image in my gallery in android?

I have an image here: /storage/emulated/0/Pictures/1487951012463.jpg
The title is a text obviously. This title is shown in the default gallery viewer in android 5.1.1. (select image-->details)
But from my app, I just cannot read it.
Can someone help me out?
The code I am using is:
public static void loadTitle(Context context) {
Uri contentUri = Uri.parse("/storage/emulated/0/Pictures/1487951012463.jpg");
String[] projection = new String[] {
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.LATITUDE,
MediaStore.Images.ImageColumns.LONGITUDE,
MediaStore.Images.ImageColumns.DESCRIPTION,
MediaStore.Images.ImageColumns.SIZE,
};
Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
cursor.moveToFirst();
String title, name;
title = cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.TITLE));
name = cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DISPLAY_NAME));
Log.e("Title", title);
Log.e("Display_Name", name);
}
The app crashes as the cursor contains nothing.
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'boolean android.database.Cursor.moveToFirst()' on a null object reference
I call this from an Activity if this matters...
What am I doing wrong?
EDIT - EDIT - EDIT - EDIT - EDIT - EDIT - EDIT
I have tried to do the same with the ExifInterface as it was suggested. The result I am getting with this is 'null'.
ExifInterface exif = new ExifInterface("/storage/emulated/0/Pictures/1487955364408.jpg");
String x = exif.getAttribute("XPTitle");
Log.e("Title with Exif: ", "X = "+ x );
Please help.
First, /storage/emulated/0/Pictures/1487951012463.jpg is not a Uri. It is a path. A Uri has a scheme.
Second, even if you put the file scheme on that Uri (which would make the Uri valid), you cannot use that Uri with query() on ContentResolver. query() only works with a content Uri, and you do not have one of those.
Presumably, that title is in an EXIF header in the JPEG file, though I am not certain which EXIF tag is the correct one. If you can find that out, you can use the support library's ExifInterface to read in the value.

Android: Cursor doesn't return all videos saved in app folder in external storage

I'm currently developing video app and can save videos to app folder successfully.
But when I want to display app videos in recyclerview, it doesn't display all videos (as I debug app, the cursor doesn't return all videos, and when I restart device, it returns all videos, I have to restart device if new video is added in app folder to see all videos)
Here's source code.
public static List<MyVideo> getAppVideos(Context context) {
String[] projection = { MediaStore.Video.Media.DATA, MediaStore.Video.Media.DATE_TAKEN, MediaStore.Video.Media.DURATION};
String selection = MediaStore.Images.Media.BUCKET_ID + " = ?";
String[] selectionArgs = { APP_VIDEO_BUCKET_ID };
Cursor cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
MediaStore.Files.FileColumns.DATE_ADDED + " DESC");
ArrayList<MyVideo> result = new ArrayList<MyVideo>(cursor.getCount());
if (cursor.moveToFirst()) {
final int dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
final int dateColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATE_TAKEN);
final int durationColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);
do {
final String data = cursor.getString(dataColumn);
final String createdDate = cursor.getString(dateColumn);
final String durationTime = cursor.getString(durationColumn);
result.add(new MyVideo(data, DateUtils.convertToSeconds(durationTime), "^ " + DateUtils.getDateFromMilliSeconds(Long.parseLong(createdDate), "MMM dd, yyyy")));
} while (cursor.moveToNext());
}
cursor.close();
return result;
}
1.Actually it's the Android Nature.
When you add some New files to External Storage it will take sometime to Add it to Media Content Provider.Androdid System will automatically runs a mediascan in particular period.There is a workaround for that you need to trigger the Android System for a media scan
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(videoAdded)));
2.When you restart the device it will scan for the media and you will get all the videos
I have to restart device if new video is added in app folder to see all videos
Yes. That is normal behavior. As after restart the MediaSotore will have indexed all mediafiles on your device. If you add a file the mediastore does not know aboutt that file.
So you have to tell the mediastore (with a few lines of code) that there is a new file to be indexed every time you created a new file.
Google for mediascanner and new file as code has been posted many times here.

How to get Ringtone name in Android?

I'm allowing my user to pick a ringtone for notifications in my app. I want to store the URI of the sound along with the human readable title of the sound.
So far the URI code works great:
Uri uri = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
But when I try to get the title, and set it as a button text, I don't get anything. Seems to have no title?
String title = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_TITLE);
button.setText(title);
But my button text is empty. If I do:
button.setText(uri.toString());
then I see the uri perfectly. Should I just try to get the title from the URI? Thanks
This should get it:
Ringtone ringtone = RingtoneManager.getRingtone(this, uri);
String title = ringtone.getTitle(this);
Refer to http://developer.android.com/reference/android/media/Ringtone.html for the documentation, but the short story: Ringtone.getTitle(Context ctx);
I personally had a serious performance problem when I tried the accepted answer, it took about 2 seconds to just load a list of 30 ringtones. I changed it a bit and it works about 10x faster:
uri = ringtoneMgr.getRingtoneUri(cursor.getPosition());
ContentResolver cr = getContext().getContentResolver();
String[] projection = {MediaStore.MediaColumns.TITLE};
String title;
Cursor cur = cr.query(uri, projection, null, null, null);
if (cur != null) {
if (cur.moveToFirst()) {
title = cur.getString(0);
cur.close();
I had problems with 'MediaPlayer finalized without being released'. I use this:
Cursor returnCursor = getContentResolver().query(uri, null, null, null, null);
returnCursor.moveToFirst();
String title = returnCursor.getString(returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
returnCursor.close();
Refer to https://developer.android.com/training/secure-file-sharing/retrieve-info.html for the documentation.

Categories