Android - Unable to save images - android

I'm currently trying to get image saving to happen using the device built in camera. This is the code I'm using:
PackageManager pm = getActivity().getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// * Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(pm) != null) {
// * Create the File where the photo should go
File photoFile = null;
try {
photoFile = ImageFileHelper.createImageFile();
} catch (IOException ex) {
// * Error occurred while creating the File
Timber.d("An error occurred while creating file: " + ex.getLocalizedMessage());
}
// * Continue only if the File was successfully created
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PICTURE);
} else {
alertUserOfError(0);
}
}
} else {
// * Inform user that they need a camera
// * to use this feature
alertUserOfError(1);
}
And here is the ImageFileHelper.createImageFile() function:
public static File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyy-MM-dd.ss", Locale.getDefault()).format(new Date());
String imageFileName = "Original_Avatar_" + timeStamp;
// * Create MyApp folder if not exist
String path = Environment.getExternalStorageDirectory() + File.separator + Environment.DIRECTORY_PICTURES;
File dir = new File(path + "/MyApp/Originals/");
dir.mkdirs();
File image = File.createTempFile(
imageFileName, /* prefix */
".png", /* suffix */
dir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
filePath = "file:" + image.getAbsolutePath();
Timber.d("image created at: " + filePath);
return image;
}
My permissions & features:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
This seems to work just fine on my test devices and the majority of my beta tester devices. However, there is one guy who reports that he gets an error message generated by alertUserOfError(0) (you'll see that in the above code), essentially that the photoFile is null.
He is using a rooted HTC One (M8) (htc_m8). Could this be an issue due to the device being rooted?
Any help is appreciated.
UPDATE 2015-05-30
I haven't had a chance to add reporting to the catch statement yet, but I did add a method to test for valid paths/directories. Here is how it works:
StringBuilder build = new StringBuilder();
String path_1 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + "MyApp" + File.separator + "Cropped" + File.separator;
File dir_1 = new File(path_1);
dir_1.mkdirs();
if (dir_1.exists()) {
build.append("path 1 valid, ");
} else {
build.append("path 1 invalid, ");
}
Using this same setup I also tested the following dirs:
Environment.getExternalStorageDirectory() + File.separator + "MyApp" + File.separator + "Cropped" + File.separator;
Environment.getDataDirectory() + File.separator + "MyApp" + File.separator + "Cropped" + File.separator;
The StringBuilder.toString() is then used as the message in an alert for the tester to send the results back to us.
The above resulted in all paths being invalid:
path_1 invalid, path_2 invalid, path_3 invalid
So does this mean that those directories just don't exist on the HTC One (M8) (htc_m8) and cannot be created?

I had a similar situation. You are implementing the example given in the official docs. There is a problem implementing that example in some devices. This is how I solved it.
Replace:
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES)
With:
private File createImageFile() throws IOException {
// Create an image file name
Finally, make sure you call:
mkdirs() // and not mkdir()
Here's the code that should work for you:
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = new File(Environment.getExternalStorageDirectory().toString(), "whatever_directory_existing_or_not/sub_dir_if_needed/");
storageDir.mkdirs(); // make sure you call mkdirs() and not mkdir()
File image = File.createTempFile(
imageFileName, // prefix
".jpg", // suffix
storageDir // directory
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
Log.e("our file", image.toString());
return image;
}
I had a bad experience following the example given in Android Studio Documentation and I found out that there are many others experiencing the same about this particular topic here in stackoverflow, that is because even if we set
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
the problem persists in some devices.
My experience was that the example worked when I tried it in debug mode, after that 3 more tests passed, it so happened that my SD was suddenly corrupted, but I don't think it had to do with their example (funny). I bought a new SD card and tried it again (because I could not reformat my sd, however I tried), only to realize that still both release and debug mode did the same error log: directory does not exist ENOENT. Finally, I had to create the directories myself whick will contain the captured pictures from my phone's camera. And I was right, it works just perfect.
I hope this will help the ones out there searching for answers, because obviously, considering the age of your enquiry, you must have already solved this issue.

Related

Android 10 write file to public DCIM directory, NON DEPRECATED method

We have an Android app where field workers take photographs which are stored on their phone and also uploaded via a web api.
If the uploads fail they do have retry mechanisms but sometimes they need to resort to pulling the images off their phone.
In order to bring the app up to Android 10 version without deprecation I was forced to write the images to an app internal directory.
The problem is that when they upgrade their app they lose their photos from the app.
(I do also copy the images to a backup directory but this is all looking a bit klutzy)
I would like to write the images to :
/storage/emulated/0/DCIM/GoTrialImages
Instead they are going to :
/storage/emulated/0/Android/data/au.come.aceware.ktr.ktr/files/DCIM/GoTrialImages/photoIntent
(where photoIntent is the activity that this is occurring in)
Here is the code I have copied and tweaked from an online article:
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = "JPEG_" + timeStamp + ".jpg";
File mediaStorageDir = new File(getExternalFilesDir(Environment.DIRECTORY_DCIM + File.separator +"GoTrialPhotos"), TAG);
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()){
Log.d(TAG, "failed to create directory");
}
// Return the file target for the photo based on filename
File file = new File(mediaStorageDir.getPath() + File.separator + fileName);
Uri bmpUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", file);
Here is my file provider entry in the manifest:
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>```
and here is #xml/provider_paths:
```<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>```
1) Is it possible to do what I am seeking to do ?
2) How do I do it without using deprecated code
Many thanks in advance
Tony
Following the suggestion to use media store I kept most of the code for creating the app internal file name
(mainly because I wanted the randomised display name):
private File createImageFileV2() throws IOException
{
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
imageFileNameToUseAtWebServerEnd = strTrial + "_" + timeStamp + "_" + strUserId + ".jpg";
File[] storageDir = getExternalMediaDirs();
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir[0] /* directory */
);
return image;
}
I then passed the file object in to the following code:
public Uri testgetPhotoFileUri2(File f)
{
Uri uri = null;
String strDisplayName = f.getName();
final ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, strDisplayName);
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM );
final ContentResolver resolver = thisContext.getContentResolver();
try
{
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
uri = resolver.insert(contentUri, values);
if (uri == null)
throw new IOException("Failed to create new MediaStore record.");
return uri;
}
catch (IOException e)
{
if (uri != null) {
// Don't leave an orphan entry in the MediaStore
resolver.delete(uri, null, null);
}
}
return uri;
}
I then used the resulting uri as my camera uri:
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri);
However, when the OnActivityResult calls HandleBigCameraPhoto and attempts to extract the bitmap using the CameraUri:
private void handleBigCameraPhoto() {
Bitmap bitmap = null;
if (cameraUri != null)
{
if (Build.VERSION.SDK_INT >= 29) {
ImageDecoder.Source source = ImageDecoder.createSource(getApplicationContext().getContentResolver(), cameraUri);
try {
bitmap = ImageDecoder.decodeBitmap(source);
} catch (IOException e) {
e.printStackTrace();
}
It error traps to "no such file or directory"
Does this mean that I need to most of my work (image resizing, rotation, etc) using my app private file only and then as a last step insert the bitmap in to media store (and then delete the app private file so the user does not see the file name twice under gallery, recents)?
You will not make use of a deprecated function:
File file = new File(getExternalFilesDir(null)
.getParentFile()
.getParentFile()
.getParentFile()
.getParentFile(), "DCIM");
;-).

Launching Camera Intent on AVD throwing IOException: open failed: EACCES (Permission denied)

I'm attempting to create a temp file to store an image from the camera intent, following the Android Photo Basics guide, but every time I try to create one from my android emulator, it's crashing. It works fine from my physical Nexus 7, so I know it's not a permissions issue.
I set a breakpoint and followed it down, and it's going into the BlockGuardOs, and after a little research it sounds like that's a way to ensure you're following proper thread control, so I attempted to move my code into an AsyncTask, but it's still crashing with the same error.
The original method I was using:
private File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName,
".jpg",
storageDir
);
return image;
}
After that I moved it into an AsyncTask
class CreateImage extends AsyncTask<Void, Void, File> {
#Override
protected File doInBackground(Void... params) {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = null;
try {
File.createTempFile(imageFileName, ".jpg", storageDir);
} catch (IOException ex) {
}
return image;
}
#Override
protected void onPostExecute(File file) {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(getPackageManager()) != null) {
if (file != null) {
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, file);
startActivityForResult(cameraIntent, CAMERA_RESP);
}
}
}
}
But I'm still running into the same issue. I know I can disable this by changing the StrictThread settings, but I'd like some advice on how I can handle the file IO off the main UI thread.
Thanks
To access the device camera, you must declare the CAMERA permission in your Android Manifest. Also be sure to include the <uses-feature> manifest element to declare camera features used by your application. For example, if you use the camera and auto-focus feature, your Manifest should include the following:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
I think you didn't define camera for you emulator .
if you are using android studio do this :
1.open AVD manager
2.Under Actions column choose edit AVD ( pen icon )
3.Click SHOW ADVANCED SETTING
4.At camera select your back and front camera
5.Finish

ERROR openFile writing on ExternalStorage when Status is MOUNTED. Manifest permission OK

and first of all... THANK YOU!
I'm trying to make work the code related at http://developer.android.com/training/camera/photobasics.html
but there's something wrong when creating a file:
private File createImageFile() throws IOException {
Log.i(TAG, "Entered ....createImageFile....StorageState= " + Environment.getExternalStorageState());
// 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 = null;
try{
image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
} catch (IOException ex){
Log.i(TAG, "Entered ....createImageFile....File= NOT CREATED");
ex.printStackTrace();
}
Log.i(TAG, "Entered ....createImageFile....File= " + image.toString());
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}
Error:
Error stack:(See state of Environment.getExternalStorageState() is mounted )
>
11-22 06:36:20.322: I/Photo(1172): Entered ....dispatchTakePictureIntent....
11-22 06:36:35.183: I/Photo(1172): Entered ....createImageFile....StorageState= **mounted**
11-22 06:36:45.072: I/Photo(1172): Entered ....createImageFile....File= NOT CREATED
11-22 06:36:54.985: W/System.err(1172): java.io.IOException: open failed: ENOENT (No such file or directory)
11-22 06:36:55.044: W/System.err(1172): at java.io.File.createNewFile(File.java:948)
11-22 06:36:55.073: W/System.err(1172): at java.io.File.createTempFile(File.java:1013)
11-22 06:36:55.093: W/System.err(1172): at com.example.prueba2.MainActivity.createImageFile(MainActivity.java:102)
My Android Manifest declares: ( I tried both)
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
or
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
And my AVD is created with SDCard = 50MB and target API = 18
UPDATED to answer greenapps comments Sorry. I've badly explined!! ....Not Solved yetI've added File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
if ( !storageDir.exists()) {
Log.i(TAG, "storageDir does not exist: " + storageDir.getAbsolutePath());
} else {
Log.i(TAG, "storageDir exists: " + storageDir.getAbsolutePath());
}
if ( !storageDir.canWrite()){
Log.i(TAG, "storageDir is not writable: " + storageDir.getAbsolutePath());
} else {
Log.i(TAG, "storageDir is writable: " + storageDir.getAbsolutePath());
} and I get 11-22 07:55:35.112: I/Photo(1240): Entered ....createImageFile....StorageState= mounted
storageDir does not exist: /storage/sdcard/Pictures
storageDir is not writable: /storage/sdcard/Pictures
Entered ....createImageFile....File= NOT CREATED
I had a similar situation. This is how I solved it.
Replace:
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES)
With:
private File createImageFile() throws IOException {
// Create an image file name
make sure you call:
mkdirs() // and not mkdir()
Here's the code that should work for you:
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = new File(Environment.getExternalStorageDirectory().toString(), "whatever_directory_existing_or_not/sub_dir_if_needed/");
storageDir.mkdirs(); // make sure you call mkdirs() and not mkdir()
File image = File.createTempFile(
imageFileName, // prefix
".jpg", // suffix
storageDir // directory
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
Log.e("our file", image.toString());
return image;
}
I had a bad experience following the example given in Android Studio Documentation and I found out that there are many others experiencing the same about this particular topic here in stackoverflow, that is because even if we set
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
the problem persists in some devices.
My experience was that the example worked when I tried it in debug mode, after that 3 more tests passed, it so happened that my SD was suddenly corrupted, but I don't think it had to do with their example (funny). I bought a new SD card and tried it again (because I could not reformat my sd, however I tried), only to realize that still both release and debug mode did the same error log: directory does not exist ENOENT. Finally, I had to create the directories myself whick will contain the captured pictures from my phone's camera. And I was right, it works just perfect.
I hope this helps you and others out there searching for answers.

Get all gallery images on Nexus 4

I am developing a simple gallery app in which I search for folders which contains images and then show images of that particular folder. First I am using Environment.getExternalStorageDirectory() and then recursively search for folders having images. It is working fine simulator and devices. When my client installed app on Nexus 4, nothing is being loaded. I have seen some posts which says that Nexus series don't have any external SD slot. I don't have Nexus 4 for debugging and client is also non-technical. He can troubleshoot on his own to find the cause of problem. Can anybody help in this regard? I think the problem is in Environment.getExternalStorageDirectory() call which is not applicable in Nexus. Any idea how I can tackle this issue?
Here is the code snipped I am using:
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File cacheDir = null;
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
cacheDir=new File(android.os.Environment.getExternalStorageDirectory().getAbsolutePath(), "MyImages");
}
else {
cacheDir = getCacheDir();
}
if(!cacheDir.exists()) {
cacheDir.mkdir();
}
// File storageDir = Environment.getExternalStoragePublicDirectory(
// Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
cacheDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "" + image.getAbsolutePath();
return image;
}
public 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
ex.printStackTrace();
}
// Continue only if the File was successfully created
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
And here the permissions I have added manifest:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
Thanks!
I think you should give a try to the MediaStore.Images component. Load the images using a cursor. See documentation: http://developer.android.com/reference/android/provider/MediaStore.html

Trouble with adding file path to the MediaStore.ACTION_IMAGE_CAPTURE intent

I am adding a photo from the phones camera to a Fragment. I am including the file path to where I would like the pic to get saved in the camera intent(MediaStore.ACTION_IMAGE_CAPTURE).
My problem is that after launching the camera and taking the pic the I am not able to get back to my app. The screen stays in the part where the user gets the option to accept the pic or take another one. The phone doesn't hang or crash and I am able to get back to my app by hitting the back button, but when I get back to the app it is without the pic.
I hope I have made my problem clear, if not let me know and I will try to explain better. I have attached (what I think) are the relevant bits of code.Let me know if you need to see anymore of the code.
Launching the camera intent:
void takePic()
{
if(isExternalStorageWritable() && isExternalStorageReadable())
{
Log.w("Rakshak", "in the take pic");
File file = getPicStoragePath();
Uri uriSavedImage=Uri.fromFile(file);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uriSavedImage);
startActivityForResult(intent, CAMERA_IMAGE_ACTIVITY_REQUEST_CODE);
}
}
public File getPicStoragePath() {
Log.w("Rakshak", "in the get pic file");
File root = android.os.Environment.getExternalStorageDirectory();
File dir = new File (root.getAbsolutePath() + File.separator +"YAN");
if(!dir.exists())
dir.mkdirs();
File file = new File(dir,getPicName());
return file;
}
public String getPicName()
{
Log.w("Rakshak", "in the get pic name");
if(title.getText().toString().trim().length() == 0)
{
Log.w("Rakshak", "no title");
Calendar cal=Calendar.getInstance();//get an instance of the calendar
return String.format("%1$te %1$tB %1$tY,%1$tI:%1$tM:%1$tS %1$Tp",cal);// get the data/time when the note was created
}
else
{
return title.getText().toString().trim();
}
}
I have these permissions in the manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
The relavent bits from the onActivityResult:
case CAMERA_IMAGE_ACTIVITY_REQUEST_CODE:
Log.w("Rakshak", "in the camera case");
myBitmap = data.getExtras().getParcelable("data");
photo.setVisibility(View.VISIBLE);
photo.setImageBitmap(myBitmap);
update_pic = true;
return;
There are no error messages in the LogCat. And I could not find anything of note in there.
I get the pic inserted onto the image view just fine if I dont add a file path to the camera intent. It is only when I add the file path that the stays in the "accept pic" bit of the camera.
Your getPicStoragePath() might be the issue. Try something like this:
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 */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}

Categories

Resources