Wednesday, 20 March 2013

Building a custom camera app in Android

Its always my craze to work on the image processing application. Infact I was thinking of developing a camera application for android mobiles which i have already done for desktop. So, let me share what?, how? did i come up with the application through this post.

Steps to follow
  • Determine camera hardware exist of not.
  • Accessing the camera.
  • Verifying camera features.
  • Creating preview class
  • Capturing the picture and save it.
  • Releasing the camera.
To access the device camera we must declare camera permission and feature in the manifest file. For instance if we need to used auto-focus feature we have to declare auto-focus feature in manifest file before to use it.

<uses-permission android:name="android.permission.CAMERA"/>
Note: If you are using camera via internet, you don't need this.
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
Before launching our camera application in the device, check whether device is having camera hardware or not. If not, we do not want to install our application. In that case we can declare our manifest file as the following below.
<uses-permission android:name="android.permission.CAMERA" />

We can also detect camera hardware in the runtime

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
Camera.Open() method to helps to access the camera.

Verifying camera features
Once we got access to a camera, we can get further information about its capabilities using the Camera.getParameters() method and checking the returned Camera.Parameters object for supported capabilities.

Creating preview class

The first thing before we snap a pic is the view of it on the screen, its the SurfacePreview class that to help view the object from camera. The following codes implement the SufraceView class and SurfaceHolder.Callback function in order to handle the destroying and the creation of views.

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder surfaceHolder;
private Camera camera;

public CameraPreview(Context context, Camera camera) {
super(context);
this.camera = camera;

// SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}

public void surfaceDestroyed(SurfaceHolder holder) {
//Here we can releasing the camera preview activity
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.

if (surfaceHolder.getSurface() == null){
// preview surface does not exist
return;
}

// stop preview before making changes
try {
cmera.stopPreview();
} catch (Exception e){
}

// set preview size and make any resize, rotate or
// reformatting changes here

// start preview with new settings
try {
camera.setPreviewDisplay(mHolder);
camera.startPreview();

} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}

Capturing Picture

After implemented a preview class and view layout to display it, we are ready to start capturing images.
In order to retrieve the images, use the Camera.takePicture() method. This method has four callback function parameters that help to handle the picture. From that parameters we must implement the Camera.PictureCallback interface to receive the data and write it into file.

private PictureCallback mPicture = new PictureCallback() {

@Override
public void onPictureTaken(byte[] data, Camera camera) {

File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions: " +
e.getMessage());
return;
}

try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
}

Saving Media File
In saving media files there are two standard locations we should consider as a developer.
  • Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) This method returns the standard, shared and recommended location for saving pictures and videos. This directory is public, so other applications can easily discover, read, change and delete files saved in this location. If your application is uninstalled by the user, media files saved to this location will not be removed.
  • Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) This method returns a standard location for saving pictures and videos which are associated with your application. If your application is uninstalled, any files saved in this location are removed. Security is not enforced for files in this location and other applications may read, change and delete them.
Releasing the Camera

Before the application exits we have to release camera instance and also media recorder.
@Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
}

private void releaseMediaRecorder(){
if (mMediaRecorder != null) {
mMediaRecorder.reset(); // clear recorder configuration
mMediaRecorder.release(); // release the recorder object
mMediaRecorder = null;
mCamera.lock(); // lock camera for later use
}
}

private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
Thats how i came up with the application. 

Handling Windows power state

 
While developing CloudStorage Drive [virtual drive] application I came across exploring windows power management to remount the CloudStorage Drive after getting up from hibernate state. Usually you can see our local drive / regular drive, like C:\, gets mounted when the system wakes up from sleep state.

We know that the operating system controls power management across the entire PC system. For example, suppose if you have paused a video and go to the hibernate state the process goes idle here. You can see the video remain on the same state when the system is on back.

The software developers can now make their application power-aware by handling the WM_POWERBROADCAST message provided by the windows operating system and scaling features accordingly. This article describes how to handle the WM_POWERBROADCAST message and also describes the sequence of messages for four typical cases. This is very helpful for whoever wants to re-launch the application after the system get back to power state.

Power States
To the user, the PC is either on or off, and other conditions are not visible. However, the ACPI (Advanced Configuration and Power Interface) specification defines a number of different power states that are supported by windows operating system.

State
Description
S0/Working
On. The CPU is fully up and running. power conversation is on a per-device basis.
S1 Sleep
Appears off. The CPU is stopped. RAM is refreshed, the system is running in a low power mode.
S2 Sleep
Appears off. The CPU has no power. RAM is refreshed. The system is in a lower mode than S1.
S3 Sleep
Appears off. The CPU has no power. RAM is in slow refresh. The power supply is in a reduced power mode.
S4 Hibernate
Appears off. The hardware is completely off. But system memory has been saved to disk.
S5/Off
Off. The hardware is completely off. The operating system has shut down, nothing has been saved. Requires a complete reboot to return to the working state.

The power management functions and messages retrieve the system power status and notify applications of power management events. The windows offer WM_POWERBROADCAST message which will be send to the application to indicate power changes. The documentation for each of these is provided as:
Event
Meaning
PBT_APMBATTERY LOW
Battery power is low.
PBT_APMOEMEVENT
OEM-defined event occurred.
PBT_APMPOWERSTATUSCHANGE
Power status has changed.
PBT_APMQUERYSUSPEND
Request for permission to suspend.
PBT_APMQUERYSUSPENDFAILED
Suspension request denied.
PBT_APMRESUMEAUTOMATIC
Operation resuming automatically after event.
PBT_APMRESUMECRITICAL
Operation resuming after critical suspension.
PBT_APMRESUMESUSPEND
Operation resuming after suspension.
PBT_APMSUSPEND
System is suspending operation.

The window proc receives the entire event which we can easily implement as shown below. In .Net you have to using interop service namespace for those things .

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);
    switch (m.Msg)
    {
    case WM_POWERBROADCAST:
    {
     switch (m.WParam.ToInt32())
      {
         case (int)PBT.PBT_APMQUERYSUSPEND:
          . . .
          . . .
      }
     }
    }
}
The above code can be made use to handle the power suspend states like when system goes sleep or to hibernate mode