I am trying to delete images taken through the Camera api and, in principle it does delete them from my application folder but the images are still in the DCIM/camera folder.
I am using an ITOS device with Android version 9.
Here is the code I am using.
manifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
------
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.cameratest.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
#xml/file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
And this is how I capture the image:
private void checkPermissions(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, MY_CAMERA_PERMISSION_CODE);
} else {
captureImage();
}
} else {
captureImage();
}
}
private void captureImage() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(getPackageManager()) != null) {
File imageFile = null;
try {
imageFile = getImageFile();
} catch (IOException e) {
Log.d("TAG", "captureImage ERROR: " + e.getMessage());
e.printStackTrace();
}
if (imageFile != null) {
Uri imageUri = FileProvider.getUriForFile(this, Constants.FILE_AUTHORITY_PROVIDER, imageFile);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
}
}
private File getImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "IMG_" + timeStamp;
File storageDir = new File(this.getExternalFilesDir(Environment.DIRECTORY_PICTURES),"MisFotos");
if (! storageDir.exists()){
if (! storageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
File image = new File(storageDir.getPath() + File.separator + imageFileName + ".jpg");
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = image.getAbsolutePath();
Log.d("PHOTO_TAG", "getImageFile: " + currentPhotoPath);
return image;
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST && resultCode == Activity.RESULT_OK) {
setPictureToDataBase();
}
}
UPDATED
I save the image path in a database and then retrieve it to delete the file.
And here is the code I use to delete the image in my Picture Adapter
public void deletePicture(Picture picture) {
try {
myDatabase.deletePicture(picture.getUid());
String path = picture.getImage();//storageDir.getPath() + File.separator + imageFileName + ".jpg"
pictures.remove(picture);
notifyDataSetChanged();
if (pictures != null && pictures.size()>0){
listener.onDeleteClick( pictures.size());
}else {
listener.onDeleteClick( 0);
}
File target = new File(path);
if (target.exists()) {
target.delete();
}
else {
Log.d("TAG_DELETE_PICTURE", "ERROR: FILE NOT EXITS");
}
} catch (Exception e) {
Log.d("deletePicture", "ERROR: " + e.getMessage());
}
}
And when I open the device file explorer it is in "MyPhotos" and in DCIM/camera.
same image, two places
It works correctly when deleting the image from the application folder, but when looking in DCIM/camera the images are still there and occupy memory.
Am I doing something wrong, is there a way to delete the image saved in DCIM/camera?
I want to take the photo, save it only in the folder of the application, and not save it anywhere else. Is there any other way to do this?
Am I doing something wrong
You are launching a camera app via ACTION_IMAGE_CAPTURE. There are tens of thousands of Android device models. There will be dozens of different pre-installed camera apps across those device models, and users can install other camera apps from the Play Store and elsewhere.
What those camera apps do is up to their developers.
In your case, the camera app that you happen to be using is both saving the photo in its normal place and making a copy in the location identified by EXTRA_OUTPUT. Few camera apps will do this, but it is perfectly legitimate for a camera app to behave that way.
I want to take the photo, save it only in the folder of the application, and not save it anywhere else. Is there any other way to do this?
Do not use ACTION_IMAGE_CAPTURE. Instead, use the camera APIs directly or via a wrapper library (Google's CameraX, FotoApparat, CameraKit-Android, etc.).
Related
I'm trying to capture a new image using the camera and after that store it in the external storage.
I followed this tutorial Save the full-size photo and this Add the photo to a gallery but after running the app, The camera starts and captured the image successfully, But when I go to the gallery, Can't find the image who captured via camera!
//I changed this from com.example.android.fileprovider to com.test.app.fileprovider
android:authorities="com.test.app.fileprovider"
//I changed this line Uri photoURI = FileProvider.getUriForFile(this, "com.example.android.fileprovider", photoFile); to below code
Uri photoURI = FileProvider.getUriForFile(this, "com.test.app.fileprovider", photoFile);
//I added this permission
<uses-permission android:name="android.permission.CAMERA" />
//I enabled storage permission read and write
//I tested the codes on API 24
//minSdkVersion 21
Manifests
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.app">
<uses-feature android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.test.app.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
</manifest>
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
</paths>
MainActivity
public class MainActivity extends AppCompatActivity {
String currentPhotoPath;
int REQUEST_IMAGE_CAPTURE = 100;
#Override
protected void onCreate(Bundle savedInstanceState) {
SplashScreen.installSplashScreen(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dispatchTakePictureIntent();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable #org.jetbrains.annotations.Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(currentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.test.app.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
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 = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = image.getAbsolutePath();
return image;
}
}
Additional Question: What is the difference between this tutorial Save the full-size photo and this tutorial Add the photo to a gallery?
The best answer will take +50 bounty from this account if I reached 50 points, Otherwise, I'll give him the bounty from my other account after 2 days.
Your file will not be scanned by the MediaStore and hence will not be visible in Gallery apps as Gallery apps mostly get their info from MediaStore.
getExternalFilesDir() is a location private for your app and the MediaStore respects that.
How can I capture a new image using the camera and after that store it in the external storage?
Wrong problem description.
Once the camera app took the picture the camera app will save the picture to the file indicated by the file provider. There is nothing to do more then.
So before starting the camera and even before using FileProvider you should have determined a suitable location for your file and builded a nice uri for that file.
You have at least two options.
Use MediaStore to get an uri for a file in public DCIM or Pictures directory.
Use getExternalStoragePublicDirectory() with FileProvider to get an uri for a file in the same public directories.
I'm unable to store captured image in (getExternalFilesDir(Environment.DIRECTORY_PICTURES)) Android 11 device.
I have added
<uses-permissionandroid:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> in manifest and all file access also. But it's not working.
if (Build.VERSION.SDK_INT >= 30) {
if (!Environment.isExternalStorageManager()) {
try {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.addCategory("android.intent.category.DEFAULT")
intent.data = Uri.parse(String.format("package:%s", applicationContext.packageName))
startActivityForResult(intent, 2296)
} catch (e: Exception) {
val intent = Intent()
intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
startActivityForResult(intent, 2296)
}
}
}
This code is working below Android 11 device. But on Android 11 file is not creating File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) .toString() + "/" + FolderName )
Your phone's camera doesnot have permission to write in the specified location. So to fix this, you need to use file provider and give it appropriate permissions so that the camera can write the image to your file.
To do that,
create a FileProvider. In your manifest file, add:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" /> // <-------- see this
</provider>
Now create a files.xml file in your res/xml folder. In it, write some code:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path
name="camera"
path="Camera/" />
<cache-path
name="cache"
path="/" />
<files-path
name="files"
path="." />
<external-path
name="external"
path="." />
<external-files-path
name="my_images"
path="/"/>
// todo: add necessary folders according to your requirements...
// also, this is an old example. Consider googling for the latest style. I'm just copying from an old project I have, and it kinda works...
</paths>
So here we are giving the FileProvider the folders that can be shared with external apps.
2. Now create a uri where you want to store the photo. in your activity:
Context applicationContext = getApplicationContext();
File root = getCachedDir(); // consider using getExternalFilesDir(Environment.DIRECTORY_PICTURES); you need to check the file_paths.xml
File capturedPhoto = new File(root, "some_photo.jpeg");
if(!photoFile.exists()) {
photoFile.mkdirs();
}
Uri photoURI = FileProvider.getUriForFile(applicationContext, applicationContext.getPackageName() + ".fileprovider", capturedPhoto);
Please note that my project needed to save picture temporarily, so I had used cachedDir. If you save photo permanently, use getExternalFilesDir(Environment.DIRECTORY_PICTURES); and modify file_paths.xml properly.
Now that we have the correct uri, we can call the camera intent:
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);
startActivityForResult(takePictureIntent, REQUEST_CODE);
Finally, in activty result, do something:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
// todo: maybe show photo in an imageView
}
}
I hope this works.
Edit
If you are using this app in production, relying on android's default camera app is a bad idea. Our app previously used this way, and it works with, say, samsung's defaul camera. But a lot of our users used third party apps, such as PixArt, which doesnot save photo to our given location. So we had to implement a builtin camera using CameraX. So consider using CameraX or some other camera library.
First Thing is "android.permission.MANAGE_EXTERNAL_STORAGE" Permission has no relation with saving image.
after Android 11 google say you should do your business in your space.
that mean you cant get or save image or any file as you did before Android 11.
you can only save in Shared folder or in your application storage data/App packagename/.....
if you want to access other app files then you need "android.permission.MANAGE_EXTERNAL_STORAGE" but google say this must be app prior functionality like filemanager or virus scanner like app.
As far as your App concern you havent provide save code.
in Android 11 i am suggestion using Media Api
ContentResolver resolver = mContext.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, s);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + getResources().getString(R.string.app_name) + File.separator + "imgfolder");
contentValues.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
fos = resolver.openOutputStream(Objects.requireNonNull(imageUri));
try {
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
contentValues.clear();
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
resolver.update(imageUri, contentValues, null, null);
}
this is for image file
use this code for save captured image
String mPath = Environment.getExternalStorageDirectory() + "/Print";
Bitmap tmp = BitmapFactory.decodeFile(mPath);
File imageFile = new File(mPath);
FileOutputStream outStream;
try
{
outStream = new FileOutputStream(imageFile);
try
{
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
outStream.flush();
outStream.close();
} catch (IOException e)
{
e.printStackTrace();
}
} catch (Exception e)
{
e.printStackTrace();
}
I am trying to make an app that takes a photo and displays it using emulator instead of a device. I followed the steps from this android doc:
Part 1) Here is my code where it gets stucks : file = FileProvider.getUriForFile(this, "edu.android.notetakingapplication.provider", createFileDir());
This part is in the Mainxml
if (!mediaStorageDir.exists()){
if (!mediaStorageDir.mkdirs()){
Log.d("NoteTaking", "failed to create directory");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
return new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
}
Here is my app manifest file's provider section
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="edu.android.notetakingapplication.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
and provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="Android/data/edu.android.notetakingapplication/files/Pictures"/>
</paths>
Part 2) If i keep provider_paths as this
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
I am able to open camera app, take photo and view it on the same page, but, here is the catch, I am storing the path into database and trying to retrieve all the images on a page. Here is when it gives an error:
Unable to decode stream: java.io.FileNotFoundException: /external_files/Pictures/NoteTaking/IMG_20170226_230608.jpg (No such file or directory)
Try this surely it will work:
Uri mImageCaptureUri;
private void operCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
mImageCaptureUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
"tmp_avatar_" + String.valueOf(System.currentTimeMillis()) + ".jpg"));
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
intent.putExtra("return-data", true);
startActivityForResult(intent, 1);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1 && mImageCaptureUri != null && resultCode != 0) {
if (mImageCaptureUri != null) {
String path1 = mImageCaptureUri.getPath();
if (path1 != null) {
File file1 = new File(path1);
Uri capturedUri = Uri.fromFile(file1);//here you get the URI
//you can easily get the path from URI if you need
}
}
}
}
Unable to decode stream: java.io.FileNotFoundException: /external_files/Pictures/NoteTaking/IMG_20170226_230608.jpg (No such file or directory). Of course you get that error as it is a non valid path for File object or a file stream. You are saving the uri in a wrong way to the database. You better save File:getAbsoluthePath() instead of Uri:getPath().
I am trying to save an image in a folder named "appFolder" using android camera.My target sdk is 25.My device is running on android nougat. However,when i click the image using "dispatchTakePictureIntent()". The image doesn't get saved in appFolder.It gets saved in DCIM/camera folder. Why is this happening and how to save this in my custom folder?
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
Log.i("imageCaptutreError", ex.getMessage());
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.abc.def",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
private File createImageFile() throws IOException {
File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "appFolder");
if (!folder.exists()) {
folder.mkdir();
}
File tempFile = new File(folder, "temp_image.png");
/*new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "appFolder" + File.separator + "temp_image.png");*/
mCurrentPhotoPath = tempFile.getAbsolutePath();
return tempFile;
}
Provider in Mainifest
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.abc.def"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
#xml/file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="appFolder/" />
</paths>
Partly, it is because you did not call addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) on the Intent. As it stands, the other app does not have write access to the location identified by your Uri.
However, do bear in mind that third-party camera apps have bugs. Ideally, they honor EXTRA_OUTPUT. Some, however, will not:
...because they ignore EXTRA_OUTPUT in general, or
...because they do not know how to deal with the content scheme on the Uri in EXTRA_OUTPUT (even Google's own camera app had this problem until mid-2016)
FWIW, this sample app shows using ACTION_IMAGE_CAPTURE together with FileProvider.
I'm trying to take a photo with standard camera app and save it to a storage visible only to my app.
public void startCamera(View view)
{
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null)
{
File imageFile = null;
try
{
imageFile = createImageFile();
}
catch (IOException ex)
{
ex.printStackTrace();
}
if(imageFile != null)
{
Uri imageUri = FileProvider.getUriForFile(this, "vasiljevic.filip.secretnotes", imageFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(takePictureIntent, 1);
}
}
}
createImageFile method:
private File createImageFile() throws IOException
{
String timeStamp = new SimpleDateFormat("yyyyddMM_HHmmss").format(new Date());
EditText editText = (EditText) findViewById(R.id.txtNoteName);
String noteName = editText.getText().toString();
String imageFileName = noteName + "_" + timeStamp;
File storageDir = new File(getFilesDir(), "images");
if(!storageDir.exists())
{
storageDir.mkdir();
}
File image = File.createTempFile(imageFileName, ".jpg", storageDir);
return image;
}
This is part of the manifest containing FileProvider:
<provider
android:authorities="vasiljevic.filip.secretnotes"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
And file_paths.xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="images/"/>
</paths>
After I take a photo, it displays the message "camera has stopped" if I run it on the emulator or "gallery has stopped" if I run it on real device. Later if I try to access it with ACTION_VIEW intent it says "can't open image" if I try it on a real device or if I try it on emulator it just behaves as if it had opened an image but the screen is all black and no real image is displayed.
Am I doing it right? is this code supposed to save the image properly? It's mostly based on Taking photos simply official android tutorial: Taking photos simply
Add FLAG_GRANT_WRITE_URI_PERMISSION to the Intent. Right now, your third-party app has no rights to save the photo to your Uri.
If you are supporting older than Android 5.0, you might also need to use a ClipData workaround, as Intent flags do not affect EXTRA_OUTPUT on older Android versions.