I am trying to save the image in the folder which is captured using camera.The image does get saved in the particular folder but there is another copy of the same image in the "Camera" folder.This happens only in Android Version 2.2.1.
When I tried the same case in android version 4.1.2, there is only one copy saved in the particular folder and not in "Camera" folder.
This is the code I am using to start the camera and save the image in "MyFolder".
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File storagePath = new
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
+ "/MyFolder/");
if(!storagePath.isDirectory()){
storagePath.mkdirs();
}
File myImage = new File(storagePath,Long.toString(System.currentTimeMillis()) + ".jpg");
Uri fromURI=Uri.fromFile(myImage);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fromURI);
startActivityForResult(intent,CAMERA_REQUEST_CODE);
After saving the image, I will create a custom Gallery view where I will try to get all the images so that the user can select any one of the image.when I try getting images, the new image which is taken from the camera is not retrieved in the cursor.
This is the code I am using to get all the images...
final String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID };
final String orderBy = MediaStore.Images.Media._ID+" DESC";
Cursor imagecursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns,null,null, orderBy);
In Android V 2.2.1, since the copy of the image is saved in "Camera" folder, I get the new image, but in Android V 4.1.2, I don't get the image in the cursor.
Does anyone know how to get the image from a particular folder??
TIA,
VijayRaj
Related
I've been developing an android music player and I would like to load the cover image which each mp3 tag has. I previously used the following code to extract the image but, when the list view is starts scrolling it gives a lot of errors and the app crashes at random times. The code is as following.
MediaMetadataRetriever retrieve = new MediaMetadataRetriever();
retrieve.setDataSource(songsList.get(songIndex).get("songPath"));
byte [] data = mmr.getEmbeddedPicture();
This throws an error saying the following message and at random points the application crashes.
getEmbeddedPicture: Call to getEmbeddedPicture failed
So I used the glide library to load the images using the following code.
Glide.with(parent.getContext()).load(currSong.getPath())
.placeholder(R.drawable.default_img).into(holder.albumImage);
The thing is I pass the song path to the load function but doesn't load any image to it! I logged the path and it shows the correct path to the mp3 file.
How can I load the images using the Glide library! If there is a tutorial on this, please be kind enough to let me know.
I did the following to retrieve and set the image in the list.
To retrieve album art for the song:-
This is the query
final Cursor mCursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.ALBUM_ID}, null, null,
"LOWER(" + MediaStore.Audio.Media.TITLE + ") ASC");
To capture URI
long album_id=mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri albumArtUri = ContentUris.withAppendedId(sArtworkUri, album_id);
And then to set in list via Adapter
Uri uri=Uri.parse(data.get(position).getAlbum_art());
try {
bitmap = MediaStore.Images.Media.getBitmap(ctx.getContentResolver(), uri);
holder.image.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
I'm trying to get real path from Uri(Of selected image from gallery) but This function returns always null value :
//Convert the image URI to the direct file system path of the image file
public String getRealPathFromURI(Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = getActivity().getContentResolver().query(contentUri, proj, null, null, null);
cursor.moveToFirst();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
That's because the image you're selecting is not physically available on the device.
Images from gallery or other choose can come from different sources that does not provide a physical file, like a cloud storage for example.
Check this code here on how to open the Uri as a InputStream that can be used to create a copy of the file (or just read directly).
Android: Getting a file URI from a content URI?
edit:
I'm doing some extra research on it, apparently it also varies on how you request this Uri.
if you request it like this (which is the current preferred method as per Android guides):
i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(i, REQUEST_STORAGE);
and it opens the KitKat style unified selector, if you choose an image from there, it will always return null. If you open the left-drawer menu, select the gallery (or a file browser), and pick an image from there, then, if it is a local file image, you will have the correct path.
on the other hand, if you request it like this (which is the old method):
i = new Intent(Intent.ACTION_PICK);
i.setType("image/*");
startActivityForResult(i, REQUEST_STORAGE);
it will directly open the Gallery, and again, if it is a local file image, you will have the correct path.
So yeah, I still don't believe there's a way to force local only, but at least you have more information to make an informed decision on your coding.
my application is making photos and viewing them in ImageView.
Everything works fine, but images I make in my application are saved in folder DCIM/CAMERA/ with names like "1369434756474" or "1369920366597".
I would like to save images like original camera in default folder DCIM/100MSDCF with default names like "DSC00013" or DSC00233".
I am using Sony Xperia X10Mini but I would like my app worked fine on all devices.
Below is my code of requesting image capture:
if (isImageCatchingIntentAvailable()){
String fileName = "photo.jpg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
mImageCaptureUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
startActivityForResult(intent, MAKE_PHOTO);
}
I have an application in which I can use the device's camera to take a picture. What I would like to do is to start the ACTION_IMAGE_CAPTURE intent without assigning an EXTRA_OUTPUT, and then move the file that is created in the default location to my own custom location using file.renameTo. My code is something like this:
/* Start camera activity without EXTRA_OUTPUT */
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, _REQUESTCODE_ATTACH_CAMERA);
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch(requestCode) {
case _REQUESTCODE_ATTACH_CAMERA:
/* Get path to most recently added image */
final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
final String imageOrderBy = MediaStore.Images.Media._ID + " DESC";
Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);
String fullPath = "";
if(imageCursor.moveToFirst()){
fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
imageCursor.close();
}
File f = Environment.getExternalStorageDirectory();
f = new File(f.getAbsolutePath() + File.separator + "DCIM" + File.separator + MY_APP_NAME;
if(!f.exists()) {
f.mkdirs();
}
/* Create new file based on name of most recently created image */
File oldFile = new File(fullPath);
String newPath = f.getAbsolutePath() + File.separator + oldFile.getName() ;
/* Move file with renameTo */
oldFile.renameTo(new File(newPath));
break;
...
}
}
}
All of this works quite well, however there is one strange thing that is occurring. In my app, I have another button that allows selecting an existing image from the phone's gallery. That code looks like this:
Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
galleryIntent.setType("image/*");
activity.startActivityForResult(galleryIntent, _REQUESTCODE_ATTACH_GALLERY);
This also works, but if I take a picture with the camera using the code posted above, and then try to select another image from the gallery, there will be blank "broken link" type items in the gallery that contain no content and are unselectable. These seem to correspond with photos taken and moved using renameTo; if I put in code in onActivityResult to post the filename to LogCat, the name that gets logged is the same as the name of the previously moved file that it corresponds to. Trying to create a File object or in any way access that filename, results in null objects and force closes.
The strange part is that there is no evidence of these "broken link" files in Eclipse DDMS, nor in the phone itself if I use Root Browser, and they disappear if I remount the SD Card.
The whole reason I am moving the images after capturing them with the camera is to avoid filling up the phone's gallery storage with unnecessary images. While these empty "broken link" type files don't appear to be taking up any storage space, they would still be very annoying to an end-user trying to browse through their gallery. Does anyone have any ideas on what is happening here or how to solve this problem?
EDIT:
Here is a photo showing what the gallery looks like with a "broken link" type image displayed. One of these will appear for every photo that is taken using my app, and they will all disappear if I remount the SD Card.
Thanks in part to this SO thread, I have discovered a solution. It actually makes sense that it would behave this way since there is a table kept for media content and so removing something without telling the table would definitely create a "broken link" type scenario.
The ultimate solution is to use contentResolver.delete to remove the reference to the file within the content resolver, but there are two different ways that I have found that will work.
/* Moving with renameTo */
//Use the same exact code as I had before (shortened for brevity) to move the file
oldFile.renameTo(newFile);
//Get URI from contentResolver using file Id from cursor
Uri oldUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media._ID)));
//Delete old file
getContentResolver().delete(oldUri, null, null);
Getting the URI in this way is necessary because it requires a reference to the image in the contentResolver rather than the path to its location in storage. This way might feel dirty to some since you are moving a file and then calling a delete function on that file in order to sort of trick the content resolver into removing the link to the file. If you would rather, you can do it without using renameTo so that the call to delete(...) actually does delete the image.
/* Moving with streams */
//Get streams
InputStream in = new FileInputStream(oldFile);
OutputStream out = new FileOutputStream(newFile);
byte[] buffer = new byte[1024];
int bytesRead = 0;
//Read old file into new file
while((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
//Get URI from contentResolver using file Id from cursor
Uri oldUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media._ID)));
//Delete old file
getContentResolver().delete(oldUri, null, null);
The call to contentResolver.delete is the same either way, I just wanted to point out that it will still work if the image has already been removed.
During this I discovered a solution to a problem that I didn't even realize that I had that I will post here as well in case anyone with this same problem comes across this in the future. In order to keep the image as selectable in the device gallery from the new location, you need to let the media scanner know that a change has been made. There are two ways that I found to do this:
/* This is the only way that I know of to handle multiple new files at once. I
really would use this sparingly, however, since it will rescan the entire
SD Card. Not only could this take a long time if the user has a lot of files
on their card, it will also show a notification so it is not exactly a
transparent operation. */
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
/* You *could* do multiple files with this by passing in the path for each one
in the array of Strings, however an instance of this will get called for each
one rather than it doing them all at once. Likewise, your onScanCompleted
(if you choose to include one) will get called once for each file in the list.
So really, while this is much better for a small number of files, if you plan
on scanning a very large amount then the full rescan above would probably be
a better option. */
MediaScannerConnection.scanFile(context, new String[]{ newFilePathAsString }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
//This executes when scanning is completed
}
}
);
My Android app opens images and makes manipulations on them. My Activity requests an image to be opened as follows:
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Complete action using"),
PICK_FROM_FILE);
On doing this, it launches a dialog with three to four options, like the ES File Explorer: Files, Gallery, etc.
I wish to read this as a Bitmap using BitmapFactory.decodeFile(path).
When I choose the file from ES File Explorer, the path is computed like this:
String path = imageData.getData().getPath();
However, this does not work for choosing an image from the Gallery or Files, where the value of path is /external/images/media/38 for example.
So I put a check, to convert such a path that begins with external using:
if (path.startsWith("/external")) {
path = getFilePathFromUri(imageData.getData());
}
private String getFilePathFromUri(Uri uri) {
Cursor cursor = managedQuery(uri,
new String[] { MediaStore.Images.Media.DATA },
null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
This converts the above path to /mnt/sdcard/dcim/Camera/2011-11-13_15-33-24_304.jpg and now this works for BitmapFactory.decodeFile(path).
I understand that hardcoding such a check (/external) is not a good idea, is there a better, perhaps generic way to resolve the format of the URI returned in the Intent?
I understand that hardcoding such a check (/external) is not a good idea, is there a better, perhaps generic way to resolve the format of the URI returned in the intent?
imageData.getData() returns a Uri. If its path starts with file:// (this is what most file managers will return), then the uri represents a file. Another option is uri represents a content item (this is what Gallery will return), in this case its path starts with content:// and you should call ContentProvider for an actual image file path (as you do in your sample). So I think you could go with something like this:
Uri uri = imageData.getData();
String scheme = uri.getScheme();
if ("file".equals(scheme)) {
// process as a uri that points to a file
} else if ("content".equals(scheme)) {
// process as a uri that points to a content item
}
You can ask MediaStore to create your Bitmap from the Uri:
Bitmap bmp = MediaStore.Images.Media.getBitmap( getContext().getContentResolver(), uri );