I am trying the source code of a very basic camera app on Android Studio 3.4.1 with Android Virtual Device (AVD) Nexus 7 (2012) API 29. I took a picture with the camera in the emulator and tried to save it as /storage/emulated/0/Pictures/myPic.png, but got an exception of /storage/emulated/0/Pictures/myPic.png open failed: EACCES (Permission Denied). I have tried all advice available online, for instance:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
public class MainActivity extends Activity {
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
boolean checkPermission = (permission == PackageManager.PERMISSION_GRANTED);
Toast toastPermission = Toast.makeText(activity,
"Is permission granted? " + checkPermission,
Toast.LENGTH_SHORT);
LinearLayout toastLayoutPermission = (LinearLayout) toastPermission.getView();
TextView toastTVPermission = (TextView) toastLayoutPermission.getChildAt(0);
toastTVPermission.setTextSize(30);
toastPermission.show();
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
verifyStoragePermissions(this);
......
private void saveImageToFile(File file)
{
if (mCameraBitmap != null)
{
FileOutputStream outStream = null;
verifyStoragePermissions(this);
try
{
outStream = new FileOutputStream(file);
...
}
catch (Exception e)
{
Toast toastException = Toast.makeText(MainActivity.this,
"Exception: " + e.getMessage(),
Toast.LENGTH_SHORT);
LinearLayout toastLayoutException = (LinearLayout) toastException.getView();
TextView toastTVException = (TextView) toastLayoutException.getChildAt(0);
toastTVException.setTextSize(30);
toastException.show();
}
...
However, NONE of the advice works!
The code threw an exception of
/storage/emulated/0/Pictures/myPic.png open failed: EACCES (Permission Denied)
when it reached the line of
outStream = new FileOutputStream(file);
Any idea to further solve this? Thanks a lot.
Your problem is due to the introduction of scoped storage in API 29. You have three solutions to the problem (some have already been mentioned, but I thought it would help to clarify and consolidate):
Only run your app on devices running API 28 and below.
Add android:requestLegacyExternalStorage="true"
to AndroidManifest.xml so your app can run on API 29 and above:
<application android:requestLegacyExternalStorage="true" ...
Modernize your app for API 29+. Start by getting rid of WRITE_EXTERNAL_STORAGE permissions. And replace the call to deprecated Environment.getExternalStoragePublicDirectory()
with getExternalFilesDir()
, which will save your image on external storage but in a directory only your app can access.
Below is a method to save a Bitmap as a JPG using the MediaStore, which allows other apps to access the image:
private void saveImage(Bitmap bitmap) throws IOException {
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "myImage.jpg");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
ContentResolver resolver = getContentResolver();
Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
OutputStream imageOutStream = null;
try {
if (uri == null) {
throw new IOException("Failed to insert MediaStore row");
}
imageOutStream = resolver.openOutputStream(uri);
if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 100, imageOutStream)) {
throw new IOException("Failed to compress bitmap");
}
}
finally {
if (imageOutStream != null) {
imageOutStream.close();
}
}
}
Adding android:requestLegacyExternalStorage="true" to the Android Manifest worked for me with Android 29
<application
android:name=".MyApplication"
android:allowBackup="true"
android:requestLegacyExternalStorage="true" ...
I also got this error in my project.
I fixed it by adding
android:requestLegacyExternalStorage="true"
in the manifests file. (see here)
I also tried to use a camera and save the photo to ImageView and had problems with permissions. I changed API from 29 to 28 - didn't help, add
android:requestLegacyExternalStorage="true"
didn't help. I changed the method which I used to create a file to store the image from:
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
to:
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
And the problem gone. BTW I don't know why. Maybe because the first one was deprecated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With