Launch Custom NavigationView

A complete turn-by-turn experience using custom NavigationView

This example shows:

  • How to fetch a route using RouteFetcher.getRoute with RouteRequestParams.Builder

  • How to initialize a NavigationView and bind it to the activity lifecycle

  • How to config NavEngineConfig.Builder and NavViewConfig.Builder in the onNavigationReady() callback

  • How to start navigation using navigationView.startNavigation

docs-image

For all code examples, refer to Navigation Code Examples

activity_custom_navigation.xml view source

1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:orientation="vertical"
6 android:padding="10dp">
7
8 <LinearLayout
9 android:layout_width="wrap_content"
10 android:layout_height="wrap_content">
11 <Button
12 android:id="@+id/fetchRoute"
13 android:layout_width="wrap_content"
14 android:layout_height="wrap_content"
15 android:text="@string/fetch_route"/>
16
17 <Button
18 android:id="@+id/startNav"
19 android:layout_width="wrap_content"
20 android:layout_height="wrap_content"
21 android:layout_marginLeft="15dp"
22 android:text="@string/start_navigation"/>
23 </LinearLayout>
24
25 <TextView
26 android:id="@+id/routeGeometry"
27 android:layout_width="wrap_content"
28 android:layout_height="wrap_content"
29 android:layout_marginTop="10dp"/>
30
31 <ProgressBar
32 android:id="@+id/progress"
33 android:visibility="gone"
34 android:layout_width="wrap_content"
35 android:layout_height="wrap_content"
36 android:layout_gravity="center"/>
37
38</LinearLayout>

activity_navigation_view.xml view source

1<?xml version="1.0" encoding="utf-8"?>
2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent">
7 <ai.nextbillion.navigation.ui.NavigationView
8 android:id="@+id/navigation_view"
9 app:navigationLightTheme="@style/Theme.CustomNavigationLight"
10 android:layout_width="match_parent"
11 android:layout_height="match_parent"/>
12
13</androidx.constraintlayout.widget.ConstraintLayout>

CustomNavigationActivity view source

1package ai.nextbillion.navigation.demo.activity;
2
3import android.content.Intent;
4import android.os.Bundle;
5import android.view.View;
6import android.widget.Button;
7import android.widget.ProgressBar;
8import android.widget.TextView;
9
10import java.io.Serializable;
11import java.util.List;
12
13import ai.nextbillion.kits.directions.models.DirectionsResponse;
14import ai.nextbillion.kits.directions.models.DirectionsRoute;
15import ai.nextbillion.kits.directions.models.RouteRequestParams;
16import ai.nextbillion.kits.geojson.Point;
17import ai.nextbillion.navigation.core.routefetcher.RouteFetcher;
18import ai.nextbillion.navigation.demo.R;
19import androidx.appcompat.app.AppCompatActivity;
20import retrofit2.Call;
21import retrofit2.Callback;
22import retrofit2.Response;
23
24public class CustomNavigationActivity extends AppCompatActivity implements View.OnClickListener {
25
26 private Button fetchRoute;
27 private Button startNav;
28 private TextView routeGeometry;
29 private DirectionsRoute directionsRoute;
30 private List<DirectionsRoute> directionsRoutes;
31 private ProgressBar progress;
32 @Override
33 protected void onCreate(Bundle savedInstanceState) {
34 super.onCreate(savedInstanceState);
35 setContentView(R.layout.activity_custom_navigation);
36 fetchRoute = findViewById(R.id.fetchRoute);
37 startNav = findViewById(R.id.startNav);
38 routeGeometry = findViewById(R.id.routeGeometry);
39 progress = findViewById(R.id.progress);
40 fetchRoute.setOnClickListener(this);
41 startNav.setOnClickListener(this);
42 startNav.setEnabled(false);
43
44 }
45
46 @Override
47 public void onClick(View view) {
48 if (view.getId() == R.id.fetchRoute) {
49 progress.setVisibility(View.VISIBLE);
50 Point origin = Point.fromLngLat(103.75986708439264, 1.312533169133601);
51 Point destination = Point.fromLngLat(103.77982271935586, 1.310473772283314);
52
53 RouteRequestParams.Builder builder = RouteRequestParams.builder()
54 .origin(origin)
55 .destination(destination)
56 .language("en")
57 .departureTime((int) (System.currentTimeMillis()/1000));
58
59 RouteFetcher.getRoute(builder.build(), new Callback<DirectionsResponse>() {
60 @Override
61 public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
62 progress.setVisibility(View.GONE);
63 //start navigation with the route we just fetched.
64 if (response.body() != null && !response.body().routes().isEmpty()) {
65 directionsRoute = response.body().routes().get(0);
66 directionsRoutes = response.body().routes();
67 routeGeometry.setText(String.format("Route Geometry: %s", directionsRoute.geometry()));
68 startNav.setEnabled(true);
69 }
70 }
71
72 @Override
73 public void onFailure(Call<DirectionsResponse> call, Throwable t) {
74 progress.setVisibility(View.GONE);
75 }
76 });
77 } else if (view.getId() == R.id.startNav) {
78 Intent intent = new Intent(this, NavigationViewActivity.class);
79 intent.putExtra("route", directionsRoute);
80 intent.putExtra("routes", (Serializable) directionsRoutes);
81 startActivity(intent);
82 }
83 }
84}

NavigationViewActivity view source

1package ai.nextbillion.navigation.demo.activity;
2
3import android.Manifest;
4import android.os.Build;
5import android.os.Bundle;
6import android.view.WindowInsets;
7
8import java.util.List;
9
10import ai.nextbillion.kits.directions.models.DirectionsRoute;
11import ai.nextbillion.maps.location.modes.RenderMode;
12import ai.nextbillion.navigation.core.navigation.NavEngineConfig;
13import ai.nextbillion.navigation.demo.R;
14import ai.nextbillion.navigation.ui.NavViewConfig;
15import ai.nextbillion.navigation.ui.NavigationView;
16import ai.nextbillion.navigation.ui.OnNavigationReadyCallback;
17import ai.nextbillion.navigation.ui.listeners.NavigationListener;
18import ai.nextbillion.navigation.ui.utils.StatusBarUtils;
19import androidx.annotation.NonNull;
20import androidx.appcompat.app.AppCompatActivity;
21import pub.devrel.easypermissions.EasyPermissions;
22import pub.devrel.easypermissions.PermissionRequest;
23
24public class NavigationViewActivity extends AppCompatActivity implements OnNavigationReadyCallback, EasyPermissions.PermissionCallbacks, NavigationListener, StatusBarUtils.OnWindowInsetsChange {
25
26 NavigationView navigationView;
27
28 private String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
29
30 @Override
31 protected void onCreate(Bundle savedInstanceState) {
32 setTheme(ai.nextbillion.navigation.ui.R.style.Theme_AppCompat_NoActionBar);
33
34 super.onCreate(savedInstanceState);
35 setContentView(R.layout.activity_navigation_view);
36
37 navigationView = findViewById(R.id.navigation_view);
38 navigationView.onCreate(savedInstanceState);
39 StatusBarUtils.transparentStatusBar(this,this);
40 if (navigationView.isNightTheme()) {
41 StatusBarUtils.setDarkMode(this);
42 } else {
43 StatusBarUtils.setLightMode(this);
44 }
45
46 requestPermissions();
47 }
48
49 @Override
50 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
51 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
52 EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
53 }
54
55 private void requestPermissions() {
56 EasyPermissions.requestPermissions(new PermissionRequest.Builder(this, 200, permissions)
57 .setRationale("Navigation requires location access")
58 .setNegativeButtonText("No")
59 .setPositiveButtonText("OK")
60 .build());
61 }
62
63 @Override
64 public void onNavigationReady(boolean b) {
65 NavEngineConfig.Builder navConfig = NavEngineConfig.builder();
66 NavViewConfig.Builder viewConfigBuilder = NavViewConfig.builder();
67 viewConfigBuilder.navigationListener(this);
68
69 configRoute(viewConfigBuilder);
70 viewConfigBuilder.shouldSimulateRoute(true);
71 viewConfigBuilder.showSpeedometer(true);
72 viewConfigBuilder.locationLayerRenderMode(RenderMode.GPS);
73 viewConfigBuilder.navConfig(navConfig.build());
74
75 navigationView.startNavigation(viewConfigBuilder.build());
76 }
77
78 private void configRoute(NavViewConfig.Builder viewConfigBuilder) {
79 DirectionsRoute route = (DirectionsRoute) getIntent().getSerializableExtra("route");
80 List<DirectionsRoute> routes = (List<DirectionsRoute>) getIntent().getSerializableExtra("routes");
81 viewConfigBuilder.route(route);
82 viewConfigBuilder.routes(routes);
83 }
84
85
86 @Override
87 public void onStart() {
88 super.onStart();
89 navigationView.onStart();
90 }
91
92 @Override
93 public void onResume() {
94 super.onResume();
95 navigationView.onResume();
96 }
97
98 @Override
99 public void onLowMemory() {
100 super.onLowMemory();
101 navigationView.onLowMemory();
102 }
103
104 @Override
105 public void onBackPressed() {
106 // If the navigation view didn't need to do anything, call super
107 if (!navigationView.onBackPressed()) {
108 super.onBackPressed();
109 }
110 }
111
112 @Override
113 protected void onSaveInstanceState(Bundle outState) {
114 navigationView.onSaveInstanceState(outState);
115 super.onSaveInstanceState(outState);
116 }
117
118 @Override
119 protected void onRestoreInstanceState(Bundle savedInstanceState) {
120 super.onRestoreInstanceState(savedInstanceState);
121 navigationView.onRestoreInstanceState(savedInstanceState);
122 }
123
124 @Override
125 public void onPause() {
126 super.onPause();
127 navigationView.onPause();
128 }
129
130 @Override
131 public void onStop() {
132 super.onStop();
133 navigationView.onStop();
134 }
135
136 @Override
137 protected void onDestroy() {
138 super.onDestroy();
139 navigationView.onDestroy();
140 }
141
142 @Override
143 public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
144 navigationView.initialize(this);
145
146 }
147
148 @Override
149 public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
150
151 }
152
153 @Override
154 public void onCancelNavigation() {
155 finish();
156 }
157
158 @Override
159 public void onNavigationFinished() {
160
161 }
162
163 @Override
164 public void onNavigationRunning() {
165
166 }
167
168 @Override
169 public void onApplyWindowInsets(WindowInsets windowInsets) {
170 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
171 navigationView.fitSystemWindow(windowInsets);
172 }
173 }
174}

Code summary

This code example shows how to customize the NavigationView and launch it

  • The code provided an AppCompatActivity called NavigationViewActivity that demonstrates the usage of the NavigationView class for navigation purposes.

  • The onCreate() method is overridden to set up the activity layout and initialize the NavigationView

    • StatusBarUtils.transparentStatusBar(this,this): sets the status bar to be transparent

    • StatusBarUtils.setLightMode/DarkMode(this); set the status bar text and icons to be displayed in light/dark color, making them visible against the light/dark background.

  • The requestPermissions() method is called to request location permissions.

    • The onRequestPermissionsResult() method handles the result of the permission request.

    • navigationView.initialize(this) was called after the location permission was granted. The onNavigationReady() method is implemented from the OnNavigationReadyCallback interface, which is called when the navigation is ready to start.

  • The configRoute() method is used to configure the navigation route by extracting route information from the intent extras.

    • Various configuration options are set using NavViewConfig.Builder, such as enabling route simulation, showing a speedometer, setting the location layer render mode, and providing the navigation configuration.

    • The startNavigation() method is called on the NavigationView instance to begin the navigation.

  • Lifecycle methods (onStart(), onResume(), onLowMemory(), etc.) are overridden to forward the calls to the NavigationView instance.

    • The onBackPressed() method is overridden to handle the back button press and allows the NavigationView to handle it if necessary.

    • Methods for handling instance state, permissions granted/denied, navigation callbacks, and window insets are implemented.

    • The activity's lifecycle methods (onSaveInstanceState(), onRestoreInstanceState(), etc.) are overridden to propagate the corresponding calls to the NavigationView.

    • the activity is destroyed by calling onDestroy() on the NavigationView.