L’objectif est d’afficher une localisation sur une carte.
Pré-requis : Géolocalisation [PDF]
Pour afficher une localisation sur une carte, on peut utiliser :
OpenStreetMap (OSM) est un projet initié en 2004 qui a pour but de constituer une base de données géographiques libre du monde (permettant par exemple de créer des cartes sous licence libre), en utilisant le système GPS et d’autres données libres.
Android est un système d’exploitation basé sur Linux pour les téléphones mobiles et autres appareils mobiles.
Les appareils sous Android peuvent être utilisés pour afficher et éditer des cartes basées sur OpenStreetMap.
Il existe plusieurs bibliothèques permettant aux développeurs Android d’intégrer OpenStreetMap dans leurs propres applications, qu’il s’agisse d’une carte statique, d’une carte entièrement interactive ou d’utilisations plus sophistiquées telles que le géocodage et le routage.
Osmdroid est une bibliothèque Android qui fournit des outils pour interagir avec OpenStreetMap. L’OpenStreetMapView est un remplacement (presque) complet pour la classe MapView d’Android. Remarque : osmdroid est une application de démonstration disponible sur google play.
Pour intégrer la bibliothèque osmdroid dans votre application avec Android Studio, il faut éditer le fichier build.gradle
situé dans votre dossier app
:
...
dependencies {
...
compile 'org.osmdroid:osmdroid-android:5.6.5'
}
Lire : HowTo osmdroid library
L’application a besoin de certains droits d’accès (uses-permission
) et pour cela, il faut modifier le fichier AndroidManifest.xml
de l’application :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tv.myapplication6">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
...
</manifest>
On va intégrer un composant MapView
à notre GUI :
Le layout XML :
...
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<org.osmdroid.views.MapView
android:id="@+id/mapview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
...
La classe MapView est une vue qui permet d’afficher une carte. Lorsqu’elle a le focus, elle capture les pressions de touche et les gestes tactiles pour déplacer la carte.
Exemple :
...
import org.osmdroid.views.MapView;
...
private MapView myOpenMapView;
protected void onCreate(Bundle savedInstanceState)
{
...
myOpenMapView = (MapView)findViewById(R.id.mapview);
myOpenMapView.setBuiltInZoomControls(true);
myOpenMapView.setClickable(true);
myOpenMapView.getController().setZoom(15);
...
}
...
On utilisera la méthode setCenter()
pour se déplacer en un point de la carte :
...
LocationListener ecouteurGPS = new LocationListener() {
@Override
public void onLocationChanged(Location localisation)
{
...
myOpenMapView.getController().setCenter(new GeoPoint(localisation.getLatitude(), localisation.getLongitude()));
...
}
}
On peut ajouter une échelle sur la carte en superposition à l’aide de la classe ScaleBarOverlay
:
ScaleBarOverlay myScaleBarOverlay = new ScaleBarOverlay(myOpenMapView);
myOpenMapView.getOverlays().add(myScaleBarOverlay);
On peut ajouter une boussole sur la carte en superposition à l’aide de la classe CompassOverlay
:
CompassOverlay mCompassOverlay = new CompassOverlay(getApplicationContext(), new InternalCompassOrientationProvider(getApplicationContext()), myOpenMapView);
mCompassOverlay.enableCompass();
myOpenMapView.getOverlays().add(mCompassOverlay);
On peut ajouter sa position GPS en superposition à l’aide de la classe MyLocationNewOverlay
:
MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(getApplicationContext()), myOpenMapView);
mLocationOverlay.enableMyLocation();
myOpenMapView.setMultiTouchControls(true);
myOpenMapView.getOverlays().add(mLocationOverlay);
Voir aussi : la classe DirectedLocationOverlay
private MapView myOpenMapView;
private DirectedLocationOverlay myLocationOverlay;
// Dans LocationListener
public void onLocationChanged(Location localisation)
{
...
// voir OSMNavigator
GeoPoint nouvelleLocalisation = new GeoPoint(localisation);
if (!myLocationOverlay.isEnabled())
{
myLocationOverlay.setEnabled(true);
myOpenMapView.getController().animateTo(nouvelleLocalisation);
}
GeoPoint localisationPrecedente = myLocationOverlay.getLocation();
myLocationOverlay.setLocation(nouvelleLocalisation);
myLocationOverlay.setAccuracy((int)localisation.getAccuracy());
if (localisationPrecedente != null && localisation.getProvider().equals(LocationManager.GPS_PROVIDER))
{
mSpeed = localisation.getSpeed() * 3.6;
long speedInt = Math.round(mSpeed);
if (mSpeed >= 0.1)
{
mAzimuthAngleSpeed = localisation.getBearing();
myLocationOverlay.setBearing(mAzimuthAngleSpeed);
}
}
myOpenMapView.getController().animateTo(nouvelleLocalisation);
myOpenMapView.setMapOrientation(-mAzimuthAngleSpeed);
...
}
...
@Override
protected void onCreate(Bundle savedInstanceState)
{
...
myLocationOverlay = new DirectedLocationOverlay(this);
myLocationOverlay.setEnabled(false);
myOpenMapView.getOverlays().add(myLocationOverlay);
...
}
On peut ajouter un Marker
(ici avec sa propre image copiée dans res -> drawable) :
Marker tec = new Marker(myOpenMapView);
tec.setPosition(new GeoPoint(localisation.getLatitude(), localisation.getLongitude()));
tec.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
tec.setIcon(getResources().getDrawable(R.drawable.trottinette));
tec.setTitle("TEC");
myOpenMapView.getOverlays().add(tec);
myOpenMapView.invalidate();
On peut ajouter un tracé à base de lignes avec la classe Polyline
:
ArrayList<GeoPoint> trajet.add(new GeoPoint(localisation.getLatitude(), localisation.getLongitude()));
Polyline line = new Polyline(getApplicationContext());
line.setTitle("Un trajet");
line.setSubDescription(Polyline.class.getCanonicalName());
line.setWidth(10f);
line.setColor(Color.RED);
line.setPoints(trajet);
line.setGeodesic(true);
line.setInfoWindow(new BasicInfoWindow(R.layout.bonuspack_bubble, myOpenMapView));
myOpenMapView.invalidate();
package com.example.tv.myapplicationcartegps;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.Criteria;
import android.location.LocationProvider;
import android.os.StrictMode;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
// before 5.2
//import org.osmdroid.DefaultResourceProxyImpl;
//import org.osmdroid.ResourceProxy;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.Marker;
import org.osmdroid.views.overlay.Polyline;
import org.osmdroid.views.overlay.ScaleBarOverlay;
import org.osmdroid.views.overlay.compass.CompassOverlay;
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider;
import org.osmdroid.views.overlay.gestures.RotationGestureOverlay;
import org.osmdroid.views.overlay.infowindow.BasicInfoWindow;
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider;
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;
public class MyActivity extends AppCompatActivity
{
LocationManager locationManager = null;
private int etat;
private String fournisseur;
private TextView latitude;
private TextView longitude;
private TextView Adresse;
private MapView myOpenMapView;
ScaleBarOverlay myScaleBarOverlay;
CompassOverlay mCompassOverlay;
MyLocationNewOverlay mLocationOverlay;
RotationGestureOverlay mRotationGestureOverlay;
ArrayList<GeoPoint> trajet;
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
LocationListener ecouteurGPS = new LocationListener() {
@Override
public void onLocationChanged(Location localisation)
{
Toast.makeText(getApplicationContext(), fournisseur + " localisation", Toast.LENGTH_SHORT).show();
Log.d("GPS", "localisation : " + localisation.toString());
String coordonnees = String.format("Latitude : %f - Longitude : %f\n", localisation.getLatitude(), localisation.getLongitude());
Log.d("GPS", coordonnees);
String autres = String.format("Vitesse : %f - Altitude : %f - Cap : %f\n", localisation.getSpeed(), localisation.getAltitude(), localisation.getBearing());
Log.d("GPS", autres);
//String timestamp = String.format("Timestamp : %d\n", localisation.getTime());
//Log.d("GPS", "timestamp : " + timestamp);
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date date = new Date(localisation.getTime());
Log.d("GPS", sdf.format(date));
String strLatitude = String.format("Latitude : %f", localisation.getLatitude());
String strLongitude = String.format("Longitude : %f", localisation.getLongitude());
latitude.setText(strLatitude);
longitude.setText(strLongitude);
myOpenMapView.getController().setCenter(new GeoPoint(localisation.getLatitude(), localisation.getLongitude()));
//myOpenMapView.setMapOrientation(localisation.getBearing());
trajet.add(new GeoPoint(localisation.getLatitude(), localisation.getLongitude()));
// Un tracé à base de lignes rouges
Polyline line = new Polyline(getApplicationContext());
line.setTitle("Un trajet");
line.setSubDescription(Polyline.class.getCanonicalName());
line.setWidth(10f);
line.setColor(Color.RED);
line.setPoints(trajet);
line.setGeodesic(true);
line.setInfoWindow(new BasicInfoWindow(R.layout.bonuspack_bubble, myOpenMapView));
myOpenMapView.getOverlayManager().add(line);
/*Marker tec = new Marker(myOpenMapView);
tec.setPosition(new GeoPoint(localisation.getLatitude(), localisation.getLongitude()));
tec.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
tec.setIcon(getResources().getDrawable(R.drawable.trottinette));
tec.setTitle("TEC");
myOpenMapView.getOverlays().add(tec);*/
/*ArrayList<OverlayItem> items = new ArrayList<OverlayItem>();
items.add(new OverlayItem("Title", "Description", new GeoPoint(localisation.getLatitude(), localisation.getLongitude())));
ItemizedOverlayWithFocus<OverlayItem> mOverlay = new ItemizedOverlayWithFocus<OverlayItem>(getApplicationContext(), items,
new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
@Override
public boolean onItemSingleTapUp(final int index, final OverlayItem item) {
Toast.makeText( getApplicationContext(), "Overlay Titled: " +
item.getTitle() + " Single Tapped" + "\n" + "Description: " +
item.getSnippet(), Toast.LENGTH_LONG).show();
return true;
}
@Override
public boolean onItemLongPress(final int index, final OverlayItem item) {
return false;
}
});
//mOverlay.setFocusItemsOnTap(true);
myOpenMapView.getOverlays().add(mOverlay);*/
myOpenMapView.invalidate();
List<Address> adresses = null;
try
{
adresses = geocoder.getFromLocation(localisation.getLatitude(), localisation.getLongitude(), 1);
}
catch (IOException ioException)
{
Log.e("GPS", "erreur", ioException);
} catch (IllegalArgumentException illegalArgumentException)
{
Log.e("GPS", "erreur " + coordonnees, illegalArgumentException);
}
if (adresses == null || adresses.size() == 0)
{
Log.e("GPS", "erreur aucune adresse !");
}
else
{
Address adresse = adresses.get(0);
ArrayList<String> addressFragments = new ArrayList<String>();
String strAdresse = adresse.getAddressLine(0) + ", " + adresse.getLocality();
Log.d("GPS", "adresse : " + strAdresse);
for(int i = 0; i <= adresse.getMaxAddressLineIndex(); i++)
{
addressFragments.add(adresse.getAddressLine(i));
}
Log.d("GPS", TextUtils.join(System.getProperty("line.separator"), addressFragments));
Adresse.setText(TextUtils.join(System.getProperty("line.separator"), addressFragments));
}
}
@Override
public void onProviderDisabled(String fournisseur)
{
Toast.makeText(getApplicationContext(), fournisseur + " désactivé !", Toast.LENGTH_SHORT).show();
}
@Override
public void onProviderEnabled(String fournisseur)
{
Toast.makeText(getApplicationContext(), fournisseur + " activé !", Toast.LENGTH_SHORT).show();
}
@Override
public void onStatusChanged(String fournisseur, int status, Bundle extras)
{
if (etat != status)
{
switch (status)
{
case LocationProvider.AVAILABLE:
Toast.makeText(getApplicationContext(), fournisseur + " état disponible", Toast.LENGTH_SHORT).show();
break;
case LocationProvider.OUT_OF_SERVICE:
Toast.makeText(getApplicationContext(), fournisseur + " état indisponible", Toast.LENGTH_SHORT).show();
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
Toast.makeText(getApplicationContext(), fournisseur + " état temporairement indisponible", Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(getApplicationContext(), fournisseur + " état : " + status, Toast.LENGTH_SHORT).show();
}
}
etat = status;
}
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.commande);
etat = 0;
latitude = (TextView) findViewById(R.id.textViewLatitude);
longitude = (TextView) findViewById(R.id.textViewLongitude);
Adresse = (TextView) findViewById(R.id.textViewAdresse);
myOpenMapView = (MapView)findViewById(R.id.mapview);
myOpenMapView.setBuiltInZoomControls(true);
myOpenMapView.setClickable(true);
myOpenMapView.getController().setZoom(18);
myScaleBarOverlay = new ScaleBarOverlay(myOpenMapView);
myOpenMapView.getOverlays().add(myScaleBarOverlay);
mCompassOverlay = new CompassOverlay(getApplicationContext(), new InternalCompassOrientationProvider(getApplicationContext()), myOpenMapView);
mCompassOverlay.enableCompass();
myOpenMapView.getOverlays().add(mCompassOverlay);
mRotationGestureOverlay = new RotationGestureOverlay(getApplicationContext(), myOpenMapView);
mRotationGestureOverlay.setEnabled(true);
myOpenMapView.setMultiTouchControls(true);
myOpenMapView.getOverlays().add(this.mRotationGestureOverlay);
trajet = new ArrayList<GeoPoint>();
Log.d("GPS", "onCreate");
initialiserLocalisation();
mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(getApplicationContext()), myOpenMapView);
mLocationOverlay.enableMyLocation();
myOpenMapView.setMultiTouchControls(true);
myOpenMapView.getOverlays().add(mLocationOverlay);
}
@Override
protected void onDestroy()
{
super.onDestroy();
arreterLocalisation();
}
private void initialiserLocalisation()
{
if (locationManager == null)
{
locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
Criteria criteres = new Criteria();
// la précision : (ACCURACY_FINE pour une haute précision ou ACCURACY_COARSE pour une moins bonne précision)
criteres.setAccuracy(Criteria.ACCURACY_FINE);
// l'altitude
criteres.setAltitudeRequired(true);
// la direction
criteres.setBearingRequired(true);
// la vitesse
criteres.setSpeedRequired(true);
// la consommation d'énergie demandée
criteres.setCostAllowed(true);
//criteres.setPowerRequirement(Criteria.POWER_HIGH);
criteres.setPowerRequirement(Criteria.POWER_MEDIUM);
fournisseur = locationManager.getBestProvider(criteres, true);
Log.d("GPS", "fournisseur : " + fournisseur);
}
if (fournisseur != null)
{
// dernière position connue
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
Log.d("GPS", "no permissions !");
return;
}
Location localisation = locationManager.getLastKnownLocation(fournisseur);
if(localisation != null)
{
// on notifie la localisation
ecouteurGPS.onLocationChanged(localisation);
}
// on configure la mise à jour automatique : au moins 10 mètres et 15 secondes
locationManager.requestLocationUpdates(fournisseur, 15000, 10, ecouteurGPS);
}
}
private void arreterLocalisation()
{
if(locationManager != null)
{
locationManager.removeUpdates(ecouteurGPS);
ecouteurGPS = null;
}
}
}
Voir : La localisation et les cartes (OpenClassRooms)