Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BitmapFactory: Unable to decode stream: java.io.FileNotFoundException:open failed: EACCES (Permission denied) on Android Q

I granted permissions but BitmapFactory.decodeFile() returns this error:

E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/DCIM/Camera/IMG_20200130_165131.jpg: open failed: EACCES (Permission denied)

I want to take the last image from the gallery and save it to another file. I tested it on the Android P test device it was running on. But it returns this error in android emulator with android version Q (API level 29). What's wrong with that?

These are my code snippets:

writeStoragePermissionGranted();

BitmapFactory.Options options = null;
Bitmap bm = null;

String[] projection = new String[]{
            MediaStore.Images.ImageColumns._ID,
            MediaStore.Images.ImageColumns.DATA,
            MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
            MediaStore.Images.ImageColumns.DATE_TAKEN,
            MediaStore.Images.ImageColumns.MIME_TYPE,
            MediaStore.Images.ImageColumns.DISPLAY_NAME,
    };

    final Cursor cursor = this.getContentResolver()
            .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null,
                    null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
      if (cursor.moveToFirst()) {
        final ImageView imageView = (ImageView) findViewById(R.id.pictureView);
        String imageLocation = cursor.getString(1);
        File imageFile = new File(imageLocation);

        if (imageFile.exists()) {
            options = new BitmapFactory.Options();
            options.inSampleSize = 2;

            try {
                    bm = BitmapFactory.decodeFile(imageLocation, options);
            } catch(Exception e) {
                    e.printStackTrace();
            }
        }

        imageView.setImageBitmap(bm);



        try {
            saveImage(bm,"NAME" );
        } catch (IOException e) {
                e.printStackTrace();
        }
    }

writeStoragePermissionGranted() function:

 public void writeStoragePermissionGranted() {
       if (Build.VERSION.SDK_INT >= 23) {
           if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                   == PackageManager.PERMISSION_GRANTED) {
            startPeriodicRequest();
        } else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Constants.REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION);
        }
    } else {
        return;
    }
} 

and manifest permissions:

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

I know there are many question about that. But no one worked on the android emulator version Q. On the other hand, this code works on android pie (API level 28)

like image 843
K.tas Avatar asked Jan 31 '20 19:01

K.tas


2 Answers

Adding android:requestLegacyExternalStorage="true" to the manifest's application block could actually solve the issue!

like image 84
Abdulmajeed Alyafei Avatar answered Sep 24 '22 10:09

Abdulmajeed Alyafei


On Android 10, they introduced the concept of "Scoped Storage" and this way, you no longer can OPEN a image using its path. You can get more info HERE.

So now you have to decode it using its ParcelFileDescriptor and its Uri.

You can:

final Cursor cursor = this.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        projection, null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
if (cursor.moveToFirst()) {
    final ImageView imageView = (ImageView) findViewById(R.id.pictureView);


    if (Build.VERSION.SDK_INT >= 29) {
        // You can replace '0' by 'cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)'
        // Note that now, you read the column '_ID' and not the column 'DATA'
        Uri imageUri= ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getInt(0));

        // now that you have the media URI, you can decode it to a bitmap
        try (ParcelFileDescriptor pfd = this.getContentResolver().openFileDescriptor(mediaUri, "r")) {
            if (pfd != null) {
                bitmap = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
            }
        } catch (IOException ex) {

        }
    } else {
        // Repeat the code you already are using
    }
}
like image 38
W0rmH0le Avatar answered Sep 21 '22 10:09

W0rmH0le