Странная проблема с разрешением UCrop в Android Java
Итак, вот кое-что, с чем у меня просто возникают проблемы с пониманием проблемы. Позвольте мне начать с того, что у меня есть правильные настройки разрешений в файле манифеста. Я также проверяю, что у пользователя есть разрешение на доступ к файлам во внешнем хранилище. Итак, вот безумная проблема. Я использую UCrop, чтобы можно было обрезать изображение в моем приложении. По какой-то причине мне нужно скопировать файл во внутреннее хранилище, прежде чем я смогу использовать его с UCrop. Вот что я имею в виду
private void LoadImage( Intent data ) {
try {
Uri imageUri = data.getData();
Uri tempUri = IO.CopyTemporaryBitmap( getApplicationContext(), imageUri );
StartCrop( tempUri , getFilesDir() + "/tempimage.png" );
}
catch ( Exception e) {
e.printStackTrace();
Toast.makeText(this, "Unable to load picture: ", Toast.LENGTH_LONG).show();
}
}
IO.CopyTemporaryBitmap
public static Uri CopyTemporaryBitmap( Context context, Uri src ) {
Bitmap bmp;
try {
InputStream imageStream = context.getContentResolver().openInputStream( src );
bmp = BitmapFactory.decodeStream(imageStream);
}
catch ( Exception e ) {
e.printStackTrace();
return null;
}
if ( bmp == null ) return null;
File tempPath = new File( GetTempFolder() );
File file = new File( GetTempFolder() + "tempImage.png" );
try {
boolean b = true;
if (!tempPath.exists()) b = tempPath.mkdirs();
if ( !file.exists() && b ) b = file.createNewFile();
if (b) {
FileOutputStream out = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 100, out);
}
return Uri.fromFile( file );
}
catch ( Exception e ) {
e.printStackTrace();
}
return null;
}
Если я это сделаю, это сработает. У меня есть доступ на чтение / запись, поэтому я могу скопировать изображение на внутреннее, а затем обрезать его, но если я просто сделаю
private void LoadImage( Intent data ) {
try {
Uri imageUri = data.getData();
StartCrop( imageUri, getFilesDir() + "/tempimage.png" );
}
catch ( Exception e) {
e.printStackTrace();
Toast.makeText(this, "Unable to load picture: ", Toast.LENGTH_LONG).show();
}
}
Тогда я получаю
E/TransformImageView: onFailure: setImageUri
java.io.FileNotFoundException: open failed: EACCES (Permission denied)
at android.os.ParcelFileDescriptor.openInternal(ParcelFileDescriptor.java:315)
at android.os.ParcelFileDescriptor.open(ParcelFileDescriptor.java:220)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1498)
at android.content.ContentResolver.openFileDescriptor(ContentResolver.java:1338)
at android.content.ContentResolver.openFileDescriptor(ContentResolver.java:1286)
at com.yalantis.ucrop.task.BitmapLoadTask.doInBackground(BitmapLoadTask.java:97)
at com.yalantis.ucrop.task.BitmapLoadTask.doInBackground(BitmapLoadTask.java:41)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
После довольно продолжительной отладки я обнаружил, что виноват метод setImageUri в классе TransformImageView.java, который является частью UCrop, и я не писал.
/**
* This method takes an Uri as a parameter, then calls method to decode it into Bitmap with specified size.
*
* @param imageUri - image Uri
* @throws Exception - can throw exception if having problems with decoding Uri or OOM.
*/
public void setImageUri(@NonNull Uri imageUri, @Nullable Uri outputUri) throws Exception {
int maxBitmapSize = getMaxBitmapSize();
BitmapLoadUtils.decodeBitmapInBackground(getContext(), imageUri, outputUri, maxBitmapSize, maxBitmapSize,
new BitmapLoadCallback() {
@Override
public void onBitmapLoaded(@NonNull Bitmap bitmap, @NonNull ExifInfo exifInfo, @NonNull String imageInputPath, @Nullable String imageOutputPath) {
mImageInputPath = imageInputPath;
mImageOutputPath = imageOutputPath;
mExifInfo = exifInfo;
mBitmapDecoded = true;
setImageBitmap(bitmap);
}
@Override
public void onFailure(@NonNull Exception bitmapWorkerException) {
Log.e(TAG, "onFailure: setImageUri", bitmapWorkerException);
if (mTransformImageListener != null) {
mTransformImageListener.onLoadFailure(bitmapWorkerException);
}
}
});
}
По какой-то причине BitmapLoadUtils.decodeBitmapInBackground... всегда запускает опцию onFailure со значением "Permission Denied". Какие-нибудь подсказки?
2 ответа
Вот что я обнаружил, что устранило проблему:
я добавил
android:requestLegacyExternalStorage="true"
в мой манифест в разделе приложений.
Похоже, с хранилищем все изменилось. Подробности вы можете прочитать,
https://commonsware.com/blog/2019/06/07/death-external-storage-end-saga.html
Что ж, похоже, это проблема уровня API, Targeting API LEVEL 29 из-за проблемы в так называемом "механизме масштабирования", особенно в новых версиях Android, таких как Android 10.
решение, которое вы предоставили первым, на данный момент будет лучшим.