Search code examples
androidandroid-sensorsandroid-orientation

Calling getOrientation() causes crash


I am building my first app and I want to get orientation of my phone when button is pressed and phone doesn't move. User can see view of back camera, point and then press the button and should get the angle.

The code seems to work ok when I use it in onSensorChanged (I was using as a sample code from: finding orientation using getRotationMatrix() and getOrientation()), but crashes when I use it in 'onClick'.

I want to get pitch value for other calculations (I made pitch global variable). Here is my onClick code:

public void onClick(View arg0)
{
    camera.takePicture(myShutterCallback,
            myPictureCallback_RAW, myPictureCallback_JPG);

    switch (event.sensor.getType()) {
    case Sensor.TYPE_ACCELEROMETER:
        gravity = event.values.clone();
        break;
    case Sensor.TYPE_MAGNETIC_FIELD:
        magnet = event.values.clone();
        break;
    }


    if(gravity!=null && magnet!=null) {
        rotMatrix = SensorManager.getRotationMatrix(inR, I, gravity, magnet);

        SensorManager.remapCoordinateSystem(inR,
                SensorManager.AXIS_X, SensorManager.AXIS_Z, outR);
        SensorManager.getOrientation(outR, orientVals);

        float azimuth = orientVals[0]*rad2deg;
        pitch = orientVals[1]*rad2deg;
        float roll = orientVals[2]*rad2deg;

        TextView rezDisplay = (TextView) findViewById(R.id.finalRezult);
        rezDisplay.setText("Atstumas iki objekto yra:" + pitch + "m");
    }
}

Any suggestions, links, examples or tuts would be great.

EDIT:

I add the whole class code.

import java.io.IOException;

import com.mindjack.measuremydistance.SensorEvnt.mSensorEventListener;

import android.app.Activity;
//import android.content.Intent;
import android.content.Context;
import android.content.pm.ActivityInfo;
//import android.graphics.Bitmap;
//import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.TextView;

public class AndroidCamera extends Activity implements SurfaceHolder.Callback
{
    Camera camera;
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;
    boolean previewing = false;
    LayoutInflater controlInflater = null;
    TextView display, display1;
    float[] magnet = new float[3];
    float[] gravity = new float[3];
    SensorEvent event;
    boolean rotMatrix;
    float[] outR = new float[16];
    float[] inR = new float[16];
    float[] I = new float[16];
    float[] orientVals = new float[3];
    final float pi = (float) Math.PI;
    final float rad2deg = 180/pi;
    float pitch;
    SensorManager mSensorManager;


    /** Called when the activity is first created. */
    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.andcam);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        getWindow().setFormat(PixelFormat.UNKNOWN);
        surfaceView = (SurfaceView)findViewById(R.id.surfaceview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        controlInflater = LayoutInflater.from(getBaseContext());
        View viewControl = controlInflater.inflate(R.layout.control, null);
        LayoutParams layoutParamsControl
            = new LayoutParams(LayoutParams.FILL_PARENT,
        LayoutParams.FILL_PARENT);
        this.addContentView(viewControl, layoutParamsControl);

        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

        Button buttonTakePicture = (Button)findViewById(R.id.takepicture);
        buttonTakePicture.setOnClickListener(new Button.OnClickListener() {
            // TODO Auto-generated method stub
            @Override
            public void onClick(View arg0) {
                camera.takePicture(myShutterCallback,
                     myPictureCallback_RAW, myPictureCallback_JPG);

                switch (event.sensor.getType()){
                case Sensor.TYPE_ACCELEROMETER:
                    gravity = event.values.clone();
                    break;
                case Sensor.TYPE_MAGNETIC_FIELD:
                    magnet = event.values.clone();
                    break;
                }

                //if(gravity!=null && magnet!=null){
                    rotMatrix = SensorManager.getRotationMatrix(inR,
                        I, gravity, magnet);
                    SensorManager.remapCoordinateSystem(inR,
                        SensorManager.AXIS_X, SensorManager.AXIS_Z, outR);
                    SensorManager.getOrientation(outR, orientVals);

                    float azimuth = orientVals[0]*rad2deg;
                    pitch = orientVals[1]*rad2deg;
                    float roll = orientVals[2]*rad2deg;
                // }

                TextView rezDisplay = (TextView) findViewById(R.id.finalRezult);
                rezDisplay.setText("Atstumas iki objekto yra:" + pitch + "m");
            }
        });
    }

    ShutterCallback myShutterCallback = new ShutterCallback() {
        @Override
        public void onShutter() {
            // TODO Auto-generated method stub
        }
    };

    PictureCallback myPictureCallback_RAW = new PictureCallback() {
        @Override
        public void onPictureTaken(byte[] arg0, Camera arg1) {
            // TODO Auto-generated method stub
        }
    };

    PictureCallback myPictureCallback_JPG = new PictureCallback() {
        @Override
        public void onPictureTaken(byte[] arg0, Camera arg1) {
            // TODO Auto-generated method stub
            //Bitmap bitmapPicture
            //= BitmapFactory.decodeByteArray(arg0, 0, arg0.length);
        }
    };

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height)
    {
        // TODO Auto-generated method stub
        if(previewing) {
            camera.stopPreview();
            previewing = false;
        }

        if (camera != null){
            try {
                camera.setPreviewDisplay(surfaceHolder);
                camera.startPreview();
                previewing = true;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        camera = Camera.open();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        camera.stopPreview();
        camera.release();
        camera = null;
        previewing = false;
    }
}

As I am new there might be some stupid errors, but I can't figure out tis situation. LogCat says that it crashes on line 84. I tried to to take out the part from line 84 till 91 and then it doesn't crash, but also gives 0 on pitch value.


Solution

  • Your event field is never initialized, you must be getting a NullPointerException while trying to access it in your switch statement.

    You should implement SensorEventListener and get the event in onSensorChanged(), otherwise you'll never have the values.

    However, don't store the SensorEvent directly, because the object is reused by the SensorManager. You have to copy the values of the sensors into other fields (like the variables in your switch statement) as soon as you get them in onSensorChanged(). You can then use these fields in onClick().