An Introduction to CameraX

Photo by Evan Wise on Unsplash

How it helps

Ease of use:

Consistency across devices:

Add ons:

Project:

Importing the dependencies

//Material Design
implementation 'com.google.android.material:material:1.1.0-alpha05'

// CameraX
def
camerax_version = "1.0.0-alpha01"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"

Creating the UI

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">

<TextureView
android:id="@+id/view_finder"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="normal"
android:src="@drawable/ic_camera"
android:layout_alignParentBottom="true"
android:layout_margin="32dp"
android:layout_centerHorizontal="true"
app:backgroundTint="@android:color/white"/>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_flash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="normal"
android:src="@drawable/ic_flash"
android:layout_alignParentBottom="true"
android:layout_margin="32dp"
app:backgroundTint="@android:color/white"/>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_switch_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="normal"
android:src="@drawable/ic_switch_camera"
android:layout_alignParentBottom="true"
android:layout_margin="32dp"
android:layout_alignParentRight="true"
app:backgroundTint="@android:color/white"/>

</RelativeLayout>

Requesting the required permissions

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
val permissions = arrayOf(android.Manifest.permission.CAMERA, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)private fun hasNoPermissions(): Boolean{
return ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
}
fun requestPermission(){
ActivityCompat.requestPermissions(this, permissions,0)
}

Configuring the preview

private fun bindCamera(){
val
previewConfig = PreviewConfig.Builder()
.setLensFacing(lensFacing)
.build()
}
val preview = Preview(previewConfig)

// The view that displays the preview
val
textureView: TextureView = findViewById(R.id.view_finder)
// Handles the output data of the camera
preview.setOnPreviewOutputUpdateListener { previewOutput ->
// Displays the camera image in our preview view
textureView.surfaceTexture = previewOutput.surfaceTexture
}

Taking an image

// Image capture config which controls the Flash and Lens
val
imageCaptureConfig = ImageCaptureConfig.Builder()
.setTargetRotation(windowManager.defaultDisplay.rotation)
.setLensFacing(lensFacing)
.setFlashMode(FlashMode.ON)
.build()

imageCapture = ImageCapture(imageCaptureConfig)
private val filename = "test.png"
private val sd = Environment.getExternalStorageDirectory()
private val dest = File(sd, filename)
// Takes an images and saves it in the local storage
fab_camera.setOnClickListener {
imageCapture?.takePicture(dest,
object : ImageCapture.OnImageSavedListener {
override fun onError(error: ImageCapture.UseCaseError,
message: String, exc: Throwable?) {
Log.e("Image", error.toString())
}
override fun onImageSaved(file: File) {
Log.v("Image", "Successfully saved image")
}
})
}

Switching flash state

// Changes the flash mode when the button is clicked
fab_flash.setOnClickListener {
val flashMode = imageCapture?.flashMode
if
(flashMode == FlashMode.ON) imageCapture?.flashMode = FlashMode.OFF
else imageCapture?.flashMode = FlashMode.ON
}

Switching lenses

CameraX.unbindAll()
private var lensFacing = CameraX.LensFacing.BACK// Changes the lens direction if the button is clicked
fab_switch_camera.setOnClickListener {
lensFacing = if (CameraX.LensFacing.FRONT == lensFacing) {
CameraX.LensFacing.BACK
} else {
CameraX.LensFacing.FRONT
}
bindCamera()
}

Bind the camera to the lifecycle

CameraX.bindToLifecycle(this as LifecycleOwner, imageCapture, preview)

Complete Source Code for the MainActivity.kt

Looking up the image

Closing Notes

Android Developer | Web Developer | Part-time Blogger | Catch me at https://gabrieltanner.org/ | Buy me a coffee buymeacoff.ee/gabrieltanner

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store