Can't save a photo to external storage using getFilesDir() - android

I'm trying to save a photo to external storage and display it in a ImageView, but I don't want other apps can access this photo. I try to create a new File with the method getFilesDir() as the directory argument when I want to create that file, but if I ask if I can write to it (to save the image), it return that I can't (see the code for more details).
Note that the app has the android.permission.WRITE_EXTERNAL_STORAGE permission.
public void takePhoto(View v) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file = new File(getFilesDir(), "my_image.jpg");
// Check if I can write in this path (I always get that I can't)
if (file.canWrite()) {
Toast.makeText(this, "I can write!", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "I CAN'T WRITE!", Toast.LENGTH_LONG).show();
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
startActivityForResult(intent, IMAGE_REQUEST_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == IMAGE_REQUEST_CODE) {
File file = new File(getFilesDir(), "my_image.jpg");
Bitmap bitmap = decodeSampledBitmapFromFile(file.getAbsolutePath(), 1000, 700);
imageView.setImageBitmap(bitmap);
}
}
However, if I use the Environment.getExternalStorageDirectory() method, I'm able to save the photo.
I think I might be misunderstanding anything about how File works, but I don't know exactly what. I have no FC, the image just doesn't show in the ImageView.

If you save to an external storage everyone will see the image :
Here's External Storage!
Then when you receive the callback onActivityResult you will receive the URI from the image
Uri mUriFile = data.getData()
Then depending on the OS version you can get the file path
Here´s a good post to get it Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENT

Related

Cannot create a file using the Uri of `ACTION_GET_CONTENT`

I'm trying to select pdf file from the device and upload them to the server. ACTION_GET_CONTENT is used to select pdf from the device.
sel_book.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("application/pdf");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select PDF"), 1);
}
});
On activity result I get the Uri and save it as a String.
public void onActivityResult(int requestCode, int resultCode, Intent result) {
if (resultCode == RESULT_OK) {
if (requestCode == 1) {
Uri uri = result.getData();
String uriString = uri.toString();
File myFile = new File(uriString);
path = myFile.getAbsolutePath();
}
}
}
It results the path as, /document/primary:Download/Aptitude_2016_17.pdf. I need to use this to create a new file. File selectedFile = new File(selectedFilePath);. But it doesn't create File. selectedFile.isFile() returns false. I have no idea why is it. Please help me to solve this. Thanks in advance.
ACTION_GET_CONTENT is used to select pdf from the device.
This allows the user to select a piece of content. It does not have to be a file.
On activity result I get the Uri and save it as a String.
That is not how you use a Uri.
It results the path as, /document/primary:Download/Aptitude_2016_17.pdf.
That is not a filesystem path. That is a part of a Uri that has a content scheme. You do not get a file from ACTION_GET_CONTENT. You get a Uri that points to a piece of content. That Uri could point to anything that the user and the other app choose:
A file that you can access, via a Uri with a file scheme
A file, but one that you cannot access (e.g., on internal storage of another app)
The contents of a BLOB column in the database
A piece of content that needs to be downloaded
And so on
Use ContentResovler and openInputStream() to get a stream on whatever the content is. Either use that directly (with whatever you are using to upload this content), or use that stream to make your own file with a copy of that content, so that you have a file that you can use.

In the android application, image isn't showing after closing app and restarting it

In an app I am allowing user to pick image from gallery or he can choose from camera. Though I can manage the image and show it in the activity in the first time, after closing the app and restarting it, the image is gone and the space is blank.There was an explanation given to me to save the image data in sharedPreferences but I am new in android and don't pretty much understand. I looked for sharedPreferences but don't know how to make it work.
So if anybody help kindly with some explanation and code, it would help me a lot.
Thanks.
Here is what I tried to do.
private void openCamera(){
// create Intent to take a picture and return control to the calling application
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,getPhotoFileUri(photoFileName)); // set the image file name
// If you call startActivityForResult() using an intent that no app can handle, your app will crash.
// So as long as the result is not null, it's safe to use the intent.
if (intent.resolveActivity(getPackageManager()) != null) {
// Start the image capture intent to take photo
startActivityForResult(intent, TAKE_IMAGE);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// final android.widget.LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) imageview.getLayoutParams();
if (requestCode == PICK_IMAGE && resultCode == RESULT_OK) {
Uri imageUri = data.getData();
imageview.setImageURI(imageUri);
//selectedImagePath = getPath(imageUri);
//ystem.out.println("Image Path : " + selectedImagePath);
}
else if (requestCode == TAKE_IMAGE && resultCode == Activity.RESULT_OK) {
Uri takenPhotoUri = getPhotoFileUri(photoFileName);
// by this point we have the camera photo on disk
Bitmap rawTakenImage = BitmapFactory.decodeFile(takenPhotoUri.getPath());
// RESIZE BITMAP, see section below
// See BitmapScaler.java: https://gist.github.com/nesquena/3885707fd3773c09f1bb
// Get height or width of screen at runtime
int screenWidth = DeviceDimensionsHelper.getDisplayWidth(this);
// Resize a Bitmap maintaining aspect ratio based on screen width
Bitmap resizedBitmap = BitmapScaler.scaleToFitWidth(rawTakenImage,screenWidth);
// Load the taken image into a preview
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
// Compress the image further
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
// Create a new file for the resized bitmap (`getPhotoFileUri` defined above)
Uri resizedUri = getPhotoFileUri(photoFileName + "_resized");
File resizedFile = new File(resizedUri.getPath());
// Write the bytes of the bitmap to file
try{
resizedFile.createNewFile();
FileOutputStream fos = new FileOutputStream(resizedFile);
fos.write(bytes.toByteArray());
fos.close();
}catch (IOException e){
System.out.println("Error occured");
}
imageview.setImageBitmap(rawTakenImage);
}
}
public Uri getPhotoFileUri(String fileName) {
// Only continue if the SD Card is mounted
if (isExternalStorageAvailable()) {
// Get safe storage directory for photos
// Use `getExternalFilesDir` on Context to access package-specific directories.
// This way, we don't need to request external read/write runtime permissions.
File mediaStorageDir = new File(
getExternalFilesDir(Environment.DIRECTORY_PICTURES), APP_TAG);
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()){
Log.d(APP_TAG, "failed to create directory");
}
// Return the file target for the photo based on filename
return Uri.fromFile(new File(mediaStorageDir.getPath() + File.separator + fileName));
}
return null;
}
// Returns true if external storage for photos is available
private boolean isExternalStorageAvailable() {
String state = Environment.getExternalStorageState();
return state.equals(Environment.MEDIA_MOUNTED);
}
You can use below ways to store image.
1. Database with Base64
You can convert image into base64 string and store in database.
So when you open application you can retrieve base64 String from database and display image in ImageView.
2. Store Image Path in Database
You can store image path in database, when you open application, just retrieve image path and display image in ImageView.
But if you delete image from memory, you will not get image from iamge path.
3. Store Image in Server.
If you store image in server, you can retrieve image path and download image using AsyncTask or sime 3rd party liberary. And display image in ImageView.
(Liberaries : Picaso, LazyLoading etc.)

Take a picture and saved it in /data/data

I have this code to take a picture and save the picture in /data/data/..., but after taking the picture I get Image saved to: /media/external/images/media/a_number. I have checked the /data/data/... directory and the picture file is not there.
protected void onCreate(Bundle savedInstanceState) {
context = this;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File fileUri = new File(context.getFilesDir(), "INSTALLATION.jpg");
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
// start the image capture Intent
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
//...
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Image captured and saved to fileUri specified in the Intent
Toast.makeText(this, "Image saved to:\n" + data.getData(), Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_CANCELED) {
// User cancelled the image capture
} else {
// Image capture failed, advise user
}
}
}
Third-party camera apps have no rights to write to your portion of internal storage.
You are welcome to try writing a ContentProvider that supports the streaming API and supports writing to your internal storage, then use a content:// Uri for ACTION_IMAGE_CAPTURE. I haven't tried this, so I don't know how well it works, and I suspect many camera apps won't expect a content:// Uri there.
Otherwise, your options are:
Give the third-party camera app a location on external storage, then copy the file yourself to internal storage, or
Do not use ACTION_IMAGE_CAPTURE, but instead use the Camera and/or camera2 APIs to take a picture directly in your app

How to change the directory of SquareCamera library?

I am using SquareCamera library (https://github.com/boxme/SquareCamera) for taking square picture.The problem I am facing is that SquareCamera is creating its own folder where taken pics are getting stored. I want these pics to store in my own folder. I don't know how to achieve that. I am very new to android. Below is the code where instead of default camera I am calling its own class.
public void onLaunchCamera(View view) {
// create Intent to take a picture and return control to the calling application
Intent intent = new Intent(this,CameraActivity.class);
// Start the image capture intent to take photo
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
And this is the onActivityResult method
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Uri takenPhotoUri = data.getData();
Bitmap takenImage = BitmapFactory.decodeFile(takenPhotoUri.getPath());
imageView.setImageBitmap(takenImage);
I thought about saving this bitmap into my own folder but I couldn't think how to delete the created directory of SquareCamera.
So I found the solution. I added the library as a module in my app. Referring (https://www.youtube.com/watch?v=1MyBO9z7ojk). And there I changed the source code a little bit and now it's working perfect.
I'm a bit long in the tooth at Android and am not 100% with the new Uri methods of file access enforced since KitKat. For conventional file access you can get a private writeable file using.
private static final File OUTPUT_DIR = Environment.getExternalStorageDirectory();
FileOutputStream fos;
void yourMethodBeginsHere() {
String outputPath = new File(OUTPUT_DIR, "test.png").toString();
try {
fos = new FileOutputStream(outputPath, false);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//Work with file
}
If you need a truly external file path please refer to the excellent answer already existing at https://stackoverflow.com/a/26765884/5353361 which deals fully with the new Uri based system of permissions and the integrated file explorer.

Capture a Photo without saving

I'm trying to take a photo with this code:
capturarFoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("debugging","Has clicat al botó");
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, 1888);
}
});
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if( requestCode == 1888 && resultCode == -1) { //-1 = TOT HA ANAT BE.
Bitmap photo = (Bitmap) data.getExtras().get("data");
Log.d("debugging",""+photo.getHeight());
Log.d("debugging",""+photo.getWidth());
((ImageView) myFragmentView.findViewById(R.id.fotoCapturada)).setImageBitmap(photo);
}
}
And this is working perfectly, as I capture the photo, it's shown in the ImageView. But I'm trying to create some sort of editable options, rotation, etc. So I don't want to save it (so gallery already cached it!!).
I've read some similar questions, and this is something that would be great to do:
Create a folder on SDCARD
Save temporary picture there
Create a .nomedia file so gallery don't access it.
Remove or save applies on the picture, and leave it on that folder.
I'm trying to update above code, to adapt it to achieve these points, but the code I find in google, always use other apis, some of them, old...
Is there any "easy" way to achieve this?
The part of creating folder and creating that file, isn't a big deal, so:
- How can I set a saving route to the pictures I take with my App?
Thank you.
Edit:
Okay, I found some code, but It isn't working (even I gave SD writing permissions):
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File file = new File(Environment.getExternalStorageDirectory().getPath() + "/folder/" + "filename" + ".jpg");
Uri imageUri = Uri.fromFile(file);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(cameraIntent, 1888);
Well, finally I found out how to save the picture into a URI we want:
public void onClick(View v) {
Log.d("debugging","Has clicat al botó");
File folder = new File(Environment.getExternalStorageDirectory().toString()+"/ImagesFolder/");
folder.mkdirs();
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
Uri uriSavedImage=Uri.fromFile(new File(Environment.getExternalStorageDirectory().toString()+"/ImagesFolder/imatge.jpg"));
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriSavedImage);
startActivityForResult(cameraIntent, 1888);
}
That's it.
Remember to give permissions to write on SDCard.

Categories

Resources