Ab V
Ab V

Reputation: 3

calling camera.takepicture through code android

I am trying to call camera.takepicture through the code and it always throws a run time exception. I cant seem to find the error in my code. If i call the same thing using a button, the takepicture works just fine. I need to call takepicture through code since i need it to randomly capture photos when the user is actually performing a different activity. I need to set a timer/interval to see these pictures being taken. I cant depend on the user interaction in this part of the program.

Here is the code for more details. Also attached is the logcat.

CameraActivity.class

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class CameraActivity extends Activity implements Callback {

final static String DEBUG_TAG = "CameraActivity";
final static String TAG = "CameraActivity";
Camera camera;
private int cameraId = 0;
Button photo;
PhotoHandler mPhotoHandler = null;

Camera.Parameters parameters;
private SurfaceHolder sHolder;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // do we have a camera?
    if (!getPackageManager()
            .hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG)
                .show();
    } else {
        cameraId = findFrontFacingCamera();
        if (cameraId < 0) {
            Toast.makeText(this, "No front facing camera found.",
                    Toast.LENGTH_LONG).show();
        } else {
            camera = Camera.open(cameraId);
            SurfaceView sv = new SurfaceView(getApplicationContext());
            setContentView(R.layout.camera);
            sv = (SurfaceView) findViewById(R.id.surfaceview);
            photo = (Button) findViewById(R.id.takepicture);
            photo.setText("Click a photo!!");
            // Get a surface
            sHolder = sv.getHolder();
            sHolder.addCallback(this);
            sHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            try {
                camera.setPreviewDisplay(sHolder);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            parameters = camera.getParameters();
            // set camera parameters
            camera.setParameters(parameters);
            camera.startPreview();
            camera.setDisplayOrientation(90);
            try {

                photo.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View arg0) {
                        // TODO Auto-generated method stub
                        // Toast.makeText(getApplicationContext(),
                        // "photo clicked!",
                        // Toast.LENGTH_SHORT).show();

                        // just calling the function which captures the
                        // photo
                        takePhoto();
                    }
                });
                photo.performClick();

                // finish();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    try {
        camera.setPreviewDisplay(holder);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    // set any cam params you need...
    camera.startPreview();
}

private int findFrontFacingCamera() {
    int cameraId = -1;
    // Search for the front facing camera
    int numberOfCameras = Camera.getNumberOfCameras();
    for (int i = 0; i < numberOfCameras; i++) {
        CameraInfo info = new CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
            Log.d(DEBUG_TAG, "CameraActivity found");
            cameraId = i;
            break;
        }
    }
    return cameraId;
}

@Override
protected void onPause() {
    if (camera != null) {
        camera.release();
        camera = null;
    }
    super.onPause();
}

Camera.ShutterCallback shuttercallback = new Camera.ShutterCallback() {

    @Override
    public void onShutter() {
        // TODO Auto-generated method stub
        Log.d(TAG, "onShutter'd");
    }
};

Camera.PictureCallback rawpicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] arg0, Camera arg1) {
        // TODO Auto-generated method stub
        Log.d(TAG, "onPictureTaken - raw");
    }

};

Camera.PictureCallback jpegcallback = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera arg1) {
        // TODO Auto-generated method stub
        File pictureFileDir = getDir();

        if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {

            Log.d(CameraActivity.DEBUG_TAG,
                    "Can't create directory to save image.");
            Toast.makeText(CameraActivity.this,
                    "Can't create directory to save image.",
                    Toast.LENGTH_LONG).show();
            return;
        }

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
        String date = dateFormat.format(new Date());
        String photoFile = "Picture_" + date + ".jpg";

        String filename = pictureFileDir.getPath() + File.separator
                + photoFile;

        File pictureFile = new File(filename);

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
            Toast.makeText(CameraActivity.this,
                    "New Image saved:" + photoFile, Toast.LENGTH_LONG)
                    .show();
        } catch (Exception error) {
            Log.d(CameraActivity.DEBUG_TAG, "File" + filename
                    + "not saved: " + error.getMessage());
            Toast.makeText(CameraActivity.this,
                    "Image could not be saved.", Toast.LENGTH_LONG).show();
        }
    }

};

@Override
public void surfaceCreated(SurfaceHolder holder) {
    // set any cam params you need...
    camera.startPreview();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    camera.stopPreview();
    camera.release();

}

private static File getDir() {
    File sdDir = Environment
            .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    return new File(sdDir, "CameraAPIDemo");
}

public void takePhoto() {

    camera.takePicture(shuttercallback, rawpicture, jpegcallback);
}

}

Attached is the logcat output

*

> 04-17 00:41:03.264: D/CameraActivity(19076): CameraActivity found
> 04-17 00:41:03.444: D/Camera(19076): app passed NULL surface 04-17
> 00:41:03.474: W/System.err(19076): java.lang.RuntimeException:
> takePicture failed 04-17 00:41:03.474: W/System.err(19076):   at
> android.hardware.Camera.native_takePicture(Native Method) 04-17
> 00:41:03.474: W/System.err(19076):    at
> android.hardware.Camera.takePicture(Camera.java:1095) 04-17
> 00:41:03.474: W/System.err(19076):    at
> android.hardware.Camera.takePicture(Camera.java:1040) 04-17
> 00:41:03.474: W/System.err(19076):    at
> com.egnoita.ignoramus.CameraActivity.takePhoto(CameraActivity.java:226)
> 04-17 00:41:03.474: W/System.err(19076):  at
> com.egnoita.ignoramus.CameraActivity$4.onClick(CameraActivity.java:93)
> 04-17 00:41:03.474: W/System.err(19076):  at
> android.view.View.performClick(View.java:4204) 04-17 00:41:03.484:
> W/System.err(19076):  at
> com.egnoita.ignoramus.CameraActivity.onCreate(CameraActivity.java:96)
> 04-17 00:41:03.484: W/System.err(19076):  at
> android.app.Activity.performCreate(Activity.java:5104) 04-17
> 00:41:03.484: W/System.err(19076):    at
> android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
> 04-17 00:41:03.484: W/System.err(19076):  at
> android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
> 04-17 00:41:03.484: W/System.err(19076):  at
> android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
> 04-17 00:41:03.484: W/System.err(19076):  at
> android.app.ActivityThread.access$600(ActivityThread.java:141) 04-17
> 00:41:03.484: W/System.err(19076):    at
> android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
> 04-17 00:41:03.484: W/System.err(19076):  at
> android.os.Handler.dispatchMessage(Handler.java:99) 04-17
> 00:41:03.484: W/System.err(19076):    at
> android.os.Looper.loop(Looper.java:137) 04-17 00:41:03.484:
> W/System.err(19076):  at
> android.app.ActivityThread.main(ActivityThread.java:5041) 04-17
> 00:41:03.484: W/System.err(19076):    at
> java.lang.reflect.Method.invokeNative(Native Method) 04-17
> 00:41:03.484: W/System.err(19076):    at
> java.lang.reflect.Method.invoke(Method.java:511) 04-17 00:41:03.484:
> W/System.err(19076):  at
> com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
> 04-17 00:41:03.484: W/System.err(19076):  at
> com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 04-17
> 00:41:03.484: W/System.err(19076):    at
> dalvik.system.NativeStart.main(Native Method) 04-17 00:41:03.534:
> D/libEGL(19076): loaded /system/lib/egl/libEGL_adreno200.so 04-17
> 00:41:03.534: D/libEGL(19076): loaded
> /system/lib/egl/libGLESv1_CM_adreno200.so 04-17 00:41:03.544:
> D/libEGL(19076): loaded /system/lib/egl/libGLESv2_adreno200.so 04-17
> 00:41:03.554: I/Adreno200-EGL(19076): <eglInitialize:269>: EGL 1.4
> QUALCOMM build: Nondeterministic
> AU_full_mako_PARTNER-ANDROID/JB-MR1-DEV_CL2961380_release_AU
> (CL2961380) 04-17 00:41:03.554: I/Adreno200-EGL(19076): Build Date:
> 12/10/12 Mon 04-17 00:41:03.554: I/Adreno200-EGL(19076): Local Branch:
> 04-17 00:41:03.554: I/Adreno200-EGL(19076): Remote Branch:
> m/partner-android/jb-mr1-dev 04-17 00:41:03.554:
> I/Adreno200-EGL(19076): Local Patches: NONE 04-17 00:41:03.554:
> I/Adreno200-EGL(19076): Reconstruct Branch: NOTHING 04-17
> 00:41:03.624: D/OpenGLRenderer(19076): Enabling debug mode 0

* Let me know if you need anything more. All the permissions and features are added in the manifest

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_DATA" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

Upvotes: 0

Views: 1254

Answers (2)

Alex Cohn
Alex Cohn

Reputation: 57173

You don't need to go rounds so that takePhoto() is called from onClick(). The reason your programmatic approach fails, is that camera.takePicture() can only be called after camera.startPreview() is complete. This happens to be a common misunderstanding about the Android camera lifecycle.

The bottom line is that in onCreate(), you should let the activity get ready to take the picture, and let all necessary callbacks get called in their order. Here is a minimal rewrite of your code. I hope it will not only do the job, but also help you understand the way to treat the camera properly.

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class CameraActivity extends Activity implements Callback {

final static String DEBUG_TAG = "CameraActivity";
final static String TAG = "CameraActivity";
Camera camera;
private int cameraId = 0;
Button photo;
PhotoHandler mPhotoHandler = null;
private boolean wantPhoto = false;

Camera.Parameters parameters;
private SurfaceHolder sHolder;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // do we have a camera?
    if (!getPackageManager()
            .hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG)
                .show();
    } else {
        cameraId = findFrontFacingCamera();
        if (cameraId < 0) {
            Toast.makeText(this, "No front facing camera found.",
                    Toast.LENGTH_LONG).show();
        } else {
            camera = Camera.open(cameraId);
            SurfaceView sv = new SurfaceView(getApplicationContext());
            setContentView(R.layout.camera);
            sv = (SurfaceView) findViewById(R.id.surfaceview);
            photo = (Button) findViewById(R.id.takepicture);
            photo.setText("Click a photo!!");
            // Get a surface
            sHolder = sv.getHolder();
            sHolder.addCallback(this);
            sHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            try {
                camera.setPreviewDisplay(sHolder);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            parameters = camera.getParameters();
            // set camera parameters
            camera.setParameters(parameters);
            camera.startPreview();
            camera.setDisplayOrientation(90);
            try {

                photo.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View arg0) {
                        // TODO Auto-generated method stub
                        // Toast.makeText(getApplicationContext(),
                        // "photo clicked!",
                        // Toast.LENGTH_SHORT).show();

                        // just calling the function which captures the
                        // photo
                        takePhoto();
                    }
                });
//                photo.performClick();
                wantPhoto = true;

                // finish();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    try {
        camera.setPreviewDisplay(holder);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    // set any cam params you need...
    camera.startPreview();
    if (wantPhoto) {
        wantPhoto = false;
        takePhoto();
    }
}

private int findFrontFacingCamera() {
    int cameraId = -1;
    // Search for the front facing camera
    int numberOfCameras = Camera.getNumberOfCameras();
    for (int i = 0; i < numberOfCameras; i++) {
        CameraInfo info = new CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
            Log.d(DEBUG_TAG, "CameraActivity found");
            cameraId = i;
            break;
        }
    }
    return cameraId;
}

@Override
protected void onPause() {
    if (camera != null) {
        camera.release();
        camera = null;
    }
    super.onPause();
}

Camera.ShutterCallback shuttercallback = new Camera.ShutterCallback() {

    @Override
    public void onShutter() {
        // TODO Auto-generated method stub
        Log.d(TAG, "onShutter'd");
    }
};

Camera.PictureCallback rawpicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] arg0, Camera arg1) {
        // TODO Auto-generated method stub
        Log.d(TAG, "onPictureTaken - raw");
    }

};

Camera.PictureCallback jpegcallback = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera arg1) {
        // TODO Auto-generated method stub
        File pictureFileDir = getDir();

        if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {

            Log.d(CameraActivity.DEBUG_TAG,
                    "Can't create directory to save image.");
            Toast.makeText(CameraActivity.this,
                    "Can't create directory to save image.",
                    Toast.LENGTH_LONG).show();
            return;
        }

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
        String date = dateFormat.format(new Date());
        String photoFile = "Picture_" + date + ".jpg";

        String filename = pictureFileDir.getPath() + File.separator
                + photoFile;

        File pictureFile = new File(filename);

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
            Toast.makeText(CameraActivity.this,
                    "New Image saved:" + photoFile, Toast.LENGTH_LONG)
                    .show();
        } catch (Exception error) {
            Log.d(CameraActivity.DEBUG_TAG, "File" + filename
                    + "not saved: " + error.getMessage());
            Toast.makeText(CameraActivity.this,
                    "Image could not be saved.", Toast.LENGTH_LONG).show();
        }
    }

};

@Override
public void surfaceCreated(SurfaceHolder holder) {
    // set any cam params you need...
    camera.startPreview();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    camera.stopPreview();
    camera.release();

}

private static File getDir() {
    File sdDir = Environment
            .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    return new File(sdDir, "CameraAPIDemo");
}

public void takePhoto() {

    camera.takePicture(shuttercallback, rawpicture, jpegcallback);
}

}

Please understand that there are some important improvements that could benefit your code. For example, it is recommended to call camera.open() on a background thread, because on some devices, this may be a lengthy process, and it could freeze UI for more than a second.

Upvotes: 0

Ben Janes
Ben Janes

Reputation: 11

I had the same problem, and to fix it I simply defined takephoto as static and the callbacks as static. After doing this i was able to call takephoto through the code.

For Example:

public static void takePhoto() {

    camera.takePicture(shuttercallback, rawpicture, jpegcallback);
}

static Camera.PictureCallback jpegcallback = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera arg1) {
        // TODO Auto-generated method stub
        File pictureFileDir = getDir();

        if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {

            Log.d(CameraActivity.DEBUG_TAG,
                    "Can't create directory to save image.");
            Toast.makeText(CameraActivity.this,
                    "Can't create directory to save image.",
                    Toast.LENGTH_LONG).show();
            return;
        }

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
        String date = dateFormat.format(new Date());
        String photoFile = "Picture_" + date + ".jpg";

        String filename = pictureFileDir.getPath() + File.separator
                + photoFile;

        File pictureFile = new File(filename);

        try {
             FileOutputStream fos = new FileOutputStream(pictureFile);
             fos.write(data);
             fos.close();
             Toast.makeText(CameraActivity.this,
                    "New Image saved:" + photoFile, Toast.LENGTH_LONG)
                     .show();
        } catch (Exception error) {
            Log.d(CameraActivity.DEBUG_TAG, "File" + filename
                    + "not saved: " + error.getMessage());
            Toast.makeText(CameraActivity.this,
                    "Image could not be saved.", Toast.LENGTH_LONG).show();
        }
    }

};

static Camera.ShutterCallback shuttercallback = new Camera.ShutterCallback() {

    @Override
    public void onShutter() {
        // TODO Auto-generated method stub
        Log.d(TAG, "onShutter'd");
    }
};

static Camera.PictureCallback rawpicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] arg0, Camera arg1) {
        // TODO Auto-generated method stub
        Log.d(TAG, "onPictureTaken - raw");
    }

};

I hope this helps you or anyone else with the same problem.

Upvotes: 1

Related Questions