I'm trying to save an image on JPG format on a specific folder from my gallery. But my code is not creating a directory, whenever i create a Toast it return for me /storage/emulated/0/DCIM/MyFodler,but when will i open the gallery, this foder not exist. I'm building the application direct of my devide with Android Marshmallow 6.0.
Code to create Bitmap:
private Bitmap getToBitmap(ImageView view, int Width, int Heigth){
Bitmap bitmap = Bitmap.createBitmap(Width,Heigth, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
Code to try save the image on gallery:
private void TrySaveMediaStore(){
String path = Environment.getExternalStorageDirectory().toString();
OutputStream FileOut = null;
File file = new File(path,"DCIM/MyFolder");
file.mkdirs();
Toast.makeText(getApplicationContext(),file.getAbsolutePath(),Toast.LENGTH_SHORT).show();
try{
FileOut = new FileOutputStream(file);
FileOut.flush();
FileOut.close();
Bitmap bitmap = getToBitmap(img,img.getMaxWidth(),img.getMaxHeight());
bitmap.compress(Bitmap.CompressFormat.JPEG,100,FileOut);
MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());
Toast.makeText(this,file.getAbsolutePath(),Toast.LENGTH_SHORT).show();
}catch (FileNotFoundException e){
return;
}catch (IOException e){
e.printStackTrace();
}
}
Androidmanifest permissions:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
DCIM/MyFolder is a directory. You create this as a directory using mkdirs().
You cannot then try using DCIM/MyFolder as a filename for saving a JPEG. You need to create a file inside the directory.
So, instead of:
FileOut = new FileOutputStream(file);
use something like:
File theActualImageFile=new File(file, "something.jpeg");
FileOut = new FileOutputStream(theActualImageFile);
Also:
You need to deal with runtime permissions, if your targetSdkVersion is 23 or higher
A gallery app will see neither the directory nor the file, until you tell the MediaStore to index the newly-created JPEG
i think a had the same problem, actually the image do insert just fine in the memory, but when i tried to watch it didn't show as i expected, i solved it refreshing the gallery with the scanner class, used this code:
MediaScannerConnection.scanFile(this,
new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
See this link for more info: How can I refresh the Gallery after I inserted an Image in android?
You may use the below code for asking runtime storage permission:
final int MyVersion = Build.VERSION.SDK_INT;
if (MyVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (!checkIfAlreadyhavePermission()) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} else {
TrySaveMediaStore() ;
}
checkIfAlreadyhavePermission() method:
private boolean checkIfAlreadyhavePermission() {
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED;
}
Add onRequestPermission():
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 1: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
TrySaveMediaStore();
} else {
Toast.makeText(this, "Please give your permission.", Toast.LENGTH_LONG).show();
}
break;
}
}
}
After creating the file scan MediaStore:
public void scanFile(Context c, File file, String mimeType) {
MediaScannerConnection
.scanFile(c, new String[] {file.getAbsolutePath()},
new String[] {mimeType}, null);
}
Yes, the problem is the media scanner. Yo can simply check the file using a terminal (download the app if you don't have it) and go manually to the directory. I had the same problem, but at least I know the file is there.
Related
I have build sample app for user to write some text and save it on internal storage.
Format TXT or pdf. I have tried on android Kitkat sdk 19 and It's working fine but when I tried on the latest android 9 I got denied could not save the text in internal storage
Edit : I wonder If have to manually create My files folder
What I'm I missing ?
AndroidManifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSaveTextBtn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
mText = mResultEt.getText().toString().trim();
if(mText.isEmpty()){
Toast.makeText(MainActivity.this, "write text First...", Toast.LENGTH_SHORT).show();
}
else{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED){
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissions,WRITE_EXTERNAL_STORAGE_CODE);
}else {
saveToTxtFile(mText);
}
}else {
saveToTxtFile(mText);
}
}
}
});
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode){
case WRITE_EXTERNAL_STORAGE_CODE: {
if (grantResults.length > 0 && grantResults[0]
== PackageManager.PERMISSION_GRANTED) {
//permission granted save data
saveToTxtFile(mText);
} else {
//permission denied
Toast.makeText(this, "Storage Permission required to store", Toast.LENGTH_SHORT).show();
}
}
break;
}
}
private void saveToTxtFile(String mText){
//get current time for file name
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.getDefault()).format(System.currentTimeMillis());
try{
//path tp storage
File path = Environment.getExternalStorageDirectory();
//create folder named "My file"
File dir = new File( path + "/My Files/");
dir.mkdirs();
//file name
String fileName = "MyFile_" + timestamp + ".txt";
File file = new File (dir, fileName);
//used to store characater in file
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(mText);
bw.close();
//show file name and path where file saved
Toast.makeText(this, fileName+"is saved to\n" +dir, Toast.LENGTH_SHORT).show();
}catch (Exception e){
//if anything goes wrong
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
As suggested both Shashanth and kashyap answers.
This is just a workaround but it works.
I have added
android:requestLegacyExternalStorage="true"
to my <application> element in the AndroidManifest.xml file.
And changed the line
File path = Environment.getExternalStorageDirectory();
to
File path = new File(getExternalFilesDir(null).getAbsolutePath());
In your MainActivity you should check if permission is granted or not, then use != operator.
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {}
this line should be-
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED){}
I have an app that can open and edit binary file from external SD card. I want to have possibility to save this file back from where it was opened.
I have added permissions in manifest file and I also ask user for permission.
Thanks to those permissions I can open file and get the data but when I want to save file to external SD card there is an error: java.io.FileNotFoundException: /storage/3834-3433/file.bin: open failed: EACCES (Permission denied).
Here is code for granting permission:
public boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
return true;
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
}
else {
return true;
}
}
Here is the code for choosing and getting file path:
button.setOnClickListener(v -> {
intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
startActivityForResult(intent, 200);
});
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 200:
if (resultCode == RESULT_OK) {
String filePath = Objects.requireNonNull(data.getData()).getPath();
filePathMain = filePath;
}
break;
}
}
And this is the part of code to save file:
void byteArrayToFile() {
try (OutputStream out = new FileOutputStream(filePathMain)) {
out.write(outBytes);
} catch (IOException e) {
e.printStackTrace();
}
}
I have no idea why it allows me to open file but not to write when I have <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />.
I also had to run this app on the real device because when I run this on emulator there is an error that it can't find the file I choose.
I could really use some help on this. Thank You.
Based on #CommonsWare comment I changed from ACTION_GET_CONTENT to ACTION_OPEN_DOCUMENT to get a file Uri.
Also used ContentResolver to read:
InputStream inputStream = getContentResolver().openInputStream(uri);
and write to file:
ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, "w");
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
And now it's working properly.
I have a button for my camera, but I can't figure out how to make the pictures taken get stored somewhere else. Can you help? My code that I've already got for this button:
<Button style="#style/ButtonsAtHome" android:onClick="cameraButton"
android:textColor="#4CAF50" android:text="CAMERA" />
Java:
public void cameraButton(View view) {
Intent openCamera = new
Intent("android.media.action.IMAGE_CAPTURE");
startActivity(openCamera);
getWindow().setBackgroundDrawable(null);
}
This button opens the camera, but it saves in a default directory, but I don't want it to save there, how can I change the directory, or make the image show up after I take it, so I can edit it. (My app is a photo-editor)
You can use below code to take picture and then store in your app directory:
Open the camera
public void openCamera(View view){
Intent openCamera = new
Intent("android.media.action.IMAGE_CAPTURE");
startActivityForResult(openCamera,1);
getWindow().setBackgroundDrawable(null);
}
Get the result in onActivityResult() // modify it according to your own need
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case 1:
Bitmap photo = (Bitmap) data.getExtras().get("data");
createDirectoryAndSaveFile(photo,"fileName");
}
}
Save image in specified folder
private void saveImageToFolder(Bitmap image, String fileName) {
File directoryName = new File(Environment.getExternalStorageDirectory() + "/MyAppDirectory");
if (!directoryName.exists()) {
directoryName.mkdir();
}
File file = new File(new File("/sdcard/MyAppDirectory/"), fileName + ".JPEG");
if (file.exists()) {
file.delete();
}
try {
FileOutputStream out = new FileOutputStream(file);
imageToSave.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Add necessary permission :
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
I am using this code in async to create directory if not exists in android with permissions. My code sucessfully works in android 5.1 but when i deployed app in android 7.0 the directory not created automatically
File sdcard = Environment.getExternalStorageDirectory() ;
File folder = new File(sdcard.getAbsoluteFile(), "Quoteimages");
if(!folder.exists()){
folder.mkdir();
}
Manifest file is
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
Link to detail of application apk App apk detail link
Now what should i do i want to create folder write images from url to it and then read them. This work for me in android 5.1 but not in Android version 7 .
You need to implement runtime permissions for android versions above lollipop
Maybe this piece of code will help you:
private static final int PERMS_REQUEST_CODE = 123;
//...........................................................................................................
private boolean hasPermissions(){
int res = 0;
//string array of permissions,
String[] permissions = new String[]
{android.Manifest.permission.WRITE_EXTERNAL_STORAGE};
for (String perms : permissions){
res = checkCallingOrSelfPermission(perms);
if (!(res == PackageManager.PERMISSION_GRANTED)){
return false;
}
}
return true;
}
private void requestPerms(){
String[] permissions = new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
requestPermissions(permissions,PERMS_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
boolean allowed = true;
switch (requestCode){
case PERMS_REQUEST_CODE:
for (int res : grantResults){
// if user granted all permissions.
allowed = allowed && (res == PackageManager.PERMISSION_GRANTED);
}
break;
default:
// if user not granted permissions.
allowed = false;
break;
}
if (allowed){
//user granted all permissions we can perform our task.
ListItem listItem = new ListItem();
Glide.with(getApplicationContext()).asBitmap().load(listItem.getImgurl()).into(new SimpleTarget<Bitmap>(){
#Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
FileOutputStream fileOutputStream = null;
File file = getDisc();
if(!file.exists()&& !file.mkdirs()){
Toast.makeText(getApplicationContext(),"Can't create directory to save image", Toast.LENGTH_LONG).show();
return;
}
SimpleDateFormat simpleDataFormat = new SimpleDateFormat("yyyymmsshhmmss");
String date = simpleDataFormat.format(new Date());
String name = "img"+date+".jpg";
String file_name = file.getAbsolutePath()+"/"+name;
File new_file= new File(file_name);
try {
fileOutputStream=new FileOutputStream(new_file);
resource.getHeight();
resource.getWidth();
resource.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
Toast.makeText(getApplicationContext(),"SAVED", Toast.LENGTH_LONG).show();
fileOutputStream.flush();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
refreshGallery(new_file);
}
public void refreshGallery(File file){
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
sendBroadcast(intent);
}
private File getDisc(){
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return new File(file, "FolderNamerYourChoice");
}
});
}
else {
// we will give warning to user that they haven't granted permissions.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)){
Toast.makeText(this, "Storage Permissions denied.", Toast.LENGTH_SHORT).show();
}
}
}
I am following Google's Taking Photos Simply tutorial, but it is failing on the temp file creation with an java.io.IOException: open failed: EACCES (Permission denied).
Here is my AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="pricez.fastshop_android" >
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>
<uses-feature android:required="true" android:name="android.hardware.camera"/>
<!-- Rest of file... -->
</manifest>
So, I guess that at least this is correct.
Here is the relevant code of my activity:
private String mCurrentPhotoPath;
private static final int REQUEST_TAKE_PHOTO = 1;
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "/JPEG_" + timeStamp + "_"; // I forgot from where I got this, but it was from some SO question that tried to deal with a similar problem
File absoluteFileDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsoluteFile(); // Same as above
Log.i("createImageFile", "absoluteFileDir.getAbsolutePath(): " + absoluteFileDir.getAbsolutePath()); // I/createImageFile﹕ absoluteFileDir.getAbsolutePath(): /storage/sdcard/Android/data/-redacted-/files/Pictures
File image = File.createTempFile(imageFileName, ".jpg", absoluteFileDir);
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
public void takePhoto(View view) {
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
Toast.makeText(this, "External SD card not mounted", Toast.LENGTH_LONG).show();
return;
}
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile;
try {
photoFile = createImageFile();
} catch (IOException e) {
Log.e("takePhoto", "IOException", e);
return;
}
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
// Get the dimensions of the View
ImageView imgv = (ImageView)findViewById(R.id.imgPreview);
int targetW = imgv.getWidth();
int targetH = imgv.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
//
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
imgv.setImageBitmap(bitmap);
}
}
EDIT 1:
I'm running this on a emulator, with SDK level 19.
EDIT 2:
If I delete the folders by hand, the getExternalStorageDirectory starts working fine. I'm leaving this question open because it's not really a fix. If everything keeps working in my code, I'm going to close in a few days.
I have no idea why (my guess is that something in the file locks has silently gone horribly wrong), but it started working when I deleted and recreated the folder (Kudos to #greenapps, would upvote if I could). What I can do at this point is to think how to recover somehow.
I don't think deleting the folder is the actual solution, but I have to move on at this point.
Plus, the situation might not present itself in an actual device.