Sunday, April 11, 2010

Android CameraPreview sample in JavaScript

Here is a DroidScript program that displays preview images from the camera. I have taken the CameraPreview sample program and rewritten it in JavaScript.

Beware! This program runs fine on Motorola Droid :-) but crashes on Nexus One :-(

Update: @JonasBeckman hinted that uncommenting camera.setParameters(parameters); when running on Nexus One does the trick. I tested and it works fine! :-)

To run this program, open the DroidScript app, and select the "Open script" menu item, and enter the short url to this blog post: http://bit.ly/aB2fik

DroidScript will recognise the DROIDSCRIPT_BEGIN and DROIDSCRIPT_END tags and extract the code between the tags. Then press the "Run Activity" button to run the program.

Note that these tags can occur only once on a page. If there are multiple occurrences, the text between the first pair will be used. Therefore, I have escaped the underscore character in the tags above, so that they will not be interpreted as containing DroidScript code.

DROIDSCRIPT_BEGIN
var Camera = Packages.android.hardware.Camera;
var SurfaceHolder = Packages.android.view.SurfaceHolder;
var SurfaceView = Packages.android.view.SurfaceView;
var Window = Packages.android.view.Window;

function onCreate(bundle)
{
    Activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
    var preview = createPreviewSurface();
    Activity.setContentView(preview.getSurfaceView());
}

function createPreviewSurface()
{
    var camera = null;
    var surface = new SurfaceView(Activity);
    
    var object = {
        
        getSurfaceView : function() {
            return surface; },
            
        surfaceCreated : function(holder) {
            camera = Camera.open();
            try {
                camera.setPreviewDisplay(holder); }
            catch (exception) {
                camera.release();
                camera = null; } },
                
        surfaceDestroyed : function(holder) {
            camera.stopPreview();
            camera.release();
            camera = null; },
            
        surfaceChanged : function(holder, format, w, h) {
            var parameters = camera.getParameters();
            parameters.setPreviewSize(w, h);
            // Causes camera to fail on Nexus One
            //camera.setParameters(parameters);
            camera.startPreview(); }
    };
 
    var callback = createInstance(
        Packages.android.view.SurfaceHolder.Callback, 
        object);
    surface.getHolder().addCallback(callback);
    surface.getHolder().setType(
        SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    return object;
}

// Create an instance of a Java interface.
//   javaInterface - the interface type
//   object - JS object that will receive messages
//     sent to the instance
function createInstance(javaInterface, object)
{
    // Convert a Java array to a JavaScript array
    function javaArrayToJsArray(javaArray)
    {
        var jsArray = [];
        for (var i = 0; i < javaArray.length; ++i) {
            jsArray[i] = javaArray[i];
        }
        return jsArray;
    }
    
    var lang = Packages.java.lang;
    var interfaces = 
        lang.reflect.Array.newInstance(lang.Class, 1);
    interfaces[0] = javaInterface;
    var obj = lang.reflect.Proxy.newProxyInstance(
        lang.ClassLoader.getSystemClassLoader(),
        interfaces,
        // Note, args is a Java array.
        function(proxy, method, args) {
            // Convert Java array to JavaScript array
            return object[method.getName()].apply(
                null,
                javaArrayToJsArray(args));
        });
    return obj;
}
DROIDSCRIPT_END

2 comments:

  1. Displaying Javascript errors as notifications is very nice! It was incredibly easy to find out where the script failed on my Nexus One.

    I have no idea what goes wrong. But deleting line 40: "camera.setParameters(parameters);" makes the preview work just fine on a Nexus, too.

    ReplyDelete
  2. @JonasBeckman Cool! Will try to omit setParameters!

    ReplyDelete