I'm writing an android application that takes some pictures and would like to save them all in a unique directory associated to my application.
This directory should be accessible from the standard Gallery, in such a way that the user can later (when application is not necessarily running) check the pictures that were taken.
My problem is that every different phone vendor, with a different android version, has different paths for gallery.As an example:
Environment.getExternalStorageDirectory() + Environment.DIRECTORY_PICTURES +"/myFolder"
will work on Samsung Galaxy Nexus
running android 4.1.1
, and on Asus Transformer Pad
running android 4.0.3
, but not on HTC Desire
running android 2.3.5
.
This will cause my application to crash when trying to save a new directory within the specified path, as stated below:
boolean success = false;
myFolder = new File( Environment.getExternalStorageDirectory() + Environment.DIRECTORY_PICTURES + "/myFolder" );
if( myFolder.exists() ){
//do nothing
}else{
success = dvaFolder.mkdir();
if( success ){
// Do something on success
/*
* folder has been created
*/
} else {
// Do something else on failure
/*
* folder creation failed
*/
throw new RuntimeException("File Error in writing new folder");
}
}
How can I write a directory that will be accessible in gallery for all
different vendors and android versions?
NOTE:
Logcat isn't much useful, cause it just returns the run time Exception.
I've had the same issue with the bluetooth folder, I created a two methods to search for the bluetooth folder on the phone, by traversing the whole file structure on the phone. The code I wrote is beneath, it is a bit dirty, but it works quite well in my case
public List<File> folderSearchBT(File src, String folder) {
List<File> result = new ArrayList<File>();
File[] filesAndDirs = src.listFiles();
if (filesAndDirs != null && filesAndDirs.length > 0) {
List<File> filesDirs = Arrays.asList(filesAndDirs);
for (File file : filesDirs) {
result.add(file); // always add, even if directory
if (file.isDirectory()) {
List<File> deeperList = folderSearchBT(file, folder);
result.addAll(deeperList);
}
}
}
return result;
}
Use the method above in this method:
public String searchForGallery() {
String splitchar = "/";
File root = Environment.getExternalStorageDirectory();
List<File> btFolder = null;
String folder = "gallery"; //your foldername to search for..
btFolder = folderSearchBT(root, folder);
if(btFolder.size() < 1)
Log.i("btFolder: ", "Empty");
for (int i = 0; i < btFolder.size(); i++) {
String g = btFolder.get(i).toString();
String[] subf = g.split(splitchar);
String s = subf[subf.length - 1].toUpperCase();
boolean equals = s.equalsIgnoreCase(folder);
if (equals)
return g;
}
return null; //not found
}
By saying that the code is dirty, I mean that I could wrote it more compact and another issue by doing it this way: if there are two folders with the name bluetooth, I'm stuck..
I hope I understood your question right.
Here is working code for taking picture and saving to external storage and another method for saving to 'files' directory on device. In my case I needed only one image (something.png) which will be always refreshed after user takes new picture.
Action when user clicks on button for camera:
ImageView productImageView = (ImageView) findViewById(R.id.imageView1);
static int RESULT_TAKE_PICTURE = 1;
String selectedImagePath;
Bitmap bitmap;
String imageName = "something.png";
public void cameraImageButton_onClick(View view) {
Intent cameraIntent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
String path = Environment.getExternalStorageDirectory()
+ File.separator + Environment.DIRECTORY_PICTURES;
File dir = new File(path);
if (!dir.exists()) {
dir.mkdir();
}
dir = new File(path, imageName);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(dir));
startActivityForResult(cameraIntent, RESULT_TAKE_PICTURE);
}
Action which is performed on activity result:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_TAKE_PICTURE && resultCode == RESULT_OK) {
selectedImagePath = Environment.getExternalStorageDirectory()
+ File.separator + Environment.DIRECTORY_PICTURES
+ File.separator + imageName;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(selectedImagePath, options);
options.inSampleSize = Calculator.calculateInSampleSize(options,
254, 254);
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(selectedImagePath, options);
productImageView.setImageBitmap(bitmap);
saveImage(bitmap, imageName);
}
}
Bonus method for saving image to device in files directory if someone needs:
private void saveImage(Bitmap bitmap, String name) {
String path = getApplicationContext().getFilesDir().toString()
+ File.separator;
File dir = new File(path);
if (!dir.exists()) {
dir.mkdir();
}
path = path + name;
dir = new File(path);
try {
dir.createNewFile();
FileOutputStream fos = new FileOutputStream(dir);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
fos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
You should check that you have included the "WRITE_EXTERNAL_STORAGE" permission in your application Manifest, it could give such errors.
Also, have you checked that the path does not simply look invalid by printing it?