Mostrando postagens com marcador Android. Mostrar todas as postagens
Mostrando postagens com marcador Android. Mostrar todas as postagens

domingo, 26 de abril de 2015

Android - Login com Facebook no Eclipse - PARTE 2 (Final)

E aí galera! Estamos aqui outra vez e vamos dar continuidade à primeira parte deste tutorial. Se você não seguiu a primeira parte deste tutorial, clique aqui.

Então, sem mais delongas, vamos ao passo-a-passo!

No final da parte 1 deste tutorial eu peço pra que você copie o "facebook.jar" de dentro da pasta "bin" do projeto do FacebookSDK para a pasta "/libs/" do seu projeto, porém, nesta segunda parte do tutorial eu tentei de todas as formas concluí-la utilizando tal "facebook.jar" mas não consegui e nem descobri o "porque". Sendo assim, vamos apagá-lo da pasta "/libs/" e vamos referenciar a biblioteca como um todo:

Clique com o botão direito do mouse em seu projeto e selecione properties:





No menu da esquerda selecione Android e clique em Add no fim da janela:





Selecione o projeto referente ao FacebookSDK e clique em OK:





Pronto, agora vamos à utilização!

1) Vamos modificar o arquivo AndroidManifest.xml referente ao seu projeto adicionando duas permissões e o ApplicationID referente à aplicação que criamos no site developers do Facebook na primeira parte deste tutorial. Para isso, acima da tag Application do arquivo, fora da mesma, adicione o seguinte trecho de código:

   
   <uses-permission android:name="android.permission.INTERNET"/>  
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  

Agora DENTRO da tag Application vamos vincular nosso aplicativo à aplicação criada no site developers do Facebook adicionar o seguinte trecho de código:

   
     <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>  


Note que o valor não está diretamente no arquivo AndroidManifest.xml, e sim está referenciando a chave facebook_app_id no arquivo strings.xml. Abra o arquivo /values/strings.xml de seu projeto e adicione o seguinte trecho de código dentro da tag <resources>:

   
   <string name="facebook_app_id">SEU_APP_ID_CRIADO_NO_FACEBOOK_DEVELOPERS</string>  


Caso você não tenha guardado tal chave, acesse o site do Facebook para Desenvolvedores, faça login e na aba My Apps selecione o seu aplicativo antes criado e você terá acesso à sua chave. Substitua o valor acima e seu arquivo AndroidManifest.xml estará totalmente configurado (lembrando que na primeira parte deste tutorial já adicionamos a Activity do Facebook no mesmo).

2) Vamos utilizar o componente LoginButton (já mencionado na primeira parte deste tutorial) que é um componente visual já disponibilizado pelo Facebook para possibilitar o login com o mesmo.

Para isso, primeiramente vamos adicionar o componente ao nosso arquivo de layout onde queremos que o mesmo esteja visível. O componente é o seguinte:

   
   <com.facebook.login.widget.LoginButton  
     android:id="@+id/login_button_facebook"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"/>  

Feito isso, agora iremos trabalhar com tal botão em nossa Activity.

3) Em nossa Activity precisaremos de 3 propriedades:
* com.facebook.login.widget.LoginButton ao qual referenciará o botão que incluímos em nosso layout no passo 2.
* java.util.List de Strings que conterá as permissões que usaremos para recuperar dados do usuário definidos no Facebook.
*com.facebook.CallbackManager que será responsável por gerenciar as ações em suas aplicações após o retorno das chamadas ao FacebookSDK.

Sendo assim, crie três variáveis globais em sua Activity:

        
      private LoginButton buttonFacebook;  
      private List<String> facebookPermitions;  
      private CallbackManager callbackManager;  
        

Em sua Activity, no método onCreate, ANTES DE CONFIGURAR O XML DE LAYOUT COM O MÉTODO setContentView precisamos inicializar o FacebookSDK e fazemos isso adicionando o seguinte trecho de código:

   
   FacebookSdk.sdkInitialize(this);  
   ...  
   setContentView(R.layout.activity_login);  
   

Se você estiver utilizando o botão do facebook dentro de um Fragment ao invés de uma Activity então troque a chave this por getApplicationContext().

Após configurar o xml de layout de sua Activity com o método setContentView iniciamos o nosso CallbackManager com a seguinte instrução:

   
    setContentView(R.layout...);
    ...
    callbackManager = CallbackManager.Factory.create();  
   


Agora vamos inicializar nossa lista com as permissões que queremos para recuperar os dados necessários à nossa aplicação diretamente dos dados cadastrados no Facebook do usuário. Para este primeiro teste, utilizaremos apenas algumas permissões básicas, porém você pode adicionar ou remover permissões conforme sua necessidade. Inicialize a lista da seguinte forma:

   
   facebookPermitions = Arrays.asList("email", "public_profile", "user_friends");  
             

Vincule seu objeto LogginButton com o botão de logar com Facebook antes adicionado ao seu xml de layout:

   
   buttonFacebook = (LoginButton)findViewById(R.id.login_button_facebook);  
   

Configure no LogginButton as permissões que definimos anteriormente:

   
   buttonFacebook.setReadPermissions(facebookPermitions);  
   

E agora registramos nosso CallbackManager através do método registerCallback do LoginButton que recebe como parâmetro o nosso callbackManager responsável por encapsular nosso callback e nosso callback responsável por tratar os eventos e respostas enviadas pelo FacebookSDK ao concluir o login:

   
    buttonFacebook.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {            
        @Override  
        public void onSuccess(LoginResult arg0) {  
             Toast.makeText(mContext, "SUCESSO!", Toast.LENGTH_LONG).show();  
        }  
                  
        @Override  
        public void onError(FacebookException arg0) {  
             Toast.makeText(mContext, "ERROR!", Toast.LENGTH_LONG).show();  
        }  
                  
        @Override  
        public void onCancel() {  
             Toast.makeText(mContext, "CANCEL!", Toast.LENGTH_LONG).show();  
        }  
    });  



Estamos quase prontos para fazer nosso primeiro teste.

4) Agora devemos copiar a nossa Key Hash que já configuramos na primeira parte deste tutorial para o campo de Key Hashs de nosso aplicativo. Para isso, navegue ate o site do Facebook para Desenvolvedores, faça login, clique na sua imagem no canto superior direito do site e selecione Developer Settings:





Selecione a aba Sample App e copie o código que está no campo Android Key Hash conforme mostra a imagem:





No menu superior posicione o mouse em My Apps e selecione o seu aplicativo:





Na tela que se segue, no menu da esquerda selecione Settings e no campo Key Hashs cole o código copiado:




5) Faça o teste de sua aplicação e veja se até aqui tudo está funcionando (não estranhe por nenhum dos Toasts que colocamos no FacebookCallback pois o mesmo ainda não será executado).

6) Agora vamos "brincar" com o nosso CallbackManager e com nosso FacebookCallback definidos anteriormente para conseguirmos recuperar os dados que precisamos em nossa aplicação direto dos dados do usuário guardados na base do Facebook.

Ao clicar no botão de logar com o Facebook você deve ter percebido que uma nova Activity é inicializada pedindo ao usuário as permissões que você configurou. Essa Activity é inicializada automaticamente com o método startActivityForResult ao invés do startActivity, ou seja, para recuperarmos o seu retorno devemos sobrescrever o método onActivityResult de nossa Activity como o seguinte código:

   
   @Override  
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
      super.onActivityResult(requestCode, resultCode, data);  
      callbackManager.onActivityResult(requestCode, resultCode, data);  
   }  
   

A partir deste momento, o nosso FacebookCallback será executado. :)

7) Ao chegar no método onSuccess de nosso FacebookCallback teremos no parâmetro LoginResult a lista de permissões que foram aceitas pelo usuário assim como a lista de permissões que foram negadas. Se temos agora a permissão do usuário para acessar seus dados então podemos fazer uma requisição e acessar tais dados.

Dentro do método onSuccess criamos uma requisição com o objeto GraphRequest através do método newMeRequest passando como parâmetro o AccessToken contendo a lista de permissões aceitas e um novo GraphJSONObjectCallback que trata o retorno da requisição com o seguinte código:

 
    GraphRequest request = GraphRequest.newMeRequest(arg0.getAccessToken(), new GraphJSONObjectCallback() {  
        @Override  
         public void onCompleted(JSONObject object, GraphResponse response) {  
             System.out.println(object.toString());  
         }  
    });  
                       
    request.executeAsync();  


No método onCompleted o JSONObject object contém os dados que queremos. No código acima eu apenas imprimo no log os dados recuperados.

É isso aí! Agora é só adicionar/remover permissões de nossa lista de permissões de acordo com os dados que sua aplicação necessita e tratar tais dados no método onCompleted conforme necessidade de sua aplicação!

Caso haja alguma crítica/sugestão, por favor deixe abaixo nos comentários para que possamos melhorar cada vez mais.

Até a próxima pessoal!

domingo, 5 de abril de 2015

Android - Login com Facebook no Eclipse PARTE 1



Como fazer login na minha aplicação utilizando o Facebook? Quais as possíveis formas de fazer isso?


Sem mais enrolação, vamos ao passo-a-passo!

Existem duas formas de você fazer login na sua aplicação utilizando o Facebook. A primeira, utilizando a classe LoginButton que fornece um componente de botão para você incluir na sua tela e a segunda é utilizando a classe LoginManager que não disponibiliza componentes visuais.


Como pré-requisito você precisa ter:

* Facebook App configurado e lincado à sua aplicação;
* Facebook SDK adicionado à sua aplicação;
* Facebook App ID configurado e lincado à sua aplicação;
* Android Key Hash configurado e adicionado ao seu perfil de desenvolvedor;
* Facebook Activity incluso ao seu arquivo AndroidManifest.xml.

Calma, não se desespere ainda! Iremos fazer tudo isso passo-a-passo!

1) Pré-requesitos
1.1) Faça login no site do Facebook para desenvolvedores com sua conta do Facebook.

1.2) Na aba "My Apps" clique em Register as a Developer como mostra a figura abaixo:





A seguinte janela irá abrir. Aceite os termos e clique em cadastre-se:



1.3) Na tela que irá abrir, selecione Android, digite o nome da sua aplicação e clique em Create New Facebook App ID.



Na próxima tela escolha a categoria da sua aplicação e prossiga.

Faça o download do Facebook SDK for Android e guarde-o, iremos utilizá-lo nas próximas sessões.

No fim da página você precisará informar o pacote e a Activity principal da sua aplicação. O package você irá recuperar do arquivo AndroidManifest.xml na sua aplicação. Para o campo da Activity usaremos o caminho completo da Activity que é executada ao abrir sua aplicação. Segue imagens.





Clique em Avançar.

1.4) No próximo passo iremos gerar o Android Key Hash. Não é uma tarefa difícil, apenas execute o seguinte comando:

MAC:

 
  keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64  


WINDOWS:

 
  keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%\.android\debug.keystore | openssl sha1 -binary | openssl base64  


Se ao executar o comando você se deparar com o erro "'openssl' is not recognized as an internal or external command, operable program or batch file." faça o download do openssl aqui, instale-o e execute o comando novamente substituindo "openssl" pelo caminho de instalação do mesmo. Desta forma:



 
  keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%\.android\debug.keystore | "C:\OpenSSL-Win64\bin\openssl.exe" sha1 -binary | "C:\OpenSSL-Win64\bin\openssl.exe" base64


Caso seja solicitado alguma senha apenas dê enter. Copie o código base64 que é mostrado para a area do cadastro Facebook Developers que pede o código Hash







Clique em Avançar.


1.5) Vamos importar o Facebook SDK que baixamos no passo 1.3 para dentro de nossa aplicação.

DESCOMPACTE-O DENTRO DO WORKSPACEDO SEU PROJETO.

Crie um arquivo com nome local e com extensão ".properties" (local.properties) com o seguinte conteúdo: (substituindo "C:/Eclipse Android/sdk/" pelo caminho do seu SDK).

 
  sdk.dir = C:/Eclipse Android/sdk/
  

Salve o arquivo dento da pasta do Facebook SDK que baixamos.
Ainda dentro da pasta, abra o arquivo "settings.gradle" e adicione duas barras ( // ) no início das linhas que contém o seguinte conteúdo:

 
 //include 'tests'  
 //project(':tests').projectDir = new File('facebook/tests')  
   
 //include 'junitTests'  
 //project(':junitTests').projectDir = new File('facebook/junitTests') 
 

Salve o arquivo.

Agora, no project explorer da sua aplicação clique com o botão direito do mouse e selecione import. Expanda a pasta Gradle, selecione Gradle Project e clique em Next.







As dependências do Facebook SDK são gerenciadas pelo Gradle, se você está usando o Android Studio então não terá problemas, porém, se você está utilizando o Eclipse você precisa ter o plugin do Gradle instalado em seu Eclipse para que as dependências do Facebook SDK sejam resolvidas. Para instalar o plugin do Gradle, em seu eclipse clique em help -> Install New Software..., adicione o repositório http://dist.springsource.com/release/TOOLS/update/e4.2 e instale apenas a opção Core / Eclipse Integration for Gradle

Aponte para a pasta descompactada do Facebook SDK, Clique em Build Model, selecione apenas o projeto facebook e clique em finish.



Se ao compilar o projeto, você se deparar com esse erro:


 
[2015-04-04 22:21:21 - facebook] /facebook/gen already exists but is not a source folder. Convert to a source folder or rename it.
  

Clique com o botão direito do mouse na pasta "gen" e selecione "Build Path -> Use as Source Folder".

Se ao compilar novamente você se deparar com esse erro:



 [2015-04-04 22:25:27 - facebook] D:\facebook-android-sdk-4.0.1\facebook\res\values\messenger_button_styles.xml:66: error: Error: No resource found that matches the given name: attr 'android:textAllCaps'.
  

Comente a linha com o erro e compile o projeto.

Clique com o botão direito do mouse na pasta "src" e selecione "Build Path -> Use as Source Folder".

Clique com o botão direito do mouse no projeto facebook referente ao SDK e selecione "Android Tools -> Add Support Library". Aceite o termos e clique em "Install".

1.5.2) Clique com o botão direito do mouse no projeto facebook referente ao SDK e clique em Properties. Selecione Java Compiler no menu esquerdo e mude todos os "combos" para 1.7. Ainda nesta janela, selecione Android no menu da esquerda e marque a opção Android 4.4W ou superior. Caso não tenha essa opção (ou superior), atualize suas APIs no Android SDK Manager.

Se o seu projeto ainda contiver erros relacionados ao "bolts" baixe aqui o projeto "bolts" direto do GitHub, descompacte-o e importe-o como projeto Android para dentro do eclipse.

Repita o passo 1.5.2 acima no projeto "bolts" que acabamos de baixar.  Depois disso, ainda que o projeto "bolts" esteja com erro, provavelmente o arquivo "bolts.jar" já deverá ter sido gerado dentro da pasta "Bolts/bin/" e é apenas dele que precisamos. Copie o "bolts.jar" para dentro da pasta libs do projeto referente ao Facebook SDK e compile novamente o projeto.

Estamos quase lá!

Clique com o botão direito do mouse no projeto referente ao Facebook SDK e clique em Properties. Na janela que se seque, selecione Android no menu da esquerda e marque a opção "Is Library". Feito isso, compile novamente o projeto referente ao Facebook SDK e o arquivo facebook.jar será gerado dentro da pasta "/bin/". Copie este ".jar" para a pasta "/libs/" da sua aplicação e estaremos prontos para utilizar o Facebook SDK em nosso projeto!

 1.6) Adicione a seguinte declaração de Activity no seu arquivo AndroidManifest.xml:

 
...  
 <activity   
       android:name="com.facebook.FacebookActivity"  
       android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"  
       android:theme="@android:style/Theme.Translucent.NoTitleBar"  
       android:label="@string/app_name">  
 </activity>  
...  


Pessoal, pra essa primeira parte (a mais difícil) ficaremos por aqui. No próximo tutorial aprendemos de fato a fazer login com o Fcebook e como recuperar dados de perfil do usuário.

Clique aqui para acessar a parte 2 deste tutorial.

Até a próxima! :)

terça-feira, 25 de novembro de 2014

Android - Trabalhando com Google Maps

Como marcar pontos em um mapa com a API do Google Maps? Como traçar rotas? Como customizar marcadores?

Sem mais enrolação, vamos ao passo-a-passo!

1) Este tutorial é uma continuação do tutorial Android - Iniciando Com Google Maps encontrado AQUI. Se você tem dúvidas de como incluir a API do Google Maps em sua aplicação, como adquirir a assinatura digital de sua aplicação, etc, volte e siga a primeira parte deste tutorial AQUI. Se você já incluiu o mapa em sua aplicação e apenas tem dúvidas de como utilizá-lo, siga para o passo 2) deste tutorial.

2) Como estamos continuando o tutorial anterior vale ressaltar nossa Activity está vazia e que nosso arquivo de layout contém apenas o fragmento referente ao mapa:

 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:tools="http://schemas.android.com/tools"  
   android:layout_width="match_parent"  
   android:layout_height="match_parent"  
   tools:context="com.jonathan.projetomapas.ProjetoMapasActivity" >  
   
   <fragment  
     android:id="@+id/mapa"  
     android:layout_width="match_parent"  
     android:layout_height="match_parent"  
     android:name="com.google.android.gms.maps.MapFragment"/>  
   
 </RelativeLayout>  


Sendo assim, o próximo passo é vincular o nosso componente de tela referente ao mapa com um objeto em nossa Activity para que seja possível manipulá-lo conforme desejamos. Para isso, edite sua Activity criando um objeto do tipo "com.google.android.gms.maps.GoogleMap" e recuperando um "GoogleMap" de nosso fragmento que incluímos em nosso arquivo de layout anteriormente. Para melhor visualização e manutenção do código, eu criei um método para inicializar os componentes da tela e o invoquei no método "onCreate" de nossa Activity. Segue código de como ficou nossa Activity:

 
package com.jonathan.projetomapas;  
   
import android.app.Activity;  
import android.os.Bundle;  
import com.google.android.gms.maps.GoogleMap;  
import com.google.android.gms.maps.MapFragment;  
   
   
public class ProjetoMapasActivity extends Activity {  
        
    private GoogleMap mapa;  
        
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         setContentView(R.layout.activity_projeto_mapas);  
       
         inicializarComponentes();  
    }  
     
    private void inicializarComponentes(){  
         mapa = ((MapFragment) getFragmentManager().findFragmentById(R.id.mapa)).getMap();  
    }  
}  
   



3) Adicionando marcadores.
Adicionar marcadores em seu mapa é uma tarefa simples, você precisa apenas de uma latitude e longitude do local que você quer marcar em seu mapa. Para efeito de aprendizado irei abrir o Google Maps e digitar um endereço qualquer para recuperar sua longitude e latitude. Nesse caso utilizarei o endereço da Google do Brasil que fica localizada na Av. Brigadeiro Faria Lima, 3477, São Paulo. Sua latitude e longitude é -23.586328 e -46.682012 respectivamente. Agora que temos a localização, criaremos um objeto do tipo "com.google.android.gms.maps.model.LatLng" com as coordenadas que recuperamos:

 
private final LatLng cordGoogleSp = new LatLng(-23.586328, -46.682012);  


Feito isso, no método "inicializarComponentes", logo após inicializar o nosso atributo "mapa", adicionaremos este marcador com a seguinte linha de código:

 
mapa.addMarker(new MarkerOptions().position(cordGoogleSp)); 
 



Marcador adicionado! Simples, não?

4) Zoom e posicionamento em animação.
Nós adicionamos o marcador porém não demos o zoom necessário no mapa para visualizarmos onde realmente está posicionado o nosso marcador e também não deixamos o nosso marcador centralizado na tela. Faremos isso agora de forma "animada". Utilizaremos o método "animateCamera", porém se você quiser realizar a mesma tarefa de forma não animada, utilize o método "moveCamera". O método "animateCamera" que utilizaremos, recebe 3 parâmetros: Um objeto do tipo CameraUpdate, um inteiro representado a duração da animação em milissegundos e um Objeto do tipo CancelableCallback responsável por tratar os evento disparado quando tal animação é cancelada.
Como iremos atualizar o posicionamento da "câmera" de nosso mapa, criaremos um objeto do tipo "com.google.android.gms.maps.model.CameraPosition" da seguinte forma:

 
CameraPosition update = new CameraPosition(cordGoogleSp, 15, 0, 0); 
 

Onde o primeiro parâmetro é a coordenada que será colocada no centro de nossa tela do mapa, o segundo parâmetro é o nível de zoom que daremos no mapa, o terceiro é o "tilt" que seria um efeito de rotação na vertical de até 90º e o quarto é o "bearing" que seria um efeito de rotação na horizontal em até 360º. No nosso caso, assumimos que a coordenada é a mesma que utilizamos anteriormente onde adicionamos o marcador e o zoom será de nível 15. Não utilizaremos Tilt nem Bearing.
Feito isso agora podemos utilizar o método animateCamera. Usaremos a classe "com.google.android.gms.maps.CameraUpdateFactory" para criar um objeto CameraUpdate a partir de nosso CameraPosition.

 
mapa.animateCamera(CameraUpdateFactory.newCameraPosition(update), 5000, null); 
 

Definimos que ao abrir nosso mapa em nossa aplicação, o mesmo será direcionado para as coordenadas estabelecidas e dará um zoom de nível 15. Isso de forma "animada" com duração de 3 segundos! Segue como ficou o código:

 
package com.jonathan.projetomapas;  
   
import android.app.Activity;  
import android.os.Bundle;  
   
import com.google.android.gms.maps.CameraUpdateFactory;  
import com.google.android.gms.maps.GoogleMap;  
import com.google.android.gms.maps.MapFragment;  
import com.google.android.gms.maps.model.CameraPosition;  
import com.google.android.gms.maps.model.LatLng;  
import com.google.android.gms.maps.model.MarkerOptions;  
   
   
public class ProjetoMapasActivity extends Activity {  
        
     private GoogleMap mapa;  
     private final LatLng cordGoogleSp = new LatLng(-23.586328, -46.682012);  
        
     @Override  
     protected void onCreate(Bundle savedInstanceState) {  
          super.onCreate(savedInstanceState);  
          setContentView(R.layout.activity_projeto_mapas);  
       
          inicializarComponentes();  
     }  
     
     private void inicializarComponentes(){  
          mapa = ((MapFragment) getFragmentManager().findFragmentById(R.id.mapa)).getMap();  
          mapa.addMarker(new MarkerOptions().position(cordGoogleSp));  
          
          CameraPosition update = new CameraPosition(cordGoogleSp, 15, 0, 0);  
          mapa.animateCamera(CameraUpdateFactory.newCameraPosition(update), 3000, null);  
     }  
}  

5) Estruturando o código.
Antes de avançarmos nosso estudo sobre o funcionamento do Google Maps API, iremos "organizar" melhor o nosso código/aplicativo. Iremos colocar um item de menu em nossa "ActionBar" para cada item aprendido neste tutorial. Sendo assim, precisamos fazer algumas alterações em nosso código.

* A - Nossa Activity deverá estender de ActionBarActivity ao invés de Activity;
* B - Criar o arquivo ".xml" referente ao arquivo de menu;
* C - Sobrescrever os métodos "onCreateOptionsMenu" e "onOptionsItemSelected";

Vamos lá!

* A - Apenas substitua Activity por ActionBarActivity na declaração de sua Activity:

 
public class ProjetoMapasActivity extends ActionBarActivity { 
 

* B - Dentro da pasta "/res/menu" (se não existir crie-a), crie um arquivo do tipo XML com o seguinte código:

 
<menu xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:tools="http://schemas.android.com/tools">  
   
   <item  
     android:id="@+id/action_fixe_location"  
     android:orderInCategory="100"  
     android:showAsAction="never"  
     android:title="Localização Fixa"/>  
     
   <item  
     android:id="@+id/action_my_location"  
     android:orderInCategory="100"  
     android:showAsAction="never"  
     android:title="Minha Localização"/>  
     
   <item  
     android:id="@+id/action_map_types"  
     android:orderInCategory="100"  
     android:showAsAction="never"  
     android:title="Tipos de Mapa"/>  
     
   <item  
     android:id="@+id/action_personalized_mark"  
     android:orderInCategory="100"  
     android:showAsAction="never"  
     android:title="Marcador Personalizado"/>  
     
   <item
     android:id="@+id/action_personalized_infowindow"
     android:orderInCategory="100"
     android:showAsAction="never"
     android:title="Balão de Info Personalizado"/>

   <item  
     android:id="@+id/action_map_rote"  
     android:orderInCategory="100"  
     android:showAsAction="never"  
     android:title="Traçar Rota"/>  
 </menu> 
 

* C - Adicione o seguinte trecho de código em sua Activity para manipular os itens de menu que criamos acima:

  
   @Override  
   public boolean onCreateOptionsMenu(Menu menu) {  
        //Constrói nosso menu na ActionBar de nossa aplicação  
        getMenuInflater().inflate(R.menu.projeto_mapas, menu);  
        return super.onCreateOptionsMenu(menu);  
   }  
     
   @Override  
   public boolean onOptionsItemSelected(MenuItem item) {  
        switch (item.getItemId()) {  
            case R.id.action_fixe_location:  
                 //QUANDO A OPÇÃO 'LOCALIZAÇÃO FIXA' FOR CLICADA  
                 break;  
            case R.id.action_my_location:  
                 //QUANDO A OPÇÃO 'MINHA LOCALIZAÇÃO' FOR CLICADA  
                 break;  
            case R.id.action_map_types:  
                 //QUANDO A OPÇÃO 'TIPOS DE MAPA' FOR CLICADA  
                 break;  
            case R.id.action_personalized_mark:  
                 //QUANDO A OPÇÃO 'MARCADOR PERSONALIZADO' FOR CLICADA  
                 break;
            case R.id.action_personalized_infowindow:  
                 //QUANDO A OPÇÃO 'BALÃO DE INFO PERSONALIZADO' FOR CLICADA  
                 break;
            case R.id.action_map_rote:  
                 //QUANDO A OPÇÃO 'TRAÇAR ROTA' FOR CLICADA  
                 break;  
        }  
        return super.onOptionsItemSelected(item);  
   }  


A primeira opção de nosso menu (Localização Fixa) já foi criada no passo anterior deste tutorial, sendo assim, mova o código que antes colocamos no método "inicializarComponentes" referentes à adição do marcador e à animação de posicionamento e zoom para onde comentamos "QUANDO A OPÇÃO 'LOCALIZAÇÃO FIXA' FOR CLICADA". Apenas adicionaremos mais uma linha de código no início do "case" para limpar os marcadores anteriormente posicionados. Segue código completo da Activity depois das configurações:

 
 package com.jonathan.projetomapas;  
   
 import android.os.Bundle;  
 import android.support.v7.app.ActionBarActivity;  
 import android.view.Menu;  
 import android.view.MenuItem;  
   
 import com.google.android.gms.maps.CameraUpdateFactory;  
 import com.google.android.gms.maps.GoogleMap;  
 import com.google.android.gms.maps.MapFragment;  
 import com.google.android.gms.maps.model.CameraPosition;  
 import com.google.android.gms.maps.model.LatLng;  
 import com.google.android.gms.maps.model.MarkerOptions;  
   
   
 public class ProjetoMapasActivity extends ActionBarActivity {  
        
      private GoogleMap mapa;         
      private final LatLng cordGoogleSp = new LatLng(-23.586328, -46.682012);  
        
      @Override  
      protected void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         setContentView(R.layout.activity_projeto_mapas);  
       
         inicializarComponentes();  
      }  
     
      private void inicializarComponentes(){  
         mapa = ((MapFragment) getFragmentManager().findFragmentById(R.id.mapa)).getMap();  
      }  
     
      @Override  
      public boolean onCreateOptionsMenu(Menu menu) {  
         //Constrói nosso menu na ActionBar de nossa aplicação  
         getMenuInflater().inflate(R.menu.projeto_mapas, menu);  
         return super.onCreateOptionsMenu(menu);  
      }  
     
      @Override  
      public boolean onOptionsItemSelected(MenuItem item) {  
         switch (item.getItemId()) {  
             case R.id.action_fixe_location:  
                  mapa.clear();
                  mapa.addMarker(new MarkerOptions().position(cordGoogleSp));  
                  CameraPosition update = new CameraPosition(cordGoogleSp, 15, 0, 0);  
                  mapa.animateCamera(CameraUpdateFactory.newCameraPosition(update), 3000, null);  
                    
                     break;  
             case R.id.action_my_location:  
                  //QUANDO A OPÇÃO 'MINHA LOCALIZAÇÃO' FOR CLICADA  
                     break;  
             case R.id.action_map_types:  
                  //QUANDO A OPÇÃO 'TIPOS DE MAPA' FOR CLICADA  
                     break;  
             case R.id.action_personalized_mark: 
                  //QUANDO A OPÇÃO 'MARCADOR PERSONALIZADO' FOR CLICADA  
                     break;  
             case R.id.action_map_rote:  
                  //QUANDO A OPÇÃO 'TRAÇAR ROTA' FOR CLICADA  
                     break;  
          }  
          return super.onOptionsItemSelected(item);  
      }  
 }  
     


6) Recuperando minha localização.
A primeira coisa que vamos fazer ao clicarmos na opção "Minha Localização" do menu é limpar toda a configuração atual do mapa (não limpa o zoom, tilt ou bearing, porém, se por exemplo dermos mais 15 de zoom, o mesmo não é adicional ao zoom já configurado). Para isso, como primeira instrução no "case" referente à esta opção no menu, faremos o seguinte:

 
 mapa.clear();  


O processo de recuperar nossa localização da melhor forma possível exige alguns passos. Para facilitar a leitura do tutorial e minimizar o tempo de aprendizado, comentei cada passo que devemos realizar. Segue código do "case" de "Minha Localização" comentado:

 
    case R.id.action_my_location:  
         //Limpamos o mapa atual retirando marcadores, elipses, etc.  
         mapa.clear();  
        
         //Ativamos a identificação de nossa localização no google maps (pontinho azul no mapa)  
         mapa.setMyLocationEnabled(true);  
   
         //Criamos um 'Listener' para tratar o evento disparado todas as vezes que a localização é alterada  
         mapa.setOnMyLocationChangeListener(new OnMyLocationChangeListener() {  
              @Override  
              public void onMyLocationChange(Location minhaLocalizacao) {  
                   //Limpamos novamente o mapa atual retirando marcadores, elipses, etc.  
                   mapa.clear();  
                                 
                   //Criamos o abjeto LatLng a partir de nossa localizacao  
                   LatLng latLngMinhaLocalizacao = new LatLng(minhaLocalizacao.getLatitude(),   
                                                            minhaLocalizacao.getLongitude());  
                        
                   //Adicionamos o marcador no mapa para a nossa localização
                   mapa.addMarker(new MarkerOptions().position(latLngMinhaLocalizacao));  
                        
                   //Repetimos o processo de animação para a nossa posição no mapa  
                   CameraPosition updateMinhaLocalizacao = new CameraPosition(latLngMinhaLocalizacao, 15, 0, 0);  
                   mapa.animateCamera(CameraUpdateFactory.newCameraPosition(updateMinhaLocalizacao), 3000, null);  
              }  
         });  
   break;  


Já que adicionamos um "Listener" que irá criar a nossa "animação" todas as vezes que a localização for alterada, temos que lembrar de tirar esse "Listener" nas outras opções de nosso menu. Adicione a seguinte linha no inicio de todas as outras opções que temos no menu (menos no item referente aos "tipos de mapa" pois nesse item não mudaremos a localização no mapa):

 
 mapa.setOnMyLocationChangeListener(null);  
   



7) Mudando o tipo do mapa.
Mudar o tipo de mapa é uma tarefa simples e fácil. Como utilizaremos apenas um botão (item de menu) para mudar o tipo do mapa para os quatro tipos (Híbrido, Terreno, Satélite, Normal), apenas faremos uma verificação de qual o tipo atual e mudaremos para o próximo tipo respeitando a sequencia citada acima. Para isso utilizaremos o método "setMapType" para alterar o tipo de mapa e o método "getMapType" para verificar qual o tipo atual do mapa.

 
case R.id.action_map_types:  
                       
    if(mapa.getMapType() == GoogleMap.MAP_TYPE_HYBRID){  
        mapa.setMapType(GoogleMap.MAP_TYPE_TERRAIN);  
                            
    }else if(mapa.getMapType() == GoogleMap.MAP_TYPE_TERRAIN){  
        mapa.setMapType(GoogleMap.MAP_TYPE_SATELLITE);  
                            
    }else if(mapa.getMapType() == GoogleMap.MAP_TYPE_SATELLITE){  
        mapa.setMapType(GoogleMap.MAP_TYPE_NORMAL);  
                            
    }else{  
        mapa.setMapType(GoogleMap.MAP_TYPE_HYBRID);  
    }  
break; 
 

Os tipos de mapa a seguir são Hibrido, Satélite e Terreno respectivamente:



8) Customizando marcadores.
Podemos customizar os marcadores que colocamos em nosso mapa adicionando títulos, descrição, alterando cores, colocando ícones, etc. Para este exemplo, irei colocar um marcador em meu endereço residencial atual e customizarei este marcador.
Primeiro, vá ao Google Maps e recupere a latitude e longitude de sua residência. Feito isso, crie um atributo em sua Activity do tipo "LatLng" com esses valores (já fizemos isso antes):

 
 private final LatLng cordMyHome = new LatLng(-23.555997,-46.481778);  


Como já definimos anteriormente, retiramos o "Listener" que manipula a mudança de localização de nosso mapa:

 
 mapa.setOnMyLocationChangeListener(null);  
   

Limpe os marcadores colocados no mapa anteriormente:

 
 mapa.clear(); 
 

Agora crie o marcador adicionando-o ao seu mapa:

 
 Marker meuMarcadorMarker = mapa.addMarker(new MarkerOptions().position(cordMyHome));
  

Adicione um título e descrição de sua preferência ao seu marcador através dos métodos "setTitle" e "setSnippet" para configurar o título e a descrição respectivamente:

 
 meuMarcadorMarker.setTitle("Minha Casa");  
 meuMarcadorMarker.setSnippet("Esta é minha residência..."); 
 

Para alterar o ícone do marcador, recupere o ícone que deseja (o ícone que coloquei pode ser encontrado AQUI), e o coloque na pasta "/res/drawable-hdpi" de sua aplicação. Não esqueça de redimensionar a imagem para o tamanho adequado (no caso da imagem que utilizei eu a redimensionei para 40x39 pixels e de renomea-la para que o nome da mesma não contem caracteres especiais nem letras maiúsculas). Depois de colocá-la na pasta indicada, compile seu aplicativo e adicione a seguinte linha na personalização de seu marcador:

 
 meuMarcadorMarker.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.home_icon_custom));  


Onde "home_icon_custom" será o nome que você deu à sua imagem e a classe R é a do seu projeto, não a do pacote do Android.
Tornamos a nossa "Janela de Informações" (balão onde fica o título e descrição do marcador) visível por padrão. Caso queira que esta janela fique visível apenas com o clique no marcador ignore esta linha de código.

 
 meuMarcadorMarker.showInfoWindow();  
   

Repetimos a animação para o local que indicamos no mapa:

 
 CameraPosition updateMinhaCasa = new CameraPosition(cordMyHome, 15, 0, 0);  
 mapa.animateCamera(CameraUpdateFactory.newCameraPosition(updateMinhaCasa), 3000, null);  




9) Customizando 'InfoWindow' (balão de informações do marcador).
Para customizar o balão de informações do marcador precisaremos de um "Adapter". Na declaração de nossa Activity iremos definir que a mesma irá implementar a interface "com.google.android.gms.maps.GoogleMap.InfoWindowAdapter":

 
 public class ProjetoMapasActivity extends ActionBarActivity implements InfoWindowAdapter 
 

Com isso, temos que implementar os seguintes métodos:

   
 @Override  
 public View getInfoContents(Marker arg0) {  
             
      return null;  
 }  
   
 @Override  
 public View getInfoWindow(Marker arg0) {  
             
      return null;  
 }  
 

O primeiro método a ser invocado será o "getInfoWindow" que se retornado "null" então será invocado o método "getInfoContents" que por sua vez, se retornado "null" então o balão de informações padrão será utilizado.
A diferença é que o "getInfoWindow" permite a você oferecer uma view para ser utilizada. Já o método "getInfoContent" permite a você customizar os conteúdos do balão porém sem alterar o seu frame e seu background.
Utilizaremos a segunda opção que é mais simples para efeito de aprendizado.

Crie um arquivo XML de Layout para o seu balão de informações dentro da pasta "/res/layout/" do mesmo modo que é feito com Layouts referentes às Activities. Neste exemplo criei um arquivo chamado "infowindow_map_custom" com o seguinte layout:

 <?xml version="1.0" encoding="utf-8"?>  
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   android:layout_width="match_parent"  
   android:layout_height="wrap_content"   
   android:padding="20dp"  
   android:background="@color/wallet_holo_blue_light">  
   
   <ImageView  
     android:id="@+id/infowindow_imageview_imagem"  
     android:layout_width="40dp"  
     android:layout_height="40dp"  
     android:layout_alignParentLeft="true"  
     android:layout_alignParentTop="true"  
     android:src="@drawable/home_icon_custom" />  
   
   <LinearLayout   
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:orientation="vertical"  
     android:layout_toRightOf="@+id/infowindow_imageview_imagem" 
     android:gravity="center"  
     android:layout_alignBottom="@+id/infowindow_imageview_imagem"  
     android:layout_alignTop="@+id/infowindow_imageview_imagem">  
       
     <TextView  
          android:id="@+id/infowindow_textview_titulo"  
          android:layout_width="wrap_content"  
          android:layout_height="wrap_content"  
          android:gravity="center"  
          android:text="Título"  
          android:textSize="15sp"  
          android:textStyle="bold"  
          android:textColor="@android:color/black"/>  
        
        <TextView  
          android:id="@+id/infowindow_textview_descricao"  
          android:layout_width="wrap_content"  
          android:layout_height="wrap_content"  
          android:text="Descrição aqui..."  
          android:textSize="12sp"  
          android:textStyle="italic"  
          android:textColor="@android:color/black"/>  
   </LinearLayout>  
 </RelativeLayout>
  

Crie um atributo em sua Activity do tipo "View" da seguinte forma:

 
 private View markerInfo; 
 

Implementamos o método "getInfoContents" recuperando os dados de nosso marcador e exibindo-os em nossa view personalizada:

 
 @Override
 public View getInfoContents(Marker arg0) {
     //Inflamos o nosso arquivo de layout em uma view
     markerInfo = getLayoutInflater().inflate(R.layout.infowindow_map_custom, null);
  
     //Configuramos o tamanho de nossa view
     markerInfo.setLayoutParams(new RelativeLayout.LayoutParams(200, RelativeLayout.LayoutParams.WRAP_CONTENT));
  
     //Vinculamos objetos com os componentes de tela em nossa view
     TextView titulo = (TextView) markerInfo.findViewById(R.id.infowindow_textview_titulo);
     TextView descricao = (TextView) markerInfo.findViewById(R.id.infowindow_textview_descricao);
  
     //Recuperamos os valores de nosso marcador e o colocamos em nossa view
     titulo.setText(arg0.getTitle());
     descricao.setText(arg0.getSnippet());
  
     //Retornamos para a tela a nossa view personalizada
     return markerInfo;
 }


Agora no "case" referente à opção de "Balão de Info Personalizado" configuramos o nosso Adapter em nosso mapa e repetimos o processo feito no "case" de "Marcador Personalizado" apenas para termos uma posição no mapa com informações no marcador:

 
 case R.id.action_personalized_infowindow:  
                       
     //Configuramos nosso adaptador em nosso mapa  
     mapa.setInfoWindowAdapter(this);  
                       
     //Repitimos o processo do passo anterior apenas para termos um marcador com informações a mostrar  
     mapa.setOnMyLocationChangeListener(null);  
     mapa.clear();  
                       
     Marker marcadorMinhaCasa = mapa.addMarker(new MarkerOptions().position(cordMyHome));  
                       
     marcadorMinhaCasa.setTitle("Minha Casa");  
     marcadorMinhaCasa.setSnippet("Esta é minha residência...");  
     marcadorMinhaCasa.setIcon(BitmapDescriptorFactory.fromResource(R.drawable.home_icon_custom));  
     marcadorMinhaCasa.showInfoWindow();  
                       
     CameraPosition updateMyHome = new CameraPosition(cordMyHome, 15, 0, 0);  
     mapa.animateCamera(CameraUpdateFactory.newCameraPosition(updateMyHome), 3000, null);  
 break;
  

Agora, em todos os outros "cases" (menos o case de Tipos de mapa) devemos limpar esta configuração de Adapter que colocamos, assim como limpamos a configuração do Listener anteriormente. Para isso adicione a seguinte linha no inicio dos outros "cases":

 
 mapa.setInfoWindowAdapter(null);  


Resultado do nosso "balão de informações" do marcador personalizado:



10) Traçando rotas.
Para traçarmos uma rota em nosso mapa utilizaremos o serviço The Google Directions API onde faremos uma requisição HTTP e o mesmo nos retornará um JSON com o trajeto a ser "pintado".
Crie um método em sua Activity que recebe as latitudes e longitudes de origem e destino. O mesmo será responsável por montar a URL de chamada ao serviço. Segue código:

 
 private String montarURLRotaMapa(double latOrigen, double lngOrigen, double latDestino, double lngDestino){  
     //Base da URL  
     String url = "http://maps.googleapis.com/maps/api/directions/json?origin=";  
     //Local de origem  
     url += latOrigen + "," + lngOrigen;  
     url += "&destination=";  
     //Local de destino  
     url += latDestino + "," + lngDestino;  
     //Outros parametros  
     url += "&sensor=false&mode=driving&alternatives=true";  
       
     return url;  
 }  


Agora desenvolveremos o método que fará a chamada ao serviço The Google Directions API através desta URL e converterá o resultado em JSON. Segue código comentado:

 
 public JSONObject requisicaoHTTP(String url) {  
     JSONObject resultado = null;  
             
     try {  
          //Criamos um cliente HTTP para que possamos realizar a   
          //requisição a um Servidor HTTP  
          DefaultHttpClient httpClient = new DefaultHttpClient();  
          //Definimos o método de requisição como sendo POST  
          HttpPost httpPost = new HttpPost(url);  
          //Recuperamos a resposta do Servidor HTTP  
          HttpResponse httpResponse = httpClient.execute(httpPost);  
          //Recuperamos o conteúdo enviado do Servidor HTTP  
          HttpEntity httpEntity = httpResponse.getEntity();  
          //Transformamos tal conteúdo em 'String'  
          String conteudo = EntityUtils.toString(httpEntity);   
         
          //Transformamos a 'String' do conteúdo em Objeto JSON  
          resultado = new JSONObject(conteudo);  
         
     } catch (UnsupportedEncodingException e) {  
          Log.e("ProjetoMapas", e.getMessage());  
     } catch (ClientProtocolException e) {  
          Log.e("ProjetoMapas", e.getMessage());  
     } catch (IOException e) {  
          Log.e("ProjetoMapas", e.getMessage());  
     } catch (JSONException e) {  
          Log.e("ProjetoMapas", e.getMessage());  
     }  
       
     //Retornamos o conteúdo em formato JSON  
     return resultado;  
 } 
 

Desenvolvemos também o método que irá literalmente "pintar o caminho" entre os dois pontos que escolheremos em nosso mapa. Segue código comentado:

 
 public void pintarCaminho(JSONObject json) {  
     try {  
         //Recupera a lista de possíveis rotas  
         JSONArray listaRotas = json.getJSONArray("routes");  
         //Para efeito de aprendizado iremos utilizar apenas a primeira opção  
         JSONObject rota = listaRotas.getJSONObject(0);  
         //Recuperamos os pontos a serem pintados para que surga a 'linha' no mapa  
         String pontosPintar = rota.getJSONObject("overview_polyline").getString("points");  
         //Recuperamos a lista de latitudes e longitudes para sabermos exatamente onde pintar  
         List<LatLng> listaCordenadas = extrairLatLngDaRota(pontosPintar);  
   
         //Percorremos por cada cordenada obtida  
         for(int ponto = 0; ponto < listaCordenadas.size()-1 ; ponto++){  
             //Definimos o ponto atual como origem  
             LatLng pontoOrigem= listaCordenadas.get(ponto);  
             //Definimos o próximo ponto como destino  
             LatLng pontoDestino= listaCordenadas.get(ponto + 1);  
             //Criamos um objeto do tipo PolylineOption para adicionarmos os pontos de origem e destino  
             PolylineOptions opcoesDaLinha = new PolylineOptions();  
             //Adicionamos os pontos de origem e destino da linha que vamos traçar  
             opcoesDaLinha.add(new LatLng(pontoOrigem.latitude, pontoOrigem.longitude),   
                    new LatLng(pontoDestino.latitude,  pontoDestino.longitude));  
             //Criamos a linha de acordo com as opções que configuramos acima e adicionamos em nosso mapa  
             Polyline line = mapa.addPolyline(opcoesDaLinha);  
             //Mudamos algumas propriedades da linha que acabamos de adicionar em nosso mapa  
             line.setWidth(5);  
             line.setColor(Color.BLUE);  
             line.setGeodesic(true);  
         }  
     }   
     catch (JSONException e) {  
         Log.e("ProjetoMapas", e.getMessage());  
     }  
 }   


Percebe-se que invocamos uma função chamada "extrairLatLngDaRota" que ainda não existe. Como o nome já é bastante intuitivo, esta função será responsável por decodificar e nos retornar a lista de Longitudes e Latitudes da rota que será traçada. A API retornará para nós algo parecido com isso:

 
~wwnCxmuzG{GSDg@HyASWiAE?j@BLNLb@JH@Iz@E|@AlBJrBb@dDF`A?dAIpAGb@e@~Ak@`CUlBQvBy@vPYnFEh@CREBUJ}ChAqAh@i@f@[l@i@tAuBbHk@fAoBrCaAlAsCdEcDfEQT]n@Wj@e@rAOp@e@jCMpBGpAMlAm@xCa@dCYtAs@jByCrGoF~LuA|C_AfBaD~EyCjEaApAqBzCuChEoAfBwDxFmBtCu@`AoBtCqAhBkBlBmFzFk@j@eAp@s@Z}Bv@mEdBaF|BUFaBPY@LvALhALjBFhDJ`FXjFf@hITvEBzACvAMhCa@~FIzD@`DFnA`@`EfAfK\xB\lBXnBZtCLfAV|AZ`BVfBXhCLjBPdCt@|GfAnMh@bFLxBPxAjAvHdCxRt@dFVrAtAjMf@nE`BrNdBrN~@rHlAbLLnCJjAvAjNz@nHN~@tAnFp@rCd@hCXfBPfBrAnKPv@lAvDf@vBZzBTvBZbDN|@n@tE`@nDzBdRPbCT~AnBfPpAbLjBdOTtCLjAR`Az@fDp@rBdAbCrE|JpBhEfA~BdBjD~DrIbEpJ`AzBhDlHnArCd@nAb@tAf@`Cj@tCFp@Dv@EvBm@pMg@pM[~DmApQM|BSdE[zE@r@F^Vt@`@j@rAv@|C`BzDbBnF~Bp@`@h@j@b@dARz@Dz@LrFV~IDNJ|CJnJ?|@I~AOzBORIf@UpAe@|EMjAGHSHKAOEyCyBYQCGGUBULIP?bANV?tBn@j@N~@V|HzBlCx@|@\rA^l@b@~BnAzAl@|@V`AP|C^hBHdADlDR|Ch@lE`@v@@nBKtBKfCBxDVxCNbALzBHlITvDJfGZ`@Bj@J`AR^PZVRVvBlD`D|F|JxOtB|CtCfElDrF\h@fBnCfAnBXf@B\@HbAnBr@bAdAlAbAbBj@rATxAZnB^zAp@|A~@zAf@r@pCzDzHrLRf@dAxET|ABlBKdBa@|D_@xEKhASlAo@hBeAfBeBrCSHEHQTaBjCc@pAMj@Ed@Ch@EpE@jADz@|@fE|@vCZ`AfBvD^n@t@bAp@t@|BzBlDhD@PjAhA^nAN~@jAjH~@`FdA~FJr@o@Lq@LkDn@yA`@cCb@_C`@mDn@ 
 

Para decodificar isso utilizaremos um código bem famoso e facilmente encontrado. Não me atreverei a comentá-lo para não acabar interpretando de maneira errônea e ensinando besteiras (rsrs).
Segue código:

 
 private List<LatLng> extrairLatLngDaRota(String pontosPintar) {  
     List<LatLng> listaResult = new ArrayList<LatLng>();  
     int index = 0, len = pontosPintar.length();  
     int lat = 0, lng = 0;  
    
     while (index < len) {  
               
          int b, shift = 0, result = 0;  
          do {  
               b = pontosPintar.charAt(index++) - 63;  
               result |= (b & 0x1f) << shift;  
               shift += 5;  
          } while (b >= 0x20);  
            
          int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));  
          lat += dlat;  
   
          shift = 0;  
          result = 0;  
          do {  
               b = pontosPintar.charAt(index++) - 63;  
               result |= (b & 0x1f) << shift;  
               shift += 5;  
          } while (b >= 0x20);  
            
          int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));  
          lng += dlng;  
   
          LatLng p = new LatLng( (((double) lat / 1E5)),  
               (((double) lng / 1E5) ));  
          listaResult.add(p);  
     }  
   
     return listaResult;  
 }  


Estamos com "quase" toda a estrutura montada para ser testada. Sabemos que nada relacionado à tráfego de rede pode ser disparado diretamente na Thread Main, sendo assim, usaremos uma "AsyncTask" para efetuarmos a requisição HTTP que estruturamos anteriormente. Para saber mais sobre como funciona a AsyncTask clique aqui.
Crie uma classe private que seja inner (aninhada) em sua classe. Para isso, simplesmente declare uma nova classe dentro de sua Activity:

 
 private class MinhaAsyncTask extends AsyncTask<String, Void, JSONObject>{  

 }


Onde o primeiro parâmetro (String) será o tipo de parâmetro que nossa tarefa assíncrona irá precisar para ser executada, o segundo (Void) será o tipo de parâmetro que indicará qual o status em nível de completude a nossa tarefa se encontra (não utilizaremos neste tutorial) e o terceiro (JSONObject), de qual tipo será o retorno de nosso método principal.
Toda AsyncTask precisa que ao menos um método seja implementado, o "doInBackground" onde (no nosso caso) começará tudo. Sobrescreva este método com a seguinte assinatura:

 
 @Override  
 protected JSONObject doInBackground(String... params) {  
            
      return null;  
 }  


Sobrescreva também o método "onPostExecute" que será invocado automaticamente logo após o retorno do método acima. Segue assinatura:

 
 @Override  
 protected void onPostExecute(JSONObject result) {  
            
       super.onPostExecute(result);    
 }  

Em nosso método "doInBackground" iremos apenas realizar a requisição HTTP e retornar o resultado de nossa requisição:


 @Override  
 protected JSONObject doInBackground(String... params) {  
      JSONObject resultJSON = requisicaoHTTP(params[0]);  
            
      return resultJSON;  
 }  


E em nosso método "onPostExecute" apenas faremos a verificação se o resultado de nossa requisição não é nulo e caso não seja, chamaremos a função responsável por pintar a nossa rota em nosso mapa:

 
 @Override  
 protected void onPostExecute(JSONObject resultadoRequisicao) {  
    super.onPostExecute(resultadoRequisicao);    
      
    if(resultadoRequisicao != null){  
       pintarCaminho(resultadoRequisicao);  
    }  
 }  


Nossa AsyncTask completa:

 
 private class MinhaAsyncTask extends AsyncTask<String, Void, JSONObject>{  
   
     @Override  
     protected JSONObject doInBackground(String... params) {  
       JSONObject resultJSON = requisicaoHTTP(params[0]);  
         
       return resultJSON;  
     }  
          
     @Override  
     protected void onPostExecute(JSONObject resultadoRequisicao) {  
       super.onPostExecute(resultadoRequisicao);    
      
       if(resultadoRequisicao != null){  
         pintarCaminho(resultadoRequisicao);  
       }  
     }  
 }  


Feito isso, vamos executar nossa tarefa assíncrona no clique de nosso botão "Traçar Rota" do menu que definimos. Dependendo de qual versão de API do Android estamos usando a forma de executar uma AsyncTask muda. Segue código comentado referente à ação a ser executada pelo clique do botão "Traçar Rota":

 
 case R.id.action_map_rote:
      //Limpamos quaisquer configurações anteriores em nosso mapa
      mapa.setInfoWindowAdapter(null);
      mapa.setOnMyLocationChangeListener(null);
      mapa.clear();  

      //Recuperamos a URL passando as cordenadas de origem como sendo a cordenada que definimos   
      //para a nossa residência e as coordenadas de destino como sendo a do escritório da Google em SP.  
      String url = montarURLRotaMapa(cordMyHome.latitude, cordMyHome.longitude, cordGoogleSp.latitude, cordGoogleSp.longitude);  
      //Criamos uma instância de nossa AsyncTask (para cada requisição deverá ser criada uma nova instância).  
      MinhaAsyncTask tarefa = new MinhaAsyncTask();  
                       
      //Se a versão de SDK do Android do aparelho que está executando o aplicativo for menor que a HONEYCOMB (11)  
      if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB){  
          //Executa a tarefa passando a URL recuperada  
          tarefa.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);  
      }else{  
          //Executa a tarefa passando a URL recuperada  
          tarefa.execute(url);  
      }  
      
      //Adicionamos um marcador no ponto de partida e no ponto de destino
      mapa.addMarker(new MarkerOptions().position(cordMyHome));
      mapa.addMarker(new MarkerOptions().position(cordGoogleSp));

      //Animação para visualizar ponto de partida
      CameraPosition updateRota = new CameraPosition(cordMyHome, 15, 0, 0);
      mapa.animateCamera(CameraUpdateFactory.newCameraPosition(updateRota), 3000, null);
              
 break;  


Execute o código e terá a rota de "sua residência" ao escritório da Google em SP traçada no mapa em seu dispositivo!



É isso aí pessoal!! Agora você está apto a trabalhar com a API do Google Maps para Android! Aprendemos a adicionar marcadores, personalizar marcadores, personalizar o "balão de informações" do marcador, a recuperar sua localização, traçar rotas, etc..

Se você seguiu todo o passo-a-passo você terá em mãos um aplicativo com um mapa e suas principais ações!! Até o próximo!!