In the Android phone, the best feature is a camera for capturing the picture and videos. And in the apps, we can take pictures and videos just by using default mobile camera app but sometime in the app, we need to add a camera functionality inside our app.
In Google IO 2019, Google added another powerful tool for camera development in Android development called CameraX as part of Jetpack.
CameraX
CameraX is an addition to Jetpack that makes it easier to leverage the capabilities of Camera2 APIs. This topic covers the architecture of CameraX, including its structure, how to work with the API, how to work with Lifecycles, and how to combine use cases.
Steps to implement cameraX
1. Add the dependency in build.gradle file
1 2 3 4 5 |
dependencies { def camerax_version = "1.0.0-alpha01" implementation "androidx.camera:camera-core:$camerax_version" implementation "androidx.camera:camera-camera2:$camerax_version" } |
2. We are using TextureView tag in order to display camera in a view. Please review the xml file here:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<?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" tools:context=".CameraActivity"> <TextureView android:id="@+id/texture" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <com.google.android.material.button.MaterialButton android:id="@+id/btn_take_picture" style="@style/Widget.MaterialComponents.Button" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:gravity="center" android:text="@string/capture" android:textAllCaps="false" android:textColor="@android:color/black" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> |
3. Now, we have to add Camera permission in AndroidManifest file
1 |
<uses-permission android:name="android.permission.CAMERA" /> |
And we also need to take runtime permission for all android version 6 and above.
4. Now we have to add the following code in the CameraActivity.kt file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
class CameraActivity: AppCompatActivity() { private var lensFacing = CameraX.LensFacing.BACK private val TAG = "CameraActivity" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) texture.post { startCamera() } // Every time the provided texture view changes, recompute layout texture.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> updateTransform() } } private fun startCamera() { val metrics = DisplayMetrics().also { texture.display.getRealMetrics(it) } val screenSize = Size(metrics.widthPixels, metrics.heightPixels) val screenAspectRatio = Rational(metrics.widthPixels, metrics.heightPixels) val previewConfig = PreviewConfig.Builder().apply { setLensFacing(lensFacing) setTargetResolution(screenSize) setTargetAspectRatio(screenAspectRatio) setTargetRotation(windowManager.defaultDisplay.rotation) setTargetRotation(texture.display.rotation) }.build() val preview = Preview(previewConfig) preview.setOnPreviewOutputUpdateListener { texture.surfaceTexture = it.surfaceTexture updateTransform() } // Create configuration object for the image capture use case val imageCaptureConfig = ImageCaptureConfig.Builder() .apply { setLensFacing(lensFacing) setTargetAspectRatio(screenAspectRatio) setTargetRotation(texture.display.rotation) setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY) }.build() // Build the image capture use case and attach button click listener val imageCapture = ImageCapture(imageCaptureConfig) btn_take_picture.setOnClickListener { val file = File( Environment.getExternalStorageDirectory().toString() + "${CameraActivity.folderPath}${System.currentTimeMillis()}.jpg" ) imageCapture.takePicture(file, object : ImageCapture.OnImageSavedListener { override fun onError( error: ImageCapture.UseCaseError, message: String, exc: Throwable? ) { val msg = "Photo capture failed: $message" Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() } override fun onImageSaved(file: File) { val msg = "Photo capture successfully: ${file.absolutePath}" Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() } }) } CameraX.bindToLifecycle(this, preview, imageCapture) } private fun updateTransform() { val matrix = Matrix() val centerX = texture.width / 2f val centerY = texture.height / 2f val rotationDegrees = when (texture.display.rotation) { Surface.ROTATION_0 -> 0 Surface.ROTATION_90 -> 90 Surface.ROTATION_180 -> 180 Surface.ROTATION_270 -> 270 else -> return } matrix.postRotate(-rotationDegrees.toFloat(), centerX, centerY) texture.setTransform(matrix) } } |
- CameraX.bindToLifecycle() binds to the lifecycle of the view.
- PreviewConfig.Builder() is the builder class for PreviewConfig(which helps to see the Preview of Image) where you can set different type of configuration like lens facing side, target resolution, Aspect ratio with setLensFacing(value) where value = CameraX.LensFacing.BACK/FRONT etc.
- ImageCaptureConfiguration.Builder() is the configuration for the image when the image is captured.
- rotationDegrees Using this, we can rotate of the Preview and finally, texture sets the transformation using texture.setTransform(matrix)and matrix rotates the preview based on rotationDegress.
- when a button, button_take_picture is clicked, we have to click and image and store it in out Local storage.
- in the Click listeners, we take images using takePicture and it implements two methods onError() and onImageSaved().
Benefits:-
- You can also create Video Recorder App using CameraX
- You can also implement Image Analysis using CameraX
- Add multiple extensions like Portrait Mode, HDR, etc.
- We can also use Image Analysis to perform Computer Vision, ML. So it implements Analyzer method to run on each and every frame.
You can also review the more details about cameraX and its feature and enjoy in making more interesting functionality like dubsmash, edit picture in your android app. Please refer the following the link for more details:-
https://codelabs.developers.google.com/codelabs/camerax-getting-started/#0
https://developer.android.com/training/camerax/architecture