How to Create Custom Camera using CameraX in Android? - GeeksforGeeks

19 Feb, 2021
CameraX is used to create a custom camera in the app. CameraX is a Jetpack support library, built to help you make camera app development easier. A sample video is given below to get an idea about what we are going to do in this article. Note that we are going to implement this project using the Kotlin language.
Step 1: Create a new project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.
Step 2: Add dependency to the build.gradle file and click “sync now”
def camerax_version = “1.0.0-beta07”
// CameraX core library using camera2 implementation
implementation “androidx.camera:camera-camera2:$camerax_version”
// CameraX Lifecycle Library
implementation “androidx.camera:camera-lifecycle:$camerax_version”
// CameraX View class
implementation “androidx.camera:camera-view:1.0.0-alpha14”
If kotlin extension is missing, add kotlin-android-extensions as shown below and click on “Sync now”.
plugins {
   id ‘com.android.application’
   id ‘kotlin-android’
   id ‘kotlin-android-extensions’
}
Step 3: Add Camera permission
Go to AndroidManifest.xml and add the camera permission.
<uses-feature android:name=”android.hardware.camera.any” />
<uses-permission android:name=”android.permission.CAMERA” />
Step 4: Working with the activity_main.xml file
Go to the activity_main.xml file and refer to the following code. Below is the code for the activity_main.xml file. Notice that there is a view called PreviewView with id viewFinder which we will use as Viewfinder for the camera.
XML
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout     xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@color/black"    tools:context=".MainActivity">      <Button        android:id="@+id/camera_capture_button"        android:layout_width="120dp"        android:layout_height="120dp"        android:layout_marginBottom="50dp"        android:background="@drawable/capture_button"        android:elevation="2dp"        android:scaleType="fitCenter"        android:text="Capture Photo"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintLeft_toLeftOf="parent"        app:layout_constraintRight_toRightOf="parent" />      <ImageView        android:id="@+id/iv_capture"        android:layout_width="100dp"        android:layout_height="100dp"        android:layout_marginEnd="20dp"        android:layout_marginBottom="50dp"        android:visibility="gone"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintRight_toRightOf="parent" />      <androidx.camera.view.PreviewView        android:id="@+id/viewFinder"        android:layout_width="match_parent"        android:layout_height="450dp"        android:layout_marginStart="20dp"        android:layout_marginTop="20dp"        android:layout_marginEnd="20dp"        app:layout_constraintLeft_toLeftOf="parent"        app:layout_constraintRight_toRightOf="parent"        app:layout_constraintTop_toTopOf="parent" />  </androidx.constraintlayout.widget.ConstraintLayout>
Step 5: Create capture button drawable
Go to res > drawable and create a new file capture_button.xml. Below is the code of it.
XML
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="oval">    <solid android:color="#0F9D58" />    <size        android:width="118dp"        android:height="118dp" /></shape>
Step 6: Working with the MainActivity.kt file
Go to the MainActivity.kt file and refer to the following code. Below is the code for the MainActivity.kt file. Comments are added inside the code to understand the code in more detail.
Kotlin
import android.Manifestimport android.content.pm.PackageManagerimport android.net.Uriimport android.os.Bundleimport android.util.Logimport android.view.Viewimport android.widget.Buttonimport android.widget.ImageViewimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport androidx.camera.core.CameraSelectorimport androidx.camera.core.ImageCaptureimport androidx.camera.core.ImageCaptureExceptionimport androidx.camera.core.Previewimport androidx.camera.lifecycle.ProcessCameraProviderimport androidx.core.app.ActivityCompatimport androidx.core.content.ContextCompatimport kotlinx.android.synthetic.main.activity_main.*import java.io.Fileimport java.text.SimpleDateFormatimport java.util.*import java.util.concurrent.ExecutorServiceimport java.util.concurrent.Executors  class MainActivity : AppCompatActivity() {      private var imageCapture: ImageCapture? = null    private lateinit var outputDirectory: File    private lateinit var cameraExecutor: ExecutorService      override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)          // hide the action bar        supportActionBar?.hide()          // Check camera permissions if all permission granted        // start camera else ask for the permission        if (allPermissionsGranted()) {            startCamera()        } else {            ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)        }          // set on click listener for the button of capture photo        // it calls a method which is implemented below        findViewById<Button>(R.id.camera_capture_button).setOnClickListener {            takePhoto()        }        outputDirectory = getOutputDirectory()        cameraExecutor = Executors.newSingleThreadExecutor()    }      private fun takePhoto() {        // Get a stable reference of the        // modifiable image capture use case        val imageCapture = imageCapture ?: return          // Create time-stamped output file to hold the image        val photoFile = File(            outputDirectory,            SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis()) + ".jpg"        )          // Create output options object which contains file + metadata        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()          // Set up image capture listener,        // which is triggered after photo has        // been taken        imageCapture.takePicture(            outputOptions,            ContextCompat.getMainExecutor(this),            object : ImageCapture.OnImageSavedCallback {                override fun onError(exc: ImageCaptureException) {                    Log.e(TAG, "Photo capture failed: ${exc.message}", exc)                }                  override fun onImageSaved(output: ImageCapture.OutputFileResults) {                    val savedUri = Uri.fromFile(photoFile)                      // set the saved uri to the image view                    findViewById<ImageView>(R.id.iv_capture).visibility = View.VISIBLE                    findViewById<ImageView>(R.id.iv_capture).setImageURI(savedUri)                      val msg = "Photo capture succeeded: $savedUri"                    Toast.makeText(baseContext, msg, Toast.LENGTH_LONG).show()                    Log.d(TAG, msg)                }            })    }      private fun startCamera() {        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)          cameraProviderFuture.addListener(Runnable {                          // Used to bind the lifecycle of cameras to the lifecycle owner            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()              // Preview            val preview = Preview.Builder()                .build()                .also {                    it.setSurfaceProvider(viewFinder.createSurfaceProvider())                }              imageCapture = ImageCapture.Builder().build()              // Select back camera as a default            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA              try {                // Unbind use cases before rebinding                cameraProvider.unbindAll()                  // Bind use cases to camera                cameraProvider.bindToLifecycle(                    this, cameraSelector, preview, imageCapture                )              } catch (exc: Exception) {                Log.e(TAG, "Use case binding failed", exc)            }          }, ContextCompat.getMainExecutor(this))    }      private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {        ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED    }      // creates a folder inside internal storage    private fun getOutputDirectory(): File {        val mediaDir = externalMediaDirs.firstOrNull()?.let {            File(it, resources.getString(R.string.app_name)).apply { mkdirs() }        }        return if (mediaDir != null && mediaDir.exists())            mediaDir else filesDir    }      // checks the camera permission    override fun onRequestPermissionsResult(        requestCode: Int, permissions: Array<String>, grantResults:        IntArray    ) {        if (requestCode == REQUEST_CODE_PERMISSIONS) {            // If all permissions granted , then start Camera            if (allPermissionsGranted()) {                startCamera()            } else {                // If permissions are not granted,                // present a toast to notify the user that                // the permissions were not granted.                Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show()                finish()            }        }    }      companion object {        private const val TAG = "CameraXGFG"        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"        private const val REQUEST_CODE_PERMISSIONS = 20        private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)    }      override fun onDestroy() {        super.onDestroy()        cameraExecutor.shutdown()    }}
Android
Kotlin
Android
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Comments
Old Comments
Flutter - Custom Bottom Navigation Bar
How to Read Data from SQLite Database in Android?
How to Post Data to API using Retrofit in Android?
Android Listview in Java with Example
Retrofit with Kotlin Coroutine in Android
Android UI Layouts
Kotlin Array
Retrofit with Kotlin Coroutine in Android
Kotlin Setters and Getters