Search code examples
androidlocationcompass-geolocation

Android Compass point to my location instead of north


I'm developing compass application where I want the compass to point to a particular latitude longitude position instead of the usual north. I found some questions related to my problem but I don't manage to make them worked for me. Here's my code:

public class MainActivity extends AppCompatActivity implements SensorEventListener {
    private ImageView image;
    private float currentDegree = 0f;
    private SensorManager mSensorManager;
    private TextView tvHeading;
    private Location location = new Location("A");
    private Location target = new Location("B");
    private LocationManager locationManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        image = (ImageView) findViewById(R.id.imageViewCompass);
        tvHeading = (TextView) findViewById(R.id.tvHeading);

        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

        location.setLatitude(54.903535);
        location.setLongitude(23.979342);

        target.setLatitude(54.904618);
        target.setLongitude(23.978782);
    }

    @Override
    protected void onResume() {
        super.onResume();

        mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_GAME);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this); // to stop the listener and save battery
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        float degree = Math.round(event.values[0]);
        tvHeading.setText("Heading: " + Float.toString(degree) + " degrees");
        RotateAnimation ra = new RotateAnimation(
                currentDegree,
                -degree,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF,
                0.5f);
        ra.setDuration(210);
        ra.setFillAfter(true);

        image.startAnimation(ra);
        currentDegree = -degree;
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // not in use
    }
}

currently my pointer shows only in north instead of my harcoded target location.


Solution

  • I think I found the way to do it: Here's the method I have changed to get expected behaviour (Based on this question and CookieMonster answer)

    @Override
        public void onSensorChanged(SensorEvent event) {
            // get the angle around the z-axis rotated
            float degree = Math.round(event.values[0]);
            degree += geoField.getDeclination();
    
            float bearing = location.bearingTo(target);
            degree = (bearing - degree) * -1;
            degree = normalizeDegree(degree);
    
            tvHeading.setText("Heading: " + Float.toString(degree) + " degrees");
    
            // create a rotation animation (reverse turn degree degrees)
            RotateAnimation ra = new RotateAnimation(
                    currentDegree,
                    -degree,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF,
                    0.5f);
    
            // how long the animation will take place
            ra.setDuration(210);
    
            // set the animation after the end of the reservation status
            ra.setFillAfter(true);
    
            // Start the animation
            image.startAnimation(ra);
            currentDegree = -degree;
        }
    
    private float normalizeDegree(float value) {
            if (value >= 0.0f && value <= 180.0f) {
                return value;
            } else {
                return 180 + (180 + value);
            }
        }