Android M Write to Sd Card - Permission Denied

Android M write to SD Card - Permission Denied

As suggested by @CommonsWare here we have to use the new Storage Access Framework provided by android and will have to take permission from user to write SD card file as you said this is already written in the File Manager Application ES File Explorer.

Here is the code for Letting the user choose the "SD card" :

startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), requestCode);

which will look somewhat like this :

Sample Image

And get the Document path in pickedDirand pass further in your copyFile block
and use this path for writing the file :

public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode != RESULT_OK)
return;
else {
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
copyFile(sdCard.toString(), "/File.txt", path + "/new", pickedDir);
}
}

public void copyFile(String inputPath, String inputFile, String outputPath, DocumentFile pickedDir) {

InputStream in = null;
OutputStream out = null;
try {

//create output directory if it doesn't exist
File dir = new File(outputPath);
if (!dir.exists()) {
dir.mkdirs();
}

in = new FileInputStream(inputPath + inputFile);
//out = new FileOutputStream(outputPath + inputFile);

DocumentFile file = pickedDir.createFile("//MIME type", outputPath);
out = getContentResolver().openOutputStream(file.getUri());

byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();

// write the output file (You have now copied the file)
out.flush();
out.close();
} catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}

Android write to secondary external storage (Permission denied)

Removable micro SD cards are not writable since Android Kitkat.

Except for one app specific directory.

Write a file in the SD card of an Android 7 device

I have decided not to use the Android API. Since the application has elevated privileges, I have created the file by executing a shell command. This is the code to create a file (works with removable SD card folder):

public static String createFile(String filePath)
{
String returnValue = "";

try
{
Runtime runtime = Runtime.getRuntime();

String[] command = new String[]{ "su", "0", "touch", filePath};

Process p = runtime.exec(command);
p.waitFor();

java.io.BufferedReader errorIn = new java.io.BufferedReader(
new java.io.InputStreamReader(p.getErrorStream()));

String line = "";
while ((line = errorIn.readLine()) != null)
returnValue += line + "\n";

}
catch (IOException | InterruptedException e)
{
e.printStackTrace();
}

return returnValue;
}

android - sd card writing permission denied (EACCES)

Thanks to @VladMatvienko, I was able to write a code that allows me to read, write and edit any directory or subdirectory on my SD card.

This is my complete code that you can copy and paste in your MainActivity to test the Storage Access Framework:

import android.app.Activity;
import android.content.Intent;
import android.content.UriPermission;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.support.v4.provider.DocumentFile;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

public class MainActivity extends AppCompatActivity {

int SAVE_REQUEST_CODE = 102;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

}

public void saveFile(View view) {
List<UriPermission> permissions = getContentResolver().getPersistedUriPermissions();
if (permissions != null && permissions.size() > 0) {

//pickedDir is the directory the user selected (I chose SD's root).
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, permissions.get(0).getUri());

//=====You can use these lines to write into an existent folder or directory========================
DocumentFile aux = pickedDir.findFile("aaabrao");//aaabrao is the name of a existing folder in my SD.

//Use DocumentFile file = pickedDir.createDirectory("aaabrao"); to create a new folder in the pickedDir directory.

if(aux != null) {
//Creating the object "file" is essencial for you to write "some text" INSIDE the TXT file. Otherwise, your TXT will be a blank.
DocumentFile file = aux.createFile("text/plain", "try5.txt");
writeFileContent(file.getUri());
}
//==================================================================================================

//=====You can use these lines to write to the primary chosen directory (SD's root, in my case)====
DocumentFile file2 = pickedDir.createFile("text/plain", "try5.txt");
writeFileContent(file2.getUri());
//==================================================================================================

} else {

startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), SAVE_REQUEST_CODE);
}
}

public void onActivityResult(int requestCode, int resultCode, Intent resultData) {

if (resultCode == Activity.RESULT_OK) {
if (requestCode == SAVE_REQUEST_CODE) {
if (resultData != null) {
Uri treeUri=resultData.getData();

//This line gets your persistent permission to write SD (or anywhere else) without prompting a request everytime.
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

//These lines will write to the choosen directory (SD's root was my chosen one). You could also write to an existent folder inside SD's root like me in saveFile().
DocumentFile pickedDir = DocumentFile.fromTreeUri(getBaseContext(), treeUri);
DocumentFile file = pickedDir.createFile("text/plain", "try5.txt");
writeFileContent(file.getUri());

}
}
}
}

private void writeFileContent(Uri uri) {
try {
ParcelFileDescriptor pfd = this.getContentResolver().openFileDescriptor(uri, "w");

FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());

String textContent = "some text";

fileOutputStream.write(textContent.getBytes());

fileOutputStream.close();
pfd.close();

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

I made this activity_main to call the saveFile() using a button:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.patrick.testasdcompermissaoemexecucao.MainActivity">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button2"
android:text="Write"
android:onClick="saveFile"
android:layout_below="@+id/imageButton"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
tools:ignore="UnknownId"
android:layout_gravity="center" />
</RelativeLayout>

You must change

tools:context="com.example.patrick.testasdcompermissaoemexecucao.MainActivity">

for your app's directory. If you don't know how, create a blank project and copy the equivalent line before pasting my code there.

No changes are needed in the Manifest file.

Good Luck!

Android M write to SD Card - Permission Denied

As suggested by @CommonsWare here we have to use the new Storage Access Framework provided by android and will have to take permission from user to write SD card file as you said this is already written in the File Manager Application ES File Explorer.

Here is the code for Letting the user choose the "SD card" :

startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), requestCode);

which will look somewhat like this :

Sample Image

And get the Document path in pickedDirand pass further in your copyFile block
and use this path for writing the file :

public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode != RESULT_OK)
return;
else {
Uri treeUri = resultData.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
copyFile(sdCard.toString(), "/File.txt", path + "/new", pickedDir);
}
}

public void copyFile(String inputPath, String inputFile, String outputPath, DocumentFile pickedDir) {

InputStream in = null;
OutputStream out = null;
try {

//create output directory if it doesn't exist
File dir = new File(outputPath);
if (!dir.exists()) {
dir.mkdirs();
}

in = new FileInputStream(inputPath + inputFile);
//out = new FileOutputStream(outputPath + inputFile);

DocumentFile file = pickedDir.createFile("//MIME type", outputPath);
out = getContentResolver().openOutputStream(file.getUri());

byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();

// write the output file (You have now copied the file)
out.flush();
out.close();
} catch (FileNotFoundException fnfe1) {
/* I get the error here */
Log.e("tag", fnfe1.getMessage());
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}

Android - ask write to SD card permission dialog

I found open source file manager. Looked at the code and finally found the solution.

Only works on Android N (7.0.0) (api 24) and above.

First get root path of SD card and show user permission dialog.

public void takeCardUriPermission(String sdCardRootPath) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
File sdCard = new File(sdCardRootPath);
StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
StorageVolume storageVolume = storageManager.getStorageVolume(sdCard);
Intent intent = storageVolume.createAccessIntent(null);
try {
startActivityForResult(intent, 4010);
} catch (ActivityNotFoundException e) {
}
}
}

When user accepts the request, onActivityResult() gets triggered and we can save uri from intent data

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == 4010) {

Uri uri = data.getData();

grantUriPermission(getPackageName(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);

final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);

getContentResolver().takePersistableUriPermission(uri, takeFlags);
}
}

Now we can retrieve uri of SD card root and use it with Storage Access Framework

public Uri getUri() {
List<UriPermission> persistedUriPermissions = getContentResolver().getPersistedUriPermissions();
if (persistedUriPermissions.size() > 0) {
UriPermission uriPermission = persistedUriPermissions.get(0);
return uriPermission.getUri();
}
return null;
}

Request write permission for SD Card

Micro SD cards are read only on modern Android devices.

Only one app specific directory is writable.

On Android Q+ the card is not even readable except for that directory.

You can however use SAF for full access.



Related Topics



Leave a reply



Submit