0

I'm trying to update my app to work with androids new scoped storage rules in Android 10 and up, but am having the hardest time with it. I know I need to rebuild my app with new versions of java, but I just want to get it to work while I study and learn enough to do so. In a nutshell, I really need help. I have read so many different ways to make scoped storage work, and everybody seems to be doing it differently.

Just for clarification, what I am trying to do with the uri is both display in an imageview, then upload to database.

This code is working to take a picture and select images and videos in android 9, but in android 10, it only works when camera component captures a picture or a video. When a user selects an image or video from file, it returns a null pointer exception. Because I am pretty sure the error is in how I am dealing with the different chooser intents, I have shown the on result code first.

I have been unable to find a clear example of how to retrieve a usable image or video uri in android 10. If anybody can help, I would really appreciate it. I know I have much to learn.

if ((new java.io.File(_filePath)).exists()){
} else {
_filePath = vidfile.getAbsolutePath();
if ((new java.io.File(_filePath)).exists()){
} else {
            ArrayList<String> _filePath_1 = new ArrayList<>();
            if (_data != null) {
                if (_data.getClipData() != null) {
                    for (int _index = 0; _index < _data.getClipData().getItemCount(); _index++) {
                        ClipData.Item _item = _data.getClipData().getItemAt(_index);
                        _filePath_1.add(FileUtil.convertUriToFilePath(getApplicationContext(), 
_item.getUri()));
                    }
                }
                else {
                    _filePath_1.add(FileUtil.convertUriToFilePath(getApplicationContext(), 
_data.getData()));
                }
            }

_filePath = _filePath_1.get((int)0);


}
}

Just in case I am wrong, here is the code for the click event to launch the chooser...

SimpleDateFormat date1 = new SimpleDateFormat("yyyyMMdd_HHmmss");
String fileName1 = date1.format(new Date()) + ".jpg";

picfile = new 
File(getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath() + 
File.separator + fileName1);

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

Uri _uri_camr1 = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        _uri_camr1 = FileProvider.getUriForFile(getApplicationContext(), 
getApplicationContext().getPackageName() + ".provider", picfile);
    }
    else {
        _uri_camr1 = Uri.fromFile(picfile);
    }
    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, _uri_camr1);
    takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

SimpleDateFormat date2 = new SimpleDateFormat("yyyyMMdd_HHmmss");
String fileName2 = date2.format(new Date()) + ".mp4";

vidfile = new 
File(getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath() + 
File.separator + fileName2);

Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

Uri _uri_camr2 = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        _uri_camr2 = FileProvider.getUriForFile(getApplicationContext(), 
getApplicationContext().getPackageName() + ".provider", vidfile);
    }
    else {
        _uri_camr2 = Uri.fromFile(vidfile);
    }
    takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, _uri_camr2);
    takeVideoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);

Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
 contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);

contentSelectionIntent.setType("*/*");

contentSelectionIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Intent[] intentArray = new Intent[]{ takePictureIntent, takeVideoIntent}; 

chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); 
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Choose an action"); 
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); 
startActivityForResult(chooserIntent, REQ_CD_CAMR);
  • Most likely, delete `FileUtil.convertUriToFilePath()` and use the `Uri` better (e.g., `openInputStream()` on `ContentResolver` and `DocumentFile.fromSingleUri`()`). – CommonsWare Apr 22 '21 at 11:04
  • Thank you @CommonsWare Would you happen to know any good tutorials on this? I am not as advanced as I would like to one day be. I made the mistake of learning with scratch blocks and never should have, because it does not teach the fundamentals. Now I am going back and trying to learn what I should have from the beginning. I would like to at least get this working until I do. – Daniel Perley Apr 24 '21 at 18:28
  • Well, to be honest, your question is long on code and short on what you are trying to do with these `Uri` values. The answer of how to best use a `Uri` depends a *lot* on what you are trying to do with the `Uri`. For example, if you want to show a selected image in an `ImageView`, any of the major image-loading libraries (Glide, Picasso, etc.) support handing them a `Uri`. – CommonsWare Apr 24 '21 at 18:44
  • Thank you, I submitted an edit to clarify. What I am trying to do with the uri is both display in an imageview, then upload to database. – Daniel Perley Apr 24 '21 at 20:33
  • I am going to guess that "upload to database" means "upload to a Web service". If you are using OkHttp (with or without Retrofit) for that, [the `InputStreamRequestBody` impelmentations listed in this answer](https://stackoverflow.com/a/56308643/115145) can handle that with your `Uri`. And, for showing the image in an `ImageView`, please use an image-loading library – CommonsWare Apr 24 '21 at 20:36
  • Exactly what I am looking for. Thank you! – Daniel Perley Apr 24 '21 at 20:52

1 Answers1

0

try this code. it copies the selected file to scoped storage and gives you the final path of scoped storage from where you can access it. try it out & let me know if you face any problem.

android.net.Uri sharedFileUri = android.net.Uri.fromFile(new java.io.File(_filepath));
        java.io.FileInputStream input = null;
        java.io.FileOutputStream output = null;
        try {
            String filePath = new java.io.File(getCacheDir(), "tmp").getAbsolutePath();
            android.os.ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(sharedFileUri, "rw");
            if (pfd != null) {
                java.io.FileDescriptor fd = pfd.getFileDescriptor();
                input = new java.io.FileInputStream (fd);
                output = new java.io.FileOutputStream (filePath);
                int read;
                byte[] bytes = new byte[4096];
                while ((read = input.read(bytes)) != -1) {
                    output.write(bytes, 0, read);
                }
                java.io.File sharedFile = new java.io.File(filePath);
                String finalPath = sharedFile.getPath(); // this will provide you path to scoped storage. use this final path to access the selected file from scoped storage.
            }
        }catch(Exception ex) {
            android.widget.Toast.makeText(this, ex.toString(), android.widget.Toast.LENGTH_SHORT).show();
        } finally {
            try {
                input.close();
                output.close();
            } catch (Exception ignored) {
            }
        }
Kamal Panara
  • 482
  • 7
  • 16