Android camera won't shoot when screen is off

I have a simple application that periodically calls the alarm manager to display a preview frame and take a snapshot when the preview frame is created. After taking the picture, the picture is saved with the help AsyncTask

and the activity is destroyed with the help finish()

. The code works fine when I have the screen turned on. However, he cannot take a picture of the screen from the screen. I want to control the house and take pictures periodically with the app, in which case keeping the screen always on or rotating it manually is not a viable option.

Also the code for the camera activity was copied from the Commonsware library and works fine. I have a problem shooting with the screen off. I can also see from the logs that the camera is being opened by activity. However, the Runnable, which is supposed to take a picture when the preview frame is created, does not start and the camera pauses and stays there.

I have the required permissions that can be adjusted as I can get screen-enabled images. Maybe I'm having trouble understanding the lifecycle of an activity when the screen is off and someone can shed some light there.

I tried to use wakelocks to turn on the screen but it was no good.

Below is the action code.

Also, I'm sorry to have removed the comment for the license to keep it short.

    package com.thopedia.snapper; /***
 Copyright (c) 2008-2012 CommonsWare, LLC
*/
import all;

public class CameraActivity1 extends Activity {
    private PreviewFrameLayout frame=null;
    private SurfaceView preview=null;
    private SurfaceHolder previewHolder=null;
    private Camera camera=null;
    private boolean inPreview=false;
    private boolean cameraConfigured=false;
    private  PowerManager.WakeLock wakeLock;
    private PowerManager powerManager;

    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState) {
       /* powerManager = (PowerManager) getSystemService(POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, getClass()
                .getName());*/
        Log.v(GlobalVariables.TAG,"CameraActivity On create called");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        frame=(PreviewFrameLayout)findViewById(R.id.frame);
        preview=(SurfaceView)findViewById(R.id.preview);
        previewHolder=preview.getHolder();
        previewHolder.addCallback(surfaceCallback);
        previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
     }

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    @Override
    public void onResume() {
       // wakeLock.acquire();
        Log.v(GlobalVariables.TAG,"camera activity onResume called");
       super.onResume();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            Camera.CameraInfo info=new Camera.CameraInfo();

            for (int i=0; i < Camera.getNumberOfCameras(); i++) {
                Camera.getCameraInfo(i, info);

                if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    try{
                        camera=Camera.open(i);
                    }catch (Exception e){
                        Log.v(GlobalVariables.TAG,"Camera Opening Exception");
                        if(!isFinishing()) {
                            finish();
                        }}}}}
        if (camera == null) {
            try{
                camera=Camera.open();
            }catch (Exception e){
                if(!isFinishing()) {
                    finish();
                }
                Log.v(GlobalVariables.TAG,"Camera opening exception");
            }
        }

        startPreview();
        preview.post(new Runnable() {
            @Override
            public void run() {
                if (inPreview) {
                    camera.takePicture(null, null, photoCallback);
                    inPreview=false;
                }
            }
        });
    }
    @Override
    public void onPause() {
        super.onPause();
        Log.v(GlobalVariables.TAG,"Camera activity onPause called");
        if (inPreview) {
            if(camera!=null) {
                camera.stopPreview();
            }
        }
        if(camera!=null) {
            camera.release();
            camera = null;
        }
        inPreview=false;
    }

    @Override
    protected void onDestroy() {
        Log.v(GlobalVariables.TAG,"Camera activity onDestroy called!");
        super.onDestroy();
        if(camera!=null){
            camera.release();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        new MenuInflater(this).inflate(R.menu.options, menu);
        return(super.onCreateOptionsMenu(menu));
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.camera) {
            if (inPreview) {
                camera.takePicture(null, null, photoCallback);
                inPreview=false;
            }
        }
        return(super.onOptionsItemSelected(item));
    }

    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);
    }

    private Camera.Size getSmallestPictureSize(Camera.Parameters parameters) {
        Camera.Size result=null;
        for (Camera.Size size : parameters.getSupportedPictureSizes()) {
            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);
    }

    private void initPreview(int width, int height) {
        if (camera != null && previewHolder.getSurface() != null) {
            try {
                camera.setPreviewDisplay(previewHolder);
            }
            catch (Throwable t) {
                Log.e("PreviewDemo-surfaceCallback",
                        "Exception in setPreviewDisplay()", t);
                Toast.makeText(CameraActivity1.this, t.getMessage(),
                        Toast.LENGTH_LONG).show();
            }

            if (!cameraConfigured) {
                Camera.Parameters parameters=camera.getParameters();
                Camera.Size size=getBestPreviewSize(width, height, parameters);
                Camera.Size pictureSize=getSmallestPictureSize(parameters);

                if (size != null && pictureSize != null) {
                    parameters.setPreviewSize(size.width, size.height);
                    parameters.setPictureSize(pictureSize.width,
                            pictureSize.height);
                    parameters.setPictureFormat(ImageFormat.JPEG);
                    frame.setAspectRatio((double)size.width / size.height);
                    camera.setParameters(parameters);
                    cameraConfigured=true;
                }
            }
        }
    }

    private void startPreview() {
        if (cameraConfigured && camera != null) {
            camera.startPreview();
            inPreview=true;
        }
    }

    SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback() {
        public void surfaceCreated(SurfaceHolder holder) {
            // no-op -- wait until surfaceChanged()
        }

        public void surfaceChanged(SurfaceHolder holder, int format,
                                   int width, int height) {
            initPreview(width, height);
            startPreview();
        }

        public void surfaceDestroyed(SurfaceHolder holder) {
            // no-op
        }
    };

    Camera.PictureCallback photoCallback=new Camera.PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {
            new SavePhotoTask().execute(data);
            camera.startPreview();
            inPreview=true;
            if(!isFinishing()) {
                finish();
            }
        }
    };

      

I am using the following piece of code to click the image after correctly assembling the preview surface in onResume().

preview.post(new Runnable() {
            @Override
            public void run() {
                if (inPreview) {
                    camera.takePicture(null, null, photoCallback);
                    inPreview=false;
                }
            }
        });

      

Any help is appreciated. thank

+3


source to share


3 answers


I think you can use WakeLock to make sure no Screen-Off occurs. Below is an example of code / algorithm with which you can turn on the screen every time you turn it off. Hope this helps!



  • Register a broadcast receiver with Intent.ACTION_SCREEN_OFF.
  • Whenever you force the screen to turn off broadcast, wake up using the code below.

    PowerManager pm = (PowerManager) context
                            .getSystemService(Context.POWER_SERVICE);
                    WakeLock wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
                            | PowerManager.ACQUIRE_CAUSES_WAKEUP
                            | PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
                    wakeLock.acquire();
    
          

+1


source


android:keepScreenOn="true" 

      

you can use the above line for your parent layout in XML that you call via activity



it will always support your screen, so you won't get any problem if it matches your requirement

+1


source


I figured out what the problem is after using LogCat extensively :).

It seems that when the screen is saved, it onPause()

doesn't get called instantly, which is the case with SCREEN_OFF

. When the screen is on , it is executed Runnable

before executing the method onPause()

and thus the images are received perfectly. However, in the case where the screen is off , the Runnable is executed after the Activity has completed the method onPause()

. this time we have already released the camera in onPause()

, and therefore we are not getting the image.

It started working after I understood the flow and moved the camera release to onDestroy()

, which may not be ideal for all situations, but works great for me, because the only purpose of my activity is to take a picture and then destroy myself.

Also WAKELOCKS didn't change the behavior of the code. I would expect the Activity not to run without WAKE_LOCK, but it works just fine.

Hope this helps someone get stuck in a similar situation.

+1


source







All Articles