4. session sept 2014 Yann Caron (c) 2014 4
GPS
GPS == Global Positioning System
Un total de 24 satellites (21 + 3 secours) autour du
globe répartis sur 6 orbites
Utilise des satellites NAVSTAR (Navigation Satellite
Timing And Ranging) diffusant leur position et l'heure
Situés à 20 184 km de la surface du globe, parcourent
leur orbite en 12 h et émettent à des fréquences dans
la bande des micro-ondes (~1500Mhz).
Slide original (c) JMF
5. session sept 2014 Yann Caron (c) 2014 5
Temps de propagation
Le GPS se synchronise puis calcule la distance avec le satellite
grâce à la différence de temps en émission et réception
Distance = deltaT * c (célérité du signal dans l'air ~ vitesse de
la lumière : ~300 000 km/s)
Delta
T1
T2
6. session sept 2014 Yann Caron (c) 2014 6
Triangulation
Fonctionnement par triangulation : 4 positions
sont nécessaires pour calculer la position.
Un de plus par dimension souhaitée. 3D == 4
satellites Avec 3 satellites : vous êtes ici !!
Sur un plan à 2 dimensions
Mais à quelle altitude ??
Avec 2 satellites :
2 points possibles
Avec 1 satellite :
circonférence
7. session sept 2014 Yann Caron (c) 2014 7
Triangulation - Sphères
En 3D, il faut imaginer des sphères :
Si les 2 points
sont sur la
surface de la
Terre, il faut un
4e satellite
8. session sept 2014 Yann Caron (c) 2014 8
GPS - Précision
Précision de 15 à 100 mètres
WASS (US)/EGNOS (Eur) affinent la précision
avec des balises au sol (< 3 mètres)
Slide original (c) JMF
9. session sept 2014 Yann Caron (c) 2014 9
SBAS
SBAS – Satellite-based Augmentation Systems
Réseau de stations au sol (WMS Wide Area reference
Station) qui connaissent leur position et la comparent
aux
coordonnées calculées par
GPS. La correction est ensuite
envoyée aux satellites via des
satellites géostationnaires
10. session sept 2014 Yann Caron (c) 2014 10
Géolocalisation par relais
La même chose, mais par relais téléphoniques
GSM ou Wifi
Conseillé, car consomme moins d'énergie
(batterie) et la réception est meilleure
Source :
http://developer.android.com/guide/topics/loc
ation/strategies.html
11. session sept 2014 Yann Caron (c) 2014 11
Géolocalisation CellID - GSM
L'altitude est connue
Fonctionne par
recouvrement et non
triangulation
Cell-Id : évalue quels relais
sont accessibles et déduit
la zone de recouvrement
13. session sept 2014 Yann Caron (c) 2014 13
Géolocalisation - Android
Pour utiliser la géolocalisation sur Android, il
suffit de faire appel au bon service :
Context.LOCATION_SERVICE
Deux façons de procéder :
➔
En récupérant la dernière position connue
➔
De façon évènementielle, c'est-à-dire recevoir une
mise à jour régulière via un callback (système
évènementiel)
14. session sept 2014 Yann Caron (c) 2014 14
Dernière position connue
LocationManager locationManager =
(LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
String provider = locationManager.getBestProvider(criteria, false);
Location location = locationManager.getLastKnownLocation(provider);
// Initialize the location fields
if (location != null) {
float lat = (float) (location.getLatitude());
float lng = (float) (location.getLongitude());
Log.i(BaitFragment.class.getName(), String.valueOf(lat));
Log.i(BaitFragment.class.getName(), String.valueOf(lng));
} else {
Log.i(BaitFragment.class.getName(), "Provider not available");
Log.i(BaitFragment.class.getName(), "Provider not available");
}
Service
Dernière position connue
15. session sept 2014 Yann Caron (c) 2014 15
Géolocalisation Android - Callback
On veut être notifié régulièrement pour traiter
les changements
➔
Par exemple pour tracer le déplacement sur une
carte, calculer la vitesse, le déplacement
Il suffit de le demander au service et d'y
abonner un callback (évènement)
16. session sept 2014 Yann Caron (c) 2014 16
Géolocalisation Android - Callback
LocationManager locationManager =
(LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10, 1,
locationListener);
Service
Appelé lorsque la position change ou périodiquement
Attache le callback
17. session sept 2014 Yann Caron (c) 2014 17
Géolocalisation – Permissions
Deux providers : NETWORK_PROVIDER (GSM et
Wifi) et GPS_PROVIDER
Il faut ajouter des autorisations à l'application
➔
ACCESS_COARSE_LOCATION : pour la
localisation à base de réseaux
➔
ACCESS_FINE_LOCATION : comme la précédente,
le GPS en plus
18. session sept 2014 Yann Caron (c) 2014 18
IN01 – Séance 05
Google Maps – Mise en œuvre
19. session sept 2014 Yann Caron (c) 2014 19
Google Maps
L'avantage d'Android est de bénéficier d'applications
développées par Google… dont Google Maps
Une API est mise à disposition gratuitement depuis le SDK
Manager.
Il suffit de la télécharger et de demander une clé (API Key)
Référence :
https://developers.google.com/maps/documentation/and
roid
Slide original (c) JMF
20. session sept 2014 Yann Caron (c) 2014 20
Google Maps
On utilise donc les Google Maps Android API v2
Cette API permet de manipuler des cartes terrestres
Ces classes se trouvent dans le package
com.google.android.gms.maps
Pour afficher une carte, on utilise soit un fragment soit une vue
Cette API gère les entrées clavier, le zoom, le toucher sur une
carte affichée
On peut dessiner, ajouter des images, des marqueurs et des
infos sur la carte
Slide original (c) JMF
21. session sept 2014 Yann Caron (c) 2014 21
Google Maps
Pour utiliser les cartes Google, il faut suivre les étapes
suivantes :
➔
1 - Charger la bibliothèque Google Play Services SDK
➔
2 - Importer cette bibliothèque dans votre projet
➔
3 - Obtenir une clé Maps API v2 Key
➔
4 - Configurer l'AndroidManifest.xml de l'application
➔
5 - Écrire une activité demandant à afficher une carte Google
Toute la procédure est indiquée à
https://developers.google.com/maps/documentation/android/st
art
Slide original (c) JMF
22. session sept 2014 Yann Caron (c) 2014 22
1 - Chargement
Depuis l'ADT (Eclipse),
il faut lancer l'Android
SDK manager
Choisir Extras/Google
Play Services
Sélectionner et cliquer
sur Installer
23. session sept 2014 Yann Caron (c) 2014 23
2 – Importer la bibliothèque
Dans le projet Eclipse,
sélectionner la
bibliothèque par File /
Import
Dans la fenêtre
sélectionner Android /
Existing Android
Code Into Workspace
Slide original (c) JMF
24. session sept 2014 Yann Caron (c) 2014 24
2 – Importer la bibliothèque
Parcourir le disque pour
trouver le répertoire
<android
sdkfolder>/extras/goo
gle/google_play_servi
ces/libproject/google
playservices_lib
Cliquer Finish
La bibliothèque est
maintenant intégrée au
workspace
Slide original (c) JMF
25. session sept 2014 Yann Caron (c) 2014 25
2 – Importer la bibliothèque
Cliquer sur le projet, puis propriétés
Dans la fenêtre Properties,
sélectionner Android (colonne de
gauche)
Dans la fenêtre de dialogue "Project
Selection", sélectionner la
bibliothèque (library) google
playservices_lib.
Cette bibliothèque apparait dans la
partie Library du projet (en bas à
droite). Cliquer Apply puis OK dans
la fenêtre "Properties for leProjet "
26. session sept 2014 Yann Caron (c) 2014 26
3 – Obtenir une clé
Il faut fournir à Google le certificat qui sert à
signer l'application et le nom du package ex. :
fr.cnam.in01.pecheurDuLeman
Une fois la clé obtenue, il faut ajouter les
informations au fichier Manifest.xml
27. session sept 2014 Yann Caron (c) 2014 27
3 – Obtenir une clé
Il faut activer GoogleMapsAndroidv2
Dans la Google Developers Console
URL : http://code.google.com/apis/console
Accepter les termes de la licence
29. session sept 2014 Yann Caron (c) 2014 29
3 – Obtenir une clé
Dans API Project/
APIS & AUTH/
Credentials
Il faut créer une clé
Android dans : Public
API access
30. session sept 2014 Yann Caron (c) 2014 30
3 – Obtenir une clé
Il faut copier l'empreinte sha1 depuis Eclipse
(Window/Preferences/Android/Build)
31. session sept 2014 Yann Caron (c) 2014 31
3 – Obtenir une clé
Copier l'empreinte suivie d'un point-virgule et
du nom du package de l'application
exemple :
32. session sept 2014 Yann Caron (c) 2014 32
3 – Obtenir une clé
Copier l'API KEY dans un tag <meta-data> du manifest
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="AIzaSyAO5eGksIpKNF7kUTuG5Qe3dCCIBG_hXKc"/>
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
33. session sept 2014 Yann Caron (c) 2014 33
4 – Configurer AndroidManifest.xml
Il faut ensuite créer une permission personnalisée dans le
manifest de l'app :
Et quelques permissions standard
<permission
android:name="fr.cnam.pecheurduleman.permission.MAPS_RECEIVE"
android:protectionLevel="signature" />
<uses-permission
android:name="fr.cnam.pecheurduleman.permission.MAPS_RECEIVE" />
<uses-permission
android:name="fr.cnam.pecheurduleman.permission.MAPS_RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
34. session sept 2014 Yann Caron (c) 2014 34
4 – Configurer AndroidManifest.xml
Ainsi que quelques paramètres optionnels :
➔
Pour géolocaliser
➔
Pour le rendu 3D
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:glEsVersion="0x00020000"
android:required="true"/>
37. session sept 2014 Yann Caron (c) 2014 37
Utiliser MapView
Une nouvelle vue à disposition : MapView
Attention !! Si cette vue est utilisée, il faut
relayer tous les évènements du conteneur
(Activity, Fragment) vers la vue
C.-à-d. : onCreate(), onDestroy(), onResume() et
onPause()
Sinon ça n'affiche rien (mauvaise expérience !!)
38. session sept 2014 Yann Caron (c) 2014 38
Dans le fichier XML
On peut désormais ajouter la vue dans une
Activity ou un Fragment. Ce sera un fragment.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.google.android.gms.maps.MapView
android:id="@+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
39. session sept 2014 Yann Caron (c) 2014 39
Dans le fichier Java
public class PlaceMapFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_map, container, false);
mapView = (MapView) v.findViewById(R.id.mapview);
mapView.onCreate(savedInstanceState);
MapsInitializer.initialize(this.getActivity());
return v;
}
@Override
public void onResume() {
mapView.onResume();
super.onResume();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}
On relaye les évènements
41. session sept 2014 Yann Caron (c) 2014 41
Types de Map
Il existe plusieurs types de maps : NORMAL, HYBRID,
SATELLITE, TERRAIN, NONE (juste la grille)
Propriété Java :
setMapType(GoogleMap.MAP_TYPE_NORMAL)
Tag XML : mapType
Attention ! Il faut ajouter le xml name space (xmlns)
dans la vue ou le layout XML :
xmlns:map="http://schemas.android.com/apk/res-auto"
42. session sept 2014 Yann Caron (c) 2014 42
Propriétés importantes
Position initiale de la caméra :
cameraTargetLat, cameraTargetLng,
cameraZoom, cameraBearing, cameraTilt
Contrôles visuels : uiZoomControls,
uiCompass
Comportement de la gesture :
uiZoomGestures, uiScrollGestures,
uiRotateGestures, uiTiltGestures
45. session sept 2014 Yann Caron (c) 2014 45
Placer la caméra
Un site web bien utile : http://www.gps-
coordinates.net/ pour obtenir les coordonnées
géographiques
46. session sept 2014 Yann Caron (c) 2014 46
Placer la caméra
Le placement est animé
Il faut créer un objet LatLng (un tuple latitude et longitude)
Ou utiliser la dernière position connue (GPS ?)
MapsInitializer.initialize(this.getActivity());
// position
LatLng annemasse = new LatLng(46.193253, 6.2341579);
// positionnement initial
map.moveCamera(CameraUpdateFactory.newLatLngZoom(annemasse, 15));
// animation
map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
Zoom initial
Durée de l'animation
Type d'animation et données
d'arrivée
Obligatoirement avant
48. session sept 2014 Yann Caron (c) 2014 48
Ajouter un marqueur
Marqueur par défaut
On définit une position et un titre
La propriété snippet(), c'est le texte qui apparait
lorsque l'utilisateur clique sur le marqueur
map.addMarker(new MarkerOptions()
.position(annemasse)
.title("Ma maison")
.snippet("J'habite Annemasse")
);
50. session sept 2014 Yann Caron (c) 2014 50
Custom info windows
On peut personnaliser la fenêtre d'informations
(titre et snippet)
51. session sept 2014 Yann Caron (c) 2014 51
Custom info windows
Comme pour toute
UI, il est possible de
tout écrire en Java
ou en XML (inflater)
Il faut prévoir des
TextView pour le
titre et le texte du
snippet
<android.support.v7.widget.GridLayout
xmlns:android="http://schemas.android.com/apk/
res/android"
xmlns:app="http://schemas.android.com/apk/
res/fr.cnam.pecheurduleman"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:columnCount="2" >
<ImageView
android:src="@drawable/fish_green"
app:layout_rowSpan="2" />
<TextView
android:id="@+id/info_title"
android:layout_margin="5dp"
android:textSize="20dp"
android:textColor="#ff00760f" />
<TextView
android:id="@+id/info_snippet"
android:layout_margin="5dp"
android:textSize="15dp"
android:textColor="#ff303030" />
</android.support.v7.widget.GridLayout>
52. session sept 2014 Yann Caron (c) 2014 52
Custom info windows
Il suffit d'implémenter l'interface InfoWindowAdapter
map.setInfoWindowAdapter(new InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
return null;
}
@Override
public View getInfoContents(Marker marker) {
View v = inflater.inflate(R.layout.map_info_window, null);
TextView title = (TextView) v.findViewById(R.id.info_title);
title.setText(marker.getTitle());
TextView snippet = (TextView) v.findViewById(R.id.info_snippet);
snippet.setText(marker.getSnippet());
return v;
}
});
53. session sept 2014 Yann Caron (c) 2014 53
InfoWindowAdapter
Deux méthodes à implémenter :
➔
getInfoWindow() : permet de customiser toute la
fenêtre
➔
getInfoContents() : permet de ne customiser que
le contenu de la fenêtre
Attention !! Dans le cas où on implémente
getInfoContents(), la vue est chargée comme
une image statique (pas de changement possible)
54. session sept 2014 Yann Caron (c) 2014 54
Plus d'informations
setOnInfoWindowClickListener() : comme son
nom l'indique, permet de brancher un callback
sur le clic de l'info window
map.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick(Marker marker) {
Log.i(PlaceMapFragment.class.getName(),
"On a cliqué sur " +
marker.getTitle() +
" [" + marker.getSnippet() + "]");
}
});
Le marqueur
56. session sept 2014 Yann Caron (c) 2014 56
Dessiner sur la carte
Il est possible de dessiner des formes géométriques sur
la carte selon des coordonnées géographiques
➔
Des cercles : addCircle()
➔
Des polygones : addPolygone()
➔
Des polylines (polygone vide) : addPolyline()
➔
Des images : addGroundOverlay()
➔
Des textures : addTileOverlay(). Ce dernier permet de
décorer ou de remplacer les images de terrain fournies par
Google. Il faut gérer les niveaux de zoom
57. session sept 2014 Yann Caron (c) 2014 57
Exemple de dessin
map.addCircle(new CircleOptions()
.center(annemasse)
.radius(1000) // en mètres
.strokeWidth(5).strokeColor(Color.GRAY));
map.addCircle(new CircleOptions()
.center(portChoiseul)
.radius(1000) // en mètres
.strokeWidth(5).strokeColor(Color.GRAY));
map.addPolyline((new PolylineOptions())
.add(annemasse, portChoiseul,
corsierPort, annemasse)
.width(5).color(Color.BLUE)
.geodesic(true));
Coordonnées LatLng
58. session sept 2014 Yann Caron (c) 2014 58
Dessiner un trajet entre deux points
Principe : faire une requête sur le service web de
googleMap apis
On peut choisir son format XML ou JSON
Celui-ci renvoie la route sous deux formes :
➔
La description textuelle du trajet
➔
Un nuage de points sous forme binaire
https://maps.googleapis.com/maps/api/directions/json?
origin=46.193253,6.2341579&destination=46.290144,6.1657870&sens
or=false
60. session sept 2014 Yann Caron (c) 2014 60
Dessiner un trajet entre deux points
Il nous faut parser le JSON ou le XML téléchargé
Et dessiner un polyline sur la carte
Tout est décrit ici :
http://wptrafficanalyzer.in/blog/drawing-driving-
route-directions-between-two-locations-using-
google-directions-in-google-map-android-api-v2/
61. session sept 2014 Yann Caron (c) 2014 61
Pour référence – Le décodeur
private List<LatLng> decodePoly(String encoded) {
List<LatLng> poly = new ArrayList<LatLng>();
int index = 0, len = encoded.length();
int lat = 0, lng = 0;
while (index < len) {
int b, shift = 0, result = 0;
do {
b = encoded.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 = encoded.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)));
poly.add(p);
}
return poly;
}
62. session sept 2014 Yann Caron (c) 2014 62
Conclusion
Une API très puissante. Un grand nombre de
possibilités
Utilisation de la géolocalisation (tracés temps réels,
enregistrement de position)
Utilisation de services web, quelques idées :
➔
Windspot (afficher les vents), Météo, METAR (afficher les
données météo aéronautiques par aéroports)
D'autres idées ??
63. session sept 2014 Yann Caron (c) 2014 63
Pour aller plus loin
Google met à disposition StreetView dans son API :
StreetViewPanoramaFragment
My location button setMyLocationButtonEnabled et
setOnMyLocationButtonClickListener
Afficher les batiments : setBuildingEnabled
Incliner la caméra : CameraPosition.Builder.bearing,
target, tilt et zoom
Évènements : setOnMapClickListener