Reputation: 531
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)
Upvotes: 27
Views: 70417
Reputation: 8058
This permission is shown if you try to read file from download folder for uploading it to server.
What you can do is save the file which is selected to app folder path that way the file will have access to file for uploading it to server. Below are the two method you can use to get file from uri and save in app folder path.
private static String getDataColumnMethodOne(Context context, Uri uri) {
try (Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
String fileName = cursor.getString(0);
File file = new File(context.getCacheDir(), fileName);
String path = saveFileAndGetFilePath(context, uri, file);
if (!TextUtils.isEmpty(path)) {
return path;
}
return fileName;
}
//As some of can throw illegalArgumentException or SecurityException etc. Generic exception is caught here.
} catch (Exception exception) {
return null;
}
return null;
}
private static String saveFileAndGetFilePath(Context context, Uri uri, File file) {
try (FileOutputStream outputStream = new FileOutputStream(file)) {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
if (inputStream != null) {
int read;
int maxBufferSize = 1024 * 1024;
int bytesAvailable = inputStream.available();
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
inputStream.close();
}
} catch (Exception e) {
return "";
}
return file.getPath();
}
Upvotes: 0
Reputation: 31
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 .
Upvotes: 1
Reputation: 934
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.
Upvotes: 10
Reputation: 21
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();
}
Upvotes: 2
Reputation: 756
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;
Upvotes: 0
Reputation: 303
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.
Upvotes: 7
Reputation: 321
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.
Upvotes: 0
Reputation: 1
You can change allowBackup from true to false in Manifest's application part. It worked for me.
android:allowBackup="false"
Upvotes: -9
Reputation: 1530
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.
Upvotes: 0
Reputation: 1
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.
Upvotes: 0
Reputation: 1126
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
Upvotes: 5
Reputation: 9292
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.
Upvotes: 2