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);
Related
I am using FilePicker-Plugin-for-Xamarin-and-Windows and got this error while accessing external storage:
Could not find a part of the path "/content:/com.android.externalstorage.documents/document/6759-130B%3ANew%20Text%20Document.txt".
Note:I have both read and write permissions And also I ask user at runtime.
When using this path problem gone:
storage/6759-130B%3ANew%20Text%20Document.txt
This is very known old bug in picker as officially mentioned.
For me it looks like I have to convert content:// into file path.
More info
I remembered the thing, You need to get the absolute path from your uri. Usually, content:// path is returned from download folder or any drive path, you need to get actual path for it. You can try this.
Its an device specific code for Android, Inject it with dependency service.
I faced above issue in Native android & solved that as follows in Java, below is the converted code for the same in c#
private string GetRealPathFromURI(Uri contentURI)
{
ICursor cursor = ContentResolver.Query(contentURI, null, null, null, null);
cursor.MoveToFirst();
string documentId = cursor.GetString(0);
documentId = documentId.Split(':')[1];
cursor.Close();
cursor = ContentResolver.Query(
Android.Provider.MediaStore.Images.Media.ExternalContentUri,
null, MediaStore.Images.Media.InterfaceConsts.Id + " = ? ", new [] { documentId }, null);
cursor.MoveToFirst();
string path = cursor.GetString(cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.Data));
cursor.Close();
return path;
}
EDIT -
Try this
FileData fileData = await CrossFilePicker.Current.PickFile();
string filePath;
if (fileData != null)
{
await Task.Run(() => {
filePath = DependencyService.Get<IImageUtilities>().SaveFileFromStream(new MemoryStream(fileData.DataArray), fileData.FileName));
});
Code for Xamarin.Android
public string SaveFileFromStream((System.IO.Stream imageStream, string filename)
{
string name = filename;
string filePath = null;
try
{
byte[] imageData = ((MemoryStream)imageStream).ToArray();
IFolder folder = FileSystem.Current.GetFolderFromPathAsync(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).ToString()).Result;
IFile file = folder.CreateFileAsync(name, CreationCollisionOption.GenerateUniqueName).Result;
filePath = System.IO.Path.Combine(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).ToString(), file.Name);
System.IO.Stream outputStream = file.OpenAsync(PCLStorage.FileAccess.ReadAndWrite).Result;
outputStream.Write(imageData, 0, imageData.Length);
outputStream.Flush();
outputStream.Close();
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
return filePath;
}
Later on, the new path of the file is used everywhere needed accordingly.
This is what I actually do in my project, whichever file is selected by the user, it is copied to Pictures Dir in internal storage & returns the path.
We deal with the ImageStream to make a copy of the original document.
The idea to make a duplicate copy is that we uses the copy for uploading purpose as the user may delete the original document selected. So after pushing the document to the server, we delete the copied file as well. So as we deal with the stream we don't face any issue with Content://.
Hope this maybe helpful.
In Android Q, save pictures in app-specific directory,
path like = /data/user/0/xxx.xxx.xxx/files/phone/abc.jpg
not save in the external storage, use Device FileExplorer to view,
need to check if file exist, avoid to download again
,but in Android Q file.exist() not work
File newFile = new File(path);
newFile.exists();
always return false
this question. I need to use MediaStore or SAF to resolver it.
or other function to check it.
If I use MediaStore to check. use ContentResolver. May be like this:
public void getPhotoCursor(Uri uri) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} finally {
cursor.close();
}
}
But I can't get the Uri form app-specific directory. If I get the Uri, how to use file descriptor to check.
or use SAF to check.
File testFile = new File(getExternalFilesDir()+"phone", "abc.jpg");
FileProvider.getUriForFile(,,testFile);
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
testIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
testIntent.setDataAndType();
startActivity(testIntent);
In the ActivityResult to check it
Any help will be apperciated
is my fault, every time open APP I will delete all the .jpg from APP-specific.
so into APP I want to check avoid download again. file exist always return false.
I´m developing an Android application. The user could take a photo after a button click. This photo will be saved to internal package storage (data/data/package/...) with the following method:
private String saveToInternalSorage(Bitmap bitmapImage){
ContextWrapper cw = new ContextWrapper(getApplicationContext());
File directory = cw.getDir("TEST", Context.MODE_PRIVATE);
File pod = new File(directory, object.getTitle() + "" +
object.getName() + "" + object.getAge() + ".jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(pod);
bitmapImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
return pod.getAbsolutePath();
}
Also it´s possible to delete the picture from this directory. This works like a charm. Tested on Emulator and rooted phone. But the photos were also saved to the public folder DCIM. I´m testing with HTC ONE mini (withtout SD CARD?). Below is the code which shows the methods to take and get the photos.
public void takePhoto() {
cameraintent = new Intent("android.media.action.IMAGE_CAPTURE");
startActivityForResult(cameraintent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap bmp = (Bitmap) extras.get("data");
setPath(saveToInternalSorage(bmp));
I would like to prevent the storage of the photos in a public folder. My approach to delete the latest files in the DCIM folder failed because getExternalStorageDirectory() gives me a emulated path (like emulated/sdcard/...) on HTC One mini. And that´s definitly not the correct path. So how could i be sure that photos will be only stored to the internal package structure and not (without SD card/ with SD card) in a public folder. And when i have to delete photos in the public folder how to do i get the right path (for/on different devices)?
I found no solution to prevent the storage in a public folder "from the beginning".
Thanks in advance!
EDIT
The method below should be able to delete the photo from the DCIM/ public folder.
private void deleteLatestFromDCIM() {
File f = new File(Environment.getExternalStorageDirectory() + "");
File [] files = f.listFiles();
Arrays.sort( files, new Comparator<Object>()
{
public int compare(Object o1, Object o2) {
if (((File)o1).lastModified() > ((File)o2).lastModified()) {
return -1;
} else if (((File)o1).lastModified() < ((File)o2).lastModified()) {
return 1;
} else {
return 0;
}
...
if(files[0].exists())
files[0].delete();
The problem is that photos in DCIM/public folder get generic names. See image below:
So, how to delete images whose names i don´t "know"? Storing of photos in internal memory works fine! I don´t wont them in a public folder. And with the getExternalStorageDirectory() method i get an emulated path as described above. Is this really the path to the DCIM/public folder?
Sorry for answering my own question, hope this will be helpfully for other developers:
My strategy: Capture the photo as described in the question, save it into the internal memory (data/data/com.package...)
After that delete it from the public folder (DCIM/MEDIA/100MEDIA) with the following method (delete last taken picture from that folder...):
private void deleteLastPhotoTaken() {
String[] projection = new String[] {
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.DATA,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.MIME_TYPE };
final Cursor cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection,
null,null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
if (cursor != null) {
cursor.moveToFirst();
int column_index_data =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
String image_path = cursor.getString(column_index_data);
File file = new File(image_path);
if (file.exists()) {
file.delete();
}
}
}
As mentioned in other solutions: Don´t close the cursor! Android will do that for you.
Do I understand correctly that you want to take a photo with the camera and store it in the internal memory? Then I have two proposals:
Did you try the way described in
http://developer.android.com/training/camera/photobasics.html
filling MediaStore.EXTRA_OUTPUT with an Uri to the internal storage?
If this does not help to save the image directly in the internal storage, why don't you just delete it from the emulated path returned by getExternalStorageDirectory()? As far as I know, the file access via this path works perfectly, even though it's probably only a link.
I am trying to save an image from my application to the default gallery of my phone. The code below works perfectly if I have a SD card on the phone. The image saved appears in the phone's gallery and everything, as expected:
private Uri saveMediaEntry(File f, String title, String description, int orientation, Location loc) {
ContentValues v = new ContentValues();
v.put(Images.Media.TITLE, title);
v.put(Images.Media.DISPLAY_NAME, title);
v.put(Images.Media.DESCRIPTION, description);
v.put(Images.Media.ORIENTATION, orientation);
String nameFile = f.getName();
File parent = f.getParentFile() ;
String path = parent.toString().toLowerCase() ;
String nameParent = parent.getName().toLowerCase() ;
v.put(Images.ImageColumns.BUCKET_ID, path.hashCode());
v.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, nameParent);
v.put(Images.Media.SIZE,f.length()) ;
if( nameFile.toLowerCase().contains(".png") ){
v.put(Images.Media.MIME_TYPE, "image/png");
}else if( nameFile.toLowerCase().contains(".jpg") ||
nameFile.toLowerCase().contains(".jpeg") ){
v.put(Images.Media.MIME_TYPE, "image/jpeg");
}else{
v.put(Images.Media.MIME_TYPE, "image/jpeg");
}
String imagePath = f.getAbsolutePath();
v.put("_data", imagePath) ;
ContentResolver c = getContentResolver() ;
Uri uriOfSucessfulySavedImage = null;
uriOfSucessfulySavedImage = c.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, v);
return uriOfSucessfulySavedImage;
}
However, if I try to save the same image into the internal storage (for when the phone does not have a SD card), the image does not appear in the phone's gallery! To try to do that, I only change one line from the above code:
uriOfSucessfulySavedImage = c.insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, v);
The interesting thing about this, however, is that the variable uriOfSucessfulySavedImage is not null (it returns content://media/internal/images/media/x, where 'x' is a number). So, the image is being saved somewhere in the internal storage of the phone, but it is not getting displayed in the phone gallery's as when I use MediaStore.Images.Media.EXTERNAL_CONTENT_URI.
Does anybody have any clue what is going on? How can I save an image into the internal storage of the phone and have that image in the phone's gallery?
Update
I forgot one important information. The File "f" in the parameters of the method "saveMediaEntry" is coming from this other method for when the SD card is mounted (that is, for the first code):
public static File getCacheDirectory(String desiredNameOfTheDirectory){
File fileCacheDir = null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ){
fileCacheDir = new File( Environment.getExternalStorageDirectory(), desiredNameOfTheDirectory );
}
if(!fileCacheDir.exists()){
fileCacheDir.mkdirs();
}
return fileCacheDir;
}
and from the following code for when the SD card is not founded:
public static File getCacheDirectory(String desiredNameOfTheDirectory, Context context){
File fileCacheDir = null;
fileCacheDir = context.getCacheDir();
if(!fileCacheDir.exists()){
fileCacheDir.mkdirs();
}
return fileCacheDir;
}
Another easy way to do it. Add this after saving your file.
File imageFile = ...
MediaScannerConnection.scanFile(this, new String[] { imageFile.getPath() }, new String[] { "image/jpeg" }, null);
I haven't tried this, but I believe you need to run the Media Scanner to scan the internal storage directory so that the gallery can see your newly saved image. Check this post here.
Copy Past this Function in your Activity
private void scanner(String path) {
MediaScannerConnection.scanFile(FrameActivity.this,
new String[] { path }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("TAG", "Finished scanning " + path);
}
});
}
And then add this Line where you save your image
scanner(imageFile.getAbsolutePath());
Try this.
Write down this line once image stored in gallery.
File file = ..... // Save file
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));
} else {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));
}
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) {
}