# 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`


![documentation image](https://static.nextbillion.io/docs-next/docs/navigation/android/launch-custom-navigationView.jpg)

For all code examples, refer to [Navigation Code Examples](https://github.com/nextbillion-ai/nb-navigation-android-demo)

**activity_custom_navigation.xml [view source](https://github.com/nextbillion-ai/nb-navigation-android-demo/blob/main/app/src/main/res/layout/activity_custom_navigation.xml)**

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/fetchRoute"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/fetch_route"/>

        <Button
            android:id="@+id/startNav"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:text="@string/start_navigation"/>
    </LinearLayout>

    <TextView
        android:id="@+id/routeGeometry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"/>

    <ProgressBar
        android:id="@+id/progress"
        android:visibility="gone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>

</LinearLayout>
```

**activity_navigation_view.xml [view source](https://github.com/nextbillion-ai/nb-navigation-android-demo/blob/main/app/src/main/res/layout/activity_navigation_view.xml)**

```xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
    <ai.nextbillion.navigation.ui.NavigationView
        android:id="@+id/navigation_view"
        app:navigationLightTheme="@style/Theme.CustomNavigationLight"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
```

**CustomNavigationActivity [view source](https://github.com/nextbillion-ai/nb-navigation-android-demo/blob/main/app/src/main/java/ai/nextbillion/navigation/demo/activity/CustomNavigationActivity.java)**

```java
package ai.nextbillion.navigation.demo.activity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.io.Serializable;
import java.util.List;

import ai.nextbillion.kits.directions.models.DirectionsResponse;
import ai.nextbillion.kits.directions.models.DirectionsRoute;
import ai.nextbillion.kits.directions.models.RouteRequestParams;
import ai.nextbillion.kits.geojson.Point;
import ai.nextbillion.navigation.core.routefetcher.RouteFetcher;
import ai.nextbillion.navigation.demo.R;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class CustomNavigationActivity extends AppCompatActivity implements View.OnClickListener {

    private Button fetchRoute;
    private Button startNav;
    private TextView routeGeometry;
    private DirectionsRoute directionsRoute;
    private List<DirectionsRoute> directionsRoutes;
    private ProgressBar progress;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_navigation);
        fetchRoute = findViewById(R.id.fetchRoute);
        startNav = findViewById(R.id.startNav);
        routeGeometry = findViewById(R.id.routeGeometry);
        progress = findViewById(R.id.progress);
        fetchRoute.setOnClickListener(this);
        startNav.setOnClickListener(this);
        startNav.setEnabled(false);

    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.fetchRoute) {
            progress.setVisibility(View.VISIBLE);
            Point origin = Point.fromLngLat(103.75986708439264, 1.312533169133601);
            Point destination = Point.fromLngLat(103.77982271935586, 1.310473772283314);

            RouteRequestParams.Builder builder = RouteRequestParams.builder()
                    .origin(origin)
                    .destination(destination)
                    .language("en")
                    .departureTime((int) (System.currentTimeMillis()/1000));

            RouteFetcher.getRoute(builder.build(), new Callback<DirectionsResponse>() {
                @Override
                public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
                    progress.setVisibility(View.GONE);
                    //start navigation with the route we just fetched.
                    if (response.body() != null && !response.body().routes().isEmpty()) {
                        directionsRoute = response.body().routes().get(0);
                        directionsRoutes = response.body().routes();
                        routeGeometry.setText(String.format("Route Geometry: %s", directionsRoute.geometry()));
                        startNav.setEnabled(true);
                    }
                }

                @Override
                public void onFailure(Call<DirectionsResponse> call, Throwable t) {
                    progress.setVisibility(View.GONE);
                }
            });
        } else if (view.getId() == R.id.startNav) {
            Intent intent = new Intent(this,  NavigationViewActivity.class);
            intent.putExtra("route", directionsRoute);
            intent.putExtra("routes", (Serializable) directionsRoutes);
            startActivity(intent);
        }
    }
}
```

**NavigationViewActivity [view source](https://github.com/nextbillion-ai/nb-navigation-android-demo/blob/main/app/src/main/java/ai/nextbillion/navigation/demo/activity/NavigationViewActivity.java)**

```java
package ai.nextbillion.navigation.demo.activity;

import android.Manifest;
import android.os.Build;
import android.os.Bundle;
import android.view.WindowInsets;

import java.util.List;

import ai.nextbillion.kits.directions.models.DirectionsRoute;
import ai.nextbillion.maps.location.modes.RenderMode;
import ai.nextbillion.navigation.core.navigation.NavEngineConfig;
import ai.nextbillion.navigation.demo.R;
import ai.nextbillion.navigation.ui.NavViewConfig;
import ai.nextbillion.navigation.ui.NavigationView;
import ai.nextbillion.navigation.ui.OnNavigationReadyCallback;
import ai.nextbillion.navigation.ui.listeners.NavigationListener;
import ai.nextbillion.navigation.ui.utils.StatusBarUtils;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import pub.devrel.easypermissions.EasyPermissions;
import pub.devrel.easypermissions.PermissionRequest;

public class NavigationViewActivity extends AppCompatActivity implements OnNavigationReadyCallback, EasyPermissions.PermissionCallbacks, NavigationListener, StatusBarUtils.OnWindowInsetsChange {

    NavigationView navigationView;

    private String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(ai.nextbillion.navigation.ui.R.style.Theme_AppCompat_NoActionBar);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_navigation_view);

        navigationView = findViewById(R.id.navigation_view);
        navigationView.onCreate(savedInstanceState);
        StatusBarUtils.transparentStatusBar(this,this);
        if (navigationView.isNightTheme()) {
            StatusBarUtils.setDarkMode(this);
        } else {
            StatusBarUtils.setLightMode(this);
        }

        requestPermissions();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

    private void requestPermissions() {
        EasyPermissions.requestPermissions(new PermissionRequest.Builder(this, 200, permissions)
                .setRationale("Navigation requires location access")
                .setNegativeButtonText("No")
                .setPositiveButtonText("OK")
                .build());
    }

    @Override
    public void onNavigationReady(boolean b) {
        NavEngineConfig.Builder navConfig = NavEngineConfig.builder();
        NavViewConfig.Builder viewConfigBuilder = NavViewConfig.builder();
        viewConfigBuilder.navigationListener(this);

        configRoute(viewConfigBuilder);
        viewConfigBuilder.shouldSimulateRoute(true);
        viewConfigBuilder.showSpeedometer(true);
        viewConfigBuilder.locationLayerRenderMode(RenderMode.GPS);
        viewConfigBuilder.navConfig(navConfig.build());

        navigationView.startNavigation(viewConfigBuilder.build());
    }

    private void configRoute(NavViewConfig.Builder viewConfigBuilder) {
        DirectionsRoute route = (DirectionsRoute) getIntent().getSerializableExtra("route");
        List<DirectionsRoute> routes = (List<DirectionsRoute>) getIntent().getSerializableExtra("routes");
        viewConfigBuilder.route(route);
        viewConfigBuilder.routes(routes);
    }

    @Override
    public void onStart() {
        super.onStart();
        navigationView.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        navigationView.onResume();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        navigationView.onLowMemory();
    }

    @Override
    public void onBackPressed() {
        // If the navigation view didn't need to do anything, call super
        if (!navigationView.onBackPressed()) {
            super.onBackPressed();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        navigationView.onSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        navigationView.onRestoreInstanceState(savedInstanceState);
    }

    @Override
    public void onPause() {
        super.onPause();
        navigationView.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
        navigationView.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        navigationView.onDestroy();
    }

    @Override
    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
        navigationView.initialize(this);

    }

    @Override
    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {

    }

    @Override
    public void onCancelNavigation() {
        finish();
    }

    @Override
    public void onNavigationFinished() {

    }

    @Override
    public void onNavigationRunning() {

    }

    @Override
    public void onApplyWindowInsets(WindowInsets windowInsets) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
            navigationView.fitSystemWindow(windowInsets);
        }
    }
}
```

### 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.
