I just realized my camera activity in a surfaceholder doesn't work on some devices. Some DROID branded and skinned phones. It works on all google phones with standard android implementation so far.
I got a brief moment to debug a device on 2.2 (don't know exactly what model phone this was, but it was skinned) and I saw the debugger said (ICamera failed) (Camera Error 100)
but I didn't get a chance to find out exactly where it goes wrong, but I do see that others have encountered this issue (something about getting preview size before starting preview??), but no obvious responses or anything intuitive to what I have, but here is my camera code, what would make this work more universally?
//this is in OnCreate
preview = (SurfaceView) findViewById(R.id.cameraplacer);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//this is outside the lifecycle methods
SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
if (camera == null) {
camera = Camera.open();
try {
Camera.Parameters camParams = camera.getParameters();
camParams.setFlashMode(Parameters.FLASH_MODE_AUTO);
setDisplayOrientation(camera, 90);
camera.setPreviewDisplay(previewHolder);
camera.setParameters(camParams);
} catch (IOException e) {
camera.release();
camera = null;
}
}
}//end surfaceCreated
public void surfaceChanged(SurfaceHolder holder,
int format, int width,
int height) {
Camera.Parameters parameters=camera.getParameters();
Camera.Size size=getBestPreviewSize(width, height,
parameters);
if (size!=null) {
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
camera.startPreview();
inPreview=true;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
}
};//end CallBack
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);
}//end getBestPreviewSize
//this is on OnResume
try {
//Method rotateMethod = android.hardware.Camera.class.getMethod("setDisplayOrientation", int.class);
//rotateMethod.invoke(camera, 90);
//Camera.Parameters camParams = camera.getParameters();
//camParams.setPreviewSize(480, 320);// here w h are reversed
//camera.setParameters(camParams);*/
//setCameraDisplayOrientation(MainPhoto.this, 0, camera);
if(camera!=null)
{
Camera.Parameters camParams = camera.getParameters();
camParams.setFlashMode(Parameters.FLASH_MODE_AUTO);
camera.setParameters(camParams);
setDisplayOrientation(camera, 90);
camera.setPreviewDisplay(previewHolder);
camera.startPreview();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}/* catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/ catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}/* catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
I'd delete the onResume()
logic, as it duplicates what you have in surfaceChanged()
, and it may not be safe to do that work by the time onResume()
is called, as the surface may not yet be ready.
Also, you are blindly asking for FLASH_MODE_AUTO
without seeing if that is supported by the device.
Those would be two places to start.
first a question where is your onPause method, I am assuming you are releasing all the resources related to camera, as you cant hold back on it till your app is paused.
secondly, have variable to keep track of surface status whether its destroyed or not based upon that you have to decide what to do in onResume. Some thing like this
if (hasSurface) {
// The activity was paused but not stopped, so the surface still
// exists. Therefore
// surfaceCreated() won't be called, so init the camera here.
initCamera(surfaceHolder);
} else {
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
one more thing the error 100 you are getting is actually camera indicating native camera app is crashed somehow, if you have set the errorCallback to the camera instance you will be notified back about this event and what you can do according to the error documentation is start fresh i.e. re-initialize camera instance.
hope it helps somehow!
Take a look at the android example here
or import the android examples in your IDE.
Hope this helps
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With