1

I followed this simple app AndroidScannerDemo which has two main button open camera and open gallery. The Camera is working fine on my phone API 19, but when I try to launch the camera on other devices or emulator the app crash.

From what I could understand this could be due to permission

Edit : Apparently this was asked here awhile ago as well but the issue remain

Wrong Update : the root problem coming from createImageFile method

I tried changing //cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempFileUri); to

cameraIntent.putExtra(ScanConstants.OPEN_INTENT_PREFERENCE, preference);

I'm able to start the camera but I get crash right after taking picture

Update 2 : I'm trying following this article provided the answer below the only issue I'm using fragment

So How do I change this line tempFileUri = FileProvider.getUriForFile(getActivity().getApplicationContext(), "com.scanlibrary.provider", // As defined in Manifest file);

to tempFileUri = FileProvider.getUriForFile(PickImageFragment.this, getString(R.string.file_provider_authority), file); inside a fragment !

Wrong First argument PickImageFragment

EDIT : Changed openCamera() method inside PickImageFragment

What Im I missing ?

Stack trace

2019-11-29 23:45:05.750 27993-27993/com.nabeeltech.capturedoc E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.nabeeltech.capturedoc, PID: 27993
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nabeeltech.capturedoc/com.scanlibrary.ScanActivity}: java.lang.SecurityException: UID 10091 does not have permission to content://com.scanlibrary.provider/external_files/scanSample/IMG_20191129_224505.jpg [user 0]
 Caused by: java.lang.SecurityException: UID 10091 does not have permission to content://com.scanlibrary.provider/external_files/scanSample/IMG_20191129_224505.jpg [user 0]
    at com.scanlibrary.PickImageFragment.openCamera(PickImageFragment.java:131)
    at com.scanlibrary.PickImageFragment.handleIntentPreference(PickImageFragment.java:79)
    at com.scanlibrary.PickImageFragment.init(PickImageFragment.java:60)
    at com.scanlibrary.PickImageFragment.onCreateView(PickImageFragment.java:50)

PickImageFragment

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.pick_image_fragment, null);
    init();
    return view;
}

private void init() {
    cameraButton = (ImageButton) view.findViewById(R.id.cameraButton);
    cameraButton.setOnClickListener(new CameraButtonClickListener());
    galleryButton = (ImageButton)
 view.findViewById(R.id.selectButton);
    galleryButton.setOnClickListener(new GalleryClickListener());
    if (isIntentPreferenceSet()) {
        handleIntentPreference();
    } else {
        getActivity().finish();
    }
}

private void handleIntentPreference() {
    int preference = getIntentPreference();
    if (preference == ScanConstants.OPEN_CAMERA) {
        openCamera();
    } else if (preference == ScanConstants.OPEN_MEDIA) {
        openMediaContent();
    }
}

public void openCamera() {
    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    Uri tempFileUri = null;
        File file = createImageFile();
        boolean isDirectoryCreated = file.getParentFile().mkdirs();
        Log.d("", "openCamera: isDirectoryCreated: " + isDirectoryCreated);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        tempFileUri = FileProvider.getUriForFile(getActivity().getApplicationContext(),
                "com.scanlibrary.provider", // As defined in Manifest
                file);
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempFileUri);
    } else {
        tempFileUri = Uri.fromFile(file);
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempFileUri);
    }
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
        cameraIntent.setClipData(ClipData.newRawUri("", tempFileUri));
        cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    }
    startActivityForResult(cameraIntent, ScanConstants.START_CAMERA_REQUEST_CODE);

private File createImageFile() {
    clearTempImages();
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new
            Date());
    File file = new File(ScanConstants.IMAGE_PATH, "IMG_" + timeStamp +
            ".jpg");
    fileUri = Uri.fromFile(file);
    return file;
}

private void clearTempImages() {
    try {
        File tempFolder = new File(ScanConstants.IMAGE_PATH);
        for (File f : tempFolder.listFiles())
            f.delete();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

ScanConstants

public class ScanConstants {

public final static int PICKFILE_REQUEST_CODE = 1;
public final static int START_CAMERA_REQUEST_CODE = 2;
public final static String OPEN_INTENT_PREFERENCE = "selectContent";
public final static String IMAGE_BASE_PATH_EXTRA = "ImageBasePath";
public final static int OPEN_CAMERA = 4;
public final static int OPEN_MEDIA = 5;
public final static String SCANNED_RESULT = "scannedResult";
public final static String IMAGE_PATH = Environment
        .getExternalStorageDirectory().getPath() + "/scanSample";

public final static String SELECTED_BITMAP = "selectedBitmap";
}
zakblack
  • 59
  • 11
  • Can find you answer here https://stackoverflow.com/questions/43644163/android-java-lang-securityexception-does-not-have-permission-to-uri-0-conten – Yang Liu Nov 30 '19 at 01:38
  • Thanks but sadly that's not the case here – zakblack Nov 30 '19 at 01:46
  • Have you declared the permissions required for storing and reading from the storage in your mainfest file? – Vishal Nov 30 '19 at 02:28
  • Yes I have, I'm trying following this post about createImageFile https://stackoverflow.com/a/47050327 – zakblack Nov 30 '19 at 02:48

1 Answers1

1

You've written the code Fileprovider.getUriforFile which is fine, but have you declare the permissions required.

The only way to solve this is to grant permissions to all of the packages that might need it, like this:

List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
    String packageName = resolveInfo.activityInfo.packageName;
    context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

If above doesn't solve issue i'd suggest to refer this article by Lorenzo Quiroli that solves this issue for older Android versions.

He discovered that you need to manually set the ClipData of the Intent and set the permissions for it, like so:

if ( Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP ) {
    takePictureIntent.setClipData( ClipData.newRawUri( "", photoURI ) );
    takePictureIntent.addFlags( Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_READ_URI_PERMISSION );
}
Omkar C.
  • 755
  • 8
  • 21
  • Thanks I tried 'Lorenzo Quiroli' method it didn't help as for grant permission to all how do I implement this in my code. Cannot resolve symbol 'context' , 'intent, 'uri' – zakblack Nov 30 '19 at 02:59
  • Try `Context context = this;` Since `this` refers to the current object instance of a class and `Activity` is a `Context`, or more precisely, it `extends` `Context`. – Omkar C. Nov 30 '19 at 03:18
  • Not possible my class extends Fragment ! If I do context = this, I get cannot resolve getPackageManager – zakblack Nov 30 '19 at 06:24
  • Im trying to follow the second approach from the article but I get stuck here I cannot use in my Fragment class `photoURI = FileProvider.getUriForFile(MainActivity.this, getString(R.string.file_provider_authority), photoFile);` – zakblack Nov 30 '19 at 06:45