Как проверить разрешение предоставлено для пути к каталогу и не будет превышать ошибку EACCES?

У меня есть приложение для редактирования фотографий для Android, в котором пользователи могут выбрать выходной каталог результатов. Проблема заключается в том, что Google внесла изменения в разрешение на запись SDK с версией KITKAT, а устройства с версией Android KITKAT не позволят приложениям записывать вторичные SD-карты. Теперь мне нужно проверить, предоставил ли выбранный каталог пользователю разрешение и не выбросит ошибку EACCES. Я уже проверяю canRead и canWrite, но это не поможет. Не могли бы вы рассказать мне, как я могу проверить, не выбрал ли выбранный каталог EACCES. Мое единственное решение пытается записать файл в try catch, однако я надеюсь, что есть лучший способ сделать это.

[обновление k3b 2016-09-19]

Я пробовал это на своем Android-4.4, но без успеха

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

Ответы

Ответ 1

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

И некоторые отредактировали этот класс

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

Ответ 2

Добавьте в массив, какие разрешения вам нужны: private static final int REQUEST_CODE_PERMISSION = 2;   Строка [] mPermission = {Manifest.permission.INTERNET, Manifest.permission.CHANGE_WIFI_STATE,           Manifest.permission.CHANGE_NETWORK_STATE,           Manifest.permission.ACCESS_WIFI_STATE};

Добавьте это в onCreate или где вы хотите:

    try {
        if (ActivityCompat.checkSelfPermission(this, mPermission[0])
                != MockPackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(this, mPermission[1])
                        != MockPackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(this, mPermission[2])
                        != MockPackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(this, mPermission[3])
                        != MockPackageManager.PERMISSION_GRANTED) {    Log.e("TAGTAG", "DENIED");


            ActivityCompat.requestPermissions(this,
                    mPermission, REQUEST_CODE_PERMISSION);

            // If any permission aboe not allowed by user, this condition will execute every tim, else your else part will work
        }
        else
        {
            Log.e("TAGTAG", "GRANTED");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

` Объявляет использование разрешений в Manifest.xml