How to delete file that is created using Uri? - android

My app takes photo from camera and saves it in a file whose Uri is stored in SQL database. Initializing bitmap using Uri from database works flawlessly. However, when i try to initialize a file using Uri from database and then delete using imagefile.delete()it does not work. I have tried few methods given in other posts but none worked.
This i how i save file.
Intent for Camera:
Intent startCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (startCamera.resolveActivity(getPackageManager())!=null)
{
photoFile= null;
try{
photoFile = createImageFile();
}
catch (IOException ex)
{
Log.e("File Creation","error");
}
if (photoFile!=null)
{
photoURI = FileProvider.getUriForFile(context,"lcukerd.com.android.fileprovider",photoFile);
startCamera.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);
camerastarted=true;
startActivityForResult(startCamera,CAMERA_REQUEST);
}
}
Declared method:
private File createImageFile() throws IOException
{
String EName = "Stuff";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(EName,".jpg",storageDir);
return image;
}
Compressing image:
photoFile.delete();
FileOutputStream out = null;
try {
File image = createImageFile();
photoURI = FileProvider.getUriForFile(context, "lcukerd.com.android.fileprovider", image);
out = new FileOutputStream(image);
photo.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
saving Uri to database is simple conversion of Uri to string and then saving in TEXT column of table.
Help me delete image file .
Edit:
I tried following.
private void deleteimage(String imageloc)
{
File imagefile = new File(getRealPathFromURI(Uri.parse(imageloc)));
Log.d("file deletion",String.valueOf(imagefile.delete())+" "+imageloc);
}
public String getRealPathFromURI( Uri contentUri) {
String result;
Cursor cursor = getContentResolver().query(contentUri, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
result = contentUri.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
result = cursor.getString(idx);
cursor.close();
}
return result;
}
and..
private void deleteimage(String imageloc)
{
File imagefile = new File(Uri.parse(imageloc).getpath());
Log.d("file deletion",String.valueOf(imagefile.delete())+" "+imageloc);
}
None worked.

Since this is a Uri that you are getting from FileProvider, call delete() on a ContentResolver, passing in the Uri (plus null for the remaining parameters). That will delete the underlying file, at least according to the FileProvider documentation.
Or, store the file path, rather than the Uri, in your database, since this is your file. You can recreate the Uri later as needed using FileProvider.getUriForFile(), and you can use delete() on File to delete the file, given its path.

Related

Hide camera images from user gallery

Hi I am trying to make the images captured from my app inaccessible to the user. First I tried to save these images to internal storage which didnt work. Then I tried to hide them using "." infront of the folder name.I am not sure what the correct way to do this is. I also tried creating a file called .nomedia to bypass media scanner. I am very confused about the proper way to do this. Here's my code:
public String getImageUri(Context inContext, Bitmap inImage) {
/* *//* ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, ".title", null);
return Uri.parse(path);*//*
*/
File file = new File(Environment.getExternalStorageDirectory()
+ File.separator + "/.myFolder");
file.mkdirs();
File mFile = new File(Environment.getExternalStorageDirectory()
+ File.separator + "/.nomedia");
mFile.mkdirs();
FileOutputStream fOut = null;
try {
fOut = new FileOutputStream(file);
inImage.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
fOut.flush();
fOut.close();
uri = MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return uri;
}
If I use file.mkdirs() I get filenotfoundexception. If i remove that line I get no errors but my uri is empty.
Does the above function return the file path as well? I need the file path and the uri later on. Any help is appreciated.
I guess you don't have to add another extension or something else just save them in external cache dir of your app and gallery app won't able to read your private directory until unless you notify about them.
so store your camera images here and no gallery app can detect it.
context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
sample code
public static File createPictureFile(Context context) throws IOException {
Locale locale = Locale.getDefault();
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", locale).format(new Date());
String fileName = "JPEG_" + timeStamp + "_";
// Store in normal camera directory
File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
return File.createTempFile(fileName, ".jpg", storageDir);
}
Save your image to internal storage instead. Other applications like MediaScanner or Gallery do not have permission to read from your own application memory. Sample code:
private String saveToInternalStorage(Bitmap bitmapImage){
ContextWrapper cw = new ContextWrapper(getApplicationContext());
// path to /data/data/yourapp/app_data/imageDir
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Create imageDir
File mypath=new File(directory,"profile.jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return directory.getAbsolutePath();
}
Save the image with different extension.
For example: .jpg can be saved as .ttj.
Try this code. Set where you want to save the photo. Once you receive response on onActivityResult(), in the desired URI, you will get the photo.
public void captureImageFromCamera() {
fileUri = FileUtils.getInstance().getOutputMediaFile(null);
if(fileUri == null){
Utilities.displayToastMessage(ApplicationNekt.getContext(),
context.getString(R.string.unable_to_access_image));
return;
}
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(intent, TAKE_PICTURE);
}
Following function will give you desired path. Change it based on your project need.
public Uri getOutputMediaFile(String imageNameWithExtension) {
if (imageNameWithExtension == null)
imageNameWithExtension = "image_" + System.currentTimeMillis() + ".jpg";
String extPicDir = getExtDirPicturesPath();
if (!Utilities.isNullOrEmpty(extPicDir)) {
File mediaFile = new File(extPicDir, imageNameWithExtension);
return Uri.fromFile(mediaFile);
} else {
Log.d("tag", "getOutputMediaFile." +
"Empty external path received.");
return null;
}
}
public String getExtDirPicturesPath() {
File file = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (file != null)
return file.getPath();
else
Log.d("", "getExtDirPicturesPath failed. Storage state: "
+ Environment.getExternalStorageState());
return null;
}
To get the resultant photo.
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK)
return;
switch (requestCode) {
case TAKE_PICTURE:
//fileuri variable has the path to your image.
break;
}

Cannot read image written to file

I am trying to write an image on storage then reading it. Write operation is successful but read fails. I have tried using intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); when calling the responsible activity but was of no help.
This is how I write image:
public void savepic(Bitmap pic)
{
SQLiteDatabase db = dBcontract.getWritableDatabase();
ContentValues values = new ContentValues();
FileOutputStream out = null;
try
{
File image = createImageFile();
Uri photoURI = FileProvider.getUriForFile(context, "lcukerd.com.android.fileprovider", image);
out = new FileOutputStream(image);
pic.compress(Bitmap.CompressFormat.PNG, 100, out);
values.put(eventDBcontract.ListofItem.columnpic, photoURI.toString());
db.insert(eventDBcontract.ListofItem.tableName2, null, values);
Log.i(TAG, "Pic saved " + photoURI.toString());
} catch (Exception e)
{
e.printStackTrace();
} finally
{
try
{
if (out != null)
{
out.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
private File createImageFile() throws IOException
{
String EName = "Image";
File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(EName, ".jpg", storageDir);
return image;
}
This is how I read image:
public Bitmap getDownloadedpics(int index)
{
SQLiteDatabase db = dBcontract.getReadableDatabase();
Cursor cursor = db.query(eventDBcontract.ListofItem.tableName2, projection2, null, null, null, null, null);
cursor.moveToPosition(index);
Bitmap photo = null;
try
{
Log.d(TAG,cursor.getString(cursor.getColumnIndex(eventDBcontract.ListofItem.columnpic)));
photo = MediaStore.Images.Media.getBitmap(context.getContentResolver(),
Uri.parse(cursor.getString(cursor.getColumnIndex(eventDBcontract.ListofItem.columnpic))));
} catch (IOException e)
{
Log.e(TAG, "Can't read image");
}
Log.d(TAG, "Returned " + String.valueOf(cursor.getCount()) + " pics");
return (photo);
}
I get Exception at `photo =
MediaStore.Images.Media.getBitmap(context.getContentResolver(),
Uri.parse(cursor.getString(cursor.getColumnIndex(eventDBcontract.ListofItem.columnpic))));
Exception is :
java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{6118b35 21772:lcukerd.com.instaswipe/u0a157} (pid=21772, uid=10157) that is not exported from uid 10101
I have checked other similar question but seems like they are all for some other type of problem. Help me solve it.
Instead of photoUri.toString() put image.getAbsolutePath() in your database.
If you want to read the file get the path from the database. Construct a File object en use FileInputStream. Then let BitmapFactory read the data from the stream.

Getting path from Uri from Google Photos app

I have an app which allows to select photos with an external app. Then I take the path of the photo from the uri and use it for internal actions.
When user selects a photo with Google Photo, if the picture is locally stored then the next code works perfectly. But if the picture is in the cloud the result of cursor.getString(index) is null.
I've search for some info, but not sure about the solution
final String[] projection = { "_data" };
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow("_data");
return cursor.getString(index);
}
Thank you!
Finally and according to #CommonsWare answer and the previous post about this issue I solved getting the InputStream from the uri, coping into a new temporal file and passing the path to the function I need to use.
Here is the simplified code:
public String getImagePathFromInputStreamUri(Uri uri) {
InputStream inputStream = null;
String filePath = null;
if (uri.getAuthority() != null) {
try {
inputStream = getContentResolver().openInputStream(uri); // context needed
File photoFile = createTemporalFileFrom(inputStream);
filePath = photoFile.getPath();
} catch (FileNotFoundException e) {
// log
} catch (IOException e) {
// log
}finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return filePath;
}
private File createTemporalFileFrom(InputStream inputStream) throws IOException {
File targetFile = null;
if (inputStream != null) {
int read;
byte[] buffer = new byte[8 * 1024];
targetFile = createTemporalFile();
OutputStream outputStream = new FileOutputStream(targetFile);
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
outputStream.flush();
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return targetFile;
}
private File createTemporalFile() {
return new File(getExternalCacheDir(), "tempFile.jpg"); // context needed
}
When user selects a photo with Google Photo, if the picture is locally stored then the next code works perfectly.
Not necessarily. There is no requirement for that Uri to respond with a _data column to a query(). There is no requirement for the value it returns to be useful to you (e.g., a file on internal storage or removable storage that you cannot access).
If you need the photo loaded into an ImageView, pass the Uri to an image-loading library, such as Picasso.
If you need the bytes of the photo, use openInputStream() with ContentResolver to get an InputStream on the content identified by the Uri. Please open and read from the InputStream on a background thread.

Android contact book overwrites EXIF image data

In my app I'm trying to add an EXIF attribute to a contact photo when I add it to either a new or existing contact. This is so I can later check to see if it was My_App that changed the photo. I add the EXIF data like this:
private void addPhotoToExistingContact(long rawContactId, byte[] photoByteArray) {
if (photoByteArray != null) {
try {
photoByteArray = addExifDataToContactPhoto(photoByteArray);
} catch (IOException e) {
e.printStackTrace();
}
ContentValues values = new ContentValues();
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, photoByteArray);
context.getContentResolver().insert(
ContactsContract.Data.CONTENT_URI,
values);
}
}
private byte[] addExifDataToContactPhoto(byte[] photoByteArray) throws IOException {
// Convert to temp file
File file = new File(context.getCacheDir(), "contact_photo_exif_temp_file.jpg");
if (file.exists()) {
file.delete();
}
FileOutputStream fos = new FileOutputStream(file.getAbsoluteFile());
fos.write(photoByteArray);
fos.close();
// Add EXIF data
ExifInterface exif = new ExifInterface(file.getAbsolutePath());
exif.setAttribute(MY_EXIF_TAG, MY_EXIF_VALUE);
exif.saveAttributes();
// Convert back to byte[]
byte[] photoByteArrayWithExifData = FileUtils.readFileToByteArray(file);
// Delete temp file
file.delete();
return photoByteArrayWithExifData;
}
My check for EXIF data (done at a later time) is as follows:
private boolean shouldReplaceContactPhoto(long contactId) {
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(
ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?",
new String[] { ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE, String.valueOf(contactId) },
null);
if (cursor != null) {
if (cursor.moveToFirst()) {
long photoId = cursor.getLong(cursor.getColumnIndex(ContactsContract.Data.PHOTO_ID));
if (photoId == 0) {
cursor.close();
return true;
}
else {
// Read EXIF data to check if photo is a My_App photo
File contactPhotoTempFile = getExistingContactImageFile(contactId);
if (contactPhotoTempFile != null) {
try {
ExifInterface exif = new ExifInterface(contactPhotoTempFile.getAbsolutePath());
String swopTag = exif.getAttribute(MY_EXIF_TAG);
// Temporary image, so delete it when we're done reading EXIF data
contactPhotoTempFile.delete();
cursor.close();
// If tag is null, the photo came from a different source - return 'true'
// so it is not replaced.
return myTag != null;
} catch (IOException e) {
e.printStackTrace();
// Temporary image, so delete it when we're done reading EXIF data
contactPhotoTempFile.delete();
}
}
cursor.close();
return true;
}
}
cursor.close();
}
return true;
}
private File getExistingContactImageFile(long contactId) {
Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
Uri displayPhotoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo.DISPLAY_PHOTO);
byte[] imageBytes;
try {
AssetFileDescriptor fd = context.getContentResolver().openAssetFileDescriptor(displayPhotoUri, "r");
InputStream inputStream = fd.createInputStream();
imageBytes = IOUtils.toByteArray(inputStream);
} catch (IOException e) {
return null;
}
if (imageBytes == null) {
return null;
}
File file = new File(context.getCacheDir(), "contact_photo_temp_file.jpg");
if (file.exists()) {
file.delete();
}
try {
FileOutputStream fos = new FileOutputStream(file.getPath());
fos.write(imageBytes);
fos.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
return file;
}
I've added break points and log statements and I'm almost 100% positive that the attribute is being written, but when I read the data, the property is missing. I also noticed that the orientation attribute is changed from 1 to 0 as well, which leads me to believe that Android is overwriting the EXIF data.
Is this the case, or am I doing something incorrectly? Any help at all is extremely appreciated!

why does mediastore take the last-1th picture from the gallery

Hello!
I have a problem between the picture gallery and the mediastore in my android application when i use the camera intent in my fragment.
I checked on the android website to learn how to take a picture in a fragment and on some forums to know how to get the last picture took but the media store always give me the last-1th picture as if it was not able to find the last picture.
This is my code :
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Log.i(LOG_TAG,"ERRRRROR: "+ex.toString());
}
if (photoFile != null) {
mCurrentPhotoPath = "file:" +photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQ_CAMERA_PICTURE);
}
}
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mCurrentPhotoUri = contentUri;
mediaScanIntent.setData(contentUri);
getActivity().sendBroadcast(mediaScanIntent);
Log.d(LOG_TAG,"Photo SAVED");
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
mCurrentPhotoAbsolutePath = image.getAbsolutePath();
Log.i(LOG_TAG,"image path : "+image.getAbsolutePath());
return image;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQ_CAMERA_PICTURE)
{
if (resultCode == Activity.RESULT_OK)
{
galleryAddPic();
String filePath = getActivity().getPreferences(Context.MODE_PRIVATE).getString(TMP_PHOTO_FILE_LATEST_KEY, null);
handleCameraPicture(mCurrentPhotoUri.toString());
}
else
{
clearCurrentActionData();
}
}
}
private String getLastImagePath() {
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 = getActivity().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null,null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
if (cursor.moveToFirst()) {
String imageLocation = cursor.getString(1);
File imageFile = new File(imageLocation);
Bitmap bm = BitmapFactory.decodeFile(imageLocation);
return imageFile.getPath().toString();
}
else{
return "";
}
}
The problem occurs HERE when i try to get the last image path
private void handleCameraPicture(String pictureFileUri)
{
_currentDataObjectBuilder.addParameter(DataObject.Parameter.IMAGE, String.valueOf(getFileCount()));
//create a copy of the file into the internal storage
final File pictureFile = new File(pictureFileUri);
Log.d(LOG_TAG,"picture file uri : "+pictureFileUri.toString());
FileOutputStream fos =null;
byte[] pictureData = new byte[0];
try
{
pictureData = compressImage(getLastImagePath());
fos = getActivity().openFileOutput(String.valueOf(getFileCount()), Context.MODE_PRIVATE);
fos.write(pictureData);
Log.i(LOG_TAG,"SETTING FILE OUTPUT STREAM");
}
catch (IOException e)
{
e.printStackTrace();
}
finally {
try {
fos.close();
pictureFile.delete();
} catch (IOException e) {
e.printStackTrace();
}
}
if (_currentAction.equals(Action.PICTURE_CAPTION) || _currentAction.equals(Action.ARCHIVE))
{
showMessageView();
}
else
{
sendCurrentActionData();
}
}
The handleCameraPicture function allows me to send the "last picture" to an external website.
I don't know what i do wrong so please help me! I'm gonna lose my mind else...
Thank you!
Thomas
Wouw!
I finally found the solution, actually the uri when i created the picture was different from the one when i tried to save the picture in the gallery so my cursor dropped a null pointer exception.
I updated my GalleryAddPic function to
private void galleryAddPic(Uri uri) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mCurrentPhotoUri = uri;
mediaScanIntent.setData(uri);
getActivity().sendBroadcast(mediaScanIntent);
Log.d(LOG_TAG,"Photo SAVED");
}
And now everything works fine!

Categories

Resources