this series aims to add varies app physical abilities with as little code lines inside the MainActivity. it is what the android studio IDEs should include as a default but they don't
so thank your lucky star I did it.

SoulTicker (java): this will run the code inside it's run method every tickMillies time
adding global variables to the class enables accessing them from within the tick.

Code:

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;

import static android.content.Context.SENSOR_SERVICE;

public class CompassUtil implements SensorEventListener {
    //private ImageView mPointer;
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;
    private Sensor mMagnetometer;
    private float[] mLastAccelerometer = new float[3];
    private float[] mLastMagnetometer = new float[3];
    private boolean mLastAccelerometerSet = false;
    private boolean mLastMagnetometerSet = false;
    private float[] mR = new float[9];
    private float[] mOrientation = new float[3];
    private float mCurrentDegree = 0f;

    public CompassUtil(SensorManager mSensorManager) {
        //on main : val sensorManager:SensorManager = getSystemService(SENSOR_SERVICE) as SensorManager;
        http://this.mPointer = mPointer;
        this.mSensorManager = mSensorManager;
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor == mAccelerometer) {
            System.arraycopy(event.values, 0, mLastAccelerometer, 0, event.values.length);
            mLastAccelerometerSet = true;
        } else if (event.sensor == mMagnetometer) {
            System.arraycopy(event.values, 0, mLastMagnetometer, 0, event.values.length);
            mLastMagnetometerSet = true;
        }
        if (mLastAccelerometerSet && mLastMagnetometerSet) {
            SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);
            SensorManager.getOrientation(mR, mOrientation);
            float azimuthInRadians = mOrientation[0];
            float azimuthInDegress = (float)(Math.toDegrees(azimuthInRadians)+360)%360;
//            RotateAnimation ra = new RotateAnimation(
//                    mCurrentDegree,
//                    -azimuthInDegress,
//                    Animation.RELATIVE_TO_SELF, 0.5f,
//                    Animation.RELATIVE_TO_SELF,
//                    0.5f);
//
//            ra.setDuration(250);
//
//            ra.setFillAfter(true);
//
//            mPointer.startAnimation(ra);
            mCurrentDegree = -azimuthInDegress;
        }
    }

    public String getmCurrentDegreeAsString() {
        return getmCurrentDegree()+"";
    }
    public Float getmCurrentDegree() {
        return mCurrentDegree;
    }
    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }
    public void onResume() {
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
        mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
    }

    public void onPause() {
        mSensorManager.unregisterListener(this, mAccelerometer);
        mSensorManager.unregisterListener(this, mMagnetometer);
    }
}


:shouryuken: