Blog Infos
Author
Published
Topics
,
Published
CameraX OverView:

While it leverages the capabilities of camera2, it uses a simpler, use a case-based approach that is lifecycle-aware. It also resolves device compatibility issues for you so that you don’t have to include device-specific code in your codebase. These features reduce the amount of code you need to write when adding camera capabilities to your app.

Lastly, CameraX enables developers to leverage the same camera experiences and features that preinstalled camera apps provide, with as little as two lines of code. CameraX Extensions are optional add-ons that enable you to add effects on supported devices. These effects include Portrait, HDR, Night, and Beauty.

The Architecture:
  • Preview: In the preview use case, you get a preview of what the camera is seeing. To display it to the user you can use Preview View
  • Image analysis: If you are building an application using TensorFlow lite or any other machine learning task, Image Analysis provides you with a buffer of images that is accessible by the CPU
  • Image capture: As the name suggests in this use case you can click and save pictures.
The Process:

CameraX Process of Image Capture

 

  • Step 1: The camera is hardware and to access it you need permissions. So, the first step is to ask the user for camera access permission
  • Step 2: Once you get the permission you need to bind the camera to your application to get a preview of what the camera is seeing
  • Step 3: After binding the camera to our app, We need to get the preview as described in the preview use case.
  • Step 4: Now, we need to add some control to our layout, so, the user can interact with the camera.
  • Step 5: Start capturing pictures
Let’s Get To Code:
dependencies {
  // CameraX core library using the camera2 implementation
  def camerax_version = "1.0.0-rc03"
  // The following line is optional, as the core library is included indirectly by camera-camera2
  implementation "androidx.camera:camera-core:${camerax_version}"
  implementation "androidx.camera:camera-camera2:${camerax_version}"
  // If you want to additionally use the CameraX Lifecycle library
  implementation "androidx.camera:camera-lifecycle:${camerax_version}"
  // If you want to additionally use the CameraX View class
  implementation "androidx.camera:camera-view:1.0.0-alpha22"
  // If you want to additionally use the CameraX Extensions library
  implementation "androidx.camera:camera-extensions:1.0.0-alpha22"
}

Now, we need a preview to our layout so we can see the world from the camera’s eye

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<androidx.camera.view.PreviewView
android:id="@+id/viewFinder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:foreground="@color/black"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintTop_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
view raw layout.xml hosted with ❤ by GitHub

Lets get the permissions. In your manifest file add this permission.

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.camera2"
android:required="true" />
view raw manifest.xml hosted with ❤ by GitHub

We will use Activity Result contracts to get the required permission from user.

private val cameraPermission =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
with(binding.root) {
when {
granted -> {
showToastMessageInCenter("Permission Granted")
startCamera()
}
shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
//this will be shown if the phone is running on api level > 23 else only classic dialog will be shown
showToastMessageInCenter("Permission Denied,Permission is needed to take photos")
}
else -> showToastMessageInCenter("Permission Denied")
}
}
}

After showing rationale you can also send the user to settings if the user declined the permission request

private fun openSettings() {
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
addCategory(Intent.CATEGORY_DEFAULT)
data = Uri.parse("package:$packageName")
}.run(::startActivity)
}
view raw openSettings.kt hosted with ❤ by GitHub

Now, we have to check if permission is allowed then let’s start building our camera and implement the startCamera() function.

private fun checkPermissions() {
if (allPermissionsGranted()) {
startCamera()
} else {
cameraPermission.launch(Manifest.permission.CAMERA)
}
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
requireContext(), it
) == PackageManager.PERMISSION_GRANTED
}

If you recall, the first step was to connect the camera to your application. In order to do so, first, we get an instance of the Camera using ProcessCameraProvider which returns a complete able future. Using the get method we then acquire an instance of the camera.

val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
}, ContextCompat.getMainExecutor(requireContext()))

To show the user what our camera is seeing we need to get a preview from the camera and display it into the preview that we created in the XML file. To complete the preview we set the surface provider using the preview view.

val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
preview = Preview.Builder().build().apply {
setSurfaceProvider(binding.viewFinderPkgDetails.createSurfaceProvider())
}
}, ContextCompat.getMainExecutor(requireContext()))
view raw preview.kt hosted with ❤ by GitHub

After getting the preview we will create an image capture object which will eventually help us in capturing images using our camera

val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
preview = Preview.Builder().build().apply {
setSurfaceProvider(binding.viewFinderPkgDetails.createSurfaceProvider())
}
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
}, ContextCompat.getMainExecutor(requireContext()))
view raw ImageCapture.kt hosted with ❤ by GitHub

Some other app may be using the camera so we need to unbind the camera from that application. We will use cameraProvider.unbindAll() to do this task. Then we will bind the camera to our activity/fragment lifecycle and set which camera to use, our preview so the camera can send a preview to our preview view and our image capture object.

val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
preview = Preview.Builder().build().apply {
setSurfaceProvider(binding.viewFinderPkgDetails.createSurfaceProvider())
}
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
cameraProvider.unbindAll()
cameraX = cameraProvider.bindToLifecycle(viewLifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA , preview, imageCapture)
}, ContextCompat.getMainExecutor(requireContext()))

Job Offers

Job Offers


    iOS Engineer

    American Express
    London | Phoenix | New York
    • Full Time
    apply now

    Softwareentwickler Java und Kotlin / Android (w/m/d)

    AVM GmbH
    Berlin
    • Full Time
    apply now

    Senior Android Engineer (m/f/d)

    Flink
    Berlin
    • Full Time
    apply now
Load more listings

OUR VIDEO RECOMMENDATION

, ,

Automated migration of Android apps to Bazel build system

Migrating large projects that consist of hundreds or thousands of modules and being maintained by a large team, from Gradle to Bazel might be challenging. I would like to discuss the process of automation of…
Watch Video

Automated migration of Android apps to Bazel build system

Pavlo Stavytskyi
Software Engineer
Lyft

Automated migration of Android apps to Bazel build system

Pavlo Stavytskyi
Software Engineer
Lyft

Automated migration of Android apps to Bazel build system

Pavlo Stavytskyi
Software Engineer
Lyft

Jobs

This is the final code for our start camera function after that you should be able to view the camera preview in your app

In the next part, we will add torch, flashlight, zoom and image capturing capabilities to our app.

Connect with me on LinkedIn

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
Hi, today I come to you with a quick tip on how to update…
READ MORE
blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…
READ MORE

Leave a Reply

Your email address will not be published.

Fill out this field
Fill out this field
Please enter a valid email address.

Menu