Working with camera on Android could be easy and straightforward – we may start a new activity with MediaStore.ACTION_IMAGE_CAPTURE intent and just wait for the result to be returned. But sometimes there may be a need to go inside that process: for example in our “My Seven Wonders” application we had a necessity to create a custom camera preview screen. Here we will share some details learned during development of that custom screen.

To start with a camera activity we used a sample available in the Android SDK. Since we planned to handle the orientation of the phone we firstly set our camera activity screen orientation to be “landscape” in AndroidManifest.xml. The landscape orientation will be our starting point of further image rotation operations.
To know the exact orientation of the phone we added OrientationEventListener. This listener is notified on all 360 range of values, but since we are interested only in discrete values (0,90,180,270) we made a ImageCaptureCallback.getRotationAngle() method, which filters the values sent to the listener. For each of the four orientations we created 4 separate images of binocular view, which are pre-rotated appropriately. In the camera_view.xml, which describes our camera activity layout, we added the camera surface itself (where the camera preview will be shown) and an image view (where a binocular image will be displayed). When the orientation of the phone is changed we just change the source of the ImageView to the appropriate binocular image.
Our custom capture button is also added in the camera_view.xml, which, when clicked, invokes the CameraActivity.takePicture() method. The snapshot storing procedure is performed in ImageCaptureCallback class.
Taking a snapshot and processing a picture should be performed with care, because currently available Android phones feature high resolution cameras, which produce high resolution images. When processing these images we may easily get an OutOfMemory error. To avoid this problem we will set medium camera parameters in the CameraActivity.surfaceChanged method.
First we will configure the camera picture size (this is the size in which we will receive the taken snapshot in ImageCaptureCallback.onPictureTaken method). We will get all picture sizes supported by camera, and find the one with width nearest to 480 (which is optimal width for medium resolution Android resources).
Also we will configure the camera preview size (this is the size in which the actual output from camera will be shown on camera surface). We will get all the supported preview formats from the camera and will try to find the one, which width is nearest to the width dedicated to our camera surface activity.
Now in the ImageCaptureCallback.onPictureTaken we can finally rotate the received snapshot according to our current orientation and overlay appropriate binocular image over the snapshot using Android Canvas API.
After we made all of the above there was one annoying bug left. Sometimes, when testing on a real device, after clicking on a capture button the activity was freezing and after that the hardware camera was not responding. The only thing to work around this was to restart the phone. We were not able to debug this problem because it was a rare case and it was not understandable under which circumstances this bug arises.
In resolving of the above problem the Monkey utility have helped us a lot. By the way this is a great tool which may economy debugging time spent on investigating the “miracle” bugs (http://developer.android.com/guide/developing/tools/monkey.html). When we ran the Monkey to do a stress test of our application, each time the Monkey visited the Camera Activity the hardware camera was crashing! It was really cool because it became very easy to understand what the problem was. The Monkey makes random clicks on the screen and it does this very fast. And this was the actual problem. Multiple simultaneous calls to the camera.takePicture method made the hardware camera to fail. This was a rare case during manual testing, but with a Monkey this problem became clearly visible. What we just needed to do is to disable the snapshot button right after it was clicked once.
Finally we have a nice little application which draws customized camera preview screen, obeys the phone orientation and produces cool snapshots. Happy filming!