Skip to main content
SDKs & dev tools 1 min read

Implementing the compass functionality with HERE SDK Navigate edition

HERE SDK Compass

Last week, we showed you how to render real-time realistic views during navigation using HERE SDK Navigate Edition. This week, we have another exciting tutorial for you: how to listen to the device hardware motion sensors like gyroscope or magnetometer to update the azimuth value on the device motion and orientation in HERE SDK. This will allow you to implement custom compass functionality with HERE SDK for Android (Navigate edition), and enhance your app's navigation capabilities. Let’s get started!

Compass Gif
Implementing the compass functionality while Navigation

1. Create UI Part in XML file for Navigation Screen

Copied
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent”>

———— Other UI Components ————

   <androidx.cardview.widget.CardView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:clickable="true"
        android:onClick="compassClicked"
        app:cardCornerRadius="25dp"
        app:cardPreventCornerOverlap="true"
        app:cardUseCompatPadding="false"
        app:contentPadding="6dp">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/compass_needle" />
    </androidx.cardview.widget.CardView>
</RelativeLayout>
  

2. Create a variable in class file for checking the compass status, name it as “isCompassOn”

Copied
        private boolean isCompassOn = true;
  

3. Create a function in the class for compassClicked

Copied
        public void compassClicked(View view) {
        isCompassOn = !isCompassOn;
}
  

4. Define a sensor manager for compass sensor

Copied
        //For compass UI
private CardView compassFab;
//For sensor configs
private SensorManager mSensorManager;
private Sensor mRotationSensor;
private float[] mRotationMatrix = new float[9];
private float[] mOrientation = new float[3];
//For current location
private GeoCoordinates currentLocation; 
//Additional variable for saving map camera zoom
private int cameraZoom = 0;

  

5. Initialize the variables in onCreate function 

Copied
        @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_navigation);
compassFab = findViewById(R.id.compassFab);
//sensor configs
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
// Get a reference to the rotation vector sensor
mRotationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
}
  

6. Register map camera listener with map; and register and unregister sensor listener in onResume and onStop respectively.

Copied
        public class NavigationActivity extends AppCompatActivity implements SensorEventListener, MapCameraListener {


mapView.getMapScene().loadScene(MapScheme.NORMAL_DAY, new MapScene.LoadSceneCallback() {
	@Override
           public void onLoadScene(@Nullable MapError mapError) {
		if (mapError == null) {
			——— other functions —————
			mapView.getCamera().addListener(NavigationActivity.this);
		} else {
                    		Log.d(TAG, "Loading map failed: mapErrorCode: " + mapError.name());
                	}
	}	
}

@Override
    protected void onResume() {
        super.onResume();
        // Register the sensor listener
        mSensorManager.registerListener(this, mRotationSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }

@Override
    protected void onPause() {
        super.onPause();
        // Unregister the sensor listener
        mSensorManager.unregisterListener(this);
    }
}

  

7. Save the current location from the navigation location listener on visual navigator

Copied
        visualNavigator.setNavigableLocationListener(new NavigableLocationListener() {
            @Override
            public void onNavigableLocationUpdated(@NonNull NavigableLocation currentNavigableLocation) {
		———— other functionality —————
		currentLocation = currentNavigableLocation.originalLocation.coordinates;
            }
        });
  

8. Change the compass icon rotation according to the map camera rotation if compass is ON

Copied
        @Override
    public void onMapCameraUpdated(@NonNull MapCamera.State state) {
        // Rotate the compass image
        if (isCompassOn) {
            compassFab.setRotation((float) state.orientationAtTarget.bearing);
        }
    }

  

9. Change the map camera according to the sensor

Copied
        @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
            // Convert the rotation vector to a rotation matrix
            SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
            // Convert the rotation matrix to orientation angles
            SensorManager.getOrientation(mRotationMatrix, mOrientation);
            // Convert the azimuth angle to degrees
            float azimuthInRadians = mOrientation[0];
            float azimuthInDegrees = (float) Math.toDegrees(azimuthInRadians);

            // Rotate the map camera and compass image using compass sensor
            if (!isCompassOn) {
                compassFab.setRotation(-azimuthInDegrees);
                GeoOrientationUpdate orientationUpdate = new GeoOrientationUpdate((double) -azimuthInDegrees, 0.0);
                if (currentLocation != null) {
		// please make a check for zoom as it should be one time only 
                    	mapView.getCamera().startAnimation(MapCameraAnimationFactory.flyTo(new GeoCoordinatesUpdate(currentLocation), orientationUpdate, cameraZoom == 0 ? 300 : 0, Duration.ofMillis(1)));
		cameraZoom = 300;
                }
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do nothing
    }

  
Conclusion

We hope this tutorial has shown you how to use device hardware motion sensors with HERE SDK to create custom compass functionality for your navigation apps. This feature can enhance the user experience by providing more accurate and reliable orientation information. You can also customize the appearance and behavior of the compass to suit your app design and preferences. HERE SDK offers many other features and capabilities for creating amazing navigation apps, so make sure to check out our developer blog for more tips and tricks. If you have any questions or comments, reach us out on our Slack channel, and we'll be happy to assist you! Or simply drop by to say hi and connect with fellow developers. We're looking forward to hearing from you!

Resources
Sachin Jonda

Sachin Jonda

Lead Onboarding Engineer

Have your say

Sign up for our newsletter

Why sign up:

  • Latest offers and discounts
  • Tailored content delivered weekly
  • Exclusive events
  • One click to unsubscribe