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.
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 :
Log.d(this.getClass().getName(),location.toString());
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.
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); }
où
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(); }
Mettre à jour le code de l'application en prenant en compte les intentions et les fragments
La version 2 de l'API Google Maps Android nécessite de signer chaque application qui l'embarque. Il faut pour cela
Cette partie de TP montrer comment faire ceci.
keytool -list -v -keystore ~/.android/debug.keystore
45:B5:E4:6F:36:AD:0A:98:94:B4:02:66:2B:12:17:F2:56:26:A0:E0;com.example
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.
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 :
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
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
@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();
}
Le code ci dessous,
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())));
LatLng(loc.getLatitude(),loc.getLongitude())); mGoogleMap.moveCamera(center); CameraUpdate zoom=CameraUpdateFactory.zoomTo(15); mGoogleMap.animateCamera(zoom);
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 :