As you can see, I'm new here (but not new to programming). I'm working on my first android camera app, and I cant get my video files to show up in the gallery. I understand that I need to inform the system of my new file's Content Values, but nothing I try is working.
Strangely this works just fine for images:
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, imgFile.getAbsolutePath());
getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Yet this does not always make videos visible in the gallery app:
ContentValues values = new ContentValues();
values.put(MediaStore.Video.Media.DATA, vidFile.getAbsolutePath());
getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
I assure you it is a valid video file, and sometimes the above code works. I cannot find a pattern for when it will work and when not, though.
I have also tried a few other variations to getContentResolver().insert. In fact, If I tell it my video file is an image, it always updates the gallery with a nonviewable image that is my video.
Thanks much in advance for any help!
Well this has been an ordeal, but I found a work-around. Actually this new solution might be better then what I was trying to do. Depends on the overheads of the various methods I suppose.
As stated by Pascal here, I can update the content provider by broadcasting the proper intent:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(imageAddedOrDeleted)));
This makes my videos visible to my gallery app every time (thank god, I was about to resort to writing my own built in viewer)
But I'm still curious why my method works for images but not video, in case anyone knows.
Related
In Android Q the field MediaStore.Files.FileColumns.DATA has been deprecated, and may be Null or apps have no rights to read it when targeting such OS version, so will be preferable to work using only a file’s content Uri.
Since the MediaScannerConnection only accepts file paths, I found that for Android Q this is no longer an option.
What would be the way to force an automatic MediaStore update/re-scan of a single file, without knowing its real path and using only its Uri? The intention is not to even try to find the real path and rely only in the Uri.
Consider that the Uri to force the update is a media content Uri (not a SAF Uri).
Example: content://media/external/images/media/123
The solution must not be to re-scan the entire storage or un-mount / mount the storage again, as this will have a high performance hit in our workflow and will make it completely unusable.
And because the intention is to use only the Uri, then to avoid forcing a scan of any specific directory of files, which would also have an impact if it contains lots of files, and implies that a real directory path must be resolved from the Uri, which is not an option.
UPDATE:
We have tried with unsuccessful results the ContentResolver.refresh method introduced in Android O, yet this method doesn't do any refresh at all when it comes to a media content Uri in a format such as: content://media/external/images/media/123
final ContentResolver resolver = context.getContentResolver();
resolver.refresh(uri, null, null);
I'm currently also trying to redesign my app to use just URIs rather than using all of the hacky solutions to convert them to filepaths (like guessing the path based on the uri authority, etc.) Previously, I used MediaScannerConnection.scanFile(...), which worked without a flaw, but as you've probably already tried, this doesn't work with URIs.
I am finding success by manually updating the MediaStore URI with my new data like this:
public void updateMediaStore(final Uri content, final String title) {
final ContentValues values = new ContentValues();
values.put(MediaStore.Audio.AudioColumns.TITLE, title);
// ... the rest of your data
cr.update(res, values, null, null);
}
Still, it seems like an oversight to not provide a way to rescan a specific file. For example, if this URI comes from somewhere else, such as on an sdcard via SAF, you will have to first search for it in the MediaStore before updating it.
My code behavior changes at the artwork for a single MP3 file. By opening the MP3 file on my PC the artwork got changed but by opening the MP3 file on the android device nothing happens. The shown artwork is still the old one.
I tried this:
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(song_path);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
FindCoverActivity.this.sendBroadcast(mediaScanIntent);
but nothing happend.
I tried another thing: By changing the artwork AND the name of the album the mediastore immediatly noticed what was going on and by opening the mp3 file on the android phone again, the artwork gets displayed correctly with the new artwork. But it is not my goal to change important mp3 tags like the album name. Could this be a bug or has anyone suggestions?
Thanks!
You could try MediaScannerConnection and its scanFile() method instead of ACTION_MEDIA_SCANNER_SCAN_FILE and see if you have better results.
Also, make sure that the file's last-modified timestamp is changed when you save your modified artwork. I'm not an expert at such MP3 file modifications, but if there is a timestamp tag in there, you might consider updating that timestamp as well. Basically, you need to make sure that the MediaStore realizes that there is a change that requires an update of its metadata.
If all else fails, you could try to work out an approach that temporarily modifies the album name in a minor fashion (e.g., appends a space), then changes it back. This is a hack, but it may be your only reliable option.
I have some code that takes a screen capture from the app and saves it to the SD card and makes it available in the Gallery. The problem is it saves it with the camera pictures when you look for it in the gallery. I would rather it save under the download folder or create an app specific folder (PicSay does something like this) where all the screen shots will be accessible to the user. Currently, I'm using the following to save to the camera gallery:
MediaStore.Images.Media.insertImage(getContentResolver(), imagePath, fileName, desc);
How can you get it to save to a different location other than Camera?
You can use the normal Java API's to save the image file to any place you want in the external storage directory.. (Hint - using the FileOutputStream)
The only problem you need to solve is to tell Andriod that you have added a new content, so update the content databse. Which the gallery can use to display the images to the user.
So create a new ContentValue and just insert it into the ContentResolver. You can get a handle to the ContentResolver using the API getContentResolver()
The ContentValue contains relevant information like name of the image, absolute path to it, date it was created, size of the file etc., not all of these mandatory, go through the Android Doc and pick off values that are irrelevant to you.
ContentValues values = new ContentValues(7);
values.put(Images.Media.TITLE, title);
values.put(Images.Media.DISPLAY_NAME, fileName);
values.put(Images.Media.DATE_TAKEN, currTime);
values.put(Images.Media.MIME_TYPE, "image/jpeg");
values.put(Images.Media.ORIENTATION, 0);
values.put(Images.Media.DATA, filePath);
values.put(Images.Media.SIZE, jpegData.length);
contentResolver.insert(STORAGE_URI, values);
And voila, the Gallery will show the image where it is placed :)
If you are able to convert your image to simple stream, you can use Android predefined methods: http://developer.android.com/guide/topics/data/data-storage.html#filesExternal
Something weird is happening in my application im not sure if it is worth uploading all the code...
Intent pictureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
pictureIntent.putExtra( MediaStore.EXTRA_OUTPUT, imageUriToSaveCameraImageTo );
startActivityForResult(Intent.createChooser(pictureIntent, strAvatarPrompt), TAKE_AVATAR_CAMERA_REQUEST);
I use this code to take an photo. The photo gets saved in the DCIM folder and also into imageUriSaveCameraImageto which points to sdcard/folder...The image is given the name image1.jpg..once run it works.
Then i delete the files from DCIM and sdcard/folder and run the application again and take a different photo...for some reason the old photo appears in the folder...it must be caching or storing a copy of it else where...does anyone know where and how i can delete it?thanks
Android indeed caches thumbnails of all the photos in another location.
See here:
http://www.droidforums.net/forum/droid-general-discussions/30998-thumbnail-cache-can-cleared.html
I can't give you an exact answer, but my feeling is that the MediaStore is a ContentProvider, so you may be able to call ContentResolver.delete(URI).
I have an app that allows the user to take and save a new picture using the Intent ACTION_IMAGE_CAPTURE. After the user accepts the newly taken picture, I create a ContentValue object to set the picture information, and then I insert the picture into the MediaStore and send a broadcast so that the user can see the photo when opening a picture viewer app such as gallery:
ContentValues newImage = new ContentValues(3);
newImage.put(Media.DISPLAY_NAME, mPicName);
newImage.put(Media.MIME_TYPE, "image/png");
newImage.put(MediaStore.Images.Media.DATA, path);
mPictureUri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, newImage);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mPictureUri));
All of this code works fine. The photo is correctly saved, and I can view the photo using gallery. The problem is that when I view the photo in gallery and select "Details" it shows the photo name as "null." And yes, I know for a fact that the variable mPicName above is not null and always has the correct value.
The odd thing is that, when running my app on my Droid running Android 2.1, when I choose to copy files to/from the phone and my computer, I open up the Droid on my Windows computer, and when I go into my app's created folder for photos and view the new photo, the name is correct. Then, when I disable copying files from the phone/computer and go back into gallery to view the file on my Droid, the name is suddenly correct and is no longer null.
Can someone tell me why the name is null after my code runs, and why the name is correct after viewing the file on my computer rather than on the phone? Is there a way to get the name non-null right when the picture is saved? I'd bet that the name would be correct if I turned my phone off and turned it back on, but I'm not sure how exactly to get force things to work immediately.
Answer is by looking at the sources of MediaStore.
One places is here:
http://devdaily.com/java/jwarehouse/android/core/java/android/provider/MediaStore.java.shtml
Basically they also add a thumbnail representation of the image and instead of
Media.DISPLAY_NAME they use Media.TITLE.
I used that code adapted a little and worked fine.