Aplicativo Android com OpenStreetMap: Crie Mapa, Marcadores e Rotas com uma API Open Source

O desenvolvimento de aplicativos móveis com uso de mapas é bastante utilizado para mapear localização, desenhar rotas, calcular distâncias entre pontos, etc. Na maioria da vezes quando vamos desenvolver um aplicativo para dispositivos Android com Mapas já pensamos logo na API do Google Maps. A API do Google Maps tem uma integração simples e apresenta uma grande quantidade de recursos, além de bastante flexibilidade.

Quando da utilização da API do Google Maps o que nem todos sabem é que não é totalmente gratuito e que os recursos disponível no plano free nem sempre será suficiente para seus testes e uso mesmo em um aplicativo simples. Eu mesmo já passei por isso, no desenvolvimento de um aplicativo para mapeamentos das rotas do transporte público coletivo da minha cidade. Eu juntamente com mais dois alunos estávamos utilizando a API do Google Maps Directions para desenho das rotas, em que precisávamos adicionar vários pontos de referência (Latitude e Longitude) para traçar a linha do ônibus, fizemos alguns testes que estavam dando tudo certo até o momento em que para mapear uma linha tivemos que adicionar vários pontos para desenhar a rota. Segundo a API do Google Maps Directions, conta gratuita só permite utilizar até 23 pontos de referência para desenho de rotas, sempre que adicionamos mais que 23 pontos a rota não era desenhada e API do Google Maps retornava a seguinte mensagem:

{
“error_message” : “Too many waypoints in the request (25). The maximum allowed waypoints for this request is 8, plus the origin, and destination.”,
“routes” : [],
“status” : “MAX_WAYPOINTS_EXCEEDED”
}

Como nosso aplicativo é um projeto acadêmico e ainda está em fase de desenvolvimento não foi viável o pagamento de uma assinatura da API de Google Maps. Como entusiastas open source fomos pesquisar opções gratuitas e open source para solução do problema e encontramos uma opção que nos atendeu: OpenStreetMap, é um projeto colaborativo com o objetivo de fornecer a todos os que o desejam dados geográficos livres e gratuitos tais como mapas de estradas. O projeto foi lançado porque a maioria dos mapas que parecem ser gratuitos têm restrições legais ou técnicas limitando a sua utilização e impedindo-o de as utilizar de forma criativa, produtiva ou inesperada [1]. Para utilização do OpenStreetMap no aplicativos utilizamos a a biblioteca OSMBonusPack que utiliza a API Osmdroid. As duas APIs são open source e totalmente gratuita. O OSMBonusPack é um projeto dispõe simplifica a utilização de vários recursos de mapas, tais como: MapView, MapController, Overlays (Marker, Polyline, Polygon). Ele foi bastante útil no nosso projeto para o desenho das rotas e marcação de pontos de referência (paradas de ônibus).

Agora mostrarei um tutorial de como desenhar rotas em um aplicativo para dispositivos Android com OpenStreetMap utilizando a API do OSMBonusPack no Android Studio.

Primeiro vamos criar um projeto no Android Studio, abaixo está as telas com o passo a passo para criar o projeto.

Passo 1 — Configuração do projeto

Se você não tem um projeto aberto, o Android Studio mostra a tela de boas-vindas. Para criar um novo projeto, clique em Start a New Android Studio project.

Se você já tem um projeto aberto, o Android Studio mostra o ambiente de desenvolvimento. Para criar um novo projeto, clique em File > New > New Project.

A seguir é apresentada a tela inicial para criação do projeto no Android Studio, nesta tela é preenchido o nome do aplicativo, nome do pacote e local onde o projeto ficará salvo.

Figura 1 — Tela de criação de projeto no Android Studio

Como você pode ver na imagem acima, eu nomeei meu aplicativo como RotasOSM e defini o nome do pacote como jesiel.tutorial. O nome do pacote é o domínio que identificará seu aplicativo. Essas informações você pode repedir ou colocar nomes conforme sua preferência. Depois disso, escolha a localização do projeto na sua máquina e clique em Next.

Passo 2 — Selecionar tipos de dispositivo e nível de API

A próxima janela (Figura 2) permite selecionar as versões do Android com as quais seu aplicativo será compatível e os tipos de dispositivo aos quais oferecerá suporte, como celulares, tablets, etc.

Figura 2 — Nível de suporte da API

Conforme a imagem acima eu deixei as configurações padrões do Android Studio 2.3.3, suporte somente a Celulars e Tabletes com Android na versão 5 ou superior. Para saber mais detalhes sobre os níveis de suporte de API clique no link Help me choose. Clique em Next em vamos para próxima tela.

Passo 3 — Tipo de Activity

A tela seguinte permite selecionar um tipo de Activity (Activity é um componente de aplicativo que fornece uma tela com a qual os usuários podem interagir para fazer algo, como discar um número no telefone, tirar uma foto, enviar um e-mail ou ver um mapa.)para adicionar ao aplicativo, conforme mostrado na Figura 4. Essa tela exibe um conjunto de atividades diferente para cada tipo de dispositivo selecionado na etapa anterior.

Figura 4 — Tipos de Activity

Em nosso caso selecione a Empty Activity e clique em Next para prosseguir para a próxima etapa.

Passo 4 — Configurar Activity

A próxima tela é voltada para a configuração da activity principal do aplicativo, como mostrado na figura 4

Figura 4 — Configuração da Activity

Conforme a imagem acima vamos deixar a activity com as configurações padrões, com o nome de MainActivity e layout activity_main. Após isso clique em finish e seu projeto estará criado e irá abrir na área de trabalho do Android Studio conforme a Figura 5.

Figura 5 — Área de trabalho do Android Studio

Você pode executar o aplicativo clicando no botão de run app e escolhendo o dispositivo para teste (pode ser o emulador um celular Android). O aplicativo deve abrir com a seguinte aparência.

Figura 6 — Interface do aplicativo

Agora vamos começar a configuração do aplicativo para usar a API do OpenStreetMap.

Passo 5 — Adicionar a dependência da biblioteca OSMBonusPack.

O Android utiliza o gradle como gerenciador de depências e processo de build. As configurações do gradle fica nos arquivos build.gradle, nos projetos existem dois arquivos de gradle, um no diretório raiz do projeto e outro no diretório app.

Para adicionar a depência da biblioteca OSMBonusPack vamos precisar alterar somente o arquivo build.gradle (não substitua seu arquivo pelo meu, somente altere o seu) do app. Para isso vamos colocar a dependência do OSMBonusPack dentro da tag dependencies do build.gradle.

dependencies {
compile ‘com.github.MKergall:osmbonuspack:6.4’
}

Somente com essa alteração o gradle não vai encontrar a dependência, pois o OSMBonusPack não está disponível no Maven Central (repositório padrão para busca de dependências), portanto precisamos adicionar no mesmo arquivo o repositório JitPack que é onde o OSMBonusPack está disponível.

repositories {
maven { url “https://jitpack.io" }
}

Assim o arquivo build.gradle do app deve ficar conforme o exemplo abaixo.

apply plugin: 'com.android.application'

android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "tutorial.jesielt.osmrouter"
minSdkVersion 21
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha4'
testCompile 'junit:junit:4.12'
compile 'com.github.MKergall:osmbonuspack:6.4'
}

repositories {
maven { url "https://jitpack.io" }
}

Após alteração no arquivo de build.gradle deve aparecer uma mensagem de alerta pedindo para sincronizar o projeto, clique em Sync Now e certifique-se de que seu projeto está sendo construído sem nenhum erro.

Passo 6 — Gerenciamento de permissões

Para o funcionamento correto do mapa no aplicativo a API do OSMBonusPack precisa de duas permissões, uma para acessar internet e outra para escrita no armazenamento externo do dispositivo. Para solicitar as permissões ao usuário quando executar o aplicativo é necessário adicionar as seguintes linhas no arquivo AndroidManifest.xml antes da tag <application>.

<uses-permission android:name=”android.permission.INTERNET” />
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />

Além disso, acesse o arquivo MainActivity.java e adicione o seguinte código dentro do método onCreate:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
String[] permissoes = {Manifest.permission.INTERNET, Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissoes, 1);
}
}

O código acima verifica se o aplicativo tem permissões para acessar a internet e escrever no armazenamento externo, se o usuário ainda não tiver cedido as permissões será aberta uma janela de diálogo padrão do Android para solicitar as permissões.

É importante também sobrescrever o método onRequestPermissionsResult da classe MainActivity.java, este método é executado após o usuário ceder as permissões ao aplicativo, abaixo está o código fonte comentado deste método.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1: {
// Se a solicitação de permissão foi cancelada o array vem vazio.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permissão cedida, recria a activity para carregar o mapa, só será executado uma vez
this.recreate();

}

}
}
}

Passo 7 — Adicionando o mapa na tela da activity principal

Acesse o arquivo activity_main.xml, que esta dentro do diretório layout e substitua o código existente nele pelo código abaixo.

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

<org.osmdroid.views.MapView android:id="@+id/mapaId"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</LinearLayout>

Passo 8— Manipulação do mapa na Activity

Agora vamos começar a manipular nosso mapa, volte para o arquivo MainActivity.java e adicione as seguintes linhas de código dentro do método onCreate:

//Pega o mapa adicionada no arquivo activity_main.xml
MapView mapa = (MapView) findViewById(R.id.mapaId);
//Fonte de imagens
mapa.setTileSource(TileSourceFactory.MAPNIK);

//Cria um ponto de referência com base na latitude e longitude
GeoPoint pontoInicial = new GeoPoint(-7.082433, -41.468516);

IMapController mapController = mapa.getController();
//Faz zoom no mapa
mapController.setZoom(15);
//Centraliza o mapa no ponto de referência
mapController.setCenter(pontoInicial);

//Cria um marcador no mapa
Marker startMarker = new Marker(mapa);
startMarker.setPosition(pontoInicial);
startMarker.setTitle("Ponto Inicial");
//Posição do ícone
startMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mapa.getOverlays().add(startMarker);

O código acima está comentado para facilitar seu entendimento, resumindo o que esse código faz:

Acessa o mapa que está no arquivo activity_main.xml que foi declarado com a tag org.osmdroid.views.MapView e com o id mapaId;

Cria um ponto de referênca com base na latitude e longitude;

Centraliza o mapa neste ponto e dá um zoom de 15x;

Cria um marcador no mapa no ponto de referência.

Então neste momento os arquivos activity_main.xml e AndroidManifest.xml devem estar conforme as figuras abaixo:

Figura 7 — Arquivo activity_main.xml
Figura 8 — Arquivo AndroidManifest.xml

E o arquivo MainActivity.java conforme abaixo:

package tutorial.jesielt.osmrouter;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;

import org.osmdroid.api.IMapController;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.Marker;

import static android.os.Build.VERSION_CODES.M;

public class MainActivity extends AppCompatActivity {

private static final int PERMISSAO_REQUERIDA = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (Build.VERSION.SDK_INT >= M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
String[] permissoes = {Manifest.permission.INTERNET, Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissoes, PERMISSAO_REQUERIDA);
}
}

//Pega o mapa adicionada no arquivo activity_main.xml
MapView mapa = (MapView) findViewById(R.id.mapaId);
//Fonte de imagens
mapa.setTileSource(TileSourceFactory.MAPNIK);

//Cria um ponto de referência com base na latitude e longitude
GeoPoint pontoInicial = new GeoPoint(-7.082433, -41.468516);

IMapController mapController = mapa.getController();
//Faz zoom no mapa
mapController.setZoom(15);
//Centraliza o mapa no ponto de referência
mapController.setCenter(pontoInicial);

//Cria um marcador no mapa
Marker startMarker = new Marker(mapa);
startMarker.setPosition(pontoInicial);
startMarker.setTitle("Ponto Inicial");
//Posição do ícone
startMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mapa.getOverlays().add(startMarker);


}


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSAO_REQUERIDA: {
// Se a solicitação de permissão foi cancelada o array vem vazio.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permissão cedida, recria a activity para carregar o mapa, só será executado uma vez
this.recreate();

}

}
}
}
}

Aqui tem uma pequena alteração que é a contante PERMISSAO_REQUERIDA que armazena o valor 1, é uma boa prática utilizar constante em vezes de “número mágicos”, como tinha antes na linha requestPermissions(permissoes, 1); e na linha do case do switch do método onRequestPermissionsResult.

Após todas essas etapas ao executar o aplicativo devemos ver a seguinte aparência.

Figura 9 — Mapa com marcador

Agora vamos criar um segundo ponto no mapa, como o primeiro foi chamado de ponto inicial este novo ponto será o ponto final. Para isso basta adicionar o seguinte código abaixo da linha mapa.getOverlays().add(startMarker).

GeoPoint pontoFinal = new GeoPoint(-7.078601, -41.462174);
Marker endMarker = new Marker(mapa);
endMarker.setPosition(pontoFinal);
endMarker.setTitle("Ponto Final");
//Posição do ícone
endMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mapa.getOverlays().add(endMarker);

Pronto! Já temos um ponto inicial e um ponto final, só falta desenha uma rota entre esses dois pontos. É o que vamos fazer agora, como para desenhar a rota o OSMBonusPack acessa a internet é necessário criar uma classe AsyncTask para fazer a conexão com internet sem travar a tela do aplicativo. Portanto crie uma classe java com o nome de DesenhaRotaTask.java dentro do pacote principal da aplicação. Essa classe deve ter o seguinte código:

package tutorial.jesielt.osmrouter;

import android.os.AsyncTask;

import org.osmdroid.bonuspack.routing.Road;
import org.osmdroid.bonuspack.routing.RoadManager;
import org.osmdroid.util.GeoPoint;

import java.util.ArrayList;

/**
* Created by jesielviana on 10/16/17.
*/

public class DesenhaRotaTask extends AsyncTask<RoadManager, Void, Road> {
ArrayList<GeoPoint> waypoints;
RoadManager roadManager;

public DesenhaRotaTask(ArrayList<GeoPoint> waypoints, RoadManager roadManager) {
this.waypoints = waypoints;
this.roadManager = roadManager;
}

@Override
protected Road doInBackground(RoadManager... roadManagers) {
//Cria a rota com base nos pontos(latitude e longitude) recebidos
Road road = roadManager.getRoad(waypoints);
return road;
}
}

Feito isso, para desenhar a rota basta adicionar as seguintes linhas de código no arquivo MainActivity.java abaixo da linha mapa.getOverlays().add(endMarker).

//Matriz com pontos geográficos(latitudes e longitudes) por onde a rota deve ser traçada
//Utilizando a API do Google Maps, nós só conseguimos desenhar uma rota com até 10 pontos
//Com a API do OpemStreetMap o números de pontos é ilimitado
double matrizPontos[][] = {
{-7.082433, -41.468516},
{-7.082545, -41.468478},
{-7.082544, -41.468392},
{-7.082351, -41.468155},
{-7.082136, -41.467914},
{-7.082082, -41.467858},
{-7.081876, -41.467814},
{-7.081705, -41.467789},
{-7.080256, -41.467683},
{-7.078318, -41.467548},
{-7.077923, -41.467508},
{-7.077820, -41.467493},
{-7.077697, -41.467366},
{-7.077643, -41.467301},
{-7.077497, -41.467417},
{-7.077331, -41.467523},
{-7.076784, -41.467403},
{-7.076304, -41.467351},
{-7.076023, -41.467331},
{-7.075864, -41.467264},
{-7.075754, -41.467225},
{-7.075813, -41.466974},
{-7.076019, -41.466495},
{-7.078601, -41.462174},};


//Cria uma lista de pontos (GeoPoint) pela latitude e longitude
ArrayList<GeoPoint> pontos = new ArrayList<>();
for (double[] array : matrizPontos) {
pontos.add(new GeoPoint(array[0], array[1]));
}


//Cria o objeto gerenciador de rotas
RoadManager roadManager = new OSRMRoadManager(this);
Road road = null;
try {
//Chama a classe(DesenhaRotaTask) que executa tarefas assincronas, passa os pontos de referências
//para a classe DesenhaRotaTask traçar a rota
road = new DesenhaRotaTask(pontos, roadManager).execute(roadManager).get();
} catch (Exception e) {
e.printStackTrace();
}

//Desenha a rota
Polyline roadOverlay = RoadManager.buildRoadOverlay(road);
//Adiciona a rota no mapa
mapa.getOverlays().add(roadOverlay);
//atualiza o mapa
mapa.invalidate();

Agora a nota classe MainActivity.java está completa com o código comentado, algumas explicações estão nos comentários da classe, abaixo está o código completo.

package tutorial.jesielt.osmrouter;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;

import org.osmdroid.api.IMapController;
import org.osmdroid.bonuspack.routing.OSRMRoadManager;
import org.osmdroid.bonuspack.routing.Road;
import org.osmdroid.bonuspack.routing.RoadManager;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.Marker;
import org.osmdroid.views.overlay.Polyline;

import java.util.ArrayList;

import static android.os.Build.VERSION_CODES.M;

public class MainActivity extends AppCompatActivity {

private static final int PERMISSAO_REQUERIDA = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (Build.VERSION.SDK_INT >= M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
String[] permissoes = {Manifest.permission.INTERNET, Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissoes, PERMISSAO_REQUERIDA);
}
}

//Pega o mapa adicionada no arquivo activity_main.xml
MapView mapa = (MapView) findViewById(R.id.mapaId);
//Fonte de imagens
mapa.setTileSource(TileSourceFactory.MAPNIK);

//Cria um ponto de referência com base na latitude e longitude
GeoPoint pontoInicial = new GeoPoint(-7.082433, -41.468516);

IMapController mapController = mapa.getController();
//Faz zoom no mapa
mapController.setZoom(15);
//Centraliza o mapa no ponto de referência
mapController.setCenter(pontoInicial);

//Cria um marcador no mapa
Marker startMarker = new Marker(mapa);
startMarker.setPosition(pontoInicial);
startMarker.setTitle("Ponto Inicial");
//Posição do ícone
startMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mapa.getOverlays().add(startMarker);


GeoPoint pontoFinal = new GeoPoint(-7.078601, -41.462174);
Marker endMarker = new Marker(mapa);
endMarker.setPosition(pontoFinal);
endMarker.setTitle("Ponto Final");
//Posição do ícone
endMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mapa.getOverlays().add(endMarker);


//Matriz com pontos geográficos(latitudes e longitudes) por onde a rota deve ser traçada
//Utilizando a API do Google Maps, nós só conseguimos desenhar uma rota com até 10 pontos
//Com a API do OpemStreetMap o números de pontos é ilimitado
double matrizPontos[][] = {
{-7.082433, -41.468516},
{-7.082545, -41.468478},
{-7.082544, -41.468392},
{-7.082351, -41.468155},
{-7.082136, -41.467914},
{-7.082082, -41.467858},
{-7.081876, -41.467814},
{-7.081705, -41.467789},
{-7.080256, -41.467683},
{-7.078318, -41.467548},
{-7.077923, -41.467508},
{-7.077820, -41.467493},
{-7.077697, -41.467366},
{-7.077643, -41.467301},
{-7.077497, -41.467417},
{-7.077331, -41.467523},
{-7.076784, -41.467403},
{-7.076304, -41.467351},
{-7.076023, -41.467331},
{-7.075864, -41.467264},
{-7.075754, -41.467225},
{-7.075813, -41.466974},
{-7.076019, -41.466495},
{-7.078601, -41.462174},};


//Cria uma lista de pontos (GeoPoint) pela latitude e longitude
ArrayList<GeoPoint> pontos = new ArrayList<>();
for (double[] array : matrizPontos) {
pontos.add(new GeoPoint(array[0], array[1]));
}


//Cria o objeto gerenciador de rotas
RoadManager roadManager = new OSRMRoadManager(this);
Road road = null;
try {
//Chama a classe(DesenhaRotaTask) que executa tarefas assincronas, passa os pontos de referências
//para a classe DesenhaRotaTask traçar a rota
road = new DesenhaRotaTask(pontos, roadManager).execute(roadManager).get();
} catch (Exception e) {
e.printStackTrace();
}

//Desenha a rota
Polyline roadOverlay = RoadManager.buildRoadOverlay(road);
//Adiciona a rota no mapa
mapa.getOverlays().add(roadOverlay);
//atualiza o mapa
mapa.invalidate();


}


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSAO_REQUERIDA: {
// Se a solicitação de permissão foi cancelada o array vem vazio.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permissão cedida, recria a activity para carregar o mapa, só será executado uma vez
this.recreate();

}

}
}
}
}

Pronto! Agora o seu aplicativo apresenta o mapa, com dois marcadores e uma rota entre esses marcadores. Para construção da rota utilizamos vários pontos, é importante citar que quando seu dispositivo estiver com acesso a internet somente com dois pontos, inicial e final, é possível desenhar uma rota de acordo com as ruas da localização, no entanto, para o uso offline é traçado somente linhas retas fazendo-se necessário adicionar um ponto em cada curva/esquina para poder aprensentar a rota de forma correta. Por isso no nosso exemplo adicionamos vários pontos para traçar uma rota relativamente curta.Veja abaixo a tela do aplicativo com os marcadores e a rota desenhada.

Figura 10 — Mapa com marcadores e rota desenhada

Se você chegou até o final e deu tudo certo, Parabéns!!

Espero que tenham gostado e que possam utilizar bastante a API do OpenStreetMap para desenvolvimento de aplicativo.

Abaixo alguns links úteis:

OpenStreetMap

osmdroid/osmdroid

MKergall/osmbonuspack