Issue
I have a photo editing android app that users can choose the output directory of the the result photos. Problem is Google made a change on sdcard write permission with the KITKAT version and devices with Android KITKAT version won't allow apps to write secondary sdcards. Now I need to check if the choosen directory by user has granted the permission and won't throw EACCES error. I am already checking canRead and canWrite but these won't help. Could you please tell me how can I check if the choosen directory won't throw EACCES. My only solution is trying to write a file in a try catch, however I am hoping there is better way to do it.
[update k3b 2016-09-19]
i tried this on my android-4.4 but without success
Uri uri = Uri.fromFile(file);
int permissionCode =
context.checkCallingOrSelfUriPermission(uri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (permissionCode == PackageManager.PERMISSION_DENIED) {
// on my android-4.4 i always get PERMISSION_DENIED even
// if i can overwrite the file
return false;
}
Solution
try {
Process p = new ProcessBuilder("ls", "-l", "-s", dir.getCanonicalPath()).start();
String line;
ArrayList<String> lineOut = new ArrayList<>();
BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = error.readLine()) != null) {
Log.e(TAG, "ls error = "+line);
}
error.close();
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
lineOut.add(line);
}
input.close();
String[] strings = lineOut.toArray(new String[]{});
List<FilesLS.FileEntry> fileEntries = FilesLS.processNewLines(strings);
for(FilesLS.FileEntry file : fileEntries){
Log.d(TAG, file.name +" = " + file.permissions);
}
} catch (IOException e) {
e.printStackTrace();
}
And some edits to this class
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class FilesLS {
/**
* Entry type: File
*/
public static final int TYPE_FILE = 0;
/**
* Entry type: Directory
*/
public static final int TYPE_DIRECTORY = 1;
/**
* Entry type: Directory Link
*/
public static final int TYPE_DIRECTORY_LINK = 2;
/**
* Entry type: Block
*/
public static final int TYPE_BLOCK = 3;
/**
* Entry type: Character
*/
public static final int TYPE_CHARACTER = 4;
/**
* Entry type: Link
*/
public static final int TYPE_LINK = 5;
/**
* Entry type: Socket
*/
public static final int TYPE_SOCKET = 6;
/**
* Entry type: FIFO
*/
public static final int TYPE_FIFO = 7;
/**
* Entry type: Other
*/
public static final int TYPE_OTHER = 8;
/**
* Device side file separator.
*/
public static final String FILE_SEPARATOR = "/"; //$NON-NLS-1$
/**
* Regexp pattern to parse the result from ls.
*/
private static Pattern sLsPattern = Pattern
.compile("^([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])\\s+(\\S+)\\s+ (\\S+)\\s+(\\d{4}-\\d\\d-\\d\\d)\\s+(\\d\\d:\\d\\d)\\s+(.*)$"); //$NON-NLS-1$ \s+([\d\s,]*)
public static List<FileEntry> processNewLines(String[] lines) {
List<FileEntry> listOfFiles = new ArrayList<FileEntry>();
for (String line : lines) {
// no need to handle empty lines.
if (line.length() == 0) {
continue;
}
// run the line through the regexp
Matcher m = sLsPattern.matcher(line);
if (m.matches() == false) {
continue;
}
// get the name
String name = m.group(6);
// get the rest of the groups
String permissions = m.group(1);
String owner = m.group(2);
String group = m.group(3);
// String size = m.group(4);
String date = m.group(4);
String time = m.group(5);
String info = null;
// and the type
int objectType = TYPE_OTHER;
switch (permissions.charAt(0)) {
case '-':
objectType = TYPE_FILE;
break;
case 'b':
objectType = TYPE_BLOCK;
break;
case 'c':
objectType = TYPE_CHARACTER;
break;
case 'd':
objectType = TYPE_DIRECTORY;
break;
case 'l':
objectType = TYPE_LINK;
break;
case 's':
objectType = TYPE_SOCKET;
break;
case 'p':
objectType = TYPE_FIFO;
break;
}
// now check what we may be linking to
if (objectType == TYPE_LINK) {
String[] segments = name.split("\\s->\\s"); //$NON-NLS-1$
// we should have 2 segments
if (segments.length == 2) {
// update the entry name to not contain the link
name = segments[0];
// and the link name
info = segments[1];
// now get the path to the link
String[] pathSegments = info.split(FILE_SEPARATOR);
if (pathSegments.length == 1) {
// the link is to something in the same directory,
// unless the link is ..
if ("..".equals(pathSegments[0])) { //$NON-NLS-1$
// set the type and we're done.
objectType = TYPE_DIRECTORY_LINK;
} else {
// either we found the object already
// or we'll find it later.
}
}
}
// add an arrow in front to specify it's a link.
info = "-> " + info; //$NON-NLS-1$;
}
FileEntry entry = new FileEntry();
entry.permissions = permissions;
entry.name = name;
// entry.size = size;
entry.date = date;
entry.time = time;
entry.owner = owner;
entry.group = group;
if (objectType == TYPE_LINK) {
entry.info = info;
}
listOfFiles.add(entry);
}
return listOfFiles;
}
public final static class FileEntry {
String name;
String info;
String permissions;
String size;
String date;
String time;
String owner;
String group;
int type;
}
}
Answered By - user486312
Answer Checked By - Mary Flores (JavaFixing Volunteer)