0

I have gone through many links looking for a solution, but this is my first official app in Android. I have made other small ones like Calculator, but none like this, so I am not able to understand the advice and solutions even if i read them.

The app basically does the following :-

  1. take in Gyroscope and Accelerometer readings
  2. calculate angle of motion as the user moves in a circle.
  3. take images every 10 Degrees.

The first Class works on the surface view. And the second works on taking a picture and calculating sensor readings

I have worked out the first two parts. but the third part is the problem. Every time I take an image, the app hangs and the surface view stops working. And nothing happens. When I rotate another 10 Degrees, the app crashes.

Can someone please tell me what I am doing wrong. Thank you in advance.

package com.example.mehta.accelerometerin;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.hardware.SensorEventListener;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import static android.content.ContentValues.TAG;
import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE;
import static java.lang.Math.sqrt;







class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;




    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            // this device has a camera
            return true;
        } else {
            // no camera on this device
            return false;
        }
    }




    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;


        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }


    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.


        if (mHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.setDisplayOrientation(90);
            mCamera.startPreview();

        } catch (Exception e) {
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }

    }


    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }


}


class MainActivity extends AppCompatActivity implements SensorEventListener {
    private Camera mCamera;
    private CameraPreview mPreview;

    private SensorManager senSensorManager;
    private Sensor senAccelerometer;
    private Sensor senGyroscope;
    private long lastUpdate = 0;
    private float last_x, last_y, last_z;
    private static final int SHAKE_THRESHOLD = 600;
    TextView tv1, tv2, tv3, tv4, tv5;
    int j = 0;
    int i = 1;
    int l = 10;
    int m = 0;
    private float xg, yg, zg, xa, ya, za;
    private float x1, y1;
    float x2, y2;
    private float xang, yang, zang;
    private float zacc;
    private float xacc;
    private float yacc;
    private int greset;
    public static Camera getCameraInstance() {
        Camera c = null;
        try {
            c = Camera.open(); // attempt to get a Camera instance
        } catch (Exception e) {
            // Camera is not available (in use or does not exist)
        }
        return c; // returns null if camera is unavailable
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Create an instance of Camera
        mCamera = getCameraInstance();

        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(this, mCamera);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(mPreview);
        greset = 0;
        senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        senGyroscope = senSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

        senSensorManager.registerListener(this,senAccelerometer,SensorManager.SENSOR_DELAY_NORMAL);
        senSensorManager.registerListener(this,senGyroscope,SensorManager.SENSOR_DELAY_NORMAL);


    }



    public static final int MEDIA_TYPE_IMAGE = 1;
    public static final int MEDIA_TYPE_VIDEO = 2;

    /** Create a file Uri for saving an image or video */
    private static Uri getOutputMediaFileUri(int type){
        return Uri.fromFile(getOutputMediaFile(type));
    }

    /** Create a File for saving an image or video */
    private static File getOutputMediaFile(int type){

        // To be safe, you should check that the SDCard is mounted
        // using Environment.getExternalStorageState() before doing this.

        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), "MyCameraApp");
        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.

        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                Log.d("MyCameraApp", "failed to create directory");
                return null;
            }
        }

        // Create a media file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File mediaFile;
        if (type == MEDIA_TYPE_IMAGE){
            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                    "IMG_"+ timeStamp + ".jpg");
        } else if(type == MEDIA_TYPE_VIDEO) {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                    "VID_"+ timeStamp + ".mp4");
        } else {
            return null;
        }

        return mediaFile;
    }

    private Camera.PictureCallback mPicture = new Camera.PictureCallback() {

        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            Toast.makeText(getApplicationContext(), "on Picture Taken", Toast.LENGTH_SHORT).show();

            File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
            if (pictureFile == null){
                Log.d(TAG, "Error creating media file, check storage permissions: " );
                return;
            }

            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
            } catch (FileNotFoundException e) {
                Log.d(TAG, "File not found: " + e.getMessage());
            } catch (IOException e) {
                Log.d(TAG, "Error accessing file: " + e.getMessage());
            }
        }
    };



    protected void onPause() {
        super.onPause();
        senSensorManager.unregisterListener(this);

    }

    protected void onResume() {
        super.onResume();
        senSensorManager.registerListener(this,senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
        senSensorManager.registerListener(this,senGyroscope,SensorManager.SENSOR_DELAY_NORMAL);
    }


    public void onSensorChanged(SensorEvent sensorEvent) {
        Sensor mySensor = sensorEvent.sensor;


        if (mySensor.getType() == Sensor.TYPE_GYROSCOPE) {
            greset ++;
            zg += sensorEvent.values[1];
            xg +=sensorEvent.values[0];
            yg +=sensorEvent.values[2];
            if(zg>30)
            {
                zg=0;
            }
            if(xg>30)
            {
                xg=0;
            }
            if(yg>30)
            {
                yg=0;
            }
            xang = xg*12;
            yang = yg*12;
            zang = zg*12;
            if(zang>=l) {
                Toast.makeText(getApplicationContext(), "click="+i, Toast.LENGTH_SHORT).show();
                mCamera.stopPreview();
                mCamera.takePicture(null,null,mPicture);
                mCamera.startPreview();
                l += 10;
                i++;}




            if (greset >10)
            {
                xg +=0.1;

                greset = 0;
            }

        }

        if(mySensor.getType()==Sensor.TYPE_ACCELEROMETER)
        {
            xa = sensorEvent.values[0];
            za = sensorEvent.values[1];
            ya = sensorEvent.values[2];



            zacc = (float)(za - (((90 -  xang)/ 90) * 9.8));


        }



        if (l > 360) {
            l = 10;
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    public int returnvalue(){
        return(i);
    }

}
Shabbir Dhangot
  • 8,954
  • 10
  • 58
  • 80

1 Answers1

0
  1. Don't call stopPreview() immediately before calling takePicture(): This method is only valid when preview is active (after startPreview()). Preview will be stopped after the image is taken.

  2. You should call startPreview() from onPictureTaken(), not immediately after calling takePicture().

  3. Open the camera on a separate handler thread, not on the main (UI) thread.

There may be other problems with your code, but let us start with fixing these three immediate issues.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Hi, Thanks for the pointer. I did part 1 and 2 and that got my app atleast not hanging all the time, I dont really understand point 3, could you please explain it a little. But now another problem has started, it isnt saving the images to my sd card. I started the debugger mode and all it keeps saying 1)qcamera::QCameraExif* qcamera::QCamera2HardwareInterface::getExifData(): getExifGpsDataTimeStamp failed 2)mm_jpeg_configure_job_params: config makernote data failed 3) faceproc_comp_eng_destroy: Album save failed -1 – Akash Mehta Nov 27 '16 at 18:30
  • Oh I figured it out the problem. Thanks in any case. if you could just explain point 3 that would be great. – Akash Mehta Nov 27 '16 at 18:54
  • You can find some explanation at _[Best use of HandlerThread over other similar classes](http://stackoverflow.com/questions/18149964/best-use-of-handlerthread-over-other-similar-classes/19154438#19154438)_, or code example in [Open Camera](https://github.com/almalence/OpenCamera) project. – Alex Cohn Nov 27 '16 at 21:35