private void setupDirectionObservable() {
        if (directionDataObservable != null) {
            return;
        }
        // If we have no magnetic sensor, there is no point in trying to setup any, we will always get the direction from the GPS.
        if (!hasCompassCapabilities) {
            Log.i("No compass capabilities, using only the GPS for the orientation");
            directionDataObservable = RxUtils.rememberLast(geoDataObservableLowPower.map(GPS_TO_DIRECTION).doOnNext(onNextrememberDirectionAction), DirectionData.EMPTY);
            return;
        }

        // Combine the magnetic direction observable with the GPS when compass is disabled or speed is high enough.
        final AtomicBoolean useDirectionFromGps = new AtomicBoolean(false);

        // On some devices, the orientation sensor (Xperia and S4 running Lollipop) seems to have been deprecated for real.
        // Use the rotation sensor if it is available unless the orientatation sensor is forced by the user.
        // After updating Moto G there is no rotation sensor anymore. Use magnetic field and accelerometer instead.
        final Observable<DirectionData> sensorDirectionObservable;
        final Application application = CgeoApplication.getInstance();
        if (Settings.useOrientationSensor(application)) {
            sensorDirectionObservable = OrientationProvider.create(application);
        } else if (RotationProvider.hasRotationSensor(application)) {
            sensorDirectionObservable = RotationProvider.create(application);
        } else {
            sensorDirectionObservable = MagnetometerAndAccelerometerProvider.create(application);
        }

        final Observable<DirectionData> magneticDirectionObservable = sensorDirectionObservable.onErrorResumeNext((Function<Throwable, Observable<DirectionData>>) throwable -> {
            Log.e("Device orientation is not available due to sensors error, disabling compass", throwable);
            Settings.setUseCompass(false);
            return Observable.<DirectionData>never().startWith(Single.just(DirectionData.EMPTY));
        }).filter(dirData -> Settings.isUseCompass() && !useDirectionFromGps.get());

        if (geoDataObservableLowPower == null) {
            // when can geoDataObservableLowPower be null? ->
            // this can happen in the very special case immediately after fresh and first installation of c:geo on a device when user goes into Settings BEFORE granting localization permission to c:geo
            // for some reason, c:geo does not ask for these permission immediately after installation but only later
            setupGeoDataObservables(Settings.useGooglePlayServices(), Settings.useLowPowerMode());
        }

        final Observable<DirectionData> directionFromGpsObservable = geoDataObservableLowPower.filter(geoData -> {
            final boolean useGps = geoData.getSpeed() > 5.0f;
            useDirectionFromGps.set(useGps);
            return useGps || !Settings.isUseCompass();
        }).map(GPS_TO_DIRECTION);

        directionDataObservable = RxUtils.rememberLast(Observable.merge(magneticDirectionObservable, directionFromGpsObservable).doOnNext(onNextrememberDirectionAction), DirectionData.EMPTY);
    }
Provides access to Location data (GPS and direction).
<br>
This class is responsible for fusing different available Location providers of Android
system according to their availability and user preference. Examples for different providers:
* Google Play Location provider such as FusedLocationProvider (if Google Play Service is available)
* Location via Android Low-Level APIs (LocationManager from Service Context.LOCATION_SERVICE)
* Differentiation between LowPower-optimized and precision-optimized location data
main/src/main/java/cgeo/geocaching/sensors/LocationDataProvider.java