5

I have a simple app that has an activity being called periodically by an alarm manager to display a preview frame and take a picture when the preview frame is built.After taking the picture, it is saved using a AsyncTask and the activity destroyed using finish(). The code works perfectly fine when I have the screen turned on.However it fails to take a picture with the screen off.I want to monitor a house and take pictures periodically using the app and in that case keeping the screen always on or turning it on manually is not a viable option.

Also the code for the camera activity has been copied from Commonsware library and works perfectly great.I am only having a problem with taking a picture with screen off.I can also see from the logs that the camera is opened by the activity.However the Runnable that is supposed to take picture when the preview frame is built, doesn't run and the camera goes to the pause state instead and stays there.

I have the necessary permissions set up perfectly as I am able to get the images with screen turned on.Maybe I am having trouble understanding the activity lifecylce when the screen is off and someone can shed light there.

I tried using the wakelocks to turn the screen on but that didnt do any good.

Below is the code for the Activity.

Also I am sorry but removing the comment for the license to make it short here.

    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 use the following piece of code to click a picture after the preview surface is properly created in onResume().

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

Any help is appreciated.Thanks

SteveIrwin
  • 115
  • 2
  • 14

3 Answers3

1

I think you can use WakeLock to make sure that Screen-Off does not occur. Below is the sample code/algorithm by which you can turn on screen whenever it goes off. Hope This Helps!

  1. Register a broadcast receiver on Intent.ACTION_SCREEN_OFF.
  2. Whenever you get screen off broadcast intent, wake-up by using below code.

    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();
    
srs
  • 647
  • 3
  • 11
  • The screen is always supposed to be off.So I am not sure if the Intent will be fired.I tried acquiring a Partial_WAKE_LOCK and SCREEN on lock which didnt work either.I will try your code though and see if it works.THanks – SteveIrwin Aug 26 '14 at 04:45
1
android:keepScreenOn="true" 

you can use above line to your parent layout in XML which you are calling through activity

it will keep your screen on always so you will not get any issue hope it will match your requirement

1

I figured out what the problem was after making extensive use of the LogCat :).

It seems that when the screen is kept on, the onPause() is not called instantly which is the case with the SCREEN_OFF.When the screen is ON, the Runnable is executed before the onPause() method executed and as such the pictures are taken perfectly fine.However in case when the screen is OFF, the Runnable is being executed after the Activity has completed the onPause() method.By this time we have already released the camera in onPause() and so we don't get a picture.

It started working after I figured out the flow and moved the camera release to the onDestroy() which might not be ideal for all situations but works just fine for mine because the only purpose of my Activity is to take a picture and then destroy itself.

Also the WAKELOCKS didn;t change the behaviour of the code.I would expect the Activity to not execute without the WAKE_LOCK but its working perfectly fine.

Hope this helps someone stuck in a similar situation.

SteveIrwin
  • 115
  • 2
  • 14