Как сохранить видео с помощью API mediastore в Android Q и выше? (Видео находится во внутреннем/внешнем хранилище)

#android

Вопрос:

После ограничений, введенных в Android 10 и 11, мне трудно извлечь видео из внутреннего / внешнего хранилища и скопировать его в каталог конкретного приложения, а затем использовать(возникает ошибка «Отказано в разрешении»). Для изображения я реализовал следующее:

 Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
Bitmap bm = testObj.getScaledBitmap(bitmap);//used own method
Uri uriimg = testObj.storeImage(internalPath   imageName, bm);//used own method
 

Я не могу сделать то же самое для видео.
Не могли бы вы предоставить код для извлечения видео с помощью api Mediastore и сохранить его в каталоге конкретного приложения или предоставить пример извлечения видео из api mediastore?
Я также очень признателен, если я смогу получить пример использования scopedstorage с использованием JAVA, потому что большинство примеров, которые я нашел, используют только Kotlin.

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

 File file = new File(getPath(ProductFlipperActivity.this,uri));
 

Метод getPath:

 public static String getPath(final Context context, final Uri uri) {
    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
    Log.i("URI", uri   "");
    String result = uri   "";
    // DocumentProvider
    //  if (isKitKat amp;amp; DocumentsContract.isDocumentUri(context, uri)) {
    if (isKitKat amp;amp; (result.contains("media.documents"))) {
        String[] ary = result.split("/");
        int length = ary.length;
        String imgary = ary[length - 1];
        final String[] dat = imgary.split(":");
        final String docId = dat[1];
        final String type = dat[0];
        Uri contentUri = null;
        if ("image".equals(type)) {
            contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        } else if ("video".equals(type)) {
            contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
        } else if ("audio".equals(type)) {
            contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        }
        final String selection = "_id=?";
        final String[] selectionArgs = new String[]{
                dat[1]
        };
        return getDataColumn(context, contentUri, selection, selectionArgs);
    } else if ("content".equalsIgnoreCase(uri.getScheme())) {
        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }
    return null;
}
 

Метод getDataColumn():

 public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {
            column
    };
    try {
        if (checkPermissionREAD_EXTERNAL_STORAGE(context)) {
            // do your stuff..

            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null amp;amp; cursor.moveToFirst()) {
                final int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}
 

Get the file name and use storepdf method

 String videoName = file.getName();
testObj.storePDF(internalPath   videoName, file);
 

storepdf method to save file in app specific directory:

 //store pdf to sdcard
public Uri storePDF(String path, File file) {
    Uri uri = null;
    FileInputStream in = null;
    FileOutputStream out = null;
    try {
        in = new FileInputStream(file);
        String newFileName = path;
        out = new FileOutputStream(newFileName);

        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        in.close();
        out.flush();
        out.close();
       } catch (Exception e) {
        Log.e("tag", e.getMessage());
    }
    return Uri.fromFile(file);
}
 

После использования uri для сохранения файла и когда я открываю inputstream по реальному пути к файлу или uri, оба выдают ошибку:

 File file = new File(String.valueOf(uri));
//File file = new File(getPath(ProductFlipperActivity.this,uri));
String videoName = file.getName();
InputStream in = new FileInputStream(file);
OutputStream out = new FileOutputStream(new File(internalPath   videoName));
// Copy the bits from instream to outstream
byte[] buf = new byte[1024];
int len;

while ((len = in.read(buf)) > 0) {
    out.write(buf, 0, len);
}

in.close();
out.close();
 

Ошибка устранена с помощью следующего кода, предложенного @blackapps:

 File file = new File(getPath(ProductFlipperActivity.this,uri));
String videoName = file.getName();
InputStream in = this.getContentResolver().openInputStream(uri);
OutputStream out = this.getContentResolver().openOutputStream((Uri.fromFile(new File(internalPath   videoName))));
// Copy the bits from instream to outstream
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
    out.write(buffer, 0, read);
}
in.close();
out.flush();
out.close();
 

Комментарии:

1. (Video is in Internal/External Storage) Ну … тогда зачем вам делать копию, если видео уже есть на вашем устройстве?

2. пользователь выбирает видео из своего внутреннего/внешнего хранилища, и его необходимо скопировать в каталог конкретного приложения для дальнейшего использования.. т. е. внутри данных/данных/com. myapp/папка/ … но это приводит к отказу в разрешении в Android 10 и 11 @blackapps

3. Я не вижу никакого кода. Так почему бы вам для начала не опубликовать свой код? И мы понятия не имеем, за что или когда вы увидите отказ в разрешении. Начните публиковать код для «выбора пользователя».

4. да @blackapps.. я опубликую сейчас.. спасибо

5. @blackapps Я обновил код.. он отлично работает до Android 9..