Search code examples
androidimageandroid-intentcameraandroid-camera

Returning an image to IMAGE_CAPTURE_INTENT


I am developing a camera app and would like to implement the feature that allows the app to return an image to another app which called the IMAGE_CAPTURE_INTENT.

val pictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

I have found a lot of information on the internet on how to request another camera app to capture an image and return it, but I did not find any information on how to deal with it the other way round, like in the case my app would need to accept the intent and return the image to another app. I hope this makes sense.

Would greatly appreciate any help.


Solution

  • After research and experimenting, I have partially solved the problem. If I understood it correctly, there are two ways the IMAGE_CAPTURE_INTENT works: If the ACTION_IMAGE_CAPTURE Intent contains EXTRA_OUTPUT, which is a Uri, you can save your taken image using this Uri to return an image. If there is no EXTRA_OUTPUT, the Intent for use with setResult() should contain a thumbnail-sized Bitmap in the _data extra. (Thanks @CommonsWare for the info!) I have only implemented the first option with the Uri, as I am still unsure how to do it with the thumbnail (most apps provide an Uri with their intent anyway).

    The approach I took to return an image (only with Uri):

    1. Detect if the activity has been started due to an intent. Add the code below ideally in onResume, so the code checks for an intent every time the app is opened:
    //check if activity was opened due to an intent
    val isImageCaptureIntent = this.intent.action == MediaStore.ACTION_IMAGE_CAPTURE           
    if(isImageCaptureIntent) {
      //retrieve the uri
      val output = intent.extras?.get(MediaStore.EXTRA_OUTPUT)
    
      //check if it is an Uri and not null
      if (output != null && output is Uri) {
         val uriImageCaptureIntent = output
         isImageCaptureIntentWithUri = true
         //an Uri is provided
         }else{
         isImageCaptureIntentWithUri = false
         //an Uri is not provided, return a thumbnail-sized bitmap. 
         //I have not included a solution for this case!
         }
      }
    
    1. After the picture has been taken, save the image:
    val imageOutStream: OutputStream
    val contentResolver = context.contentResolver
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
       //use this approach to save the image with Android 10+ due to    scoped storage
    
       val mimeType =  "image/jpeg"
       val values = ContentValues().apply {
         put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
         put(MediaStore.Images.Media.MIME_TYPE, mimeType)
         put(MediaStore.Images.Media.RELATIVE_PATH, directory)
       }
    
       contentResolver.run {
         imageOutStream = openOutputStream(uriImageCaptureIntent) ?:     return
       }
    }else{
       //use this code for Android 9 and below
       imageOutStream = context.contentResolver.openOutputStream(uriImageCaptureIntent)!!
    }
    
    try {
        //bitmap equals the captured image
        bitmap.compress(Bitmap.CompressFormat.JPEG, photoCompression, imageOutStream)
        imageOutStream.flush()
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
    } finally {
        imageOutStream.close()
    }
    
    1. After storing the image, set result to OK and close the app:
     requireActivity().setResult(Activity.RESULT_OK, requireActivity().intent)
     requireActivity().finish()
    

    Update: Starting from Android 11, Android will no longer allow any third-party apps to capture an image via IMAGE_CAPTURE_INTENT. While the above code should work fine for Android 10 and below, starting form Android 11, no third-party apps will show up in the camera selection interface, when selecting an app to execute the capture intent.