Android CameraX Java Example

Step 1: Adding Permission in Manifest

Step 2: Adding required dependencies in build.gradle (App level)

def camerax_version = "1.0.0-beta05"implementation "androidx.camera:camera-camera2:${camerax_version}"implementation "androidx.camera:camera-lifecycle:${camerax_version}"implementation"androidx.camera:camera-view:1.0.0-alpha12"implementation "androidx.camera:camera-extensions:1.0.0-alpha12"

Step 3: Adding Camera View (PreviewView) and Capture Button in XML

<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF000000"
>

<androidx.camera.view.PreviewView
android:id="@+id/camera"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:contentDescription="@string/preview_area"
android:importantForAccessibility="no"
app:layout_constraintBottom_toTopOf="@+id/linearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="bottom"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:weightSum="3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/camera">

<androidx.cardview.widget.CardView
android:id="@+id/capture"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:cardBackgroundColor="#ffffff"
app:cardCornerRadius="18dp">

<ImageView
android:id="@+id/captureImg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/capture"
android:src="@mipmap/ic_capture" />

</androidx.cardview.widget.CardView>

</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
  • Create a SurfaceTexture to set on TextureView and PreviewSurfaceProvider.
  • Retrieve the SurfaceTexture from TextureView and set it on PreviewSurfaceProvider.
  • Get the Surface from SurfaceView and set it on PreviewSurfaceProvider.

Step 4: Adding Camera M-permission (Realtime permission)

private int REQUEST_CODE_PERMISSIONS = 1001;
private final String[] REQUIRED_PERMISSIONS = new String[]{"android.permission.CAMERA", "android.permission.WRITE_EXTERNAL_STORAGE"};
private boolean allPermissionsGranted(){

for(String permission : REQUIRED_PERMISSIONS){
if(ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED){
return false;
}
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

if(requestCode == REQUEST_CODE_PERMISSIONS){
if(allPermissionsGranted()){
startCamera();
} else{
Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show();
this.finish();
}
}
}
}

Step 5: Setting up CameraX in Activity

  • Preview: accepts a surface for displaying a preview, such as a PreviewView.
  • Image analysis: provides CPU-accessible buffers for analysis, such as for machine learning.
  • Image capture: captures and saves a photo.
private Executor executor = Executors.newSingleThreadExecutor();private void startCamera() {

final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);

cameraProviderFuture.addListener(new Runnable() {
@Override
public void run() {
try {

ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider);

} catch (ExecutionException | InterruptedException e) {
// No errors need to be handled for this Future.
// This should never be reached.
}
}
}, ContextCompat.getMainExecutor(this));
}

void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {

Preview preview = new Preview.Builder()
.build();

CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();

ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.build();

ImageCapture.Builder builder = new ImageCapture.Builder();

//Vendor-Extensions (The CameraX extensions dependency in build.gradle)
HdrImageCaptureExtender hdrImageCaptureExtender = HdrImageCaptureExtender.create(builder);

// Query if extension is available (optional).
if (hdrImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
// Enable the extension if available.
hdrImageCaptureExtender.enableExtension(cameraSelector);
}

final ImageCapture imageCapture = builder
.setTargetRotation(this.getWindowManager().getDefaultDisplay().getRotation())
.build();
preview.setSurfaceProvider(mPreviewView.createSurfaceProvider()); Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview, imageAnalysis, imageCapture);



captureImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
File file = new File(getBatchDirectoryName(), mDateFormat.format(new Date())+ ".jpg");

ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
imageCapture.takePicture(outputFileOptions, executor, new ImageCapture.OnImageSavedCallback () {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
new Handler().post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "Image Saved successfully", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onError(@NonNull ImageCaptureException error) {
error.printStackTrace();
}
});
}
});
}
if(allPermissionsGranted()){
startCamera(); //start camera if permission has been granted by user
} else{
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
}
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.extensions.HdrImageCaptureExtender;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;

import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

import com.google.common.util.concurrent.ListenableFuture;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity {

private Executor executor = Executors.newSingleThreadExecutor();
private int REQUEST_CODE_PERMISSIONS = 1001;
private final String[] REQUIRED_PERMISSIONS = new String[]{"android.permission.CAMERA", "android.permission.WRITE_EXTERNAL_STORAGE"};

PreviewView mPreviewView;
ImageView captureImage;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mPreviewView = findViewById(R.id.previewView);
captureImage = findViewById(R.id.captureImg);

if(allPermissionsGranted()){
startCamera(); //start camera if permission has been granted by user
} else{
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
}
}

private void startCamera() {

final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);

cameraProviderFuture.addListener(new Runnable() {
@Override
public void run() {
try {

ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider);

} catch (ExecutionException | InterruptedException e) {
// No errors need to be handled for this Future.
// This should never be reached.
}
}
}, ContextCompat.getMainExecutor(this));
}

void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {

Preview preview = new Preview.Builder()
.build();

CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();

ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.build();

ImageCapture.Builder builder = new ImageCapture.Builder();

//Vendor-Extensions (The CameraX extensions dependency in build.gradle)
HdrImageCaptureExtender hdrImageCaptureExtender = HdrImageCaptureExtender.create(builder);

// Query if extension is available (optional).
if (hdrImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
// Enable the extension if available.
hdrImageCaptureExtender.enableExtension(cameraSelector);
}

final ImageCapture imageCapture = builder
.setTargetRotation(this.getWindowManager().getDefaultDisplay().getRotation())
.build();
preview.setSurfaceProvider(mPreviewView.createSurfaceProvider()); Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview, imageAnalysis, imageCapture);



captureImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
File file = new File(getBatchDirectoryName(), mDateFormat.format(new Date())+ ".jpg");

ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
imageCapture.takePicture(outputFileOptions, executor, new ImageCapture.OnImageSavedCallback () {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
new Handler().post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "Image Saved successfully", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onError(@NonNull ImageCaptureException error) {
error.printStackTrace();
}
});
}
});
}

public String getBatchDirectoryName() {

String app_folder_path = "";
app_folder_path = Environment.getExternalStorageDirectory().toString() + "/images";
File dir = new File(app_folder_path);
if (!dir.exists() && !dir.mkdirs()) {

}

return app_folder_path;
}

private boolean allPermissionsGranted(){

for(String permission : REQUIRED_PERMISSIONS){
if(ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED){
return false;
}
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

if(requestCode == REQUEST_CODE_PERMISSIONS){
if(allPermissionsGranted()){
startCamera();
} else{
Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show();
this.finish();
}
}
}
}

--

--

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