Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use stock camera app to take photo with Jetpack Compose?

In my app using Jetpack Compose, how can I use the existing stock photo app to take a picture and store it? Google's documentation mentions the depreciated Camera API by using an Intent, but they're using the old view system. And it seems like the newer Camera2 and CameraX APIs both are intended for creating custom camera interfaces directly in the app.

like image 921
rajndev Avatar asked Nov 22 '25 16:11

rajndev


2 Answers

You have to use the activity contracts, see this article for details

class ComposeFileProvider : FileProvider(
    R.xml.filepaths
) {
    companion object {
        fun getImageUri(context: Context): Uri {
            val directory = File(context.cacheDir, "images")
            directory.mkdirs()
            val file = File.createTempFile(
                "selected_image_",
                ".jpg",
                directory,
            )
            val authority = context.packageName + ".fileprovider"
            return getUriForFile(
                context,
                authority,
                file,
            )
        }
    }
}

@Composable
fun ImagePicker(
    modifier: Modifier = Modifier,
) {
    var hasImage by remember {
        mutableStateOf(false)
    }
    var imageUri by remember {
        mutableStateOf<Uri?>(null)
    }

    val imagePicker = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.GetContent(),
        onResult = { uri ->
            hasImage = uri != null
            imageUri = uri
        }
    )

    val cameraLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.TakePicture(),
        onResult = { success ->
            hasImage = success
        }
    )

    val context = LocalContext.current
    Box(
        modifier = modifier,
    ) {
        if (hasImage && imageUri != null) {
            AsyncImage(
                model = imageUri,
                modifier = Modifier.fillMaxWidth(),
                contentDescription = "Selected image",
            )
        }
        Column(
            modifier = Modifier
                .align(Alignment.BottomCenter)
                .padding(bottom = 32.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {
            Button(
                onClick = {
                    imagePicker.launch("image/*")
                },
            ) {
                Text(
                    text = "Select Image"
                )
            }
            Button(
                modifier = Modifier.padding(top = 16.dp),
                onClick = {
                    val uri = ComposeFileProvider.getImageUri(context)
                    imageUri = uri
                    cameraLauncher.launch(uri)
                },
            ) {
                Text(
                    text = "Take photo"
                )
            }
        }
    }
}
like image 92
Francesc Avatar answered Nov 24 '25 06:11

Francesc


You're a bit confused. There's 3 ways to take a picture.

1)Intent. This does not use views- it launches the camera app to take the picture. If you don't need tighter control, use this, it's the easiest way.

2)Camera 1 API. This is deprecated. This does not use views, because it doesn't require you to display anything. Displaying something is your option.

3)Camera 2 API. This is the current API way to do it. Once again, it doesn't require views, because it doesn't require you to display anything.

Also, you did know that you can wrap and view into Jetpack using AndroidView, right? So even if you did want to use a camera built in display view, you can use that. Get used to doing things like that if you go down the compose route, very few libraries use compose.

like image 44
Gabe Sechan Avatar answered Nov 24 '25 05:11

Gabe Sechan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!