Search code examples
androidlocationfusedlocationproviderclient

FusedLocationProviderClient doesn't have bearing data


I'm using FusedLocationProviderClient class in android to get user's last location. Everything is fine and I can get latitude and longitude but task.getResult().getBearing() returns 0.0 and task.getResult().hasBearing() returns false. How can I get user's bearing information?

I'm getting ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions both in AndroidManifest file and at runtime.

This is the piece of code related to user location I'm using:

@SuppressLint("MissingPermission")
private void getLastLocation() {
    fusedLocationClient
            .getLastLocation()
            .addOnCompleteListener(this, new OnCompleteListener<Location>() {
                @Override
                public void onComplete(@NonNull Task<Location> task) {
                    if (task.isSuccessful() && task.getResult() != null) {
                        onLocationChange(task.getResult());
                        Log.i(TAG, "lat " + task.getResult().getLatitude() + " lng " + task.getResult().getLongitude());
                        Log.i(TAG, "bearing? " + task.getResult().hasBearing());
                    } else {
                        Toast.makeText(MainActivity.this, "Location Not Found!", Toast.LENGTH_SHORT).show();
                    }
                }
            });

}

private void onLocationChange(Location location) {
    //do something
}

Solution

  • I solved my problem using accelerometer and magnetic field sensors. This is the Compass class I use to get bearing of my cell phone:

    import android.content.Context;
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
    
    public class Compass implements SensorEventListener {
        private static final String TAG = "Compass";
    
        public interface CompassListener {
            void onNewAzimuth(float azimuth);
        }
    
        private CompassListener listener;
    
        private SensorManager sensorManager;
        private Sensor gsensor;
        private Sensor msensor;
    
        private float[] mGravity = new float[3];
        private float[] mGeomagnetic = new float[3];
        private float[] R = new float[9];
        private float[] I = new float[9];
    
        private float azimuth;
        private float azimuthFix;
    
        public Compass(Context context) {
            sensorManager = (SensorManager) context
                    .getSystemService(Context.SENSOR_SERVICE);
            gsensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            msensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        }
    
        public void start() {
            sensorManager.registerListener(this, gsensor,
                    SensorManager.SENSOR_DELAY_GAME);
            sensorManager.registerListener(this, msensor,
                    SensorManager.SENSOR_DELAY_GAME);
        }
    
        public void stop() {
            sensorManager.unregisterListener(this);
        }
    
        public void setAzimuthFix(float fix) {
            azimuthFix = fix;
        }
    
        public void resetAzimuthFix() {
            setAzimuthFix(0);
        }
    
        public void setListener(CompassListener l) {
            listener = l;
        }
    
        @Override
        public void onSensorChanged(SensorEvent event) {
            final float alpha = 0.97f;
    
            synchronized (this) {
                if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
    
                    mGravity[0] = alpha * mGravity[0] + (1 - alpha)
                            * event.values[0];
                    mGravity[1] = alpha * mGravity[1] + (1 - alpha)
                            * event.values[1];
                    mGravity[2] = alpha * mGravity[2] + (1 - alpha)
                            * event.values[2];
    
                    // mGravity = event.values;
    
                    // Log.e(TAG, Float.toString(mGravity[0]));
                }
    
                if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                    // mGeomagnetic = event.values;
    
                    mGeomagnetic[0] = alpha * mGeomagnetic[0] + (1 - alpha)
                            * event.values[0];
                    mGeomagnetic[1] = alpha * mGeomagnetic[1] + (1 - alpha)
                            * event.values[1];
                    mGeomagnetic[2] = alpha * mGeomagnetic[2] + (1 - alpha)
                            * event.values[2];
                    // Log.e(TAG, Float.toString(event.values[0]));
    
                }
    
                boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
                        mGeomagnetic);
                if (success) {
                    float orientation[] = new float[3];
                    SensorManager.getOrientation(R, orientation);
                    // Log.d(TAG, "azimuth (rad): " + azimuth);
                    azimuth = (float) Math.toDegrees(orientation[0]); // orientation
                    azimuth = (azimuth + azimuthFix + 360) % 360;
                    // Log.d(TAG, "azimuth (deg): " + azimuth);
                    if (listener != null) {
                        listener.onNewAzimuth(azimuth);
                    }
                }
            }
        }
    
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    }
    

    I calibrated the value by adding 352 to bearing received by onNewAzimuth method of this class and used it in my code:

        Compass compass = new Compass(this);
        Compass.CompassListener cl = new Compass.CompassListener() {
    
            @Override
            public void onNewAzimuth(float azimuth) {
                // using (360 - (azimuth) + 8) value
            }
        };
        compass.setListener(cl);