Android Camera2 API with "State" Design Pattern

Viewed 549

I've been working for 2 months with different Camera2 API projects. As you may know, Camera2 API is little difficult to understand and maintain, it requires some knowledge of multiprocessing, states and callabacks. Simple example of "just" taking photo on google examples has 1000 lines (https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java). In the internet, there is also very promissing implementation, called Camera3 https://github.com/QuinnFreedman/Camera3 - which simplifies usage of Camera2.

In a few articles, and examples I saw, that core part of Camera2 applications is machine automaton(FSA). FSA is ok, but as it becomes large, it is difficult to understand, maintain and extend. Imho, sollution is to use "State" design pattern(https://en.wikipedia.org/wiki/State_pattern). There is Context object which hold state, and State interface and concrete states (open, close, preview, take photo).

Simple sketch:

CamerContext:

  • fields: contains device, session, charactericst, surfaces, handler, lock, request builders, callbacks(capture, session, device)
  • methods: onOpenCamera, onCloseCamera, onCaptureCompleted

CameraState:

  • concrete: OpenState, CloseState, PreviewState, TakingPhotoState

Questions:

  1. Have anyone do PoC "State" design pattern with camera2 api? Is this doable?
  2. Have anyone do state design pattern with parallel computing (locks, threads)? Any thoughts, tutorial, have you internesting articles?
1 Answers

Ok, I am ready to answer my question. I have done PoC of this idea. I write some kind of SDK for such thing. And I thinkg it's very usefull library for managing camera 2 api calls. I cannot share repository because I have done it for my employer(maybe it will be available in the Internet lately). But I can share a little knowledge.

As a main idea of project, I used a "State" design pattern (https://en.wikipedia.org/wiki/State_pattern), because FSA spiltted into many pieces is very hard to maintain.

So I have created following states: ClosedState, OpenedState, ConfiguredState, PreviewState, PreCapture, Capture and CaptureBurst. And the CameraContext which is main class of whole project. All states inherits from AbstractState.

Closed and Opened states are very simply. Just a few lines of code, very specific.

Configured just start preview.

PreviewState has function for capturesequence and for capture single photo (it calls camera2's session.capture, session.captureBurst and session.

Capturing states, as name suggest, are responsible for taking photo(capturestarted, capture completed, and onimageavailable)

My capturing states, holds reference for image saver(or image savers for burst), and are invoked during onimageavailable call.

After this information, time for describe camera context. As you may know from wikipedia, it is client for all calls. So it hold a lot of methods: openCamera, createSession, startPreview, captureStillPic, captureSequence. But also callback functions, onCameraOpen, onCameraClose, onImageAvailable, on and on, and on. Some of this methods are just bridge for state-specific methods (onCameraOpen of CameraContext, is bridge to onCameraOpen of ClosedState, etc.).

What is more, in Camera2Api we have 4 difference and very important callbacks which should be implemented: CameraSessionCallback, CameraStateCallback, CameraCaptureCallback and ImageAvailableListener. So I have created the StateAware equivalent classes, which are just bridge to cameraContext calls(onCameraOpen of StateAwareCameraStateCallback calls onCameraOpen of CameraContext, which calls onCameraOpen of ClosedState, and so on). These callbacks are passed to Camera2API objects.

Additionally projects contains ImageSavers for saving output, and FilenameGenerators for generating filenames. I also added some kind of postprocessing burst. Writing complete PoC with instrumented tests, and without demo app takes 1MM. Test scenario of taking burst images requires 100 - 150 lines of custom code (open, configure, prepare burst, take burst, close), and I'm think it is easy to understand/change;)

Related