user65721 user65721 - 2 months ago 12
Android Question

How to check permission is granted for a directory path and won't thorow EACCES error?

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

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