Android - Camera App passed null surface

17,054

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.

Share:
17,054
Biratus
Author by

Biratus

Updated on June 04, 2022

Comments

  • Biratus
    Biratus almost 2 years

    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 ?