Подтвердить что ты не робот

Получение исключения отказа от разрешения

У меня есть активность в моем приложении, которая позволяет пользователю выбирать несколько файлов с устройства один за другим, я использую такое намерение:

Intent intent = new Intent();
intent.setType("*/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, getString(R.string.select_attachments_activity_chooser_label)), SELECT_PICTURE);

Это работает отлично, я получаю Uri из выбранных файлов, они выглядят так:

content://com.android.providers.media.documents/document/image%3A42555

Затем, если файл является изображением, я его декодирую с помощью:

InputStream streamForDecodeBitmap = MyApp.getContext().getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(streamForDecodeBitmap, null, options);

Когда пользователь нажимает кнопку, я передаю список Uris другому действию с помощью намерения и в этом действии в AsyncTask, я кодирую файл в base64 для отправки по сети:

InputStream is = MyApp.getContext().getContentResolver().openInputStream(uri);
byte[] inputData = getBytes(is);
is.close();
return Base64.encodeToString(inputData, Base64.DEFAULT);

Проблема заключается в том, когда я открываю inputStream, иногда он работает, но большую часть времени я получаю это исключение:

E/AndroidRuntime(22270): Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{42858fe0 22270:co.uk.manifesto.freeagentapp/u0a246} (pid=22270, uid=10246) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS

Это все разрешения в моем манифесте:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>

Я тестирую устройство с KITKAT (API 19).

4b9b3361

Ответ 1

Также проверьте эти вопросы:
Android KitKat securityException при попытке чтения из MediaStore
Предотвращение отказа: открытие поставщика

Для этой же проблемы в KitKat я использовал это. Это вариант/обходной путь, который я нашел из одной из ссылок Stack Overflow, вы сможете выбирать файлы из Загрузки/Недавние.

public static final int KITKAT_VALUE = 1002;

Intent intent;

if (Build.VERSION.SDK_INT < 19) {
    intent = new Intent();
    intent.setAction(Intent.ACTION_GET_CONTENT);
    intent.setType("*/*");
    startActivityForResult(intent, KITKAT_VALUE);
} else {
    intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("*/*");
    startActivityForResult(intent, KITKAT_VALUE);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == KITKAT_VALUE ) {
        if (resultCode == Activity.RESULT_OK) {
            // do something here
        }
    }
}

Ссылка: Галерея Android на KitKat возвращает разные Uri для Intent.ACTION_GET_CONTENT http://developer.android.com/guide/topics/providers/document-provider.html#client

Ответ 2

Когда управление и данные возвращаются к вашей активности в

protected void onActivityResult(int reqCode, int resultCode, Intent data)

ваша деятельность, в то же время, дает разрешения на доступ к URL-адресу изображения в переданном намерении. Ваша активность будет в состоянии прочитать URL-адрес в намерении и отобразить изображение. Но вы не сможете передавать какие-либо разрешения другим действиям или новому потоку выполнения. Вот почему вы получаете SecurityException для android.permission.MANAGE_DOCUMENTS.

Один из способов избежать вашей проблемы с разрешением - это просто получить данные в действии с разрешениями. В вашем случае, из действия, у которого есть разрешение, ваша кодировка

InputStream is = getContentResolver().openInputStream(uri);
byte[] inputData = getBytes(is);
is.close();
String encoded = Base64.encodeToString(inputData, Base64.DEFAULT);

После того, как у вас есть закодированная строка, вы можете передать ее любым другим действиям, которые могут понадобиться, или вы можете передать ее в AsyncTask для отправки в другом месте.

Ответ 3

Убедитесь, что вы используете ContentResolver из Activity, который запрашивал контент, например:

activity.getContentResolver()  

Вместо MyApp.getContext().getContentResolver()

Это было очевидно для меня, и ему не нужно было добавлять android.permission.MANAGE_DOCUMENTS в манифест.

И вы вызываете намерение, используя это:

if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
    intent.setAction(Intent.ACTION_GET_CONTENT);
} else {
    intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
}

Дополнительная информация: https://developer.android.com/guide/topics/providers/document-provider.html#client

Ответ 4

Написание ACTION_OPEN_DOCUMENT не помогает полностью. После перезапуска ваше разрешение URI исчезнет даже после этого действия.

   if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            intent.setAction(Intent.ACTION_GET_CONTENT);
        } else {
            intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
        }

Чтобы закончить ответ Алесио Карвальо на эту документацию на той же странице, Существует хорошее объяснение разрешений URI и их сохранение.

Просто добавьте это в свой метод onActivityResult, и ваше разрешение сохраняется через перезапуск устройства. (Протестировано с помощью Google Pixel.)

override fun onActivityResult(requestCode:Int, resultCode:Int, intent:Intent?) {
if(requestCode == SELECT_PICTURE && intent != null){
    val uri = intent.getData()
    val takeFlags = intent.getFlags() and (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
    activity.getContentResolver().takePersistableUriPermission(uri, takeFlags)
    PreferenceHelper.setHeaderImageUri(activity, uri.toString())
  }
}

(извините kotlin lover... версия java находится внутри ссылки)

Ответ 5

Следует отметить, что если пользователь вручную удаляет разрешения для Uri, которые вы ранее сохранили, вы получите это же Исключение.

Настройки Android → Приложение → Имя приложения → Хранение → Очистить доступ

Вам нужно проверить, что вы все еще имеете доступ к Uri, когда используете его.