Sensor data choppy on Sony devices

246 Views Asked by At

For the past few days I've been playing around with sensors and canvas.

So far I've managed to control the location of a bitmap based on device's angles.

The way app works is it gets orientation data, and depending on how much the device is tilted, it moves the bitmap left or right on the screen.

I do most of my testing on my Samsung Galaxy S II GT-i9100 running android 4.2.2 (AOKP), and the app works pretty much flawlessly, apart from the app crashing when resuming it (I think I know what's causing that).

The problem I'm having is as follows:

When I try running the same code on a Sony Xperia Z (running android 4.1.2, stock from Sony) the whole app becomes choppy (the bitmap barely moves), and I think it's because the sensor data retrieval is choppy/slow. Same happens on my friend's Sony Xperia S.

I gave the app to my other friend who has a Nexus 4, he says he has no such problems.

GameView

public class GameView extends SurfaceView {

    private Bitmap bmp;
    private SurfaceHolder holder;
    private GameLoopThread gameLoopThread;
    private int x = 0;
    private int xMultiplier = 0;
    private Paint textPaint;

    //lowPass
    private float smoothVal = 0; //Main variable, check algorithm
    private int smoothing = 5; //How strong the smoothing is, larger the value, more time is needed before the value reaches actual sensor value



    //Sensors
    private SensorManager sensorManager;
    private SensorEventListener sensorEventListener;

    //Rotation matrices for converting coordinate systems
    private float[] rotationMatrixR = new float[9];
    private float[] rotationMatrixI = new float[9];

    //Arrays storing data for gravity and geomagnetic data needed to get device's angles
    private float[] gravity = new float[3];
    private float[] geomagnetic = new float[3];

    //Array holding angles
    private float[] angles = new float[3];




    public GameView(Context context) {
        super(context);
        gameLoopThread = new GameLoopThread(this);
        holder = getHolder();
        textPaint = new Paint();
        textPaint.setColor(Color.WHITE);
        textPaint.setTextSize(20);

        sensorManager = (SensorManager)getContext().getSystemService(Context.SENSOR_SERVICE);

        sensorEventListener = new SensorEventListener() {
            @Override
            public void onSensorChanged(SensorEvent sensorEvent) {

                Sensor sensor = sensorEvent.sensor;

                if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                    gravity = sensorEvent.values;
                }
                else if (sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                    geomagnetic = sensorEvent.values;
                }

                SensorManager.getRotationMatrix(rotationMatrixR, rotationMatrixI, gravity, geomagnetic);
                SensorManager.getOrientation(rotationMatrixR, angles);
            }

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

            }
        };

        sensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_FASTEST);
        sensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_FASTEST);



        holder.addCallback(new SurfaceHolder.Callback() {

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                boolean retry = true;
                gameLoopThread.setRunning(false);

                while (retry) {
                    try {
                        gameLoopThread.join();
                        retry = false;
                    }
                    catch (InterruptedException e) {
                        //Shit hit the fan
                        Log.e("GameLoopThread", e.toString());
                    }
                }
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder){
                gameLoopThread.setRunning(true);
                gameLoopThread.start();
            }
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }
        });
        bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);

    }
    @Override
    protected void onDraw(Canvas canvas)
    {

        x = (int) ((canvas.getWidth() / 100) * ((lowPass(angles[2]) * 100) + 50));

        canvas.drawColor(Color.DKGRAY); //This also clears the screen
        canvas.drawBitmap(bmp, x, canvas.getHeight() - bmp.getHeight() - 20, null);

        canvas.drawText("Azimuth (Z): " + Float.toString(angles[0]),25,25, textPaint);
        canvas.drawText("Pitch (X): " + Float.toString(angles[1]),25,45, textPaint);
        canvas.drawText("Roll (Y): " + Float.toString(angles[2]),25,65, textPaint);
        canvas.drawText("X: " + Integer.toString(x),25,85,textPaint);


    }

    public static BigDecimal roundFloat(float d, int decimalPlace) {
        BigDecimal bd = new BigDecimal(Float.toString(d));
        bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
        return bd;
    }

    private float lowPass(float curValue) {
        smoothVal += (curValue - smoothVal) / smoothing;
        return smoothVal;
    }
}

GameLoopThread

public class GameLoopThread extends Thread {
    static final long FPS = 25;
    private GameView view;
    private Boolean running = false;


    public GameLoopThread(GameView view){
        this.view = view;
    }

    public void setRunning(boolean run){
        running = run;
    }

    @Override
    public void run(){
        long tickPS = 1000/FPS;
        long startTime;
        long sleepTime;

        while(running){
            Canvas c = null;
            startTime = System.currentTimeMillis();
            try {
                c = view.getHolder().lockCanvas();
                synchronized (view.getHolder()){
                    view.onDraw(c);
                }
            }

            catch (NullPointerException e) {
                Log.e("GameLoopThread", e.toString());
            }

            finally {
                if (c != null) {
                    view.getHolder().unlockCanvasAndPost(c);
                }
            }

            sleepTime = tickPS - (System.currentTimeMillis() - startTime);

            try {
                if (sleepTime > 0) {
                    sleep(sleepTime);
                }
                else {
                    sleep(10);
                }
            }
            catch (Exception e) {
                Log.e("GameLoopThread", e.toString());
            }

        }
    }
}
0

There are 0 best solutions below