FileProvider is very confusing - android

I have an app in which I capture image and set it to the ImageView and then upload it to the server. But whenever I capture images the image is not getting displayed and when I try to upload the image I get FileNotFoundException as the path does not contain the image.
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.imageuploader.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="Image Uploader" path="Android/data/com.example.android.imageuploader/files/Pictures" />
</paths>
When i create image file I use this,
private File createImageFile() {
String timeStamp = new SimpleDateFormat(
getString(R.string.time_stamp_format), Locale.getDefault())
.format(new Date());
String fileName = getString(R.string.file_name_format, timeStamp);
File storageDirectory =
new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), getString(R.string.app_name));
if (!(storageDirectory.exists() || storageDirectory.mkdirs())) {
Helper.showToastMessage(mContext, getString(R.string.warn_storage_dir));
}
return new File(storageDirectory.getPath() + File.separator + fileName);
}
Actually I am saving the image in the internal storage directory 'Pictures' and in it I am creating folder after the app's name in which all the images are being saved. But while setting the image to the ImageView I am getting different file path say,
Image Uploader/Pictures/Image Uploader/20180406_101234.jpg
which is why the image is not being displayed as well as uploaded.
Where I am going wrong I am not able to figure that out. Please help.

This is how am doing, this works perfectly.
AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.yourpackagename.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_path"/>
</provider>
provider_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="/storage/emulated/0" path="."/>
</paths>
createImageFile() make sure you have read and write external storage permission
private File createImageFile() throws IOException
{
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "MYAPPNAME-" + timeStamp + ".png";
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(),
"YourAppFolder");
File storageDir = new File(mediaStorageDir + "/Profile_Images");
if (!storageDir.exists())
{
storageDir.mkdirs();
}
File image = new File(storageDir, imageFileName);
return image;
}
click listener on button to take camera image
===Global Variables===
Uri mUri;
private static final int CAMERA_IMAGE_RESULT = 202;
private static final String CAPTURE_IMAGE_FILE_PROVIDER = "com.yourpackagename.fileprovider";
===Global Variables===
takeImageBTN.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
File file = null;
try
{
file = createImageFile();
mUri = FileProvider.getUriForFile(this,
CAPTURE_IMAGE_FILE_PROVIDER, file);
Log.d("uri", mUri.toString());
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mUri);
startActivityForResult(cameraIntent, CAMERA_IMAGE_RESULT);
}
catch (IOException e)
{
e.printStackTrace();
}
}
});
Then lastly onActivityResult()
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode)
{
case CAMERA_IMAGE_RESULT:
{
if (resultCode == RESULT_OK)
{
if (mUri != null)
{
Log.d("uriPath", mUri.getPath().replace("//", "/"));
String profileImageFilepath = mUri.getPath().replace("//", "/");
Log.d("path", profileImageFilepath);
profileIV.setImageURI(mUri);
/*Your Asynctask to upload Image using profileImageFilepath*/
new PostDataAsyncTask().execute(profileImageFilepath);
}
}
break;
}
}
}
take run time permission for
<!-- == External Storage == -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Related

Images deleted from my application folder are still in the camera gallery

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.).

Issues getting captured imaged from Camera to be viewed as an ImageView object. - Android

I want to create an application that when the user clicks a button, it takes you to the phone's default camera app, captures a pictures and brings it back to the activity's imageview object to be displayed in the activity. Below is the code I have.
PROBLEM: The issue is that the image is not displaying in the imageview. It comes back to the activity after taking a pictures, but it does not display it.
AndroidManifest.xml has the below added:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera" android:required="true" />
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.application.hidden.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
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="/" />
</paths>
MainActivity.java
private File createImageFile() throws IOException {
String timeStamp =
new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.getDefault()).format(new Date());
String imageFileName = "IMG_" + timeStamp + "_";
File storageDir = this.getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName,
".jpg",
storageDir
);
imagePath = image.getAbsolutePath();
return image;
}
#OnClick({R.id.takePicture, R.id.pic})
void onTakePic() {
changeImageLayout.setVisibility(GONE);
System.out.println("Setting up for capture, clicked on camera");
Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(pictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
//Create a file to store the image
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
}
if(photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this.getContext(),"com.application.hidden.provider", photoFile);
pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(pictureIntent, RESULT_LOAD_CAMERA_IMG);
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
case RESULT_LOAD_CAMERA_IMG:
switch (resultCode) {
case Activity.RESULT_OK:
Glide.with(this).load(imagePath).into(listingImage);
break;
case Activity.RESULT_CANCELED:
isNewImageAdded = false;
break;
default:
break;
}
break;
default:
break;
}
}
Would appreciate any suggestions or help!
Thank you.
You need to convert your file path to file object, use new File(imagepath), instead of just imagepath inside glide.
I think you are trying to capture an image from the camera and store in local memory and then load from memory.
If you just want to display captured image in imageview then follow the below way.
For open camera:
intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 7);
Then in onActivityResult result:
if (requestCode == 7 && resultCode == RESULT_OK) {
Bitmap bitmap = (Bitmap) data.getExtras().get("data");
imageView.setImageBitmap(bitmap);
}

(Android) Camera Capture not saving, can't load bitmap of image

I'm trying to write code that launches the camera app, saves the image, and then displays a bitmap of the captured image.
This is the relevant code, which was adapted from https://guides.codepath.com/android/Accessing-the-Camera-and-Stored-Media:
public static final int PICTURE_REQUEST_CODE = 1034;
public static final String FILE_BEGIN = "note";
private int note_id = 4;
public static final String FILE_END = ".jpg";
private static final String APP_TAG = "School_App";
private void takePicture() {
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, getPhotoFileUri(FILE_BEGIN + note_id + FILE_END));
if (i.resolveActivity(getPackageManager()) != null){
startActivityForResult(i, PICTURE_REQUEST_CODE);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PICTURE_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Uri takenPhotoUri = getPhotoFileUri(FILE_BEGIN + note_id + FILE_END);
Log.d("NotesDetail", takenPhotoUri.toString());
// by this point we have the camera photo on disk
Bitmap takenImage = BitmapFactory.decodeFile(takenPhotoUri.getPath());
// RESIZE BITMAP, see section below
// Load the taken image into a preview
ImageView ivPreview = (ImageView) findViewById(R.id.iv_notes_picture);
ivPreview.setImageBitmap(takenImage);
} else { // Result was a failure
Toast.makeText(this, "Picture wasn't taken!", Toast.LENGTH_SHORT).show();
}
}
}
private Uri getPhotoFileUri(String fileName) {
if(isSpaceAvailable()){
File mediaStorageDir = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), APP_TAG);
if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()){
Log.d(APP_TAG, "Failed to make directory");
}
File file = new File(mediaStorageDir.getPath() + File.separator + fileName);
Uri uri = FileProvider.getUriForFile(NotesDetail.this, "com.kfode.schoolapp.fileprovider", file);
Log.d("getPhotoFileUri", uri.toString());
return uri;
}
return null;
}
private boolean isSpaceAvailable() {
String state = Environment.getExternalStorageState();
return state.equals(Environment.MEDIA_MOUNTED);
}
I also have the following permissions set:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Within the application tag of the manifest...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.kfode.schoolapp.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"
/>
</provider>
And within the file_paths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="images"
path="Pictures"/>
When I run the app, I get the following log messages and exception:
D/getPhotoFileUri: content://com.kfode.schoolapp.fileprovider/images/School_App/note4.jpg
D/NotesDetail: content://com.kfode.schoolapp.fileprovider/images/School_App/note4.jpg
E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /images/School_App/note4.jpg: open failed: ENOENT (No such file or directory)
Not sure what is going on here. Help please?
Bitmap takenImage = BitmapFactory.decodeFile(takenPhotoUri.getPath());
This will not work. A Uri is not a File.
Refactor getPhotoFileUri() into two methods:
getPhotoFile() that generates your File
getPhotoFileUri() that obtains the FileProvider Uri for that File
Then, use an image-loading library (Glide, Picasso, etc.) to populate your ImageView from the file returned by getPhotoFile(). This not only will handle all the BitmapFactory stuff for you, but it will also do that work on a background thread, so you do not freeze your UI the way you are in your current code.

Getting Failed to find configured root that contains /storage/emulated/0/Pictures/NoteTaking/IMG_20170226_231007.jpg while trying to take a photo

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().

File sharing fails for non-Google applications

I use FileProvider to share my app's images. While it works perfectly for file sharing via gmail, hangouts, drive etc, I can not share file via non-Google apps ie WhatsApp, Viber.
FileProvider in Androidmanifest
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="<package.name>.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
filepath.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path path="" name="export" />
</paths>
Method for sharing file
/**
* Static method to export charts data
*
* #param mContext object context
* #param view chart to be converted into image
* #throws IOException
**/
public static void exportChartAsPng(Context mContext, View view) throws IOException {
File baseDir = mContext.getFilesDir();
Calendar calendar = Calendar.getInstance(TimeZone.getDefault());
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
String fileName = "chart-" + df.format(calendar.getTimeInMillis()) + ".png";
String filePath = baseDir.toString() + File.separator + fileName;
File chartFile = new File(filePath);
OutputStream outStream = new FileOutputStream(chartFile);
getBitmapFromView(view).compress(Bitmap.CompressFormat.PNG, 100, outStream);
outStream.flush();
outStream.close();
try {
Uri fileUri = FileProvider.getUriForFile(
mContext,
"<package.name>.fileprovider",
chartFile);
Intent sendIntent = new Intent("<package.name>.ACTION_RETURN_FILE");
if (fileUri != null) {
// Grant temporary read permission to the content URI
sendIntent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
sendIntent.setType("image/png");
mContext.startActivity(Intent.createChooser(sendIntent, mContext.getString(R.string.share)));
} catch (IllegalArgumentException e) {
Log.e("File Selector",
"The selected file can't be shared: " +
chartFile.getName());
e.printStackTrace();
}
}

Categories

Resources