May 19, 2024

Wiki

Python

Aide

edit SideBar

Search

Android GPS

L'objectif de ce TP est d'exploiter la localisation par GPS. On y voit comment récupérer les données GPS et les afficher en surimpression d'une image.

Le Manager de Localisation

La localisation du mobile est prise en charge par la classe Android LocationManager qui fournit un ensemble de services de localisation. On créé une classe LocalisationGPS qui effectue ce travail. Elle contient donc un attribut mLocationManager de type LocationManager.

Le LocationManager est commun à toutes les activités sur Android. Il ne doit donc pas être instancié plus d'une fois. Cette contrainte est réalisée en utilisant une méthode pour récupérer sa référence plutôt qu'en l'instanciant :

  Uncontext.getSystemService(Context.LOCATION_SERVICE);   

Pour récupérer régulièrement la position, on utilise la méthode

  requestLocationUpdates (
            String provider, 
            long minTime, 
            float minDistance, 
            LocationListener listener);

telle que :

  • provider: le nom du système embarqué qui donne la localisation ; pour nous c'est le système GPS, soit LocationManager.GPS_PROVIDER ; cela pourrait aussi être le réseau téléphonique.
  • minTime: le temps minimum (millisecondes) entre deux retours d'information de localisation ;
  • minDistance: la distance minimum (m) entre deux retours d'information de localisation ;
  • listener: un objet de la classe LocationListener. La méthode LocationListener.onLocationChanged(...) est invoquée à chaque mise à jour de la localisation.

Travaux Pratiques

  1. Construire la classe LocalisationGPS. qui contient les attributs privés :
    • static LocalisationGPS slocalisationGPS;
    • Context mAppContext;
    • LocationManager mLocationManager;
  2. Dans un constructeur privé LocalisationGPS(Context appContext)
    • fixer le contexte mAppContextau contexte appContext
    • lier l'attribut mLocationManager au LocationManager d'Android
  3. Construire la méthode publique statique LocalisationGPS get(Context c) qui
    • instancie l'objet slocalisationGPS en appelant le constructeur privé si l'objet n'est pas encore instancié
    • retourne l'objet slocalisationGPS sinon.
  4. Construire une méthode startLocationUpdates(). Elle invoque requestLocationUpdates sur l'objet mLocationManager avec des paramètres cohérents : le dernier paramètre est un écouteur construit à la volée par new LocationListener(){}. Demander à éclipse de générer automatiquement les méthodes à implanter.
  5. Dans la méthode onLocationChanged(Location location) de cet écouteur, ajouter en fin d'output l'information de localisation (si celle-ci n'est pas nulle):
  Log.d(this.getClass().getName(),location.toString());
  1. Dans la méthode onCreate de la classe MainActivity, récupérer une instance de LocalisationGPS et exécuter la méthode startLocationUpdates() de cet objet.
  2. Pour vérifier la correction du code :
    1. lancer l'émulateur android et repérer le numéro de port dans la barre de menu (par exemple 5554)
    2. se connecter en telnet à l'émulateur sur ce numéro de port (telnet localhost 5554)
    3. lui envoyer des coordonnées arbitraires (geo fix 6.864695 47.636753) et repérer le bon affichage dans le LogCat.

Transmettre la position via une intention:

Jusqu'à présent, la méthode onLocationChanged ne fait que mémoriser la position pour le LogCat. On va envoyer (broadcast) à l'OS Android une intention contenant l'information de localisation et on va construire un récepteur actif pour cette forme particulière d'intention.

Envoyer une intention

La méthode broadcastLocation(Location location) de la classe LocalisationGPS efectue le travail d'envoie.

  private void broadcastLocation(Location location) {
    Intent broadcast = new Intent(ACTION_LOCATION);
    broadcast.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
    mAppContext.sendBroadcast(broadcast);
  }

  • ACTION_LOCATION est une constante publique statique de la classe LocalisationGPS qui définit cette famille de message. Par exemple "com.example.android_localisation.ACTION_LOCATION"
  • les trois lignes suivantes ajoutent à l'intention les informations de position

Récupérer ces intentions

Là où l'on veut récupérer cette intention (Fragment, Activity), il suffit d'avoir un objet de type BroadcastReceiver que l'on définit à la volée comme suit :

  private BroadcastReceiver mLocationReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context arg0, Intent arg1) {
      Location loc = 
       Location)arg1.getParcelableExtra(LocationManager.KEY_LOCATION_CHANGED);   
      if (loc != null) {
         // traitement de la position	
      }
    }
  };

Il reste à activer ce récepteur et permettre son extinction. On définit pour cela les deux méthodes suivante construite pour des fragments.

  @Override
  public void onStart() {
    super.onStart();
    getActivity().registerReceiver(mLocationReceiver, 
    new IntentFilter(LocalisationGPS.ACTION_LOCATION));
  }

  @Override
  public void onStop() {
    getActivity().unregisterReceiver(mLocationReceiver);
    super.onStop();
  }	

Travaux Pratiques

Mettre à jour le code de l'application en prenant en compte les intentions et les fragments

Google Maps Android v2

La version 2 de l'API Google Maps Android nécessite de signer chaque application qui l'embarque. Il faut pour cela

  1. Construire une signature du package définissant l'application ;
  2. Créer un projet google qui embarque cette API ;
  3. Ajouter cette signature à ce projet.

Cette partie de TP montrer comment faire ceci.

Gérer les clefs de l'application

  1. L'empreinte de la clef publique SHA1 est accessible dans Windows > Preferences > Android> Build. La retenir.

keytool -list -v -keystore ~/.android/debug.keystore

Un projet Android déclaré et signé

  1. Dans un navigateur, se connecter sur https://code.google.com/apis/console/ (à l'aide d'un identifiant gmail);
  2. Dans l'onglet Project, créer un nouveau projet;
  3. Ajouter à ce projet l'API Google Maps Android API v2
  4. Dans l'onglet Api & Auth, choisir Credentials, CREATE NEW KEY puis "Android Key'''. On remplit enfin le champ demandé avec l'empreinte SHA1 donnée à la section précédente suivie du nom du package.

45:B5:E4:6F:36:AD:0A:98:94:B4:02:66:2B:12:17:F2:56:26:A0:E0;com.example

  1. On mémorise l'API Key.

Signer l'application

Dans le manifest de l'application, il suffit d'insérer l'élément suivant :

  <meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="API_KEY"/>

comme un enfant de l'élément <application> juste avant le tag </application>. On substituera API_KEY par votre API key générée à la section précédente.

Chargement de la bibliothèque "google_play_services-lib"

Notre application est basée sur GoogleAPI et sur google_play_services-lib". On doit donc d'abord changer le support de compilation pour prendre une Google API convenable. Il est nécessaire ensuite d'inclure la bibliothèque google_play_services-lib au projet. Pour cela on fait successivement :

  1. Dans le SDK manager, installer l'extra Google Play services
  2. Importer un code existant Android dans le workspace
  3. Choisir RepSDK/extras/google/google_play_services/
  4. Editer les propriétés android du projet existant
  5. En cliquant sur Add, on ajoute la bibliothèque google_play_services

Un fragment pour l'affichage de la carte

L'objectif est de remplacer la ScrollView par une carte. On va remplacer le AffichageLocalisationFragment par un AffichageCarteFragment. Le premier héritait de Fragment. Celui-ci hérite de SupportMapFragment.

On commence par construire la classe AffichageCarteFragment

  1. Dupliquer AffichageLocalisationFragment, renommer la classe AffichageCarteFragment et préciser que la classe hérite maintenant de SupportMapFragment.
  2. Dans le Manifest, ajouter les données suivantes pour pouvoir utiliser SupportMapFragment

<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

  1. Ajouter l'attribut privé mGoogleMap de type GoogleMap
  2. Modifier le onCreateView comme suit:
  @Override
    public View onCreateView(LayoutInflater inflater, 
                   ViewGroup parent, Bundle savedInstanceState) {
      View v = super.onCreateView(inflater, parent, savedInstanceState);
      mGoogleMap = getMap();
      mGoogleMap.setMyLocationEnabled(true);	 
      return v;
}

Ensuite, il reste à modifier légèrement MainActivity pour qu'elle charge ce fragment:

@Override

  protected Fragment createFragment() {
    return new 	AffichageCarteFragment();
    //return new AffichageLocalisationFragment();

}

Pour aller plus loin :

Modifier la carte

Le code ci dessous,

  • ajoute l'icone triangle.png enregistré dans le dossier drawable en le point dont les coordonnées sont données par l'objet loc de type Location
  • déplace le centre de la carte en le même point
  • fixe le zoom à 15
  mGoogleMap.addMarker(new MarkerOptions()	          
                .icon(BitmapDescriptorFactory.fromResource(R.drawable.triangle))
	             .anchor(0.0f, 1.0f) // Anchors the marker on the bottom left
	              .position(new
                                LatLng(loc.getLatitude(),loc.getLongitude())));
CameraUpdate center= CameraUpdateFactory.newLatLng(new
                                LatLng(loc.getLatitude(),loc.getLongitude()));
  mGoogleMap.moveCamera(center);

  CameraUpdate zoom=CameraUpdateFactory.zoomTo(15);
  mGoogleMap.animateCamera(zoom);

Correspondances entre adresses physiques et coordonnées GPS

L'API Android fournit la classe Geocoder qui convertit les coordonnées GPS en adresse physique et vice-versa. Le calcul de la correspondance n'est pas effectué sur le mobile : il est effectué sur un serveur de Google. Pour pouvoir être exécutée, l'application devra donc disposer d'une autorisation d'utiliser Internet comme dans la section précédente.

Dans l'activité où l'on souhaite trouver cette correspondance on définit le Geocoder comme suit

   Geocoder gc = new Geocoder(this);            

On peut alors récupérer un objet de type Adress qui est celle qui est la plus proche du lieu. Pour cela on exécute

   gc.getFromLocation(latitude,longitude, 1).get(0);             

où latitude et longitude sont de de type double.

TP :

  1. Instancier le geocoder dans la méthode onLocationChanged
  2. En exploitant les méthodes de la classe Address, afficher dans le textview output l'adresse la plus proche du lieu où l'utilisateur est.
  3. Tester avec les coordonnées GPS suivantes
    • -1.367563 46.204812
    • 2.289844 48.860732,
    • -74.012233 40.711164

Page Actions

Recent Changes

Group & Page

Back Links