We have an app which downloads images and store them on the device. The image is stored, but we are not able to see our app folder when we open the gallery. Here is the code we use to create directory:
public File getDataFolder(Context context) {
File dataDir = null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
dataDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + "MYAPPNAME");
if(!dataDir.isDirectory()) {
dataDir.mkdirs();
}
}
if(!dataDir.isDirectory()) {
dataDir = context.getFilesDir();
}
return dataDir;
}
Also we have noticed, Folder is visible in Jelly bean but not in KitKat+ devices. Why it's not visible in gallery? (files are .jpg format)
Have you tried using getExternalFilesDirs()?
Use getExternalFilesDirs() (note the plural). If that returns more than one entry, the second and subsequent ones are on removable media. Those directories you can read and write to without any permissions on Android 4.4.
From this answer https://stackoverflow.com/a/26006099/5837758.
EDIT
If the folder appears after rebooting, then you need to add your image to the gallery. From the Taking Photos Simply tutorial (http://developer.android.com/training/camera/photobasics.html):
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
You have to invoke the media scanner on your new file upon that file being visible in the Gallery without reboot. Call the media scaner after ever file saved.
Only a few lines of code will do. Code has been published very often on this site.
Prior to Android Kitkat, third-party apps had access to external storage, but from Kitkat, this permission is revoked. Now you can store data in the internal memory of the device only.
Related
I am having a problem with selecting image file from external storage using file picker in Android. This question is the consequence of this question - No such file or diectory error in image file upload using Retrofit in Android. What my problem is opening and reading file from external storage on activity result. I want to convert result URI into File.
I read a pdf file from download folder on activity result
Uri bookUri = data.getData();
if(bookUri!=null)
{
String filePath = bookUri.toString();//bookUri.toString()
String mime = app.getMimeType(filePath);
if(mime!=null && !mime.isEmpty() && (mime.toLowerCase()=="application/pdf" || mime.toLowerCase()=="application/txt" || mime.toLowerCase()=="application/text"))
{
bookFile = new File(bookUri.getPath());
ivBookFile.setImageResource(R.drawable.book_selected);
}
else{
Toast.makeText(getBaseContext(),"Unable to process file you have chosen.",Toast.LENGTH_SHORT).show();
}
}
As you can see I used new File(bookUri.getPath()); to convert into File. The above code works well. It is working. The problem is now I am trying to open an image file in DCIM/Camera folder on activity result.
This is the code I used
Uri selectedImageUri = data.getData();
if(selectedImageUri!=null)
{
try{
bmpCoverImage = MediaStore.Images.Media.getBitmap(getContentResolver(), selectedImageUri);
imageFile = new File(selectedImageUri.getPath());
if(bmpCoverImage!=null)
{
ivCoverImage.setImageBitmap(bmpCoverImage);
}
}
catch (IOException e)
{
Toast.makeText(getBaseContext(),"An error occurred with the file selected",Toast.LENGTH_SHORT).show();
}
}
As you can see I used new File(selectedImageUri.getPath()); like I did in reading pdf file. This time the code is not working. When I do operation with the file like in previous question, it gives me error.
I used this way also
imageFile = new File(Environment.getExternalStorageDirectory(),selectedImageUri.getPath());
I got the same error. How can I open the image file correctly from external storage? How can I convert the chosen file URI from external storage into File?
I am having a problem with selecting image file from external storage using file picker in Android
If you are referring to the code that you are using in this question, you are not "using file picker". You are using ACTION_GET_CONTENT, which has never been a "file picker", nor will it ever be a "file picker".
I want to convert result URI into File.
Usually, that is not necessary. But, if that is what you want to do:
use ContentResolver and openInputStream() to get an InputStream on the content represented by the Uri
create a FileOutputStream on your desired file
use Java I/O to copy the bytes from the InputStream into the FileOutputStream
The above code works well. It is working.
It works for the small number of devices that you tested, for the specific activities that the user chose to handle the ACTION_GET_CONTENT request. It will not work on most Android devices, and it will not work in most circumstances. The only time that code will work is if the Uri has a file scheme. Most of the time, it will not. Instead, it will have a content scheme, representing content supplied by a ContentProvider.
Please how can I open the image file correctly from external storage?
If you wish to continue using ACTION_GET_CONTENT, please understand that this has nothing to do with external storage specifically. You are not getting a file, on external storage or elsewhere. You are getting a Uri. This is akin to a URL, such as the URL for this Web page. Just as a URL does not necessarily point to a file on your hard drive, a Uri does not necessarily point to a file on the filesystem. Use a ContentResolver and DocumentFile to work with the Uri and the content that it identifies.
If you want to always get files on external storage (and nowhere else), then use an actual file picker library.
My requirement is to open all images and video's of specific folder.
I have refereed this link, Now I am able to show a image in gallery but I want to show all images from a specific folder. Almost all link I have tried on stack but did not get success.
You can set path in File object initialize at that time.
File folder = new File("/sdcard/Photo/"); in this tutorial default path is /sdcard/photo/ at this place you can set your path then get your files.
I sinc it is not good idea but you may write your own searcher in all files on mobile phone for example
public ArrayList<File> getAllphotos(String path){
ArrayList<File> photoPath = new ArrayList<>();
File yourDir = new File(path);
for (File f : yourDir.listFiles()) {
String mas[] = f.toString().split("\\.");
if(mas[mas.length - 1].equalsIgnoreCase("png") || mas[mas.length - 1].equalsIgnoreCase("jpeg")){//or other formats
//it is picture
photoPath.add(f);
}
}
return photoPath;
}
call this wis iternal and external storage
I have an app which performs processing on an image selected by the user using from the gallery, after processing the modified image is then saved back to the original image's folder with a modified filename. On specific devices (mainly Samsungs) the new KitKat permission limitations severely limit where a non system app can write to e.g. external SD card or back to typical gallery locations.
The documentation advises to write to the private package specific folder obtained via
getExternalFilesDir(null)
This is fine and the image is saved correctly but then a subsequent call to
MediaScannerConnection.scanFile
fails to update the central media database correctly as the modified image doesn't appear in the gallery, even a reboot of the device which should force a full scan of all media doesn't trigger the image to be displayed.
In other words the following code doesn't work:
File appDir = MyActivity.this.getExternalFilesDir(null);
File file = new File(appDir, "new_image.jpeg");
// Process image and write file away...
MediaScannerConnection.scanFile(this, new String[] { file.getAbsolutePath() }, null, new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
Log.i(LOG_TAG, String.format("Scanned file: %s", path));
}
});
The onScanCompleted method fires but the gallery doesn't show the new image.
Has anyone seen this behaviour, does MediaScanner not scan 'private' app folders and if so how else do I get the gallery to detect and display the new image.
If you want images to be picked up by the gallery, you should put them in the proper public location. You can get the proper location using Environment.getExternalStoragePublicDirectory().
I'm trying to save pictures in a subfolder on Android. Here's a bit of my code:
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
path = new File(path, "SubDirName");
path.mkdirs();
(I've tried getExternalStorageDirectory instead of getExternalStoragePublicDirectory and the Pictures folder instead of DCIM.)
Any subfolder I add, including its contents, don't show up in Windows Explorer when the device is connected via USB. It does show in the Android File Manager, though.
I've tried broadcasting the ACTION_MEDIA_MOUNTED intent on the new directory's parent. It didn't work.
If I add a file in Windows, it shows up on Android. If I add a file on Android via the File Manager, it shows up in Windows. If I add the file programmatically, it shows up on the Android File Manager, but not in Windows Explorer. And I need to get it from Windows, and I don't want the final user to have to create the folder manually.
What am I doing wrong?
I faced the same issue and rebooting either the Android device or the PC is not a practical solution for users. :)
This issue is through the use of the MTP protocol (I hate this protocol). You have to
initiate a rescan of the available files, and you can do this using the MediaScannerConnection class:
// Snippet taken from question
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
path = new File(path, "SubDirName");
path.mkdirs();
// Initiate a media scan and put the new things into the path array to
// make the scanner aware of the location and the files you want to see
MediaScannerConnection.scanFile(this, new String[] {path.toString()}, null, null);
The way used in Baschi's answer doesn't always work for me. Well, here is a full solution.
// Snippet taken from question
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
path = new File(path, "SubDirName");
path.mkdirs();
// Fix
path.setExecutable(true);
path.setReadable(true);
path.setWritable(true);
// Initiate media scan and put the new things into the path array to
// make the scanner aware of the location and the files you want to see
MediaScannerConnection.scanFile(this, new String[] {path.toString()}, null, null);
The only thing that worked for me was this:
Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri fileContentUri = Uri.fromFile(path);
mediaScannerIntent.setData(fileContentUri);
this.sendBroadcast(mediaScannerIntent);
Credit to https://stackoverflow.com/a/12821924/1964666
None of the above helped me, but this worked:
The trick being to NOT scan the new folder, but rather create a file in the new folder and then scan the file. Now Windows Explorer sees the new folder as a true folder.
private static void fixUsbVisibleFolder(Context context, File folder) {
if (!folder.exists()) {
folder.mkdir();
try {
File file = new File(folder, "service.tmp");//workaround for folder to be visible via USB
file.createNewFile();
MediaScannerConnection.scanFile(context,
new String[]{file.toString()},
null, (path, uri) -> {
file.delete();
MediaScannerConnection.scanFile(context,
new String[]{file.toString()} ,
null, null);
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
Thanks to https://issuetracker.google.com/issues/37071807#comment90
You also should scan every created file in the directory analogically:
private static void fixUsbVisibleFile(Context context, File file) {
MediaScannerConnection.scanFile(context,
new String[]{file.toString()},
null, null);
}
If you add the folder to the SD card from the PC directly to the card through the card reader, it will not show in Windows Explorer when connected with the phone.
The solution is to copy or move the same folder using the Android file manager program and then it will be listed in the SD card index when connected to the PC.
It's work fine for me.
MediaScannerConnection.scanFile work if there is file in directory (not directory)
private fun checkMTPFolder(f: File, context: Context) {
if (f.isDirectory) {
val newFilePath = f.absolutePath + "/tempFIle"
val newFile = File(newFilePath)
newFile.mkdir()
MediaScannerConnection.scanFile(context, arrayOf(newFilePath), null, object : MediaScannerConnection.OnScanCompletedListener {
override fun onScanCompleted(p0: String?, p1: Uri?) {
val removedFile = File(p0)
removedFile.delete()
MediaScannerConnection.scanFile(context,arrayOf(removedFile.absolutePath), null, null)
}
})
}
}
I have solved this problem by toggling the phone setting:
After a directory is created and/or a file saved, change from (MTP) mode to USB (SD card) mode for a moment, wait for the SD card mounting on the PC, so the directory and file will be shown.
Turn back to (MTP) mode again where the last file still shows up.
When re-saving a file, you have to change to USB again to see it.
Just create the directory on the PC first, and then copy it over to the SD card/phone storage.
You can either put in the contents into the folder first and copy over or just the folder first. As long as the folder is created from the PC, any content can just be copied directly to internal/external mobile devices. For zipped content, it cannot be directly unzipped and copied over unfortunately; you need to unzip them first.
I'm writing an app that downloads photos from a digital camera. What would be the most appropriate place to save them to? Must be external storage since gigabytes of images are expected.
Saving files that should be shared
If you want to save files that are not specific to your application and that should not be deleted when your application is uninstalled, save them to one of the public directories on the external storage. These directories lay at the root of the external storage, such as Music/, Pictures/, Ringtones/, and others.
In API Level 8 or greater, use getExternalStoragePublicDirectory(),
passing it the type of public directory you want, such as
DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_RINGTONES, or others.
This method will create the appropriate directory if necessary.
If you're using API Level 7 or lower, use getExternalStorageDirectory() to open a File that represents the root
of the external storage, then save your shared files in one of the
following directories:
Music/ - Media scanner classifies all media found here as user music.
Podcasts/ - Media scanner classifies all media found here as a
podcast.
Ringtones/ - Media scanner classifies all media found here as
a ringtone.
Alarms/ - Media scanner classifies all media found here as
an alarm sound.
Notifications/ - Media scanner classifies all media
found here as a notification sound.
Pictures/ - All photos (excluding
those taken with the camera).
Movies/ - All movies (excluding those
taken with the camcorder).
Download/ - Miscellaneous downloads.
filesExternal
External Storage is the best place to store images and the default location is to get it using
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
If you want to create a folder inside default picture Directory then use below
Example code:
File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+ "/Your_folder_name");
Here is method, this is how I am saving Bitmap image to default picture directory:
private String saveImage(Bitmap image) {
String savedImagePath = null;
Date d = new Date();
CharSequence s = DateFormat.format("MM-dd-yy hh-mm-ss", d.getTime());
String imageFileName = "IMG" + s + count + ".jpg";
File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+ "/Your_folder_name");
boolean success = true;
if (!storageDir.exists()) {
success = storageDir.mkdirs();
}
if (success) {
File imageFile = new File(storageDir, imageFileName);
savedImagePath = imageFile.getAbsolutePath();
try {
OutputStream fOut = new FileOutputStream(imageFile);
image.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
// Add the image to the system gallery
//galleryAddPic(savedImagePath);
//Toast.makeText(mContext, "IMAGE SAVED", Toast.LENGTH_LONG).show();
}
return savedImagePath;
}
External storage, since you will need lots of space.
If you want them to be accessible by other applications, just put them in the DCIM folder with the camera's original folder name, (android's is 100ANDROID, other cameras have other ones). Users expect pictures to be stored there, as do other applications.
Here is an example from Google. Note that you MUST define <provider> in AndroidManifest.xml and the res/xml/file_paths.xml according to description. However, to use getExternalStoragePublicDirectory() I had to set path="." in the file_paths.xml file..