Before coding

To understand Camera2 API take a fast look into sample repo and official documentation

Setup empty project

First of all create empty project in Android Studio, like on tutorial

  1. Choose "Start a new Android Studio project".
  2. Select "Empty Activity" and "Next" button.
  3. Fill "Configuration" window - Name, Package name, Save location and Language. If you are not familiar with Kotlin choose Java. This tutorial will be written in Java.
  4. Google for minimum api level for Camera2 API - 21. For now I will choose 27.
  5. Button "Finish".

We do not waste time

So let's create instrumented tests for running tests on android device, according to documentation. Why? Because good programmer write tests. For testing hid own code, for testing other's code. Running tests on android device is wonderful solution. According to tutorial we have to do:

    • a) In some Android Studio versions instrumented tests are already ready to run. You should check whether you have folder app/src/androidTest/java - if yes you have already configured instrumented tests.
    • b) If you do not have these folders - create it. Inside it, create another folders similar to your application's package structure. e.g. com.example.myapplication.
  1. In you app's build.gradle you should have in dependencies test:runner and test:rules as follows (versions may differs, if these packages are from com.android.support.test change it to androidx.text):
                        dependencies {
                            androidTestImplementation 'androidx.test:runner:1.1.0'
                            androidTestImplementation 'androidx.test:rules:1.1.0'
                        }
                        
  2. Ensure that you have setup testInstrumentationRunner in build.gradle as follows:
                        android {
                            ...
                            defaultConfig {
                                ...
                                testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
                            }
                        }            
                        
  3. If you want to order execution of tests or group your tests, create and use test suite described in documentation.

What Tiggers do best

First of all we would like to just "open camera" using method:

  1. so we need cameraId (obtained from CameraManager),

                        // get context (remember to use getTargetContext())
                        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
                        // get camera manager
                        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
                        // iterate over all device's cameras
                        String cameraId = null;
                        for (String camId : manager.getCameraIdList()) {
                            // and choose apropriete one, based on camera characteristics
                            CameraCharacteristics characteristics = manager.getCameraCharacteristics(camId);
                            
                            Integer LENS_FACING = characteristics.get(CameraCharacteristics.LENS_FACING);
                            if (LENS_FACING != null && LENS_FACING == CameraCharacteristics.LENS_FACING_BACK) {
                                cameraId = camId;
                                break;
                            }
                        }
                        
  2. CameraDevice.StateCallback object (which we will create),

    (to avoid problems, define these elements inside test class, not inside of test method)

                        // create variable for holding device
                        private CameraDevice cameraDevice;
    
                        // create state object, to pass to open method. Implements required methods
                        private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
                            @Override
                            public void onOpened(@NonNull CameraDevice camera) {
                                // this method is most important for us. Assign opened device to our variable defined above
                                cameraDevice = camera;
                            }
    
                            @Override
                            public void onDisconnected(@NonNull CameraDevice camera) {
                                camera.close();
                            }
    
                            @Override
                            public void onError(@NonNull CameraDevice camera, int error) {
                                camera.close();
                            }
                        };
                        
  3. and Handler object.

                        HandlerThread mBackgroundThread = new HandlerThread("CameraThread");
                        mBackgroundThread.start();
                        Handler backgroundHandler = new Handler(mBackgroundThread.getLooper());
                        
  4. Open camera

    manager.openCamera(cameraId, mStateCallback, backgroundHandler);
  5. At the end run test class

Troubleshooting

TL;DR

                package com.example.myapplication;


                import android.Manifest;
                import android.content.Context;
                import android.hardware.camera2.CameraAccessException;
                import android.hardware.camera2.CameraCharacteristics;
                import android.hardware.camera2.CameraDevice;
                import android.hardware.camera2.CameraManager;
                import android.os.Handler;
                import android.os.HandlerThread;
                import android.util.Log;

                import androidx.annotation.NonNull;
                import androidx.test.InstrumentationRegistry;
                import androidx.test.filters.SmallTest;
                import androidx.test.rule.GrantPermissionRule;
                import androidx.test.runner.AndroidJUnit4;

                import org.junit.Rule;
                import org.junit.Test;
                import org.junit.runner.RunWith;

                @RunWith(AndroidJUnit4.class)
                @SmallTest
                public class ExampleInstrumentedTest {


                    @Rule
                    public GrantPermissionRule permissionRule = GrantPermissionRule.grant(Manifest.permission.CAMERA);

                    // create variable for holding device
                    private CameraDevice cameraDevice;

                    // create state object, to pass to open method. Implements required methods
                    private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
                        @Override
                        public void onOpened(@NonNull CameraDevice camera) {
                            // this method is most important for us. Assign opened device to our variable defined above
                            cameraDevice = camera;
                            Log.d("ExampleInstrumentedTest", "CameraDevice.StateCallback::onOpened");
                        }

                        @Override
                        public void onDisconnected(@NonNull CameraDevice camera) {
                            camera.close();
                        }

                        @Override
                        public void onError(@NonNull CameraDevice camera, int error) {
                            camera.close();
                        }
                    };


                    @Test
                    public void test1() throws CameraAccessException {
                        // get context (remember to use getTargetContext())
                        Context context = InstrumentationRegistry.getTargetContext();
                        // get camera manager
                        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
                        // iterate over all device's cameras
                        String cameraId = null;
                        for (String camId : manager.getCameraIdList()) {
                            // and choose apropriete one, based on camera characteristics
                            CameraCharacteristics characteristics = manager.getCameraCharacteristics(camId);

                            Integer LENS_FACING = characteristics.get(CameraCharacteristics.LENS_FACING);
                            if (LENS_FACING != null && LENS_FACING == CameraCharacteristics.LENS_FACING_BACK) {
                                cameraId = camId;
                                break;
                            }
                        }

                        HandlerThread mBackgroundThread = new HandlerThread("CameraThread");
                        mBackgroundThread.start();
                        Handler backgroundHandler = new Handler(mBackgroundThread.getLooper());

                        if (cameraId != null) {
                            manager.openCamera(cameraId, mStateCallback, backgroundHandler);
                        }
                    }
                }
                

In next post we will create CaptureSession and capture first photo.