Reputation: 3474
This seems to be so easy that I feel embarrassed to ask. However, I have been fighting it for hours and scratching my head. The goal is to simply launch camera, if the button is pressed and camera permission has been granted, and then take a picture and display it in an Image composable with Coil. Each time I try this, the ActivityResultContract fails to save the image. I think something with the given URI is messy, but it's beyond my magical powers to solve it. Long story short, here's my code. Hope someone has an idea of how to remedy this issue!
@Composable
fun MyPicker() {
val context = LocalContext.current
val permissionLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission().apply{
}){
}
val imgUri by remember{mutableStateOf("${context.filesDir}/temp.jpg".toUri())}
val captureLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.TakePicture()){
Toast.makeText(context, "Image capture: ${if(it) "Successful" else "Failed"}", Toast.LENGTH_SHORT)
.show()
}
Column {
Button(onClick = {
if(ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA) != PERMISSION_GRANTED)
permissionLauncher.launch(android.Manifest.permission.CAMERA)
else captureLauncher.launch(imgUri)
}) {
Text("Load")
}
Image(painter = rememberAsyncImagePainter(imgUri), null)
}
}
The error says different things for each Uri I provide. For example, for the above uri, it says the following:
E exception while saving result to URI: Optional.of(/data/user/0/com.mycompany.activityops/files/temp.jpg)
java.io.FileNotFoundException: No content provider: /data/user/0/com.mycompany.activityops/files/temp.jpg
And then I tried to, also, provide a Uri.fromFile("${context.filesDir}/temp.jpg")
, which was also frowned upon by Android throwing a huge FileUriExposedException, and then I'm clueless, with my head wandering around storage, content resolvers, Uris, etc.
Upvotes: 1
Views: 3453
Reputation: 876
In a util file create a function which returns a temporary file
fun createImageFile(context: Context): File {
// Create an image file name
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(
"JPEG_${timeStamp}_", //prefix
".jpg", //suffix
storageDir //directory
)
}
Further get uri for the file
val file = Utils.createImageFile(context = context)
val imageUri = FileProvider.getUriForFile(
context,
"application_authority",
file
)
NOTE: The path of the image will be
val path = file.absolutePath
When starting a result contract you need to send uri
val cameraLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.TakePicture(),
onResult = {isSuccess: Boolean ->
// Handle Result
}
cameraLauncher.launch(uri)
On getting a success call back, you can get the image inside file by
File(path) // Where **path** is defined above.
Upvotes: 1