I am making an android app which lets the user transfer some files from internal storage to external storage(SD card) using SAF.
This is how I call an intent to let the user choose the SD card directory.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, 42);
And this is my onActivityResult
public void onActivityResult(int requestCode, int resultCode, Intent data) {
treeUri = data.getData();
final int takeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getActivity().getContentResolver().takePersistableUriPermission(treeUri, takeFlags);
}
I am taking permission for whole SD card so that i can move or delete any file in sd card any time .The problem is that even after taking permission i am not able to move or delete any file in SD card.
How should i move a file from internal Storage to external(SD card) for android 5.0 and above.
EDIT:This is the code i am using to move files.
public static void MoveFiles(File src, File dst) throws IOException
{
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try
{
inChannel.transferTo(0, inChannel.size(), outChannel);
}
finally
{
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
src.delete();
}
}
This is how I finally solved the issue.
First call an intent to let the user grant write permission for whole SD card.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, 42);
Then on onActivityResult take write permission.
public void onActivityResult(int requestCode, int resultCode, Intent data) {
treeUri = data.getData();
final int takeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getActivity().getContentResolver().takePersistableUriPermission(treeUri, takeFlags);
}
And this is the code I used to copy files to SD card.
public static boolean copy(File copy, String directory, Context con) {
static FileInputStream inStream = null;
static OutputStream outStream = null;
DocumentFile dir= getDocumentFileIfAllowedToWrite(new File(directory), con);
String mime = mime(copy.toURI().toString());
DocumentFile copy1= dir.createFile(mime, copy.getName());
try {
inStream = new FileInputStream(copy);
outStream =
con.getContentResolver().openOutputStream(copy1.getUri());
byte[] buffer = new byte[16384];
int bytesRead;
while ((bytesRead = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inStream.close();
outStream.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
The above code uses the following two methods.
getDocumentFileIfAllowedToWrite method which returns DocumentFile if allowed to write.
public static DocumentFile getDocumentFileIfAllowedToWrite(File file, Context con) {
List<UriPermission> permissionUris = con.getContentResolver().getPersistedUriPermissions();
for (UriPermission permissionUri : permissionUris) {
Uri treeUri = permissionUri.getUri();
DocumentFile rootDocFile = DocumentFile.fromTreeUri(con, treeUri);
String rootDocFilePath = FileUtil.getFullPathFromTreeUri(treeUri, con);
if (file.getAbsolutePath().startsWith(rootDocFilePath)) {
ArrayList<String> pathInRootDocParts = new ArrayList<String>();
while (!rootDocFilePath.equals(file.getAbsolutePath())) {
pathInRootDocParts.add(file.getName());
file = file.getParentFile();
}
DocumentFile docFile = null;
if (pathInRootDocParts.size() == 0) {
docFile = DocumentFile.fromTreeUri(con, rootDocFile.getUri());
} else {
for (int i = pathInRootDocParts.size() - 1; i >= 0; i--) {
if (docFile == null) {
docFile = rootDocFile.findFile(pathInRootDocParts.get(i));
} else {
docFile = docFile.findFile(pathInRootDocParts.get(i));
}
}
}
if (docFile != null && docFile.canWrite()) {
return docFile;
} else {
return null;
}
}
}
return null;
}
And mime method which returns the mime type of the file.
public static String mime(String URI) {
static String type;
String extention = MimeTypeMap.getFileExtensionFromUrl(URI);
if (extention != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extention);
}
return type;
}
I have tested the above code with Android Lollipop and Marshmallow.
EDIT: This is the link to the FileUtils class.