I have tried every possible solutions given on stackoverflow and still haven't reach what I want. I want to take a picture with the Camera API with a service. The picture should be taken when user light the screen, but the screen is still lock. I saw different post about dummy surface etc... but none of them worked, of course I must have made misatke in my code as I am new with the camera API. My application proceed as so : I schedule an AlarmManager to start a service :
public int onStartCommand(Intent intent,int flags,int startId) {
Log.i("service","start");
Calendar finServ=Calendar.getInstance();
String all=intent.getStringExtra("all");
nomevt=all.split(Pattern.quote("**"))[3];
Scanner sc;
String str="";
try {
sc = new Scanner(new File(getFilesDir(),"Event.evt"));
while(sc.hasNext()) {
str=sc.next();
if(all.equals(str)) break;
}
sc.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if(!all.equals(str)) stopSelf();
else {
finServ.setTimeInMillis(toMillis(str.split(Pattern.quote("**"))[1]));
Calendar now=Calendar.getInstance();
now.setTime(new Date());
while(finServ.after(now)) {
PowerManager pm=(PowerManager)getSystemService(Context.POWER_SERVICE);
if(pm.isScreenOn()) {
//AsyncCapture ac=new AsyncCapture(this);
//ac.execute("nomevt");
photo();
Log.i("screen","on");
while(pm.isScreenOn()) {
pm=(PowerManager)getSystemService(Context.POWER_SERVICE);
}
}
now.setTime(new Date());
}
stopSelf();
}
return super.onStartCommand(intent, flags, startId);
}`
<br>The service will call `photo()` when the screen is light on. <br>
`public void photo() {
cam=Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
try {
cam.unlock();
/*WindowManager wm=(WindowManager)this.getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params=new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);*/
SurfaceView sv=new SurfaceView(this);
//wm.addView(sv, params);
ViewGroup.LayoutParams param=new ViewGroup.LayoutParams(1,1);
sv.setLayoutParams(param);
sv.setZOrderOnTop(true);
SurfaceHolder mHolder=sv.getHolder();
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
Log.i("holder",(mHolder==null)+"");
cam.setPreviewDisplay(mHolder);
cam.startPreview();
cam.takePicture(null,null,this);
//wm.removeView(sv);
Log.i("take","picture");
} catch (IOException e) {
Log.e("error",e.getMessage());
e.printStackTrace();
}catch(RuntimeException re) {
Log.e("error",re.getMessage()+"");
re.printStackTrace();
}finally{
cam.stopPreview();
cam.release();
}
}
And in takePicture()
I simply save the image, this method works as I tested it in an activity.
Logs show the error Camera : app passed NULL surface
, error : setPreviewTextureFailed
. I put a log to see if mHolder
is null but it's not.
Why does setPreviewDisplay()
throw an error ?
You should use SurfaceTexture
and setPreviewTexture()
instead of SurfaceHolder
:
SurfaceTexture surfaceTexture = new SurfaceTexture(0);
cam.setPreviewTexture(surfaceTexture);
The error Camera : app passed NULL surface
has been thrown in setPreviewDisplay()
is because there was no surface created.
If you still want to use SurfaceHolder
, you should implement SurfaceHolder.Callback
first and setPreviewDisplay()
in surfaceCreated()
method to make sure a surface was created before you setPreviewDisplay()
.
Note that the surface will not be created until you add it to the View hierarchy.
EDIT
Come back to your error when you setPreviewTexture()
, because you used cam.unlock();
, your camera is temporarily released for another process to use (read more about unlock()
method here). That's why you got error java.io.IOException: setPreviewTexture failed
when you call setPreviewTexture()
.
The solution is just remove line cam.unlock();
in your code.