package com.datarecovery.master.utils; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.net.Uri; import android.os.Build; import android.os.ParcelFileDescriptor; import android.provider.MediaStore; import androidx.annotation.IntDef; import androidx.annotation.RequiresApi; import com.atmob.common.runtime.ContextUtil; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * 用于保存文件到公共存储空间 */ public class MediaStoreHelper { public static final int TYPE_IMAGE = 1; public static final int TYPE_VIDEO = 2; public static final int TYPE_AUDIO = 3; public static final int TYPE_FILES = 4; public static final int TYPE_DOWNLOADS = 5; @Retention(RetentionPolicy.SOURCE) @IntDef({TYPE_IMAGE, TYPE_VIDEO, TYPE_AUDIO, TYPE_FILES, TYPE_DOWNLOADS}) @interface MediaType { } public static void saveToSharedStorage(@MediaType int mediaType, File file, String fileName) throws Exception { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { saveToSharedStorage(mediaType, java.nio.file.Files.newInputStream(file.toPath()), fileName); } else { saveToSharedStorage(mediaType, new FileInputStream(file), fileName); } } public static void saveToSharedStorage(@MediaType int mediaType, InputStream inputStream, String fileName) throws Exception { // Add a media item that other apps don't see until the item is // fully written to the media store. Context applicationContext = ContextUtil.getContext().getApplicationContext(); ContentResolver resolver = applicationContext.getContentResolver(); Media targetMedia = getTargetMedia(mediaType); // Find all media files on the primary external storage device. Uri mediaCollection = targetMedia.getMediaCollection(); ContentValues mediaDetails = new ContentValues(); mediaDetails.put(targetMedia.displayName(), fileName); // lock media file until it's fully written. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { mediaDetails.put(targetMedia.isPending(), 1); } Uri mediaContentUri = resolver.insert(mediaCollection, mediaDetails); if (mediaContentUri == null) { throw new IllegalStateException("Failed to create new media item."); } // "w" for write. try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(mediaContentUri, "w", null); InputStream is = inputStream; FileOutputStream fos = pfd == null ? null : new FileOutputStream(pfd.getFileDescriptor()) ) { if (fos == null) { throw new IllegalStateException("Failed to open new media item."); } // Write data into the pending media file. byte[] buf = new byte[8192]; int len; while ((len = is.read(buf)) > 0) { fos.write(buf, 0, len); } fos.flush(); } finally { // finished, release the "pending" status. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { mediaDetails.clear(); mediaDetails.put(targetMedia.isPending(), 0); resolver.update(mediaContentUri, mediaDetails, null, null); } } } private static Media getTargetMedia(int mediaType) { switch (mediaType) { case TYPE_IMAGE: return new Image(); case TYPE_VIDEO: return new Video(); case TYPE_AUDIO: return new Audio(); case TYPE_FILES: return new Files(); case TYPE_DOWNLOADS: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return new Downloads(); } return new Files(); default: throw new IllegalArgumentException("Unknown media type: " + mediaType); } } private static class Image implements Media { @Override public Uri getMediaCollection() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return MediaStore.Images.Media .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY); } else { return MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } } @Override public String displayName() { return MediaStore.Images.Media.DISPLAY_NAME; } @Override public String isPending() { return MediaStore.Images.Media.IS_PENDING; } } private static class Video implements Media { @Override public Uri getMediaCollection() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return MediaStore.Video.Media .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY); } else { return MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } } @Override public String displayName() { return MediaStore.Video.Media.DISPLAY_NAME; } @Override public String isPending() { return MediaStore.Video.Media.IS_PENDING; } } private static class Audio implements Media { @Override public Uri getMediaCollection() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return MediaStore.Audio.Media .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY); } else { return MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } } @Override public String displayName() { return MediaStore.Audio.Media.DISPLAY_NAME; } @Override public String isPending() { return MediaStore.Audio.Media.IS_PENDING; } } private static class Files implements Media { @Override public Uri getMediaCollection() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY); } else { return MediaStore.Files.getContentUri("external"); } } @Override public String displayName() { return MediaStore.Files.FileColumns.DISPLAY_NAME; } @Override public String isPending() { return MediaStore.Files.FileColumns.IS_PENDING; } } private static class Downloads implements Media { @RequiresApi(api = Build.VERSION_CODES.Q) @Override public Uri getMediaCollection() { return MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY); } @Override public String displayName() { return MediaStore.Downloads.DISPLAY_NAME; } @Override public String isPending() { return MediaStore.Downloads.IS_PENDING; } } private interface Media { Uri getMediaCollection(); String displayName(); String isPending(); } }