2

I am developing an app with functionality of taking image from camera or gallery. This is working fine in all the devices but not in OnePlus.

This is the code :

public File dispatchTakePictureIntent(Activity activity) {
        File tempPhotoFile = null;
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) {

            try {
                tempPhotoFile = Utils.createImageFile(activity);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (tempPhotoFile != null) {
                Uri photoURI = FileProvider.getUriForFile(activity, Utils.getFileProvider(activity), tempPhotoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                takePictureIntent.setClipData(ClipData.newRawUri("", photoURI));
                takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                activity.startActivityForResult(takePictureIntent, Constants.REQUEST_IMAGE_CAPTURE);
            }
        }
        return tempPhotoFile;
    }

Code in Utils :

public static File createImageFile(Context context) throws IOException {
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir      /* directory */
        );

        // Save a file: path for use with ACTION_VIEW intents
        return image;
    }

Now the app is working fine in other devices. But in OnePlus when the camera opens and we click the image and the preview is shown, at that time in the logcat we see that the app is shown dead and its restarted and it opens on app home scree. when we go to the particular tab from where we open the camera app, we can see the state is saved and we land on the same page. How can we solve the issue?

Parth Anjaria
  • 3,961
  • 3
  • 30
  • 62

3 Answers3

0

You probably did not give permission for your URI

please study that https://developer.android.com/reference/android/support/v4/content/FileProvider

Edit fragment most important for you is https://developer.android.com/reference/android/support/v4/content/FileProvider#Permissions

somewhere before startActivityForResult you need to add

 activity.grantUriPermission(activity.getActivityInfo().getPackageName(), photoURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)

that is pseudo code so please , check it on your side

EDIT 2: I've made a mistake with suggesting that you need to add that permission to your own package. You need to add it to app that will make that picture for you

heres kotlin code for catching all apps that can do it

val resInfoList = activity.packageManager.queryIntentActivities(Intent(MediaStore.ACTION_IMAGE_CAPTURE), PackageManager.MATCH_DEFAULT_ONLY)
    resInfoList
            .map { it.activityInfo.packageName }
            .forEach { this.grantUriPermission(it, photoURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION) }

Also for image capturing you can use simpler Intent

    val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
            startActivityForResult(takePictureIntent, PICK_CAMERA_CODE)

cheers

wojciech_maciejewski
  • 1,277
  • 1
  • 12
  • 28
0

I tested your code on OP7Pro.

Here is the code I used for the test:

@Throws(IOException::class)
fun createImageFile(context: Context): File {
    // Create an image file name
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(Date())
    val imageFileName = "JPEG_" + timeStamp + "_"
    val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)

    // Save a file: path for use with ACTION_VIEW intents
    return File.createTempFile(
        imageFileName, /* prefix */
        ".jpg", /* suffix */
        storageDir      /* directory */
    )
}

private fun dispatchTakePictureIntent(activity: Activity): File? {
    var tempPhotoFile: File? = null
    val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    if (takePictureIntent.resolveActivity(activity.packageManager) != null) {

        try {
            tempPhotoFile = createImageFile(activity)
        } catch (e: Exception) {
            e.printStackTrace()
        }

        if (tempPhotoFile != null) {
            val photoURI = FileProvider.getUriForFile(
                activity,
                applicationContext.packageName + ".fileprovider",
                tempPhotoFile
            )
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
            takePictureIntent.clipData = ClipData.newRawUri("", photoURI)
            takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
            activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
        }
    }
    return tempPhotoFile
}

Then, called it like:

btnOpenCamera.setOnClickListener{
     val r = dispatchTakePictureIntent(this)
     imageView.setImageDrawable(Drawable.createFromPath(r?.path))
}

I have set the result in a imageview.

File Provider:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
</provider>

@xml/provider_paths:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

Following are my observations:

return tempPhotoFile 

doesn't wait for the camera to take the picture and come back with the result. It returns the path instantly as the call to activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE) is completed, where the image file might not have been created at the time of it returning the value. As a result, the behaviour is unpredictable.

To ensure that you have captured the image, you should rely on the onActivityResult and get the data from the intent. I have found the same behaviour in other phones also with your code. I hope I have explained the problem clearly.

As to why your app is crashing, probably you are trying to do something with the file it is returning from dispatchTakePictureIntent, and when you try to process it, the image actually isn't created by that time. Hence, Unable to open content: file:///storage/emulated/0/Android/data/...

This is assuming, you tried to use the file as an Image as I did.

Here is an example implementation you might want to look at.

Hope this helps.

Regards

Priyabrata

Priyabrata
  • 1,202
  • 3
  • 19
  • 57
0

Just add below property in the activity tag of the Manifest file.

android:requestLegacyExternalStorage="true"

App pointing to Android 10, above flag is false by default. We have to set it to true.

Ambar Jain
  • 508
  • 5
  • 11