Skip to main content

Working with Camera

1. Requesting Camera Permission

Permission Description Required in Manifest Runtime Check
android.permission.CAMERA Allows access to camera hardware for taking photos and recording videos true ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED

Example: Check and Request Camera Permission

val CAMERA_PERMISSION = Manifest.permission.CAMERA
val PERMISSION_REQUEST_CODE = 100

if (ContextCompat.checkSelfPermission(this, CAMERA_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, arrayOf(CAMERA_PERMISSION), PERMISSION_REQUEST_CODE)
} else {
    // Permission already granted, proceed to open camera
}

Example: Handle Permission Result

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    when (requestCode) {
        PERMISSION_REQUEST_CODE -> {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission granted, initialize camera
            } else {
                // Permission denied, show rationale or disable feature
            }
        }
    }
}

2. Using Camera Intent

Property Description Example
Intent.ACTION_IMAGE_CAPTURE Standard intent to capture an image using the device camera Intent(Intent.ACTION_IMAGE_CAPTURE)
EXTRA_OUTPUT Specifies the file URI where the captured image should be saved Intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)

Example: Launch Camera Intent

val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val photoFile = File(externalCacheDir, "photo.jpg")
val imageUri = FileProvider.getUriForFile(this, "com.example.fileprovider", photoFile)
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE)
Note: Ensure you have the necessary permissions in your manifest and handle runtime permissions for Android 6.0+.

3. Capturing Photos

Property Description Values
CameraProvider Interface to access camera functionality androidx.camera.core.CameraProvider
ImageCapture Class for capturing images from camera androidx.camera.core.ImageCapture
ImageCaptureMode Mode for image capture (e.g., JPEG, RAW) ImageCapture.Mode

Example: Capturing a Photo

val imageCapture = ImageCapture.Builder()
    .setTargetRotation(viewFinder.display.rotation)
    .build()

val photoFile = File(context.filesDir, "photo.jpg")
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

imageCapture.takePicture(
    outputFileOptions,
    ContextCompat.getMainExecutor(context),
    object : ImageCapture.OnImageSavedCallback {
        override fun onImageSaved(output: ImageCapture.OutputFileResults) {
            val savedUri = output.savedUri ?: return
            Log.d("Camera", "Photo saved: $savedUri")
        }

        override fun onError(exception: ImageCaptureException) {
            Log.e("Camera", "Photo capture failed: ${exception.message}")
        }
    }
)
Note: Ensure camera permissions are requested and granted before capturing photos.
Warning: ImageCapture may fail silently if the camera is not properly initialized or if permissions are missing.

4. Saving Captured Images

Property Description Values
outputFile File path where the captured image is saved File("/sdcard/DCIM/camera_image.jpg")
format Image format to save in "JPEG", "PNG"
quality Compression quality (0-100) 90
val outputFile = File(context.getExternalFilesDir(null), "captured_image.jpg")
val imageCapture = ImageCapture.Builder()
    .setTargetRotation(Surface.ROTATION_0)
    .setFileOutputFormat(ImageCapture.FORMAT_JPEG)
    .build()

val imageCaptureCallback = ImageCapture.OnImageSavedCallback { output ->
    val savedUri = output.savedUri
    if (savedUri != null) {
        // Notify gallery about new image
        val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
        intent.data = savedUri
        context.sendBroadcast(intent)
    }
}
Note: Ensure you have WRITE_EXTERNAL_STORAGE permission in your manifest to save images to external storage.
Warning: On Android 10+, you must use MediaStore API for media access.

5. Using CameraX

Example: Basic CameraX Setup

import androidx.camera.core.CameraProvider
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class CameraActivity : AppCompatActivity() {
    private lateinit var cameraProvider: ProcessCameraProvider
    private lateinit var previewView: PreviewView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_camera)

        previewView = findViewById(R.id.preview_view)
        startCamera()
    }

    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        cameraProviderFuture.addListener({
            cameraProvider = cameraProviderFuture.get()
            val preview = Preview.Builder().build().apply {
                setSurfaceProvider(previewView.surfaceProvider)
            }
            cameraProvider.bindToLifecycle(this, CameraSelector.DEFAULT_BACK_CAMERA, preview)
        }, ContextCompat.getMainExecutor(this))
    }
}
Property Description Values Notes
Preview.Builder() Creates a preview use case Preview Used to display live camera feed
CameraSelector.DEFAULT_BACK_CAMERA Selects the back camera CameraSelector Can also use DEFAULT_FRONT_CAMERA
setSurfaceProvider() Assigns the surface to display preview SurfaceProvider Required for preview to render
Note: CameraX requires androidx.camera:camera-core, camera-lifecycle, and camera-view dependencies.
Warning: CameraX is not available on all Android versions. Ensure compatibility using CameraProvider.

Key Features of CameraX

  • Easy camera integration with lifecycle-aware components
  • Supports both front and back cameras
  • Handles camera permission requests automatically
  • Provides a consistent API across device models

6. Configuring CameraX Use Cases

Use Case Description Configuration Notes
Preview Displays live camera feed to the screen Preview.Builder() Must be added to CameraProvider
ImageCapture Captures still images from the camera ImageCapture.Builder() Supports JPEG and RAW formats
VideoCapture Records video from the camera VideoCapture.Builder() Uses MediaRecorder under the hood

Example: Setting up Preview Use Case

val preview = Preview.Builder().build()
preview.setSurfaceProvider(viewFinder.surfaceProvider)

Example: Setting up ImageCapture Use Case

val imageCapture = ImageCapture.Builder()
    .setTargetRotation(viewFinder.display.rotation)
    .build()

Example: Setting up VideoCapture Use Case

val videoCapture = VideoCapture.Builder()
    .setTargetRotation(viewFinder.display.rotation)
    .build()

7. Capturing Images with CameraX

Property Description Values
cameraProvider Provides access to camera devices CameraProvider
imageCapture Handles image capture operations ImageCapture
previewView Displays live camera preview PreviewView

Example: Setting up CameraX for image capture

import androidx.camera.core.CameraProvider
import androidx.camera.core.ImageCapture
import androidx.camera.core.PreviewView

class CameraActivity : AppCompatActivity() {
    private lateinit var cameraProvider: CameraProvider
    private lateinit var imageCapture: ImageCapture

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_camera)

        val previewView = findViewById<PreviewView>(R.id.previewView)
        imageCapture = ImageCapture.Builder().build()

        cameraProvider = ProcessCameraProvider.getInstance(this).get()
    }
}

Example: Capturing an image

val outputFile = File(context.filesDir, "image.jpg")
val outputOptions = ImageCapture.OutputFileOptions.Builder(outputFile).build()

imageCapture.takePicture(
    outputOptions,
    ContextCompat.getMainExecutor(context),
    object : ImageCapture.OnImageSavedCallback {
        override fun onImageSaved(savedImage: ImageCapture.OutputFileResults) {
            val msg = "Image saved successfully"
            Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
        }

        override fun onError(exception: ImageCaptureException) {
            val msg = "Image capture failed: ${exception.message}"
            Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
        }
    }
)
Note: Ensure you have added the necessary permissions in AndroidManifest.xml for camera access and storage.
Warning: CameraX requires Android 5.0 (API level 21) or higher.

8. Recording Video with CameraX

Property Description Values
videoEncoder Specifies the video encoder to use H264, H265
videoFrameRate Frame rate for video recording 30, 60
videoBitRate Video bit rate in bits per second 1000000, 5000000
videoSize Resolution of the recorded video 1920x1080, 1280x720

Example: Start Video Recording

val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

cameraProviderFuture.addListener({
    val cameraProvider = cameraProviderFuture.get()

    val preview = Preview.Builder().build()
    val videoCapture = VideoCapture.Builder().build()

    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    cameraProviderFuture.addListener({
        val cameraProvider = cameraProviderFuture.get()

        val preview = Preview.Builder().build()
        val videoCapture = VideoCapture.Builder().build()

        cameraProvider.unbindAll()
        cameraProvider.bindToLifecycle(
            this, 
            CameraSelector.DEFAULT_BACK_CAMERA,
            preview,
            videoCapture
        )

        val outputFile = File(filesDir, "video.mp4")
        val outputOptions = VideoCapture.OutputFileOptions.Builder(outputFile).build()

        videoCapture.startRecording(
            outputOptions,
            ContextCompat.getMainExecutor(this)
        )
    }, ContextCompat.getMainExecutor(this))
}, ContextCompat.getMainExecutor(this))
Note: Ensure that the app has necessary permissions for camera and storage access.
Warning: Video recording can consume significant battery and storage resources.

9. Setting Camera Parameters

Parameter Description Values Notes
cameraId Unique identifier for the camera 0, 1, etc. Use CameraManager to get available cameras
previewSize Resolution of the camera preview Size(1920, 1080) Must be supported by the camera
pictureSize Resolution of captured images Size(4032, 3024) Must be supported by the camera
flashMode Flash mode for capturing images "auto", "on", "off" Not all devices support flash modes
focusMode Focus mode for capturing images "auto", "macro", "continuous-picture" May not be supported on all devices

Example: Setting Camera Parameters

val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
val cameraId = cameraManager.cameraIdList[0]
val characteristics = cameraManager.getCameraCharacteristics(cameraId)

// Get supported preview sizes
val previewSizes = characteristics.get(
    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
    ?.getOutputSizes(SurfaceTexture::class.java)

// Set preview size
val previewSize = Size(1920, 1080)

// Set picture size
val pictureSize = Size(4032, 3024)

// Set flash mode
val flashMode = CameraMetadata.FLASH_MODE_AUTO

// Set focus mode
val focusMode = CameraMetadata.LENS_FOCUS_DISTANCE

10. Handling Camera Lifecycle

State Description Key Actions Notes
INITIALIZED Camera object created but not opened Initialize camera parameters, set up preview surface Can configure camera settings before opening
OPENED Camera is open and ready for use Start preview, capture frames, set up listeners Preview must be started before capturing images
PREVIEW_STARTED Preview is active and displaying frames Adjust preview size, handle frame callbacks Preview must be running to capture images
CAPTURE_STARTED Image capture in progress Take photo, record video, handle capture results May block preview until capture completes
CLOSED Camera is closed and resources released Release camera resources, remove listeners Must release all resources to prevent memory leaks

Example: Camera Lifecycle Management

class CameraLifecycleManager {
    private var cameraProvider: CameraProvider? = null
    private var camera: Camera? = null

    fun initializeCamera() {
        // INITIALIZED state
        cameraProvider = CameraProvider()
        camera = cameraProvider?.createCamera()
    }

    fun openCamera() {
        // OPENED state
        camera?.open()
        startPreview()
    }

    fun startPreview() {
        // PREVIEW_STARTED state
        camera?.startPreview()
    }

    fun captureImage() {
        // CAPTURE_STARTED state
        camera?.captureImage()
    }

    fun closeCamera() {
        // CLOSED state
        camera?.close()
        camera = null
        cameraProvider = null
    }
}
Note: Always ensure camera resources are released in the CLOSED state to prevent memory leaks and ensure proper device resource management.
Warning: Failing to properly close the camera can lead to device resource exhaustion and app crashes.

11. Implementing Image Analysis

Example: Basic Image Analysis Setup

import android.graphics.Bitmap
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageAnalysisConfig
import androidx.camera.core.ImageProxy
import java.nio.ByteBuffer

class ImageAnalyzer : ImageAnalysis.Analyzer {
    override fun analyze(image: ImageProxy) {
        val bitmap = image.toBitmap()
        // Process bitmap for analysis
        val buffer = image.planes[0].buffer
        val data = ByteArray(buffer.remaining())
        buffer.get(data)
        // Analyze image data
    }
}

val imageAnalysis = ImageAnalysis.Builder()
    .setTargetResolution(Size(640, 480))
    .build()
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context), ImageAnalyzer())
Property Description Values
ImageAnalysis.Builder() Creates a new instance of ImageAnalysis ImageAnalysis.Builder
setTargetResolution() Sets the target resolution for image analysis Size(640, 480)
setAnalyzer() Sets the analyzer to process images ImageAnalysis.Analyzer
Note: Ensure that the camera permission is granted before using ImageAnalysis.
Warning: Image analysis can be CPU-intensive; consider using background threads for processing.

12. Switching Between Cameras

Property Description Values
cameraId Unique identifier for the camera 0, 1, etc.
cameraFacing Direction the camera is facing "front", "back"

Example: Switching Camera

val cameraProvider = CameraProviderManager.getInstance(context)
val cameraSelector = CameraSelector.Builder()
    .requireLensFacing(CameraSelector.LENS_FACING_BACK)
    .build()

val cameraProviderFuture = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// Switch to front camera
val frontCameraSelector = CameraSelector.Builder()
    .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
    .build()

cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(lifecycleOwner, frontCameraSelector, preview)
Note: Ensure the camera is unbound before switching to avoid conflicts.

Was this article helpful?