Permission to Write to the Sd Card

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.

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 - 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;
}

No permission to WRITE on SD Card

You have to handle runtime permission for this,Take a look in this steps

Copy this Class:

    public class PermissionHandler {


// Run Time Permission List
private static final String MNC = "MNC";

// Calendar group.
public static final String READ_CALENDAR = Manifest.permission.READ_CALENDAR;
public static final String WRITE_CALENDAR = Manifest.permission.WRITE_CALENDAR;

// Camera group.
public static final String CAMERA = Manifest.permission.CAMERA;

// Contacts group.
public static final String READ_CONTACTS = Manifest.permission.READ_CONTACTS;
public static final String WRITE_CONTACTS = Manifest.permission.WRITE_CONTACTS;


// Location group.
public static final String ACCESS_FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
public static final String ACCESS_COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;

// Microphone group.
public static final String RECORD_AUDIO = Manifest.permission.RECORD_AUDIO;

// Phone group.
public static final String READ_PHONE_STATE = Manifest.permission.READ_PHONE_STATE;
public static final String CALL_PHONE = Manifest.permission.CALL_PHONE;
public static final String READ_CALL_LOG = Manifest.permission.READ_CALL_LOG;
public static final String WRITE_CALL_LOG = Manifest.permission.WRITE_CALL_LOG;
public static final String ADD_VOICEMAIL = Manifest.permission.ADD_VOICEMAIL;
public static final String USE_SIP = Manifest.permission.USE_SIP;
public static final String PROCESS_OUTGOING_CALLS = Manifest.permission.PROCESS_OUTGOING_CALLS;

// Sensors group.
public static final String BODY_SENSORS = Manifest.permission.BODY_SENSORS;
public static final String USE_FINGERPRINT = Manifest.permission.USE_FINGERPRINT;

// SMS group.
public static final String SEND_SMS = Manifest.permission.SEND_SMS;
public static final String RECEIVE_SMS = Manifest.permission.RECEIVE_SMS;
public static final String READ_SMS = Manifest.permission.READ_SMS;
public static final String RECEIVE_WAP_PUSH = Manifest.permission.RECEIVE_WAP_PUSH;
public static final String RECEIVE_MMS = Manifest.permission.RECEIVE_MMS;
public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";

// Bookmarks group.
public static final String READ_HISTORY_BOOKMARKS = "com.android.browser.permission.READ_HISTORY_BOOKMARKS";
public static final String WRITE_HISTORY_BOOKMARKS = "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS";


public static boolean isPermissionGranted(Activity mContext, String Permission, String Text, int PermissionCode) {

if (ContextCompat.checkSelfPermission(mContext, Permission) != PackageManager.PERMISSION_GRANTED) {
reqPermission(mContext, Text, PermissionCode, Permission);
return false;
}

return true;
}


public static void reqPermission(Activity mContext, String Text, int PermissionCode, String Permission) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(mContext, Permission)) {
ActivityCompat.requestPermissions(mContext, new String[]{Permission}, PermissionCode);
} else {
openAlertDialog(mContext, Text);
}
}

public static void openAlertDialog(final Context mContext, String Text) {

new AlertDialog.Builder(mContext)
.setTitle("Permission")
.setMessage(mContext.getResources().getString(R.string.app_name) + " needs to access " + Text + " Permission for using this features from Setting >> Permissions.")
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Your code
String packageName = "you.App.Id";
try {
//Open the specific App Info page:
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + packageName));
mContext.startActivity(intent);

} catch (ActivityNotFoundException e) {
//e.printStackTrace();
//Open the generic Apps page:
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
mContext.startActivity(intent);

}

}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
})
.show();


}

}

Before you save image you need to check this

if (PermissionHandler.isPermissionGranted((Activity) mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE, "External Storage", 1000)) {
// Save your Image code
}

Thats it.Happy Coding :)

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());
}
}

Has SD card writing been blocked?

Yes writing to the sd card is blocked in modern Android versions.

Mostly you have read acces to the whole sd card.

Writing only to one app specific directory which if you are lucky is available in the second item returned by getExternalFilesDirs().

If you want to write to the whole sd card then use the Storage Access Framework.

For instance Intent.ACTION_OPEN_DOCUMENT_TREE.



Related Topics



Leave a reply



Submit