My application current saves to a folder I've specified /Pictures/<app_name>/ but it also saves to the default folder /DCIM/Camera/. This results in the file being saved to the SD card twice but in different folders. How do I make it so it doesn't save it to both folders, only the folder I specify?
The answer was already get Here.
Just go to the original answer ---> HERE THE SOLUTION
I just add the solution to avoid a invalid answer if linked page changes.
Check the following code:
private void FillPhotoList() {
// initialize the list!
GalleryList.clear();
String[] projection = { MediaStore.Images.ImageColumns.DISPLAY_NAME };
for(int i=0;i<projection.length;i++)
Log.i("InfoLog","projection "+projection[0].toString());
// intialize the Uri and the Cursor, and the current expected size.
Cursor c = null;
Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Log.i("InfoLog","FillPhoto Uri u "+u.toString());
// Query the Uri to get the data path. Only if the Uri is valid.
if (u != null)
{
c = managedQuery(u, projection, null, null, null);
}
// If we found the cursor and found a record in it (we also have the id).
if ((c != null) && (c.moveToFirst()))
{
do
{
// Loop each and add to the list.
GalleryList.add(c.getString(0)); // adding all the images sotred in the mobile phone(Internal and SD card)
}
while (c.moveToNext());
}
Log.i(INFOLOG,"gallery size "+ GalleryList.size());
}
and this is where the method is doing all magic
/** Method will check all the photo is the gallery and delete last captured and move it to the required folder.
*/
public void movingCapturedImageFromDCIMtoMerchandising()
{
// This is ##### ridiculous. Some versions of Android save
// to the MediaStore as well. Not sure why! We don't know what
// name Android will give either, so we get to search for this
// manually and remove it.
String[] projection = { MediaStore.Images.ImageColumns.SIZE,
MediaStore.Images.ImageColumns.DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATA,
BaseColumns._ID,};
// intialize the Uri and the Cursor, and the current expected size.
for(int i=0;i<projection.length;i++)
Log.i("InfoLog","on activityresult projection "+projection[i]);
//+" "+projection[1]+" "+projection[2]+" "+projection[3] this will be needed if u remove the for loop
Cursor c = null;
Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Log.i("InfoLog","on activityresult Uri u "+u.toString());
if (CurrentFile != null)
{
// Query the Uri to get the data path. Only if the Uri is valid,
// and we had a valid size to be searching for.
if ((u != null) && (CurrentFile.length() > 0))
{
//****u is the place from data will come and projection is the specified data what we want
c = managedQuery(u, projection, null, null, null);
}
// If we found the cursor and found a record in it (we also have the size).
if ((c != null) && (c.moveToFirst()))
{
do
{
// Check each area in the gallery we built before.
boolean bFound = false;
for (String sGallery : GalleryList)
{
if (sGallery.equalsIgnoreCase(c.getString(1)))
{
bFound = true;
Log.i("InfoLog","c.getString(1) "+c.getString(1));
break;
}
}
// To here we looped the full gallery.
if (!bFound) //the file which is newly created and it has to be deleted from the gallery
{
// This is the NEW image. If the size is bigger, copy it.
// Then delete it!
File f = new File(c.getString(2));
// Ensure it's there, check size, and delete!
if ((f.exists()) && (CurrentFile.length() < c.getLong(0)) && (CurrentFile.delete()))
{
// Finally we can stop the copy.
try
{
CurrentFile.createNewFile();
FileChannel source = null;
FileChannel destination = null;
try
{
source = new FileInputStream(f).getChannel();
destination = new FileOutputStream(CurrentFile).getChannel();
destination.transferFrom(source, 0, source.size());
}
finally
{
if (source != null)
{
source.close();
}
if (destination != null)
{
destination.close();
}
}
}
catch (IOException e)
{
// Could not copy the file over.
ToastMaker.makeToast(this, "Error Occured", 0);
}
}
//****deleting the file which is in the gallery
Log.i(INFOLOG,"imagePreORNext1 "+imagePreORNext);
Handler handler = new Handler();
//handler.postDelayed(runnable,300);
Log.i(INFOLOG,"imagePreORNext2 "+imagePreORNext);
ContentResolver cr = getContentResolver();
cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, BaseColumns._ID + "=" + c.getString(3), null);
break;
}
}
while (c.moveToNext());
}
}
}
For Android Gingerbread version 2.3.3 you can change the cameras default save location. Launch the camera app, click on settings (cog), click on wrench tab, scroll down then select Memory card. Change to Memory card (versus Internal memory).
Related
In my app the user can select files and open them in the appropriate app (using an ACTION_VIEW intent).
I need to do some work on the data before giving it to the other app. So I'm using a streaming solution : I implemented a ContentProvider that implements openTypedAssetFile and writeDataToPipe (this method fills the output ParcelFileDescriptor created by openPipeHelper).
This works : I can open .pdf files, .txt files etc. The streaming seems correct.
I can open images usings 3-party apps.
However when I open an image using the Gallery, it doesn't work (Gallery shows a black screen), and I get the following exception :
fail to open myfile.jpg
UriImage(21890): java.io.FileNotFoundException: Not a whole file
I had a look at the Gallery source (here) and I could see that the exception is thrown here :
try {
if (MIME_TYPE_JPEG.equalsIgnoreCase(mContentType)) {
InputStream is = mApplication.getContentResolver()
.openInputStream(mUri);
mRotation = Exif.getOrientation(is);
Utils.closeSilently(is);
}
**mFileDescriptor = mApplication.getContentResolver()
.openFileDescriptor(mUri, "r");**
if (jc.isCancelled()) return STATE_INIT;
return STATE_DOWNLOADED;
} catch (FileNotFoundException e) {
Log.w(TAG, "fail to open: " + mUri, e);
return STATE_ERROR;
}
However, once in the Gallery app, if I select "Set as wallpaper", then I can see my image, it is then well streamed. So the problem appears when Gallery opens.
After a deeper look (in the ContentResolver code etc.) I couldn't understand why it behaves this way. It seems that Gallery does not support streaming files. Is that right ?
Do you have any idea ?
Thanks a lot.
String scheme = mUri.getScheme();
ContentResolver contentResolver = getContentResolver();
// If we are sent file://something or
// content://org.openintents.filemanager/mimetype/something...
if (scheme.equals("file")
|| (scheme.equals("content") && fileUri
.getEncodedAuthority().equals(
"org.openintents.filemanager"))) {
// Get the path
filePath = fileUri.getPath();
// Trim the path if necessary
// openintents filemanager returns
// content://org.openintents.filemanager/mimetype//mnt/sdcard/xxxx.jpg
if (filePath.startsWith("/mimetype/")) {
String trimmedFilePath = filePath
.substring("/mimetype/".length());
filePath = trimmedFilePath.substring(trimmedFilePath
.indexOf("/"));
}
} else if (scheme.equals("content")) {
// If we are given another content:// URI, look it up in the
// media provider
filePath = getFilePathFromContentUri(fileUri,
contentResolver);
} else {
Log.e("filePath--------->>>>>", filePath + "");
}
and
private String getFilePathFromContentUri(Uri selectedVideoUri,
ContentResolver contentResolver) {
String filePathString;
String[] filePathColumn = { MediaColumns.DATA };
Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn,
null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePathString = cursor.getString(columnIndex);
cursor.close();
return filePathString;
}
and now use this filepath ..
try {
if (MIME_TYPE_JPEG.equalsIgnoreCase(mContentType)) {
InputStream is = mApplication.getContentResolver()
.openInputStream(filePath); // ** change is here
mRotation = Exif.getOrientation(is);
Utils.closeSilently(is);
}
** mFileDescriptor = mApplication.getContentResolver()
.openFileDescriptor(filePath, "r"); **
if (jc.isCancelled()) return STATE_INIT;
return STATE_DOWNLOADED;
} catch (FileNotFoundException e) {
Log.w(TAG, "fail to open: " + mUri, e);
return STATE_ERROR;
}
this is work for me
I have an idea for an app, and to do it i need to be in the folder where the stock camera stores it's pictures. But since most manufactureres name the folder inside DCIM diferently, is there a way to find the specific folder that the camera saves pictures into. Also I can't list and open the first result because, for example i have 5 folders in there. Thanks!
One of the solution is to insert photo to MediaStore using ContentResolver (it will create empty JPG file), retrieve its path and delete it from MediaStore (file will be deleted as well).
public static File getPhotoDirPath(ContentResolver cr)
{
try
{
Uri takenPhotoUri=cr.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues( 1 ) );
if ( takenPhotoUri == null )
return null;
String photoFilePath=null;
Cursor cursor = cr.query( takenPhotoUri, new String[] { MediaColumns.DATA }, null, null, null );
if ( cursor != null )
{
int dataIdx = cursor.getColumnIndex( MediaColumns.DATA );
if (dataIdx>=0&&cursor.moveToFirst())
photoFilePath = cursor.getString( dataIdx );
cursor.close();
}
cr.delete( takenPhotoUri, null, null );
if (photoFilePath!=null)
return new File(photoFilePath).getParentFile();
return null;
}
catch (Exception ex)
{//insert or delete failed
return null;
}
}
Note that in some cases (the same as when camera apps are not able to save photos) photos may not be inserted successfully eg. SD card is removed (if device cannot emulate external storage), external storage is mounted read-only or some directory in path is write protected etc.
So i ended up doing it with .exists()
String abcd = "is it working ?";
File pathimg = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File testimg = new File (pathimg, "100MEDIA/");
if (testimg.exists()){abcd = testimg.toString();}
else {
File testimg2 = new File (pathimg, "100ANDRO/");
if (testimg2.exists()){abcd = testimg2.toString();}
else {
File testimg3 = new File (pathimg, "Camera/");
if (testimg3.exists()){abcd = testimg3.toString();}
else {
File testimg4 = new File (pathimg, "100LGDSC/");
if (testimg4.exists()){abcd = testimg4.toString();}
else {
abcd = "It's not working";
}
}
}
}
On my G2 with the folder "100LGDSC" it's working.
you may take Environment.DIRECTORY_PICTURES as the valid directory.
The following will refer to that directory (but it is not guaranteed in all devices):
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
In my app the user can choose a notification using RingtonePreference. From the latter I'm able to retrieve the Uri of the selected notification, and using the following code to extract the real file name:
private String getUriRealPath(Uri contentUri) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "Getting real path of uri: " + contentUri.toString());
}
String path = null;
final String[] projection = new String [] { MediaStore.Audio.Media.DATA };
final Cursor cursor;
try {
cursor = mContext.getContentResolver().query(contentUri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
int idx = cursor.getColumnIndex(projection[0]);
if (idx != -1) {
path = cursor.getString(idx);
if (BuildConfig.DEBUG) {
Log.d(TAG, "Real path is: " + path);
}
}
else {
if (BuildConfig.DEBUG) {
Log.d(TAG, "Path can't be resolved.");
}
}
}
} catch (Exception e) {
Log.e(TAG, "getUriRealPath - " + e);
}
return path;
}
However, once the user chooses a notification that was downloaded via a 3-rd party, the above code can't find the real path.
The reason for the extraction is I need the path for playing the notification in a SoundPool object.
I may be over seeing this, but getContentResolver() returns a ContentResolver instance for my application. Should I be using a "global" ContentResolver ?
However, once the user chooses a notification that was downloaded via a 3-rd party, the above code can't find the real path.
You may not have access to the actual file, anyway. First, it may not exist as a file, but only as a stream. Second, it may not be in storage for which you have read access. You can only reliably access this media via the Uri supplied to you.
The reason for the extraction is I need the path for playing the notification in a SoundPool object.
Then you will have to stop using SoundPool and switch to MediaPlayer, AudioTrack, or something else.
Should I be using a "global" ContentResolver ?
There is no "global" ContentResolver.
When I save an image to new location and then use MediaScanner to refresh the gallery then everything is fine - thumbnails and images are refreshed well.
But when I save an image to EXISTING location and then use MediaScanner - then only 'new' thumbnail isnt refreshed. (even though file is overwritten).
How to solve it?
Here is my code :
File file = new File(SDCARD_PATH, filename);
try {
FileOutputStream out = new FileOutputStream(file);
bmp.compress(format, BEST_IMAGE_QUALITY, out);
}catch (FileNotFoundException e) {
}
//refreshing single file using media scanner, no need to paste
This is a common and well know problem in Android. If you edit a media file, the thumbnail does not seem to update.
I have a fix for this, however, its still a fix and not a clean solution.
My fix is simple, and it basically deletes the stale thumbnail and then uses media scanner to update the thumbnails.
Here're the steps to be followed:
Step 1. Edit the file as you like. Say filename, "myVideoToBeEdited".
Step 2. Once you are done editing, delete its existing thumbnail.
First, get the video id using code like this:
final String[] columns = {
BaseColumns._ID, MediaColumns.DATA
};
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, columns, null, null, null);
boolean cancel = false;
if(null != cursor){
while(cursor.moveToNext() && !cancel){
String fileName = cursor.getString(cursor.getColumnIndex(MediaColumns.DATA));
int imageId = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID));
if(fileName.equals(myVideoToBeEdited)){
removeVideoThumbnail(getContentResolver(), imageId); // step 3
cancel = true;
}
}
}
There are other ways to get the id, and more optimised ones as well.
Step 3. Delete the thumbnail.
public void removeVideoThumbnail(ContentResolver contentResolver, long photoId) {
Cursor thumbnails = contentResolver.query(android.provider.MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI, null, android.provider.MediaStore.Video.Thumbnails.VIDEO_ID + "=?", new String[]{String.valueOf(photoId)}, null);
for (thumbnails.moveToFirst(); !thumbnails.isAfterLast(); thumbnails.moveToNext()) {
long thumbnailId = thumbnails.getLong(thumbnails.getColumnIndex(android.provider.MediaStore.Video.Thumbnails._ID));
String path = thumbnails.getString(thumbnails.getColumnIndex(android.provider.MediaStore.Video.Thumbnails.DATA));
File file = new File(path);
if (file.delete()) {
contentResolver.delete(android.provider.MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI, android.provider.MediaStore.Video.Thumbnails._ID + "=?", new String[]{String.valueOf(thumbnailId)});
}
}
}
Or, here's the method to delete image thumbnail
public void removeImageThumbnail(ContentResolver contentResolver, long photoId) {
Cursor thumbnails = contentResolver.query(android.provider.MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, null, android.provider.MediaStore.Images.Thumbnails.IMAGE_ID + "=?", new String[]{String.valueOf(photoId)}, null);
for (thumbnails.moveToFirst(); !thumbnails.isAfterLast(); thumbnails.moveToNext()) {
long thumbnailId = thumbnails.getLong(thumbnails.getColumnIndex(android.provider.MediaStore.Images.Thumbnails._ID));
String path = thumbnails.getString(thumbnails.getColumnIndex(android.provider.MediaStore.Images.Thumbnails.DATA));
File file = new File(path);
if (file.delete()) {
contentResolver.delete(android.provider.MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, android.provider.MediaStore.Images.Thumbnails._ID + "=?", new String[]{String.valueOf(thumbnailId)});
}
}
}
Step 4. And finally use media scanner connection to scan the file so that it updates the thumbnails.
MediaScannerConnection.scanFile(context,
new String[] { myVideoToBeEdited }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
// pass the mime type, else passing a null will enable file extension to dictate the mime type
// you are good to go
}
});
Have you tried to remove the "old" picture prior to saving the new one to file system? Like so:
File file = new File(SDCARD_PATH, filename);
try {
// Delete the "old" file.
if (file.exists()) {
file.delete();
}
FileOutputStream out = new FileOutputStream(file);
bmp.compress(format, BEST_IMAGE_QUALITY, out);
}catch (FileNotFoundException e) {
}catch (SecurityException e) {
}
I am building my own contact picker, because I needed multi-select support. Everything is working fine, except for one small problem with the contact images.
For contacts who don't have images I am showing a "no image" image. This works fine for contacts in the phone's address book. I am having a problem however when it comes to images from my google contacts.
Most of my google contacts do not have photos. However, when i query the Contacts database for photos, it still returns a URI for them of the form of content://com.android.contacts/contacts/657/photo (which is the same format as for contacts who do have a photo.
Then when I try to assign the photo to a QuickContactBadge, using bdg.setImageURI(pic); it sets it to essentially a blank picture, and logs a silent INFO message stating:
INFO/System.out(3968): resolveUri failed on bad bitmap uri:
content://com.android.contacts/contacts/657/photo
I need to know how I can either
a) validate the URI or
b) catch the INFO message above
c) query the imageview/badge to see if it found a valid image
so that i can assign these contacts my "no image" image.
How can I go about doing this?
EDIT 20110812.0044
I have tried adding this to my code as per Laurence's suggestion (which he's since removed):
// rv is my URI variable
if(rv != null) {
Drawable d = Drawable.createFromPath(rv.toString());
if (d == null) rv = null;
}
While the google contacts now get my "no image" image, ... so do all the other contacts, including ones that do in fact have images.
Okay, I figured out how to do this after poking through the ImageView source code. It is actually using the QuickContactBadge's own methods, but if necessary, one could always extract the relevant code from the Badge/ImageView control here.
After setting the QCB's image, I check to see if its drawable is null, instead of trying my own (as per Laurence's suggestion). This works better, because there is actually a whole slew of checking code the ImageView widget uses.
Here is my final code:
bdg.setImageURI(pic);
if(bdg.getDrawable() == null) bdg.setImageResource(R.drawable.contactg);
This works perfectly as I was hoping and expecting.
Just to answer the question on how to check the (data) value in the MediaStore:
ContentResolver cr = getContentResolver();
String[] projection = {MediaStore.MediaColumns.DATA}
Cursor cur = cr.query(Uri.parse(contentUri), projection, null, null, null);
if(cur != null) {
cur.moveToFirst();
String filePath = cur.getString(0);
if (filePath == null || filePath.isEmpty()) {
// data not set
} else if((new File(filePath)).exists()){
// do something if it exists
} else {
// File was not found
// this is binary data
}
} else {
// content Uri was invalid or some other error occurred
}
Inspiration taken from: https://stackoverflow.com/a/7649784/621690 and others.
There is also the column SIZE that might be checked: http://developer.android.com/reference/android/provider/MediaStore.MediaColumns.html#SIZE
It sounds like it should contain 0 if there is no data value. But I wouldn't know what it contains if data is a file path.
It could be that the images are not downloaded. I faced a similar problem with whatsapp images.
One way to go about this could be like below:
InputStream is = null;
try {
is = context.getContentResolver().openInputStream(myuri);
}catch (Exception e){
Log.d("TAG", "Exception " + e);
}
if(is==null)
//Assign to "no image"
Based on the code (http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/android/widget/ImageView.java) my solution for checking Uri:
public static Uri checkUriExists (Context mContext,Uri mUri) {
Drawable d = null;
if (mUri != null) {
if ("content".equals(mUri.getScheme())) {
try {
d = Drawable.createFromStream(
mContext.getContentResolver().openInputStream(mUri),
null);
} catch (Exception e) {
Log.w("checkUriExists", "Unable to open content: " + mUri, e);
mUri = null;
}
} else {
d = Drawable.createFromPath(mUri.toString());
}
if (d == null) {
// Invalid uri
mUri = null;
}
}
return mUri;
}
I am using this code for Uri that has file:// authority
Uri resimUri = Uri.parse(path_str);
File imgFile = new File(resimUri.getPath());
if (imgFile.exists()) {
// file exists
}else {
// file is not there
}