Access and share file under Picture folder in Internal/External Storage Android Q

时间秒杀一切 提交于 2020-04-17 22:18:09

问题


Many breaking changes happen in Android Q when it comes to storage management and one of my feature in the app is to allow user to take a shot in a View like CardView item, create a Bitmap of it and save that to mass storage of the device. Once saving is done it will then trigger an Intent.ACTION_SEND so user can share the recently save image with some description to social apps and compose a email with GMail.

This code snippet works fine.

        try {
        //Get primary storage status
        String state = Environment.getExternalStorageState();
        File filePath = new File(view.getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + "/" + "Shared");

        if (Environment.MEDIA_MOUNTED.equals(state)) {
            try {
                if (filePath.mkdirs())
                    Log.d("Share Intent", "New folder is created.");
            } catch (Exception e) {
                e.printStackTrace();
                Crashlytics.logException(e);
            }
        }

        //Create a new file
        File imageFile = new File(filePath, UUID.randomUUID().toString() + ".png");

        //Create bitmap screen capture
        Bitmap bitmap = Bitmap.createBitmap(loadBitmapFromView(view));

        FileOutputStream outputStream = new FileOutputStream(imageFile);
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);

        outputStream.flush();
        outputStream.close();

        Toast.makeText(view.getContext(), "Successfully save!", Toast.LENGTH_SHORT).show();

        shareToInstant(description, imageFile, view);


    } catch (IOException e) {
        e.printStackTrace();
        Crashlytics.logException(e);
    }

But this will save the image file into /storage/emulated/0/Android/data/YOUR_APP_PACKAGE_NAME/files/Pictures.

What I want is to save them like most app do in the default Pictures folder in the root /storage/emulated/0/Pictures so the image is more expose and can be easily seen and scan as well by the Gallery.

In order to do that I change the above code snippet to this.

 //Create bitmap screen capture
    Bitmap bitmap = Bitmap.createBitmap(loadBitmapFromView(view));

    final String relativeLocation = Environment.DIRECTORY_PICTURES + "/" + view.getContext().getString(R.string.app_name);

    final ContentValues contentValues = new ContentValues();
    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, UUID.randomUUID().toString() + ".png");
    contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
    contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);

    final ContentResolver resolver = view.getContext().getContentResolver();

    OutputStream stream = null;
    Uri uri = null;

    try {

        final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        uri = resolver.insert(contentUri, contentValues);

        if (uri == null || uri.getPath() == null) {
            throw new IOException("Failed to create new MediaStore record.");
        }

        stream = resolver.openOutputStream(uri);

        if (stream == null) {
            throw new IOException("Failed to get output stream.");
        }

        if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)) {
            throw new IOException("Failed to save bitmap.");
        }

        //If we reach this part we're good to go
        Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        File imageFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), contentValues.getAsString(MediaStore.MediaColumns.DISPLAY_NAME));
        Uri fileContentUri = Uri.fromFile(imageFile);
        mediaScannerIntent.setData(fileContentUri);
        view.getContext().sendBroadcast(mediaScannerIntent);

        shareToInstant(description, imageFile, view);

    } catch (IOException e) {
        if (uri != null) {
            // Don't leave an orphan entry in the MediaStore
            resolver.delete(uri, null, null);
        }
        e.printStackTrace();
        Crashlytics.logException(e);
    } finally {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
                Crashlytics.logException(e);
            }
        }
    }

Also worked but not able to attached/share the image to other app like GMail, also the Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) is said to be deprecated so I wonder how things should be done now as I already tried numerous research for this but no luck to finde similar scenario on this matter.

This is my FileProvider looks like.

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external"
        path="." />
    <external-files-path
        name="external_files"
        path="." />
    <cache-path
        name="cache"
        path="." />
    <external-cache-path
        name="external_cache"
        path="." />
    <files-path
        name="files"
        path="." />
</paths>

This is my snippet for Intent sharing.

private static void shareToInstant(String content, File imageFile, View view) {

    Intent sharingIntent = new Intent(Intent.ACTION_SEND);
    sharingIntent.setType("image/png");
    sharingIntent.setType("text/plain");
    sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    sharingIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    sharingIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(view.getContext(), BuildConfig.APPLICATION_ID + ".provider", imageFile));
    sharingIntent.putExtra(Intent.EXTRA_TEXT, content);

    try {
        view.getContext().startActivity(Intent.createChooser(sharingIntent, "Share it Via"));
    } catch (android.content.ActivityNotFoundException ex) {
        Toast.makeText(view.getContext(), R.string.unknown_error, Toast.LENGTH_SHORT).show();
    }
}

回答1:


It seems you can still access the file without needing FileProvider.getUriForFile(context, authority, file); in Android Q by just passing the uri from the resolver.insert(contentUri, contentValues);



来源:https://stackoverflow.com/questions/60987504/access-and-share-file-under-picture-folder-in-internal-external-storage-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!