bugfix: crash when rotating image on SD card on older devices
This commit is contained in:
parent
02dbb3fcbf
commit
829e97783e
2 changed files with 46 additions and 18 deletions
|
@ -141,8 +141,20 @@ public abstract class ImageProvider {
|
|||
|
||||
private void rotateJpeg(final Activity activity, final String path, final Uri uri, boolean clockwise, final ImageOpCallback callback) {
|
||||
final String mimeType = MimeTypes.JPEG;
|
||||
|
||||
final DocumentFileCompat originalDocumentFile = StorageUtils.getDocumentFile(activity, path, uri);
|
||||
if (originalDocumentFile == null) {
|
||||
callback.onFailure(new Exception("failed to get document file for path=" + path + ", uri=" + uri));
|
||||
return;
|
||||
}
|
||||
|
||||
// copy original file to a temporary file for editing
|
||||
final String editablePath = StorageUtils.copyFileToTemp(path);
|
||||
final String editablePath = StorageUtils.copyFileToTemp(originalDocumentFile, path);
|
||||
if (editablePath == null) {
|
||||
callback.onFailure(new Exception("failed to create a temporary file for path=" + path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Env.requireAccessPermission(path)) {
|
||||
if (PermissionManager.getSdCardTreeUri(activity) == null) {
|
||||
Runnable runnable = () -> rotate(activity, path, uri, mimeType, clockwise, callback);
|
||||
|
@ -171,8 +183,8 @@ public abstract class ImageProvider {
|
|||
exif.setAttribute(ExifInterface.TAG_ORIENTATION, Integer.toString(newOrientationCode));
|
||||
exif.saveAttributes();
|
||||
|
||||
// copy the edited temporary file to the original DocumentFile
|
||||
DocumentFileCompat.fromFile(new File(editablePath)).copyTo(DocumentFileCompat.fromSingleUri(activity, uri));
|
||||
// copy the edited temporary file back to the original
|
||||
DocumentFileCompat.fromFile(new File(editablePath)).copyTo(originalDocumentFile);
|
||||
} catch (IOException e) {
|
||||
callback.onFailure(e);
|
||||
return;
|
||||
|
@ -205,8 +217,20 @@ public abstract class ImageProvider {
|
|||
|
||||
private void rotatePng(final Activity activity, final String path, final Uri uri, boolean clockwise, final ImageOpCallback callback) {
|
||||
final String mimeType = MimeTypes.PNG;
|
||||
|
||||
final DocumentFileCompat originalDocumentFile = StorageUtils.getDocumentFile(activity, path, uri);
|
||||
if (originalDocumentFile == null) {
|
||||
callback.onFailure(new Exception("failed to get document file for path=" + path + ", uri=" + uri));
|
||||
return;
|
||||
}
|
||||
|
||||
// copy original file to a temporary file for editing
|
||||
final String editablePath = StorageUtils.copyFileToTemp(path);
|
||||
final String editablePath = StorageUtils.copyFileToTemp(originalDocumentFile, path);
|
||||
if (editablePath == null) {
|
||||
callback.onFailure(new Exception("failed to create a temporary file for path=" + path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Env.requireAccessPermission(path)) {
|
||||
if (PermissionManager.getSdCardTreeUri(activity) == null) {
|
||||
Runnable runnable = () -> rotate(activity, path, uri, mimeType, clockwise, callback);
|
||||
|
@ -229,8 +253,8 @@ public abstract class ImageProvider {
|
|||
try (FileOutputStream fos = new FileOutputStream(editablePath)) {
|
||||
rotatedImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
|
||||
// copy the edited temporary file to the original DocumentFile
|
||||
DocumentFileCompat.fromFile(new File(editablePath)).copyTo(DocumentFileCompat.fromSingleUri(activity, uri));
|
||||
// copy the edited temporary file back to the original
|
||||
DocumentFileCompat.fromFile(new File(editablePath)).copyTo(originalDocumentFile);
|
||||
} catch (IOException e) {
|
||||
callback.onFailure(e);
|
||||
return;
|
||||
|
|
|
@ -220,18 +220,22 @@ public class StorageUtils {
|
|||
@Nullable
|
||||
public static DocumentFileCompat getDocumentFile(@NonNull Activity activity, @NonNull String path, @NonNull Uri mediaUri) {
|
||||
if (Env.requireAccessPermission(path)) {
|
||||
// need a document URI (not a media content URI) to open a `DocumentFile` output stream
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// cleanest API to get it
|
||||
Uri docUri = MediaStore.getDocumentUri(activity, mediaUri);
|
||||
return DocumentFileCompat.fromSingleUri(activity, docUri);
|
||||
} else {
|
||||
Uri sdCardTreeUri = PermissionManager.getSdCardTreeUri(activity);
|
||||
String[] storageVolumeRoots = Env.getStorageVolumeRoots(activity);
|
||||
Optional<DocumentFileCompat> docFile = StorageUtils.getSdCardDocumentFile(activity, sdCardTreeUri, storageVolumeRoots, path);
|
||||
return docFile.orElse(null);
|
||||
if (docUri != null) {
|
||||
return DocumentFileCompat.fromSingleUri(activity, docUri);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return DocumentFileCompat.fromFile(new File(path));
|
||||
// fallback for older APIs
|
||||
Uri sdCardTreeUri = PermissionManager.getSdCardTreeUri(activity);
|
||||
String[] storageVolumeRoots = Env.getStorageVolumeRoots(activity);
|
||||
Optional<DocumentFileCompat> docFile = StorageUtils.getSdCardDocumentFile(activity, sdCardTreeUri, storageVolumeRoots, path);
|
||||
return docFile.orElse(null);
|
||||
}
|
||||
// good old `File`
|
||||
return DocumentFileCompat.fromFile(new File(path));
|
||||
}
|
||||
|
||||
// returns the directory `DocumentFile` (from tree URI when scoped storage is required, `File` otherwise)
|
||||
|
@ -277,15 +281,15 @@ public class StorageUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static String copyFileToTemp(String path) {
|
||||
public static String copyFileToTemp(@NonNull DocumentFileCompat documentFile, @NonNull String path) {
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(path)).toString());
|
||||
try {
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(path)).toString());
|
||||
File temp = File.createTempFile("aves", '.' + extension);
|
||||
Utils.copyFile(new File(path), temp);
|
||||
documentFile.copyTo(DocumentFileCompat.fromFile(temp));
|
||||
temp.deleteOnExit();
|
||||
return temp.getPath();
|
||||
} catch (IOException e) {
|
||||
Log.w(LOG_TAG, "failed to copy file at path=" + path);
|
||||
Log.w(LOG_TAG, "failed to copy file from path=" + path);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue