Compatible with all Android versions of Androidx Camera preview and image acquisition

Compatible with all Android versions of Androidx camera preview and image acquisition

1. Add reference
dependencies {<!-- -->
    def camerax_version = "1.0.0-beta06"
    // CameraX core library
    implementation "androidx.camera:camera-camera2:$camerax_version"
    // CameraX life cycle
    implementation "androidx.camera:camera-lifecycle:$camerax_version"
    // CameraX view collection, such as cameraview, preview, etc.
    implementation "androidx.camera:camera-view:1.0.0-alpha10"

2. Add permissions to AndroidManifest.xml

 <uses-feature android:name="android.hardware.camera.autofocus" />
    <uses-feature android:name="android.hardware.camera.any" />

3. Layout file

 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">


        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <Button
                android:id="@ + id/btn_trans"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Switch camera"
                app:layout_constraintStart_toStartOf="@ + id/viewFinder"
                app:layout_constraintTop_toTopOf="@ + id/viewFinder" />

            <Button
                android:id="@ + id/btn_takePhoto"
                android:layout_width="100dp"
                android:layout_height="60dp"
                android:layout_marginBottom="50dp"
                android:elevation="2dp"
                android:scaleType="fitCenter"
                android:text="photograph"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent" />

            <androidx.camera.view.PreviewView
                android:id="@ + id/viewFinder"
                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" />

        </androidx.constraintlayout.widget.ConstraintLayout>

    </LinearLayout>

4. All source codes in the activity

package cn.wildfire.chat.app;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;


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

import java.io.File;
import java.io.IOException;

import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import cn.wildfirechat.chat.R;

public class RLSB2Activity extends AppCompatActivity implements View.OnClickListener {<!-- -->
    SurfaceView surfaceview;
    SurfaceHolder holder;
    Camera mCamera;
    PreviewView mViewFinder;

    private ImageCapture mImageCapture;
    private int mFacing = CameraSelector.LENS_FACING_BACK;
    @Override
    protected void onCreate(Bundle savedInstanceState) {<!-- -->
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rlsb2);
        ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        mViewFinder=findViewById(R.id.viewFinder);
        initView();

        findViewById(R.id.btn_trans).setOnClickListener(this);
        findViewById(R.id.btn_takePhoto).setOnClickListener(this);

    }

    private static final String TAG = "MainActivity";






    protected void initView() {<!-- -->
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {<!-- -->
            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {<!-- -->
                requestPermissions(new String[] {<!-- -->Manifest.permission.CAMERA}, 1);
            }
        }
        startCamera();
    }

    private void startCamera() {<!-- -->
        //Return the ProcessCameraProvider that can currently bind the life cycle
        ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        cameraProviderFuture.addListener(new Runnable() {<!-- -->
            @SuppressLint("RestrictedApi")
            @Override
            public void run() {<!-- -->
                try {<!-- -->
                    //Bind the life cycle of the camera with the life cycle of the activity, camerax will release itself, don't worry
                    ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                    //Preview capture, which supports angle conversion
                    Preview preview = new Preview. Builder(). build();

                    //Create a capture of the image
                    mImageCapture = new ImageCapture. Builder()
                            .setFlashMode(ImageCapture.FLASH_MODE_AUTO)
                            .build();


                    // select rear camera
                    CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(mFacing).build();

                    //Unbind before preview
                    cameraProvider. unbindAll();

                    //Bind the data into the life cycle of the camera
                    Camera camera = cameraProvider.bindToLifecycle(RLSB2Activity.this, cameraSelector, preview, mImageCapture);

                    // Give the surface of the previewview to the camera to preview
                    preview.setSurfaceProvider(mViewFinder.createSurfaceProvider(camera.getCameraInfo()));

                } catch (Exception e) {<!-- -->
                    e.printStackTrace();
                }
            }
        }, ContextCompat. getMainExecutor(this));
    }


    @Override
    public void onClick(View v) {<!-- -->
        switch (v.getId()) {<!-- -->
            case R.id.btn_trans:
                switchCamera();
                break;

            case R.id.btn_takePhoto:
                takePhoto();
                break;
        }
    }


    public void switchCamera() {<!-- -->
        /**
         * The problem with the white screen is that PreviewView removes all Views and no data is sent to Surface.
         * So only the background color is left, and it can be processed next time
         */
        mFacing = mFacing == CameraSelector.LENS_FACING_FRONT?
                CameraSelector.LENS_FACING_BACK: CameraSelector.LENS_FACING_FRONT;
        startCamera();
    }

    public void takePhoto() {<!-- -->
        //Get the root directory
        String path="" + Environment. getExternalStorageDirectory();
        if (mImageCapture != null) {<!-- -->
            File dir = new File(path);
            if (!dir. exists()) {<!-- -->
                dir.mkdirs();
            }
            //Create a file
            File file = new File(path,"testx.jpg");
            if (file. exists()) {<!-- -->
                file.delete();
            }
            //Create the data of the package file, such as creating a file
            ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();

            //Start taking pictures
            mImageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() {<!-- -->
                @Override
                public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {<!-- -->
                    // Uri savedUri = outputFileResults. getSavedUri();
                    Toast.makeText(RLSB2Activity.this, "Saved successfully: ", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onError(@NonNull ImageCaptureException exception) {<!-- -->
                    Toast.makeText(RLSB2Activity.this, "Failed to save", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }



}