<p>This post is about Android Jetpack <span style="color: #000080;"><strong>CameraX </strong><span style="color: #000000;">API and how to implement it in an android application with a simple basic example.</span></span></p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link has-white-color has-text-color has-background" href="https://github.com/arunk7839/AndroidCameraXDemo" style="background-color:#520599" target="_blank" rel="noreferrer noopener"><strong>DOWNLOAD CODE</strong></a></div>
</div>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube"><div class="wp-block-embed__wrapper">
<amp-youtube layout="responsive" width="1200" height="675" data-videoid="tYprBGzW6SY" title="Android Jetpack CameraX Example"><a placeholder href="https://youtu.be/tYprBGzW6SY"><img src="https://i.ytimg.com/vi/tYprBGzW6SY/hqdefault.jpg" layout="fill" object-fit="cover" alt="Android Jetpack CameraX Example"></a></amp-youtube>
</div></figure>



<h3 class="wp-block-heading"><span style="color: #000080;"><strong>CameraX</strong></span></h3>



<ul class="wp-block-list"><li class="p1">CameraX is a Jetpack support library, makes it easier to add camera capabilities to your app.</li><li>It has backward compatibility down to Android API 21.</li><li>It uses a simpler, <span style="color: #000080;"><strong>use case</strong></span>-based approach that is <span style="color: #0000ff;"><strong>lifecycle-aware</strong></span>.</li><li>It resolves device compatibility issues for you so that you don’t have to include device-specific code in your code base.</li><li>It also reduces the amount of code you need to write when adding camera capabilities to your app.</li></ul>



<h3 class="wp-block-heading"><span style="color: #000080;"><strong>CameraX: Use Cases</strong></span></h3>



<p class="p1">We use CameraX to interface with a device’s camera through an abstraction called a <span style="color: #008000;"><strong>use case</strong></span>. The following use cases are available:</p>



<ul class="ul1 wp-block-list"><li class="li1"><span style="color: #0000ff;"><b>Preview</b></span>: accepts a surface for displaying a preview, such as a ;<span style="color: #0000ff;"><strong><span class="s2">PreviewView</span></strong></span>.</li><li class="li1"><span style="color: #0000ff;"><b>Image analysis</b></span>: analyse an image.</li><li class="li1"><span style="color: #0000ff;"><b>Image capture</b></span>: captures and saves an image.</li></ul>



<h3 class="wp-block-heading"><span style="color: #000080;"><strong>Creating new project</strong></span></h3>



<p>1 . Create a new project by going to ;<span style="color: #008000;"><b>File ;</b><span class="s1"><b>⇒</b></span></span><b><span style="color: #008000;"> ;New Android Project</span>,</b> ;select ;<span style="color: #008000;"><strong>Empty Activity</strong></span> ;, provide ;<span style="color: #008000;"><strong>app name</strong></span>, select language to ;<strong><span style="color: #008000;">kotlin</span> ;</strong>and then finally click on ;<span style="color: #008000;"><strong>finish</strong></span>.</p>



<p>2. Open the ;<strong><span class="s1" style="color: #008000;">build.gradle(Module: app)</span></strong> file and add the below <strong>CameraX</strong> dependencies inside the dependencies ;section:</p>



<p><span style="color: #0000ff;"><strong><span class="s1">build.gradle(Module: app)</span></strong></span></p>



<pre class="wp-block-preformatted">dependencies {<br> def camerax_version = "1.0.0-beta07"<br><span style="color: #008000;"><strong>// CameraX core library using camera2 implementation</strong></span><br> implementation "androidx.camera:camera-camera2:$camerax_version"<br><strong><span style="color: #008000;">// CameraX Lifecycle Library</span></strong><br> implementation "androidx.camera:camera-lifecycle:$camerax_version"<br><strong><span style="color: #008000;">// CameraX View class</span></strong><br> implementation "androidx.camera:camera-view:1.0.0-alpha14"<br>}</pre>



<p class="p1">3 . CameraX needs some methods that are part of Java 8, so we need to set our compile options accordingly. At the end of the ;<span class="s1">android</span> ;block, right after ;<span class="s1">buildTypes</span>, add the following:</p>



<pre class="wp-block-preformatted">compileOptions {<br> sourceCompatibility JavaVersion.VERSION_1_8<br> targetCompatibility JavaVersion.VERSION_1_8<br>}</pre>



<p>4 .Open ;<strong><span class="s1" style="color: #008000;">AndroidManifest.xml</span></strong> and add the below permissions before the <span class="s1">application</span> ;tag.</p>



<pre class="wp-block-preformatted"><;uses-feature android:name="android.hardware.camera.any" />;<br><;uses-permission android:name="android.permission.CAMERA" />;</pre>



<ul class="wp-block-list"><li class="p1">Adding <span style="color: #0000ff;"><strong><span class="s1">android.hardware.camera.any</span></strong></span> ;makes sure that the device has a camera. Specifying ;<strong><span class="s1" style="color: #0000ff;">.any</span></strong> ;means that it can be a front camera or a back camera.</li></ul>



<p>5. Adding Camera View (PreviewView) and Capture Button in XML.</p>



<p><strong><span class="has-inline-color" style="color: #0000ff;">activity_main.xml</span></strong></p>


<pre><;?xml version="1.0" encoding="utf-8"?>;<br><;androidx.constraintlayout.widget.ConstraintLayout<br> xmlns:android="http://schemas.android.com/apk/res/android"<br> xmlns:tools="http://schemas.android.com/tools"<br> xmlns:app="http://schemas.android.com/apk/res-auto"<br> android:layout_width="match_parent"<br> android:layout_height="match_parent"<br> tools:context=".MainActivity">;<br><br> <;Button<br> android:id="@+id/camera_capture_button"<br> android:layout_width="100dp"<br> android:layout_height="100dp"<br> android:layout_marginBottom="50dp"<br> android:scaleType="fitCenter"<br> android:text="Capture Photo"<br> app:layout_constraintLeft_toLeftOf="parent"<br> app:layout_constraintRight_toRightOf="parent"<br> app:layout_constraintBottom_toBottomOf="parent"<br> android:elevation="2dp" />;<br><br> <;androidx.camera.view.PreviewView<br> android:id="@+id/viewFinder"<br> android:layout_width="match_parent"<br> android:layout_height="match_parent" />;<br><br><;/androidx.constraintlayout.widget.ConstraintLayout>;</pre>
<h3 class="step-title"><span style="color: #000080;"><strong>Implement Preview use case</strong></span></h3>
<p>6 . To implement the CameraX preview use case, we will implement the <span style="color: #0000ff;"><strong>startCamera()</strong></span> method, which is called after allowing camera permission from user.</p>
<pre><span style="color: #008000;"><strong>// Request camera permissions</strong></span><br>if (allPermissionsGranted()) {<br> <span style="color: #0000ff;"><strong> startCamera()</strong></span><br>} else {<br> ActivityCompat.requestPermissions(<br> this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS<br> )<br>}<br><br>private fun startCamera() {<br><br> val cameraProviderFuture = ProcessCameraProvider.getInstance(this)<br><br> cameraProviderFuture.addListener(Runnable {<br><strong><span style="color: #008000;"> // Used to bind the lifecycle of cameras to the lifecycle owner</span></strong><br> val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()<br><br> <strong><span style="color: #008000;">// Preview </span></strong><br> val preview = Preview.Builder()<br> .build()<br> .also {<br> it.setSurfaceProvider(viewFinder.createSurfaceProvider())<br> }<br><br> <strong><span style="color: #008000;">// Select back camera as a default</span></strong><br> val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA<br><br> try {<br> <strong><span style="color: #008000;">// Unbind use cases before rebinding</span></strong><br> cameraProvider.unbindAll()<br><br> <strong><span style="color: #008000;">// Bind preview use case to camera</span></strong><br> cameraProvider.bindToLifecycle(<br> this, cameraSelector, preview<br> )<br><br> } catch (exc: Exception) {<br> Log.e(TAG, "Use case binding failed", exc)<br> }<br><br> }, ContextCompat.getMainExecutor(this))<br>}</pre>
<ul class="ul1">
<li class="li1">Create an instance of the ;<span style="color: #0000ff;"><strong><a style="color: #0000ff;" href="https://developer.android.com/reference/androidx/camera/lifecycle/ProcessCameraProvider"><span class="s2">ProcessCameraProvider</span></a></strong></span>. This is used to bind the lifecycle of cameras to the lifecycle owner. This eliminates the task of opening and closing the camera since CameraX is lifecycle-aware.</li>
</ul>
<pre>val cameraProviderFuture = ProcessCameraProvider.getInstance(this)</pre>
<ul class="ul1">
<li class="li1">Add a listener to the ;<span class="s2">cameraProviderFuture</span>. Add a ;<span style="color: #008000;"><strong><span class="s2">Runnable</span></strong></span> as one argument and <strong><span style="color: #008000;"><a style="color: #008000;" href="https://developer.android.com/reference/kotlin/androidx/core/content/ContextCompat"><span class="s3">ContextCompat</span></a><span class="s3">.getMainExecutor()</span></span></strong> as the second argument ( returns an <span style="color: #008000;"><strong><a style="color: #008000;" href="https://developer.android.com/reference/java/util/concurrent/Executor"><span class="s3">Executor</span></a></strong></span> that runs on the main thread).</li>
</ul>
<pre>cameraProviderFuture.addListener(Runnable {}, ContextCompat.getMainExecutor(this))</pre>
<ul class="ul1">
<li class="li1">In the ;<span class="s2">Runnable</span>, add a ;<span style="color: #008000;"><strong><a style="color: #008000;" href="https://developer.android.com/reference/androidx/camera/lifecycle/ProcessCameraProvider"><span class="s3">ProcessCameraProvider</span></a></strong></span>. This is used to bind the lifecycle of your camera to the ;<span class="s2">LifecycleOwner</span> within the application&#8217;s process.</li>
</ul>
<pre>val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()</pre>
<ul class="ul1">
<li class="li1">Initialize the <span style="color: #008000;"><strong><a style="color: #008000;" href="https://developer.android.com/reference/kotlin/androidx/camera/core/Preview"><span class="s2">Preview</span></a></strong></span> object, get a surface provider from viewfinder, and then set it on the preview.</li>
</ul>
<pre><strong><span style="color: #008000;">// Preview</span></strong><br>val preview = Preview.Builder()<br> .build()<br> .also {<br> it.setSurfaceProvider(viewFinder.createSurfaceProvider())<br> }</pre>
<ul class="ul1">
<li class="li1">Create a ;<span style="color: #008000;"><strong><a style="color: #008000;" href="https://developer.android.com/reference/androidx/camera/core/CameraSelector"><span class="s2">CameraSelector</span></a></strong></span> ;object and select ;<span style="color: #0000ff;"><strong><span class="s3">DEFAULT_BACK_CAMERA</span></strong></span>.</li>
</ul>
<pre><span style="color: #008000;"><strong>// Select back camera as a default</strong></span><br>val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA</pre>
<ul class="ul1">
<li class="li1">Inside <span class="s2">try</span> block, make sure nothing is bound to your ;<span class="s2">cameraProvider</span>, and then bind your ;<span class="s2">cameraSelector</span> ;and preview object to the ;<span class="s2">cameraProvider</span>. Add catch block to log if there&#8217;s a failure.</li>
</ul>
<pre>try {<br> <strong><span style="color: #008000;"> // Unbind use cases from app lifecycle</span></strong><br> cameraProvider.unbindAll()<br><br> <span style="color: #008000;"><strong>// Bind use cases to camera</strong></span><br> cameraProvider.bindToLifecycle(<br> this, cameraSelector, preview<br> )<br><br>} catch (exc: Exception) {<br> Log.e(TAG, "Use case binding failed", exc)<br>}</pre>
<ul>
<li>Run the app. You should see a camera preview!</li>
</ul>


<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img src="https://c1ctech.com/wp-content/uploads/2021/03/Screenshot_1615977610-1-576x1024.png" alt="" class="wp-image-2427" width="392" height="697"/></figure></div>



<h3 class="step-title wp-block-heading"><span style="color: #000080;"><strong>Implement ImageCapture use case</strong></span></h3>



<p>7 . To capture and save photos, we will implement the<span style="color: #008000;"><strong> takePhoto()</strong></span> method, which is called when the <span style="color: #0000ff;"><strong>CAPTURE PHOTO</strong></span> ;button is pressed .</p>
<!-- WP QUADS Content Ad Plugin v. 2.0.98.1 -->
<div class="quads-location quads-ad2" id="quads-ad2" style="float:none;margin:0px;">

</div>




<pre class="wp-block-preformatted"><strong><span style="color: #008000;">// Set up the listener for capture photo button</span></strong><br>camera_capture_button.setOnClickListener { takePhoto() }<br><br>private fun takePhoto() {<br><br> val imageCapture = imageCapture ?: return<br><br><span style="color: #008000;"><strong> // Create time-stamped output file to hold the image</strong></span><br> val photoFile = File(<br> outputDirectory,<br> SimpleDateFormat(<br> FILENAME_FORMAT, Locale.US<br> ).format(System.currentTimeMillis()) + ".jpg"<br> )<br><br><span style="color: #008000;"><strong> // Create output options object which contains file + metadata</strong></span><br> val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()<br><br> <span style="color: #008000;"><strong>// Set up image capture listener, which is triggered after photo has</strong></span><br><span style="color: #008000;"><strong> // been taken</strong></span><br> imageCapture.takePicture(<br> outputOptions,<br> ContextCompat.getMainExecutor(this),<br> object : ImageCapture.OnImageSavedCallback {<br> override fun onError(exc: ImageCaptureException) {<br> Log.e(TAG, "Photo capture failed: ${exc.message}", exc)<br> }<br><br> override fun onImageSaved(output: ImageCapture.OutputFileResults) {<br> val savedUri = Uri.fromFile(photoFile)<br> val msg = "Photo capture succeeded: $savedUri"<br> Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()<br> Log.d(TAG, msg)<br> }<br> })<br>}</pre>



<ul class="ul1 wp-block-list"><li class="li1">First, get a reference to the ;<span style="color: #0000ff;"><strong><a style="color: #0000ff;" href="https://developer.android.com/reference/kotlin/androidx/camera/core/ImageCapture"><span class="s2">ImageCapture</span></a></strong></span> use case. If the use case is null, exit out of the function. ;</li></ul>



<pre class="wp-block-preformatted">val imageCapture = imageCapture ?: return</pre>



<ul class="ul1 wp-block-list"><li class="li1">Create a file to hold the image. Add a time stamp so the file name will be unique.</li></ul>



<pre class="wp-block-preformatted">val photoFile = File(<br> outputDirectory,<br> SimpleDateFormat(<br> FILENAME_FORMAT, Locale.US<br> ).format(System.currentTimeMillis()) + ".jpg"<br>)</pre>



<ul class="ul1 wp-block-list"><li class="li1">Create an ;<span style="color: #0000ff;"><strong><a style="color: #0000ff;" href="https://developer.android.com/reference/kotlin/androidx/camera/core/ImageCapture.OutputFileOptions"><span class="s2">OutputFileOptions</span></a></strong></span> object, where you can specify things about how you want your output to be. You want the output saved in the file we just created, so add your <span style="color: #008000;"><strong><span class="s3">photoFile</span></strong></span>.</li></ul>



<pre class="wp-block-preformatted"><span style="color: #008000;"><strong>// Create output options object which contains file + metadata</strong></span><br>val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()</pre>



<ul class="ul1 wp-block-list"><li class="li1">Call ;<span style="color: #0000ff;"><strong><span class="s2">takePicture()</span></strong></span> ;on the ;<span class="s2">imageCapture</span> ;object. Pass in ;<span class="s2">outputOptions</span>, the executor, and a callback for when the image is saved. ;</li></ul>



<pre class="wp-block-preformatted">imageCapture.takePicture(<br> outputOptions,<br> ContextCompat.getMainExecutor(this),<br> object : ImageCapture.OnImageSavedCallback {<br> override fun onError(exc: ImageCaptureException) {<br> Log.e(TAG, "Photo capture failed: ${exc.message}", exc)<br> }<br><br> override fun onImageSaved(output: ImageCapture.OutputFileResults) {<br> val savedUri = Uri.fromFile(photoFile)<br> val msg = "Photo capture succeeded: $savedUri"<br> Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()<br> Log.d(TAG, msg)<br> }<br> })</pre>



<ul class="ul1 wp-block-list"><li class="li1"><span style="color: #0000ff;"><strong>onError()</strong></span> : call when image capture fails or saving the image capture fails.</li><li class="li1"><strong><span style="color: #0000ff;">onImageSaved()</span></strong> : call when the photo was taken successfully. Saves the photo to the file you created earlier, present a toast to let the user know it was successful, and print a log statement.</li><li class="li1">Go to the ;<strong><span style="color: #008000;"><span class="s1">startCamera()</span> ;</span></strong>method and copy this code under the code for preview.</li></ul>



<pre class="wp-block-preformatted">imageCapture = ImageCapture.Builder()<br> .build()</pre>



<ul class="ol1 wp-block-list"><li class="li1">Finally, update the call to ;<span style="color: #0000ff;"><strong><span class="s1">bindToLifecycle()</span></strong></span> ;in the ;<span class="s1">try</span> ;block to include the new use case:</li></ul>



<pre class="wp-block-preformatted"><span style="color: #008000;"><strong>// Add imageCapture use case to camera</strong></span><br>cameraProvider.bindToLifecycle(<br> this, cameraSelector, preview, <span style="color: #0000ff;"><strong>imageCapture</strong></span><br>)</pre>



<ul class="wp-block-list"><li>Rerun the app and press ;<span style="color: #008000;"><strong>Capture Photo</strong></span>. You will see a toast presented on the screen and a message in the logs.</li></ul>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img src="https://c1ctech.com/wp-content/uploads/2021/03/Screenshot_1615977619-1-576x1024.png" alt="" class="wp-image-2426" width="303" height="539"/></figure></div>



<p><span style="font-size: inherit; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;">8 . Open </span><strong style="font-size: inherit; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;"><span style="color: #008000;">MainActivity.kt</span></strong><span style="font-size: inherit; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;"> and add the below code.</span></p>



<p><strong><span style="color: #0000ff;">MainActivity.kt</span></strong></p>



<pre class="wp-block-preformatted">package com.c1ctech.androidcameraxdemo<br><br>import androidx.appcompat.app.AppCompatActivity<br>import android.os.Bundle<br>import android.Manifest<br>import android.content.pm.PackageManager<br>import android.net.Uri<br>import android.util.Log<br>import android.widget.Toast<br>import androidx.core.app.ActivityCompat<br>import androidx.core.content.ContextCompat<br>import java.util.concurrent.Executors<br>import androidx.camera.core.*<br>import androidx.camera.lifecycle.ProcessCameraProvider<br>import kotlinx.android.synthetic.main.activity_main.*<br>import java.io.File<br>import java.text.SimpleDateFormat<br>import java.util.*<br>import java.util.concurrent.ExecutorService<br><br>class MainActivity : AppCompatActivity() {<br> private var imageCapture: ImageCapture? = null<br><br> private lateinit var outputDirectory: File<br> private lateinit var cameraExecutor: ExecutorService<br><br> override fun onCreate(savedInstanceState: Bundle?) {<br> super.onCreate(savedInstanceState)<br> setContentView(R.layout.activity_main)<br><br> <span style="color: #008000;"><strong>// Request camera permissions</strong></span><br> if (allPermissionsGranted()) {<br> startCamera()<br> } else {<br> ActivityCompat.requestPermissions(<br> this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS<br> )<br> }<br><br> <span style="color: #008000;"><strong>// Set up the listener for take photo button</strong></span><br> camera_capture_button.setOnClickListener { takePhoto() }<br><br> outputDirectory = getOutputDirectory()<br><br> cameraExecutor = Executors.newSingleThreadExecutor()<br> }<br><br> private fun takePhoto() {<br><br><span style="color: #008000;"><strong> // Get a stable reference of the modifiable image capture use case</strong></span><br> val imageCapture = imageCapture ?: return<br><br><span style="color: #008000;"><strong> // Create time-stamped output file to hold the image</strong></span><br> val photoFile = File(<br> outputDirectory,<br> SimpleDateFormat(<br> FILENAME_FORMAT, Locale.US<br> ).format(System.currentTimeMillis()) + ".jpg"<br> )<br><br><span style="color: #008000;"><strong> // Create output options object which contains file + metadata</strong></span><br> val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()<br><br> <strong><span style="color: #008000;"> // Set up image capture listener, which is triggered after photo has</span></strong><br><strong><span style="color: #008000;"> // been taken</span></strong><br> imageCapture.takePicture(<br> outputOptions,<br> ContextCompat.getMainExecutor(this),<br> object : ImageCapture.OnImageSavedCallback {<br> override fun onError(exc: ImageCaptureException) {<br> Log.e(TAG, "Photo capture failed: ${exc.message}", exc)<br> }<br><br> override fun onImageSaved(output: ImageCapture.OutputFileResults) {<br> val savedUri = Uri.fromFile(photoFile)<br> val msg = "Photo capture succeeded: $savedUri"<br> Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()<br> Log.d(TAG, msg)<br> }<br> })<br> }<br><br> private fun startCamera() {<br><br> val cameraProviderFuture = ProcessCameraProvider.getInstance(this)<br><br> cameraProviderFuture.addListener(Runnable {<br><span style="color: #008000;"><strong> // Used to bind the lifecycle of cameras to the lifecycle owner</strong></span><br> val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()<br><br> <span style="color: #008000;"><strong>// creating Preview instance</strong></span><br> val preview = Preview.Builder()<br> .build()<br> .also {<br> it.setSurfaceProvider(viewFinder.createSurfaceProvider())<br> }<br><br><span style="color: #008000;"><strong> // creating ImageCapture instance</strong></span><br> imageCapture = ImageCapture.Builder()<br> .build()<br><br> <span style="color: #008000;"><strong>// Select back camera as a default</strong></span><br> val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA<br><br> try {<br> <span style="color: #008000;"><strong>// Unbind use cases before rebinding</strong></span><br> cameraProvider.unbindAll()<br><br> <span style="color: #008000;"><strong> // Bind use cases to camera</strong></span><br> cameraProvider.bindToLifecycle(<br> this, cameraSelector, preview, imageCapture<br> )<br><br> } catch (exc: Exception) {<br> Log.e(TAG, "Use case binding failed", exc)<br> }<br><br> }, ContextCompat.getMainExecutor(this))<br> }<br><br> private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {<br> ContextCompat.checkSelfPermission(<br> baseContext, it<br> ) == PackageManager.PERMISSION_GRANTED<br> }<br><br> private fun getOutputDirectory(): File {<br> val mediaDir = externalMediaDirs.firstOrNull()?.let {<br> File(it, resources.getString(R.string.app_name)).apply { mkdirs() }<br> }<br> return if (mediaDir != null &;&; mediaDir.exists())<br> mediaDir else filesDir<br> }<br><br> override fun onDestroy() {<br> super.onDestroy()<br> cameraExecutor.shutdown()<br> }<br><br> companion object {<br> private const val TAG = "CameraXBasic"<br> private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"<br> private const val REQUEST_CODE_PERMISSIONS = 10<br> private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)<br> }<br><br> override fun onRequestPermissionsResult(<br> requestCode: Int, permissions: Array<;String>;, grantResults:<br> IntArray<br> ) {<br> if (requestCode == REQUEST_CODE_PERMISSIONS) {<br> if (allPermissionsGranted()) {<br> startCamera()<br> } else {<br> Toast.makeText(<br> this,<br> "Permissions not granted by the user.",<br> Toast.LENGTH_SHORT<br> ).show()<br> finish()<br> }<br> }<br> }<br>}</pre>


