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
Related
I have an app which performs processing on an image selected by the user using from the gallery, after processing the modified image is then saved back to the original image's folder with a modified filename. On specific devices (mainly Samsungs) the new KitKat permission limitations severely limit where a non system app can write to e.g. external SD card or back to typical gallery locations.
The documentation advises to write to the private package specific folder obtained via
getExternalFilesDir(null)
This is fine and the image is saved correctly but then a subsequent call to
MediaScannerConnection.scanFile
fails to update the central media database correctly as the modified image doesn't appear in the gallery, even a reboot of the device which should force a full scan of all media doesn't trigger the image to be displayed.
In other words the following code doesn't work:
File appDir = MyActivity.this.getExternalFilesDir(null);
File file = new File(appDir, "new_image.jpeg");
// Process image and write file away...
MediaScannerConnection.scanFile(this, new String[] { file.getAbsolutePath() }, null, new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
Log.i(LOG_TAG, String.format("Scanned file: %s", path));
}
});
The onScanCompleted method fires but the gallery doesn't show the new image.
Has anyone seen this behaviour, does MediaScanner not scan 'private' app folders and if so how else do I get the gallery to detect and display the new image.
If you want images to be picked up by the gallery, you should put them in the proper public location. You can get the proper location using Environment.getExternalStoragePublicDirectory().
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.
I have a problem when saving image from web.
I create new folder and save all images to this. The problem is I want this folder order by the last download image on first but When i open gallery, the folder is order by the image date created and the date created in the downloaded image is not the time I download but the first time it created. I've already search on stack over flow and see that java can't modified the date created in image to the time I download it.
Any one has the solution? (Sorry for the bad English)
Thanks you for the comment. I will explain more details.
First, I download image from web to cache directory
HttpURLConnection localHttpURLConnection = (HttpURLConnection) new java.net.URL(urldisplay).openConnection();
localHttpURLConnection.setConnectTimeout(30000);
localHttpURLConnection.setReadTimeout(30000);
localHttpURLConnection.setInstanceFollowRedirects(true);
InputStream in = localHttpURLConnection.getInputStream();
File localFile = Constans.fileCache.getCacheFile(urldisplay);
FileOutputStream fos = new FileOutputStream(localFile);
Utils.CopyStream(in, fos); // simple copy by trunks
fos.close();
Second, I copy downloaded image to external storage
File toFile = new File(Environment.getExternalStorageDirectory() + "/folder", "folder_" + System.currentTimeMillis() + ".png");
FileOutputStream fos = new FileOutputStream(toFile);
Utils.CopyStream(new FileInputStream(fromFile), fos);
fos.close();
// Scan image to display when open with gallery otherwise it couldn't see in gallery
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(toFie);
mediaScanIntent.setData(contentUri);
mContext.sendBroadcast(mediaScanIntent);
Lastly, I see that gallery don't sort my image by the time I downloaded. That is the problem i want to fix.
Not sure I understood, but let's try.
First the issue you mention is more specific to Gallery application than a java code issue.
I assume Gallery use EXIF information to order the picture by date they were taken, not oder they are downloaded/copied. Unfortunatly Gallery does not provide any option to sort picture in other oders.
Maybe you can try to use another explorer that allows you to sort the pictures in another order (maybe ESFileExplore which has more options?)
Ultimate solution: you can try to change EXIF in your pictures using a java EXIF library to modify picture taken date and this should change the order they appear in the Galery (but very ugly solution...). Some random EXIF libraries after 5 seconds of Google:
http://drewnoakes.com/code/exif/
http://www.toanthang.net/modules.php?name=News&new_topic=2&catid=7
Hope this helps
Thierry
As the title states, I'm trying to launch the camera and take a picture that I can use with the APP locally. This is for the Motorola Xoom and, by default, they do not come with SD cards. Or at least the ones my client is looking into purchasing do not have SD cards.
I've found a pretty nice tutorial on how to launch the camera and I can get it to launch and everything up to it physically saving the image and then being able to re-use that image.
A lot of the solutions or other tutorials I've found only show how to save to an SD card -- not to resident memory or local to the app. It looks like it is possible to do so but am stumped. :-/
You could perhaps load it to ContentProvider so that you could use the images later for anything:
// Add some parameters to the image that will be stored in the Image ContentProvider
int UNIQUE_BUCKET_ID = 1337;
ContentValues values = new ContentValues(7);
values.put(MediaStore.Images.Media.DISPLAY_NAME,"name of the picture");
values.put(MediaStore.Images.Media.TITLE,"Thats the title of the image");
values.put(MediaStore.Images.Media.DESCRIPTION, "Some description");
values.put(MediaStore.Images.Media.BUCKET_DISPLAY_NAME,"Album name");
values.put(MediaStore.Images.Media.BUCKET_ID,UNIQUE_BUCKET_ID);
values.put(MediaStore.Images.Media.DATE_TAKEN,System.currentTimeMillis());
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
// Inserting the image meta data inside the content provider
Uri uri = getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
// Filling the real data returned by the picture callback function into the content provider
try {
OutputStream outStream = getContentResolver().openOutputStream(uri);
outStream.write(buffer); // buffer is the data stream returned by the picture callback
outStream.close();
}catch (Exception e) {
Log.e(TAG, "Exception while writing image", e);
}
Check out Activity.getFilesDir() and Activity.getCacheDir() they provide access to storage where the app is stored. Also check out Environment.getExternalStoragePublicDirectory (), external, here, means outside the application's private directories. There are several others so look around the API's similarly named methods to find the best fit for you.
So one thing you should note is that when you call Environment.getExternalStorageDirectory(), this does not necessarily correspond to an external memory space (i.e. and SD card) and would return a local memory space on devices without SD card slots.
Note: don't be confused by the word "external" here. This directory can better be thought as media/shared storage. It is a filesystem that can hold a relatively large amount of data and that is shared across all applications (does not enforce permissions). Traditionally this is an SD card, but it may also be implemented as built-in storage in a device that is distinct from the protected internal storage and can be mounted as a filesystem on a computer.
http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()
The same applies for Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
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.