Image to custom directory android 11+ - java

-edit: i would love some input on what i am doing wrong here why is this not working i am currently working on a college project which has a deadline pretty soon i looked at a lot of tutorials online but nothing seems to address this topic specifically for android 11 everyone seems to be using mediastore api
-edit-2: i dont understand what i am doing wrong also i have not gotten any response yet i am not able to figure out the error this is for my college project i would be very thankful if someone helped me in finding out what is wrong why is this not getting any traction i am unsure
I want to add images to a custom directory in android 11 + i have an array of bitmaps and would like to store images in a custom directory
here are my permissions in manifest file
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<!-- Without this entry storage-permission entry will not be visible under app-info permissions list Android-10 and below -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
tools:ignore="ScopedStorage"/>
here is the java code
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && false == Environment.isExternalStorageManager()) {
Uri uri = Uri.parse("package:" + BuildConfig.APPLICATION_ID);
startActivity(new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri));
}
File direct = new File(Environment.getExternalStorageDirectory() + "/LaundryImages");
if (!direct.exists()) {
File wallpaperDirectory = new File(Environment.getExternalStorageDirectory() + "/LaundryImages");
wallpaperDirectory.mkdir();
}
String name = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.getDefault()).format(new Date());
TextView tv = (TextView)findViewById(R.id.textView);
File direct2 = new File(Environment.getExternalStorageDirectory() + "/LaundryImages/"+name);
direct2.mkdir();
int i=0;
for (Bitmap bm : l) {
i++;
// tv.setText(String.valueOf(i));
File file = new File(direct2,String.valueOf(i)+".jpg");
try {
FileOutputStream out = new FileOutputStream(file);
if(file == null)tv.setText("null");
bm.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
i tried to run it but it does not work it is creating the directories properly but it does not add the images
i tried to add images in the folder used permissions as i found on the internet and also checked whether permissions were there in my phone but still the images wont store

Related

Android cannot create directory

I cannot create directory, I have all the permissions and this in my Manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
In MainActivity onCreate, checks permission, if it has it should create a directory but it always returns a false:
if (!checkPermission()) requestPermission();
else {
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "receipts");
if (!folder.exists()) {
boolean bool = folder.mkdirs();
System.out.println(bool);
}
}
Any clue or hint to why? Thanks
Unfortunately, with the security updates brought by Android 11 and up, as #CommonsWare said, you simply can't write directories on external storage (sdcard).
Straight from the docs:
Access to directories
You can no longer use the ACTION_OPEN_DOCUMENT_TREE intent action to
request access to the following directories:
The root directory of the internal storage volume.
The root directory of each SD card volume that the device manufacturer considers to be reliable, regardless of whether the card
is emulated or removable. A reliable volume is one that an app can
successfully access most of the time.
The Download directory.
Additionally from the same place:
App-specific directory on external storage Starting in Android 11, apps
cannot create their own app-specific directory on external storage. To
access the directory that the system provides for your app, call
getExternalFilesDirs().
Your app has a system generated directory to store any information. This makes sense, of course, because at any given time the user could remove/format the sd card inside the device, and your app's data would be entirely lost.
From more docs:
You would use this to write:
//Write to a file
String filename = "myfile";
String fileContents = "Hello world!";
try (FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE)) {
fos.write(fileContents.toByteArray());
}
And to read a file:
//To read from the file
FileInputStream fis = context.openFileInput(filename
);
InputStreamReader inputStreamReader =
new InputStreamReader(fis, StandardCharsets.UTF_8);
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(inputStreamReader)) {
String line = reader.readLine();
while (line != null) {
stringBuilder.append(line).append('\n');
line = reader.readLine();
}
} catch (IOException e) {
// Error occurred when opening raw file for reading.
} finally {
String contents = stringBuilder.toString();
}
These are both within your app's "sandbox" folder. Because of this, you do not need to declare permissions.
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "receipts");
Change to:
File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "receipts");

My android java app cant see any .xml files in external storage

I`m making an app to test the Opencv haarcascades and it seems like my app does not see the .xml files. My permission include:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
My code for collecting the file names and path is:
public ArrayList<String []> getLongAndShortFileHandles(String root_dir) {
ArrayList<String[]> ret = new ArrayList<>();
String path = Environment.getExternalStorageDirectory().toString()+"/"+root_dir;
File directory = new File(path);
File[] files = directory.listFiles();
Log.e(TAG, "getLongAndShortFileHandles: Has dir "+path+", with "+((files==null) ? "null" : files.length) + " number of files");
for (int i = 0; i < Objects.requireNonNull(files).length; i++)
{
Log.e(TAG, "getLongAndShortFileHandles: HAS FILE "+files[i].getName());
String [] temp = new String [] {files[i].getAbsolutePath(),files[i].getName()};
ret.add(temp);
}
return ret;
}
The debug shows that no files are present when I call this function to populate my RecycleView subclass like so:
this.cascade_selector = (RecyclerView) findViewById(R.id.cascade_view);
this.cascade_selector.setAdapter(new FileAdaptah(getLongAndShortFileHandles("cascade_app/cascades"),this, CASCADE));
this.xml_ano_selector = (RecyclerView) findViewById(R.id.annotation_view);
this.xml_ano_selector.setAdapter(new FileAdaptah(getLongAndShortFileHandles("cascade_app/annotations"),this, ANNOTATION_XML));
The result in the app does show the output for second call but not for the first one.
If the first one is replaced with any other folder like DCIM, or Music it shows the files.
However if I add .xml file into any directory it will not be shown.
EDIT:
I was playing around with different directories and files and determined that the problem goes further then just .xml it seem to be all the ascii encoded text file formats I could think of. All binaries like .jpg, .wav, .mp4, .bin and etc. are found in when put in same directory.
EDIT (2):
So I`ve established that if I rename any of the text file extensions into any binary one (e.g. 50.xml -> 50.jpg they are detected by the script.
This prompted me to try different filename filters, but they didn't yield any success.
I`ve also tried to use Directory Stream instead but to no avail:
#RequiresApi(api = Build.VERSION_CODES.O)
public ArrayList<String[]> getFiles(String suffix, String root_dir){
ArrayList<String[]> ret = new ArrayList<String[]>();
try {
root_dir = Environment.getExternalStorageDirectory().toString() + "/" + root_dir;
Path dirName = Paths.get(root_dir);
DirectoryStream<Path> paths = Files.newDirectoryStream(dirName, "*.pdf");
paths.forEach(path -> {
Log.e(TAG, "getFiles: HAS FILE : "+path.toString());
if (path.endsWith(suffix)) {
String sPath = path.toString();
String[] splitted = sPath.split(File.separator);
ret.add(new String[]{sPath, splitted[splitted.length - 1]});
}
});
} catch (IOException exception) {
exception.printStackTrace();
}
return ret;
}
I`ve started to suspect it might be a bug, so I provide my environment information: My android studio is version 4.1.2 and my target SDK is 30, while my minimum accepted is 19. My test device is a physical Galaxy A40 with android 11.
EDIT (3):
So I've noticed that the second snippet for getFiles has leftover glob expression from the point I've copied the original snippet. Out of interest I've modified and removed it but in either case nothing changed.
EDIT (4):
So I've tried to access file directly with the following code:
this.test = (Button) findViewById(R.id.select_to_test);
this.test.setOnClickListener(v -> {
String path = Environment.getExternalStorageDirectory().toString()+"/cascade_app/cascades/50.xml";
Intent intent = new Intent(v.getContext(),CheckCascade.class);
intent.putExtra("fh",path);
File debugFile = new File(path);
Toast.makeText(this, "File "+path+" does "+((debugFile.exists())? "exist":"not exist"), Toast.LENGTH_SHORT).show();
startActivity(intent);
});
}
and it seem to detect it no problem.
So after some time I was helped by a kind person who suggested to check if my app needs
this permission. This solved the problem! I hope this can help people who will have same issue.

Android 11 open failed: EACCES (Permission denied)

I am developing an app. In which I am uploading different file types (e.g. docx, pdf, zip) to a WAMP Server. Below is path of file to my internal Storage.
/storage/emulated/0/WhatsApp/Media/WhatsApp Documents/api.txt
I have added and allowed storage permission in Manifest file and also on runtime for reading a file. However there is no Internal Storage Permission request available.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
and also for Android 10 I was using this attribute also
android:requestLegacyExternalStorage="true"
But I am getting this error on Android 11 OS a.k.a Android R onboard Samsung Galaxy when I am reading file from Internal Storage for uploading.
java.io.FileNotFoundException: /storage/emulated/0/WhatsApp/Media/WhatsApp Documents/api.txt: open failed: EACCES (Permission denied)
On An Android 11 device your app only has access to its own files.
And to general mediafies in public directories.
Try to list the files in that whatsapp directory and you will see that
they are not listed.
You have two options to read the file.
Let the user pick the file with ACTION_OPEN_DOCUMENT. Request
MANAGE_EXTERNAL_STORAGE in manifest and let the user confirm.
Ordinary request is not working for the MANAGE_EXTERNAL_STORAGE permission. This permission must be set in Android setting by user.
You can try to use the android:preserveLegacyExternalStorage="true" tag in the manifest file in the application tag. This tag is used to access the storage in the android 11 devices. And for more detail follow this link it will explain you more as per your requirement.
I search a lot of time and get the solution that adds <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> in the manifest file and try to get the file access permission in the android 11 phones. Then you will open and read the file from the storage.
But the thing is that the play store does not allow you to use of the MANAGE_EXTERNAL_STORAGE permission in your app. it will take time to give access to the developer to use it to access all the files.
Here the link is
For Android 11 or above use the code below on the onCreate() of the activity. It will run once and ask for permission.
if (Build.VERSION.SDK_INT >= 30){
if (!Environment.isExternalStorageManager()){
Intent getpermission = new Intent();
getpermission.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivity(getpermission);
}
}
Next declare the MANAGE_EXTERNAL_STORAGE permission in the manifest.
However, the problem with this method is that you cannot upload it to play store if you don't have a good reason on why you need access to all files.
On An Android 11 device your app only has access to its own files.
And to general mediafies in public directories.
Try to list the files in that whatsapp directory and you will see that they are not listed.
You have two options to read the file.
Let the user pick the file with ACTION_OPEN_DOCUMENT.
Request MANAGE_EXTERNAL_STORAGE in manifest and let the user confirm.
Try to get path with this method.....
public static String getDriveFile(Context context, Uri uri) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getCacheDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return file.getPath();
}
I worked on Android application based on Cordova and I had to change the version the application was focused on to save files in the device.
I change the API Level version to 28 and works correctly. This change is used to avoid the scoped storage feature added on Android 10.
This information is extracted from this page:
https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage
I hope this information is helpful.
First, check whether you have implemented scoped storage logic in-app.
You can also use android:requestLegacyExternalStorage="true"
But this legacyStoragePermission is limited to version 10.
You need to implement scoped logic.
Also, check whether your targetSDKVersion value is 30 or greater or not,
this is needed if you are using the app in Device android version 30 or more.
I spent a week getting the info on how to read files from External storage on Android 11 API 29 and Later.
You still need Manifest permission READ_EXTERNAL_STORAGE.
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// Open a specific media item using ParcelFileDescriptor.
ContentResolver resolver = getApplicationContext()
.getContentResolver();
// "rw" for read-and-write;
// "rwt" for truncating or overwriting existing file contents.
String readOnlyMode = "r";
// uri - I have got from onActivityResult
//uri = data.getData();
ParcelFileDescriptor parcelFile = resolver.openFileDescriptor(uri, readOnlyMode);
FileReader fileReader = new FileReader(parcelFile.getFileDescriptor());
BufferedReader reader = new BufferedReader(fileReader);
String line;
while ((line = reader.readLine()) != null) {
//Your action here!!!
}
reader.close();
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
Read this: Open a media file.
from android 10, it is not possible to access all the files through your app,
so while saving data for example image , use following code and then you can read it normally. getExternalFilesDir is important
File file=new File(getActivity().getApplicationContext().getExternalFilesDir(null),"/scantempo"+"/Image_" + System.currentTimeMillis() + ".jpg");
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
Uri uri=Uri.fromFile(file);
return uri;
After you update your app to target Android 11, the system ignores the requestLegacyExternalStorage flag.
For read files from external storage following codes:
fun startFilePicker(activity: Activity, requestCode: Int) {
val pickIntent: Intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
type = "*/*"
}
activity.startActivityForResult(pickIntent, requestCode)
}
override fun onActivityResult(requestCode : Int , resultCode : Int , data : Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val fileUri=data.data
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(
fileUri,
takeFlags
)
}
Create temp file
fun createTempFileForUpload(context:Context,fileUri:Uri){
val docFile = DocumentFile.fromSingleUri(context, fileUri)
val fileName: String = if (docFile == null || docFile.name.isNullOrBlank()) {
FilenameUtils.getName(fileUri.path)
} else {
docFile.name!!
}
val tempFile = File.createTempFile("tempFile", "tmp")
val ins: InputStream = context.contentResolver.openInputStream(fileUri)!!
val out: OutputStream = FileOutputStream(tempFile)
val buf = ByteArray(1024)
var len: Int = ins.read(buf)
while (len > 0) {
out.write(buf, 0, len)
len = ins.read(buf)
}
out.close()
ins.close()
tempFile.mkdirs()
}
Then you can upload temp file .
You can change allowBackup from true to false in Manifest's application part. It worked for me.
android:allowBackup="false"

java.io.FileNotFoundException: (Permission denied) when writing an object using ObjectOutputStream

I have been trying to work around this for several hours and I am extremely frustrated so I am coming to you guys for some guidance.
I am trying to save and retrieve a User object I have created. I want to make it so that I can save and retrieve this User object from any intent throughout my application, so I decided to go with a FileInput and Output stream. I have included my code for both below.
Here is my output data method:
public static void serializeDataOut(User ish) {
try {
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
File newFile = new File(path + "myFile.ser");
FileOutputStream fos = new FileOutputStream(newFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(ish);
oos.flush();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
And here is my input data method:
public static User serializeDataIn(){
try{
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
FileInputStream fin = new FileInputStream(path + "myFile.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
User iUser = (User) ois.readObject();
ois.close();
return iUser;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
Note: both of these methods reside inside my User class, which also implements Serializable.
The whole error with the file path looks like this: java.io.FileNotFoundException: /storage/emulated/0myFile.ser (Permission denied) and it appeared at this line: FileOutputStream fos = new FileOutputStream(newFile); when I called it from a different intent like so: User.serializeDataOut(addingUser); in which addingUser was a valid User object.
The first thing I did after seeing (Permission denied) in the exception log, was go into my manifest and check if I was allowing my application to read and write to storage, which I did in fact do. I have included my permissions below:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Then I read that some people were having this error if they had the wrong path, more specifically not including the absolute path, which I then edited my code to include the Environment.getExternalStorageDirectory().getAbsolutePath(); part, which I am pretty sure I am using correctly.
I also made sure that, since I am testing this on an emulator, that I had enabled an SD card and the emulator had an SD folder. I checked and it indeed did have an SD card folder, and I also tested this application on an S8 and I got the same error.
What exactly am I doing wrong here? All I want to do is save one User object and retrieve it somewhere else, and I am perfectly ok with a previous file being overwritten and only having one User saved at a time.
Also something that is probably related I just noticed: about every 3-5 seconds in my Android Monitor, an error keeps on popping up non stop even after I kill my application. The error looks like this: onFatalError, processing error from engine(4)
com.google.android.apps.gsa.shared.speech.a.g: Error reading from input stream Although I can only assume this isn't the source of the problem, I just wanted to add it in, in case it could help. Thanks
You've added the permission in manifest, So I'm sure you are not asking runtime permissions. If you are using SDK 23 or higher, Ask runtime permission. For reference I'm adding some snippet here:
if(Build.VERSION.SDK_INT>22){
requestPermissions(new String[] {YOUR_PERMISSIONS AS STRING}, 1);
}
and to check whether permission is granted or not, you need to use onRequestPermissionResults() method.
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case 1: {
if (!(grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED)) {
Toast.makeText(addAlarm.this, "Permission denied to access your location.", Toast.LENGTH_SHORT).show();
}
}
}
}
This java.io.FileNotFoundException: /storage/emulated/0myFile.ser looks like you are missing a '/' in the path.
Use
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + '/';
Beginning in Android 6.0 (API level 23), users grant permissions to
apps while the app is running
Everything you need to know is in :
https://developer.android.com/training/permissions/requesting.html
The other error has nothing to do with it

createNewFile - open failed: ENOENT (No such file or directory)

I can't figure out what's going wrong here...I've tried writing this more succicinctly, that didn't work. I put in all the extra strings after reading other suggestions with this problem. Not helping. No clue what's happening. Could it be permissions-related? AFAIK I'm trying to write to internal memory and that doesn't need special permissions?
public void outputBitmap(){
String path = Environment.DIRECTORY_PICTURES.toString();
File folder = new File(path + "/Blabla");
String filename = new SimpleDateFormat("yyMMddHHmmss").format(Calendar.getInstance().getTime()) + ".png";
try {
if (!folder.exists()) {
folder.mkdirs();
System.out.println("Making dirs");
}
File myFile = new File(folder.getAbsolutePath(), filename);
myFile.createNewFile();
FileOutputStream out = new FileOutputStream(myFile);
myBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
It goes "Making dirs" every time, the directory is not staying made, or something. When it gets to myFile.createNewFile(); it gives the error message "open failed: ENOENT (No such file or directory)"
Not sure if it's related, but the information I am trying to output is from:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
myBitmap = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.RGB_565);
Canvas pngCanvas = new Canvas(myBitmap);
...[some maths and stuff]
canvas.drawLine(...);
pngCanvas.drawLine(...);
}
I thought I should be able to use the same canvas for the bitmap, but that caused crashed, so I'm writing the same information to both canvases. So...I don't know if that's related to the issue or a totally different bad issue or what.
Been searching all kinds of questions that seemed similar, but couldn't find any solutions that worked for me. I've been trying to solve this for days now. Anyone know what's going wrong?
Thanks
You are not using Environment.DIRECTORY_PICTURES correctly. It is not a folder by itself, you need to use it as a parameter to getExternalStoragePublicDirectory() method.
Check here : http://developer.android.com/reference/android/os/Environment.html#getExternalStoragePublicDirectory(java.lang.String)
Possible Issue:
Make sure you have given following required permission in your manifest file.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
And for Marhsmallow devices, make sure Contacts Groups Permissions is granted too by device user.
Ref: http://developer.android.com/training/permissions/requesting.html
Just change the begining of your code from this:
public void outputBitmap(){
String path = Environment.DIRECTORY_PICTURES.toString();
File folder = new File(path + "/Blabla");
To this:
public void outputBitmap(){File folder = new File(getActivity().getExternalFilesDir(null) + IMAGE_DIRECTORY + "whatever you want for your directory name");

Categories