Camera Snap Example

This example shows how to access the camera on a device and display its output in a view.

A screenshot of the application.

Note that, in order to access the camera, the application needs to be built with the android.hardware.camera feature and the android.permission.CAMERA permission. The build script takes care of this.

We import the classes and modules needed by our application. The most relevant to this example are the Camera, SurfaceHolder and SurfaceView classes that we also used in the Camera example.

from android.app import Activity
from android.os import Bundle
from android.graphics import BitmapFactory
from android.hardware import Camera
from android.view import SurfaceHolder, SurfaceView, View
from android.widget import Button, ImageView, LinearLayout

We define a class based on the standard Activity class. This represents the application, and will be used to present a graphical interface to the user.

class CameraSnapActivity(Activity):

The class implements three interfaces that are declared in the list of interfaces defined by the __interfaces__ attribute. We implement these interfaces by defining methods later in the class.

    __interfaces__ = [Camera.PictureCallback, SurfaceHolder.Callback,
                      View.OnClickListener]

We define a field that we can use as an instance attribute. This is needed because we cannot explicitly create an instance of the Camera class and the default value we want to assign to the attribute is the special None value, which corresponds to a null value in Java.

    __fields__ = {"camera": Camera}

The initialisation method calls the corresponding method in the base class. We also assign a value of None to the camera attribute, indicating that no camera is currently available.

    def __init__(self):
    
        Activity.__init__(self)
        self.camera = None

Similarly, the onCreate method calls the onCreate method of the base class to help set up the activity before creating a user interface.

    @args(void, [Bundle])
    def onCreate(self, bundle):
    
        Activity.onCreate(self, bundle)

We create a button with a "Take picture" label and register the activity with it as a listener. Since the activity implements the View.OnClickListener interface, the activity's onClick method will be called when the user clicks the button.

        button = Button(self)
        button.setText("Take picture")
        button.setOnClickListener(self)

We use a SurfaceView to obtain preview images from the camera, even though we do not display them. In order to receive updates from the camera, we register the activity to receive callbacks from the preview's SurfaceHolder object.

        preview = SurfaceView(self)
        self.holder = preview.getHolder()
        self.holder.addCallback(self)

We use an ImageView to display a picture taken by the camera.

        self.image = ImageView(self)

We also create a layout to hold both the button and image. We make the layout the main view in the activity.

        self.layout = LinearLayout(self)
        self.layout.setOrientation(LinearLayout.VERTICAL)
        self.layout.addView(button)
        self.layout.addView(preview)
        self.layout.addView(self.image)
        
        self.setContentView(self.layout)

The onResume method is called when the activity starts or when the user navigates to it. After calling the corresponding method in the base class, we try to obtain a Camera object by calling the static open method. If a valid object is returned we obtain the first size supported by the device.

    def onResume(self):
    
        Activity.onResume(self)
        
        self.camera = Camera.open()
        parameters = self.camera.getParameters()
        self.size = parameters.getSupportedPreviewSizes().get(0)

The onPause method is called when the user navigates away from the activity. After calling the corresponding method in the base class, we release the Camera object obtained earlier, releasing it so that other activities can use it, and setting the camera attribute to None to indicate that the activity no longer has access to the camera.

    def onPause(self):
    
        Activity.onPause(self)
        
        if self.camera != None:
            self.camera.release()
            self.camera = None

The following three methods must be implemented because they are part of the SurfaceHolder.Callback interface whose methods are abstract.

The surfaceCreated method is used to inform us that a surface has been created to show images from the camera. If we have access to the camera, we tell it to use the SurfaceHolder associated with the SurfaceView object we created earlier.

    @args(void, [SurfaceHolder])
    def surfaceCreated(self, holder):
    
        if self.camera != None:
            self.camera.setPreviewDisplay(self.holder)

The surfaceDestroyed method is used to inform the activity that a surface has been destroyed. If we have access to the camera, we stop the generation of preview images since the activity can no longer display them.

    @args(void, [SurfaceHolder])
    def surfaceDestroyed(self, holder):
    
        if self.camera != None:
            self.camera.stopPreview()

The surfaceChanged method is used to inform the activity about changes to the format or size of the surface. We read the current parameters of the camera, update the preview size to match the size provided and start the camera preview.

    @args(void, [SurfaceHolder, int, int, int])
    def surfaceChanged(self, holder, format, width, height):
    
        parameters = self.camera.getParameters()
        parameters.setPreviewSize(self.size.width, self.size.height)
        self.camera.setParameters(parameters)
        self.camera.startPreview()

The onClick method implements the View.OnClickListener interface and is called when the user clicks the button. If a camera is available then we call the Camera instance's takePicture method to request a picture from the device. This will cause the onPictureTaken method to be called later.

    @args(void, [View])
    def onClick(self, view):
    
        if self.camera == None:
            return
        
        self.camera.takePicture(None, None, self)

The onPictureTaken method implements the Camera.PictureCallback interface and is called when the camera delivers a picture to the activity. The data parameter contains the picture data and the camera parameter indicates which device the picture came from. We respond to the method call by showing the picture in the ImageView we created earlier.

    @args(void, [[byte], Camera])
    def onPictureTaken(self, data, camera):

If the Camera object passed to the method is not the one we are interested in then just return.

        if camera != self.camera:
            return
        
        bitmap = BitmapFactory.decodeByteArray(data, 0, len(data))
        
        if bitmap != None:
            self.image.setImageBitmap(bitmap)
            self.layout.removeAllViews()
            self.layout.addView(self.image)

Files