Android camera intent FileUriExposedException for SDK >= 24
Asked Answered
T

2

13

I use this code to get a picture from camera and put it on imageview:

  private void openCamera()
{
    mMediaUri =getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

    Intent photoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    photoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
    startActivityForResult(photoIntent, REQUEST_TAKE_PHOTO);
   // dialog.dismiss();


}


private Uri getOutputMediaFileUri(int mediaTypeImage)
{
    //check for external storage
    if(isExternalStorageAvaiable())
    {
        File mediaStorageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);

        String fileName = "";
        String fileType = "";
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new java.util.Date());

        fileName = "IMG_"+timeStamp;
        fileType = ".jpg";

        File mediaFile;
        try
        {
            mediaFile = File.createTempFile(fileName,fileType,mediaStorageDir);
            Log.i("st","File: "+Uri.fromFile(mediaFile));
        }
        catch (IOException e)
        {
            e.printStackTrace();
            Log.i("St","Error creating file: " + mediaStorageDir.getAbsolutePath() +fileName +fileType);
            return null;
        }
        return Uri.fromFile(mediaFile);
    }
    //something went wrong
    return null;

}

private boolean isExternalStorageAvaiable()
{
    String state = Environment.getExternalStorageState();

    if(Environment.MEDIA_MOUNTED.equals(state))
    {
        return true;
    }
    else
    {
        return false;
    }
}

 public void onActivityResult(int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);

    if(resultCode == DIALOG_CODE)
    {
        String s = data.getStringExtra("choose");

        if(s.equals(getString(R.string.takephoto)))
        {
          openCamera();
        }
        else if(s.equals(getString(R.string.library)))
        {
         // openGallery();
        }
    }
    else if(resultCode == RESULT_OK)
    {
        if (requestCode == REQUEST_TAKE_PHOTO || requestCode == REQUEST_PICK_PHOTO) //dalla fotocamera
        {
            if (data != null)  //caso galleria
            {
                mMediaUri = data.getData();
            }


            Picasso.with(getActivity()).load(mMediaUri).resize(1280, 1280).centerCrop().into(photo, new Callback()
            {
                public void onSuccess()
                {


                }

                @Override
                public void onError() {

                }
            });
        }
    }
}

in Marshmallow it works ok, but in Nougat I got this error:

E/AndroidRuntime: FATAL EXCEPTION: main
              PID: 15471
              android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.plen.myapp/files/Pictures/IMG_20161214_1516561294620205.jpg exposed beyond app through ClipData.Item.getUri()
                  at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
                  at android.net.Uri.checkFileUriExposed(Uri.java:2346)
                  at android.content.ClipData.prepareToLeaveProcess(ClipData.java:832)
                  at android.content.Intent.prepareToLeaveProcess(Intent.java:8925)
                  at android.content.Intent.prepareToLeaveProcess(Intent.java:8910)
                  at android.app.Instrumentation.execStartActivity(Instrumentation.java:1519)
                  at android.app.Activity.startActivityForResult(Activity.java:4224)
                  at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:48)
                  at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:77)
                  at android.support.v4.app.ActivityCompatJB.startActivityForResult(ActivityCompatJB.java:26)
                  at android.support.v4.app.ActivityCompat.startActivityForResult(ActivityCompat.java:146)
                  at android.support.v4.app.FragmentActivity.startActivityFromFragment(FragmentActivity.java:937)
                  at android.support.v4.app.FragmentActivity$HostCallbacks.onStartActivityFromFragment(FragmentActivity.java:1046)
                  at android.support.v4.app.Fragment.startActivityForResult(Fragment.java:956)
                  at android.support.v4.app.Fragment.startActivityForResult(Fragment.java:945)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.openCamera(AddAircraftFirstPartFragment.java:263)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.askReadStorage(AddAircraftFirstPartFragment.java:338)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.askWriteStorage(AddAircraftFirstPartFragment.java:355)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.loadNewPhoto(AddAircraftFirstPartFragment.java:159)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment.access$000(AddAircraftFirstPartFragment.java:48)
                  at com.plen.myapp.MyAircrafts.AddAircraftFirstPartFragment$1.onClick(AddAircraftFirstPartFragment.java:75)
                  at android.view.View.performClick(View.java:5609)
                  at android.view.View$PerformClick.run(View.java:22266)
                  at android.os.Handler.handleCallback(Handler.java:751)
                  at android.os.Handler.dispatchMessage(Handler.java:95)
                  at android.os.Looper.loop(Looper.java:154)
                  at android.app.ActivityThread.main(ActivityThread.java:6077)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

how could I solve this error? I've searched solutions but no one works.

Thanks

Tropaeolin answered 14/12, 2016 at 14:21 Comment(3)
#38200782 (also, see this sample project: github.com/commonsguy/cw-omnibus/tree/master/Camera/…)Nicholle
@Nicholle but if I use this it works also with Jelly Bean? Or I need to use other code for previous version of Android?Tropaeolin
"but if I use this it works also with Jelly Bean?" -- if "this" is FileProvider, the issue is not the Android OS version, but whether the user's camera app supports content as a scheme for the Uri in EXTRA_OUTPUT. Some will, some will not. If "this" is the StrictMode approach, AFAIK that will be fine all all versions of Android, as it reverts the FileUriExposedException change and allows you to use file schemes again.Nicholle
R
37

Instead of return Uri.fromFile(mediaFile); do

return FileProvider.getUriForFile(MainActivity.this,
    BuildConfig.APPLICATION_ID + ".provider",
    mediaFile);

That would require you to add a provider to the AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application
    ...
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>
</application>

For AndroidX, use androidx.core.content.FileProvider

And then create a provider_paths.xml file in xml folder under res folder.

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

Read more: Full article

Rafaelof answered 14/12, 2016 at 15:19 Comment(1)
Official docs - developer.android.com/training/secure-file-sharing/…Strike
B
19

It can be done as simple as below . Put these 2 lines in onCreate of your activity.

StrictMode.VmPolicy.Builder newbuilder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(newbuilder.build());

URI exposure will be ignored by Vm I resolved my issue so.

Botchy answered 5/12, 2017 at 11:51 Comment(3)
This seems like it's turning off a lot of thingsDipole
It will work flawlessly .I didn't get any new bug or malfunctioning with this code.Botchy
Yes you are right. It works. It just looks like you're installing a policy object that's unconfigured. But it works 🤙Dipole

© 2022 - 2024 — McMap. All rights reserved.