问题
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