> ## Documentation Index
> Fetch the complete documentation index at: https://docs.baato.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Navigation SDK

> Build in-app turn-by-turn navigation experiences with the Baato Navigation SDK.

The Baato Navigation SDK adds a complete turn-by-turn navigation experience to an Android
app — the map, the instruction banner, voice guidance and re-routing — on top of a route
fetched from the [Directions API](/services/directions).

<Columns cols={2}>
  <Card title="Source on GitHub" icon="github" href="https://github.com/baato/navigation-sdk" horizontal>
    `baato/navigation-sdk`
  </Card>

  <Card title="Worked example" icon="android" href="/examples/android-java/turn-by-turn" horizontal>
    A complete navigation screen, end to end.
  </Card>
</Columns>

## Features

<Columns cols={2}>
  <Card title="Turn-by-turn navigation" icon="diamond-turn-right" horizontal />

  <Card title="Voice instructions" icon="volume-high" horizontal />

  <Card title="Automatic re-routing" icon="arrows-rotate" horizontal />

  <Card title="Custom map styles" icon="layer-group" horizontal />
</Columns>

## Installation

<Steps>
  <Step title="Add the JitPack repository">
    In your project's `build.gradle`:

    ```groovy theme={null}
    allprojects{
     repositories {
      maven { url 'https://jitpack.io' }
     }
    }
    ```
  </Step>

  <Step title="Add the dependencies">
    ```groovy theme={null}
    dependencies {
      implementation 'com.github.baato.navigation-sdk:baato-navigation-android:${latest-version}'
      implementation 'com.github.baato.navigation-sdk:baato-navigation-android-ui:${latest-version}'
    }
    ```

    <Note>
      Replace `${latest-version}` with the current release tag from the
      [releases page](https://github.com/baato/navigation-sdk/releases).
    </Note>
  </Step>

  <Step title="Configure the app module">
    ```groovy theme={null}
        defaultConfig {
            multiDexEnabled true
        }
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }

        dependencies {
         // location service by google, use latest stable version
         implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
         implementation 'com.google.android.gms:play-services-location:17.0.0'
        }
    ```

    <Warning>
      If you use Mapbox as your map service, the SDK currently supports only these versions:

      ```groovy theme={null}
      //mapbox sdk
        implementation('com.mapbox.mapboxsdk:mapbox-android-sdk:6.5.0') {
            exclude group: 'group_name', module: 'module_name'
        }
        implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-locationlayer:0.8.1'
      ```
    </Warning>
  </Step>

  <Step title="Declare the permissions">
    ```xml theme={null}
    // For Notification
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    // For Location
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    // Since app uses baato-services add network services
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    // for targetSDKVersion 30 and above
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    ```

    `READ_PHONE_STATE` is required only when your `targetSdkVersion` is 30 or above.
  </Step>
</Steps>

## Managing location permission and updates

Navigation needs a live location fix, which means requesting the runtime permission and
driving a location engine.

<Steps>
  <Step title="Implement PermissionsListener">
    ```java theme={null}
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                               @NonNull int[] grantResults) {
            permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }

        @Override
        public void onExplanationNeeded(List<String> permissionsToExplain) {
                   //do something so the user see the required permission
        }

        @Override
        public void onPermissionResult(boolean granted) {
            if (!granted) {
               //do something
            }
        }
    ```
  </Step>

  <Step title="Check the location permission">
    ```java theme={null}
           permissionsManager = new PermissionsManager(context);
            if (!PermissionsManager.areLocationPermissionsGranted(context)) {
                permissionsManager.requestLocationPermissions(context);
            } else {
            // get location and set map component accordingly
                getMyLocation();
            }
    ```
  </Step>

  <Step title="Initialise the location service">
    <Warning>
      If you use multiple map instances, add the following code only to the **base map
      activity**. Once the location is calibrated, `LocationEngineListener` receives updates.
    </Warning>

    ```java theme={null}
    // Initialize once when permissions are granted
     @Override
        public void onPermissionResult(boolean granted) {
            if (granted)
                getMyLocation();
        }

     //on google api client connected
     @Override
        public void onConnected(@Nullable Bundle bundle) {
            getMyLocation();
        }

     private void getMyLocation() {
      if (googleApiClient != null) {
          if (googleApiClient.isConnected()) {
              int permissionLocation = 0;
              if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                  permissionLocation = checkSelfPermission(
                          Manifest.permission.ACCESS_FINE_LOCATION);
              }
              if (permissionLocation == PackageManager.PERMISSION_GRANTED) {

                  //get GPS Location
                  mylocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
                  if (mylocation != null) {
                        // update gps
                      locationLayer.forceLocationUpdate(mylocation);
                  }

                  // Initilaizing google location engine
                  LocationRequest locationRequest = new LocationRequest();
                  locationRequest.setInterval(3000);
                  locationRequest.setFastestInterval(3000);
                  locationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
                  LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                          .addLocationRequest(locationRequest);
                  builder.setAlwaysShow(true);
                  LocationServices.FusedLocationApi
                          .requestLocationUpdates(googleApiClient, locationRequest, (LocationListener) this);
                  PendingResult result =
                          LocationServices.SettingsApi
                                  .checkLocationSettings(googleApiClient, builder.build());
                  result.setResultCallback(result1 -> {
                      final Status status = result1.getStatus();
                      switch (status.getStatusCode()) {
                          case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                              // Location settings are not satisfied.
                              // But could be fixed by showing the user a dialog.
                              try {
                                  // Show the dialog by calling startResolutionForResult(),
                                  status.startResolutionForResult(this,
                                          Constants.GPS_REQUEST);
                              } catch (IntentSender.SendIntentException e) {
                                  // Ignore the error.
                              }
                              break;
                          case LocationSettingsStatusCodes.SUCCESS:
                              // All location settings are satisfied.
                              // You can initialize location requests here.
                              int permissionLocation1 = 0;
                              if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                                  permissionLocation1 = checkSelfPermission(
                                          Manifest.permission.ACCESS_FINE_LOCATION);
                              }
                              if (permissionLocation1 == PackageManager.PERMISSION_GRANTED) {
                                  mylocation = LocationServices.FusedLocationApi
                                          .getLastLocation(googleApiClient);
                                  originPoint = Point.fromLngLat(mylocation.getLongitude(),
                                          mylocation.getLatitude());
                                  locationLayer.forceLocationUpdate(mylocation);
    //                                    locationEngine.activate();
                              }
                              break;
                          case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                              // Location settings are not satisfied. However, we have no way to fix the
                              // settings so we won't show the dialog.
                              //finish();
                              break;
                      }
                  });
              }
          } else googleApiClient.connect();
      } else setUpGClient();
    }

    //setup google api client
    private synchronized void setUpGClient() {
        googleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this, 0, this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        googleApiClient.connect();
    }
    ```
  </Step>

  <Step title="Listen for location updates">
    ```java theme={null}
         //Initialize the location engine
         LocationEngineProvider locationEngineProvider = new LocationEngineProvider(context);
        locationEngine = locationEngineProvider.obtainBestLocationEngineAvailable();

        //Set locationEnginePriority
        locationEngine.setPriority(LocationEnginePriority.LOW_POWER);

        //Add listner
        locationEngine.addLocationEngineListener(context);

        //Location update interval
        locationEngine.setFastestInterval(ONE_SECOND_INTERVAL);

        //activate
        locationEngine.activate();
    ```
  </Step>

  <Step title="Deactivate the engine on destroy">
    ```java theme={null}

       if (locationEngine != null) {
          locationEngine.removeLocationEngineListener(context);
        }
    ```
  </Step>
</Steps>

## Requesting a route

Fetch a route with `BaatoNavigationRoute`, following the
[Java client](/libraries/java) for the request itself. Once you have a route, the
Navigation UI SDK takes over.

## Launching turn-by-turn navigation

<Warning>
  Launching navigation requires `READ_PHONE_STATE` when your `targetSdkVersion` is 30 or
  above. Declare it in the manifest **and** request it at runtime.
</Warning>

<CodeGroup>
  ```xml Manifest theme={null}
  <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  ```

  ```java Runtime request theme={null}
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
      int res = checkSelfPermission(android.Manifest.permission.READ_PHONE_STATE);
      if (res != PackageManager.PERMISSION_GRANTED) {
          requestPermissions(
              new String[]{android.Manifest.permission.READ_PHONE_STATE},
              Constants.PHONE_STATE_PERMISSION_REQUEST);
      } else {
          callTurnByTurnNavigationActivity();
      }
  }
  ```
</CodeGroup>

Once the permission is granted, launch the navigation UI from your activity with the route
you fetched:

```java theme={null}
// Route fetched from BaatoNavigationRoute
DirectionsRoute currentRoute = ...;

boolean simulateRoute = false; // true replays the route without moving

NavigationLauncherOptions options = NavigationLauncherOptions.builder()
        .directionsRoute(currentRoute)
        .shouldSimulateRoute(simulateRoute)
        .build();

NavigationLauncher.startNavigation(YourActivity.this, options);
```

<Tip>
  Setting `shouldSimulateRoute(true)` replays the route at your desk — the quickest way to
  test navigation without walking it. For a fuller mocking setup, see
  [testing without moving](/examples/android-java/turn-by-turn#testing-without-moving).
</Tip>

## Next

<Card title="Complete turn-by-turn example" icon="android" href="/examples/android-java/turn-by-turn" horizontal>
  A full navigation screen: tap a destination, draw the route, hand off to the navigation UI.
</Card>
