Reputation: 81
I have to create an android application which captures pictures in background. I have the code but it always crashes at one point. This code worked well on HTC android phone. And I tried it on motorola, nexus and its crashing always.
This is the crash:
Process: com.capturepicture, PID: 13016
java.lang.RuntimeException: takePicture failed
at android.hardware.Camera.native_takePicture(Native Method)
at android.hardware.Camera.takePicture(Camera.java:1436)
at android.hardware.Camera.takePicture(Camera.java:1381)
at com.trimble.applanix.flightplanning.FlightPlanner.takepic(FlightPlanner.java:142)
at com.trimble.applanix.flightplanning.FlightPlanner$2.onClick(FlightPlanner.java:96)
at android.view.View.performClick(View.java:4761)
at android.view.View$PerformClick.run(View.java:19767)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5312)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
This is my activity file which has triggering camera code
public class Planner extends Activity {
private Button btnStart;
private Button btnStop;
protected static Handler mHandler = null;
protected String mHttpResponse = "";
private int mHandlerWhatMessage;
Camera camera;
SurfaceView preview;
SurfaceHolder previewHolder;
ImageButton takePic;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flight_planner);
btnStart = (Button) findViewById(R.id.btn_start);
btnStop = (Button) findViewById(R.id.btn_stop);
preview = (SurfaceView) findViewById(R.id.surfaceView);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takepic();
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
public void takepic(){
if (camera == null)
camera = Camera.open();
camera.cancelAutoFocus();
camera.startPreview();
System.gc();
camera.setPreviewCallback(null);
camera.takePicture(null, null, photoCallback);
camera.startPreview();
//camera.takePicture(ShutterCallback, rawCallback, photoCallback);
}
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return (result);
}
SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable t) {
Toast toast = Toast.makeText(FlightPlanner.this,
"Exception in setPreviewDisplay", Toast.LENGTH_LONG);
toast.show();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size bestSize = getBestPreviewSize(width, height, parameters);
parameters.setPreviewSize(bestSize.width, bestSize.height);
parameters.setPictureFormat(PixelFormat.JPEG);
camera.setParameters(parameters);
camera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
}
};
/*
Camera.ShutterCallback ShutterCallback = new Camera.ShutterCallback() {
public void onShutter() {
}
};
PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
}
};
*/
Camera.PictureCallback photoCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
// Save the image JPEG data to the SD card
FileOutputStream outStream = null;
try {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
Date now = new Date();
String fileName = formatter.format(now) +".jpg";
//String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/FLIGHTPLANNER");
myDir.mkdirs();
File file = new File (myDir, fileName);
if (file.exists ()) file.delete ();
outStream = new FileOutputStream(file);
outStream.write(data);
outStream.close();
} catch (FileNotFoundException e) {
Log.d("CAMERA", e.getMessage());
} catch (IOException e) {
Log.d("CAMERA", e.getMessage());
}
camera.startPreview();
/*new SavePhotoTask().execute(data);
camera.startPreview();*/
}
};
}
I have added required camera permissions in manifest file.
Upvotes: 0
Views: 640
Reputation: 57173
You must first call startPreview() and only after that you may call takePicture(). But It is not correct to call takePicture() immediately after you called startPreview(). It may work on some devices, but not others.
The best solution would start preview as soon as the camera is opened (when the SurfaceView is created by layout manager).
But if it is not acceptable for you,
preview.postDelayed(…, 300)
will be enough (see a similar example on GitHub)
Upvotes: 1