Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.
Recomendación
No probar ejercicios que impliquen geolocalización en el emulador. Unos funcionan, otros no, otros funcionan mal, etc.
Geolocalización
La podemos obtener por 3 medios:
- GPS: (el más preciso y lento (puede tardar incluso más de un minuto)). 2 metros de error.
- Red móvil: El móvil detecta 3 antenas, hace un triángulo (el método se llama triangulación) y detecta la posición (con un margen de error de 20, 50 m…) depende de la distancia con las antenas. En ciudad hay menos error que en el campo. Tarda unos segundos
- Wi-Fi: Funciona si estoy conectado a una red WI-FI. El móvil detecta el SSID (nombre de la red) de la wi-fi y accede a una base de datos donde tiene registrada su ubicación.
La geolocalizacion del emulador no funciona correctamente pq no tiene ni gps, ni red móvil ni han integrado la geolocalización por wi-fi.
Para falsear la geolocalización del emulador: window-> show view -> other -> emulator control
Habrá que asegurarse de tener el device seleccionado en el momento de pulsar el botón de send.
Habrá que añadir los siguientes permisos:
<!--Localización usando la red WI-FI: -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--Localización usando el GPS -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Location Manager
Vamos a mostrar las coordenadas en un TextView
Tendremos que solicitar permisos al usuario de forma similar a como lo hicimos cuando queríamos acceder a los contactos.
private static final int MY_PERMISSIONS_CODE = 999;
private TextView coordenadas;
private LocationManager locationManager;
private LocationListener listener = new LocationListener() {
public void onLocationChanged(Location location) {
coordenadas.setText("Latitud: " + location.getLatitude() + "Longitud: " + location.getLongitude());
}
@Override public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override public void onProviderEnabled(String provider) {}
@Override public void onProviderDisabled(String provider) {}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mapas_locationmanager);
coordenadas = findViewById(R.id.coordenadas);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
checkPermisions();
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_CODE: {
if (grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED) {
requestLocation();
} else {
// permission denied, boo! Disable the functionality that depends on this permission.
}
}
}
}
public void onResume() {
super.onResume();
requestLocation();
}
public void onPause() {
super.onPause();
locationManager.removeUpdates(listener);
}
private void checkPermisions() {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.INTERNET,
},
MY_PERMISSIONS_CODE);
} else {
requestLocation();
}
} else {
requestLocation();
}
}
@SuppressLint("MissingPermission")
private void requestLocation() {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 500, 0, listener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 500, 0, listener);
}
Añadir un mapa
¿Qué es un fragmento?
Es una parte de una Activity, que tiene su propio ciclo de vida, recibe sus propios eventos de entrada, y que se puede añadir o quitar dinámicamente.
Paso 1: Cargar las librerías
- Obtener una Map API Key (modo debug): https://cloud.google.com/console → Seleccionamos en la barra horizontal superior el proyecto actual y se abrirá un panel que nos permitirá crear un nuevo proyecto → Create Project → APIs → go to the api’s overview → enable API → Maps SDK for Android → Enable → Credentials → Credenciales en APIs y servicios → Create Credentials → Clave de API → anotamos la API key.
- Vista Android → Gradle Scripts → build.gradle (de módulo) → en dependencias añado lo siguiente:
implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'com.google.android.gms:play-services-base:17.1.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
3. Además, en el layout habrá que añadir el siguiente código que representará el mapa:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment"/>
Paso 2: modificar el AndroidManifest.xml
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="AIzaSyDKH-mnui5hMmO3wnTdrmXy4V5IVs6KTR8" />
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
</application>
</manifest>
Paso 3: Añadir el mapa en el código Java
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SupportMapFragment mapFragment = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
Centrar mapa en la posición del usuario y seguirlo
@SuppressLint("MissingPermission")
private void requestLocation() {
Location currentLocation = null;
for(String provider: locationManager.getAllProviders()){
Location aux = locationManager.getLastKnownLocation(provider);
if(aux!=null){
Log.d("traza", "best Provider " + provider);
currentLocation = aux;
break;
}
}
if (currentLocation!=null) {
updateMapaWith(new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()));
}
Log.d("traza", "last location " + currentLocation);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 500, 0, listener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 500, 0, listener);
}
private void updateMapaWith(LatLng latLng){
if (googleMap != null) {
CameraPosition camPos = new CameraPosition.Builder()
.target(latLng) //Centramos el mapa en Madrid
.zoom(19) //Establecemos el zoom en 19
.bearing(45) //Establecemos la orientación con el noreste arriba
.tilt(70) //Bajamos el punto de vista de la cámara 70 grados
.build();
CameraUpdate camUpd = CameraUpdateFactory.newCameraPosition(camPos);
googleMap.animateCamera(camUpd);
}
}
Añadir un marcador
googleMap.addMarker(new MarkerOptions()
.position(new LatLng(41.431725, 2.192188))
.snippet("Tadel Formació")
.title("Centre de formació")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.escudo)));
Ejercicio Sqlite
Hacer una aplicación que utilizando una base de datos SqlLite situe en pantalla 3 puntos, identificados por el logo suministrado. Al pulsar sobre el logo, iremos a una pantalla dónde se mostrará información del enclave pulsado.
Recursos:
Utilizaremos el HashMap tabla para que al hacer click en un marker podamos obtener su id y a continuación pasársela al siguiente activity:monumentos es un HashMap de objetos Monumento.
@Override
public boolean onMarkerClick(Marker arg0) {
int idMonumento = tabla.get(arg0);
startActivity(new Intent(this,LugarActivity.class).putExtra(MONUMENTO, monumentos.get(idMonumento)));
return true;
}
Para recibir el monumento:
Monumento monumento = (Monumento) getIntent().getExtras().getSerializable(GeolocalizacionCapasActivity.MONUMENTO);
Obtener la ubicación de cierto lugar
String direccion = "Camino de Rubin 2, Gijón";
Geocoder geocoder = new Geocoder(this);
List<Address> addresses;
addresses = geocoder.getFromLocationName(direccion, 1);
if(addresses.size() > 0) {
double latitude= addresses.get(0).getLatitude();
double longitude= addresses.get(0).getLongitude();
tv.setText("Latitud="+latitude+" Longitud="+longitude);
}
Rutas
Debemos activar la Directions API en la sección API’s overview de la Google Developer Console.
También debemos activar la facturación para esta cuenta. Ojo con todo lo que ello conlleva.
MainActivity.java
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, TaskLoadedCallback {
private GoogleMap mMap;
private MarkerOptions place1, place2;
Button getDirection;
private Polyline currentPolyline;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rutas);
//27.658143,85.3199503
//27.667491,85.3208583
place1 = new MarkerOptions().position(new LatLng(22.3039, 70.8022)).title("Location 1");
place2 = new MarkerOptions().position(new LatLng(23.0225, 72.5714)).title("Location 2");
new FetchURL(MainActivity.this).execute(getUrl(place1.getPosition(), place2.getPosition(), "driving"), "driving");
SupportMapFragment miMapa = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
miMapa.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
Log.d("mylog", "Added Markers");
mMap.addMarker(place1);
mMap.addMarker(place2);
CameraPosition googlePlex = CameraPosition.builder()
.target(new LatLng(22.7739,71.6673))
.zoom(7)
.bearing(0)
.tilt(45)
.build();
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(googlePlex), 5000, null);
}
private String getUrl(LatLng origin, LatLng dest, String directionMode) {
// Origin of route
String str_origin = "origin=" + origin.latitude + "," + origin.longitude;
// Destination of route
String str_dest = "destination=" + dest.latitude + "," + dest.longitude;
// Mode
String mode = "mode=" + directionMode;
// Building the parameters to the web service
String parameters = str_origin + "&" + str_dest + "&" + mode;
// Output format
String output = "json";
// Building the url to the web service
String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters + "&key=AIzaSyBKJ43pjK3x1GQjnO0zaYUwDJHdy5LiooU";
return url;
}
@Override
public void onTaskDone(Object... values) {
if (currentPolyline != null)
currentPolyline.remove();
currentPolyline = mMap.addPolyline((PolylineOptions) values[0]);
}
}
TaskLoadedCallback.java
public interface TaskLoadedCallback {
void onTaskDone(Object... values);
}
FetchURL.java
public class FetchURL extends AsyncTask<String, Void, String> {
Context mContext;
String directionMode = "driving";
public FetchURL(Context mContext) {
this.mContext = mContext;
}
@Override
protected String doInBackground(String... strings) {
// For storing data from web service
String data = "";
directionMode = strings[1];
try {
// Fetching the data from web service
data = downloadUrl(strings[0]);
Log.d("mylog", "Background task data " + data.toString());
} catch (Exception e) {
Log.d("Background Task", e.toString());
}
return data;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
PointsParser parserTask = new PointsParser(mContext, directionMode);
// Invokes the thread for parsing the JSON data
parserTask.execute(s);
}
private String downloadUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
// Creating an http connection to communicate with url
urlConnection = (HttpURLConnection) url.openConnection();
// Connecting to url
urlConnection.connect();
// Reading data from url
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
data = sb.toString();
Log.d("mylog", "Downloaded URL: " + data.toString());
br.close();
} catch (Exception e) {
Log.d("mylog", "Exception downloading URL: " + e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
}
DataParser.java
public class DataParser {
public List<List<HashMap<String, String>>> parse(JSONObject jObject) {
List<List<HashMap<String, String>>> routes = new ArrayList<>();
JSONArray jRoutes;
JSONArray jLegs;
JSONArray jSteps;
try {
jRoutes = jObject.getJSONArray("routes");
/** Traversing all routes */
for (int i = 0; i < jRoutes.length(); i++) {
jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs");
List path = new ArrayList<>();
/** Traversing all legs */
for (int j = 0; j < jLegs.length(); j++) {
jSteps = ((JSONObject) jLegs.get(j)).getJSONArray("steps");
/** Traversing all steps */
for (int k = 0; k < jSteps.length(); k++) {
String polyline = "";
polyline = (String) ((JSONObject) ((JSONObject) jSteps.get(k)).get("polyline")).get("points");
List<LatLng> list = decodePoly(polyline);
/** Traversing all points */
for (int l = 0; l < list.size(); l++) {
HashMap<String, String> hm = new HashMap<>();
hm.put("lat", Double.toString((list.get(l)).latitude));
hm.put("lng", Double.toString((list.get(l)).longitude));
path.add(hm);
}
}
routes.add(path);
}
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
}
return routes;
}
/**
* Method to decode polyline points
* Courtesy : https://jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java
*/
private List<LatLng> decodePoly(String encoded) {
List<LatLng> poly = new ArrayList<>();
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;
}
}
PointsParser.java
package com.pablomonteserin.mapas.rutas2;
import android.content.Context;
import android.graphics.Color;
import android.os.AsyncTask;
import android.util.Log;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.PolylineOptions;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class PointsParser extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {
TaskLoadedCallback taskCallback;
String directionMode = "driving";
public PointsParser(Context mContext, String directionMode) {
this.taskCallback = (TaskLoadedCallback) mContext;
this.directionMode = directionMode;
}
// Parsing the data in non-ui thread
@Override
protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) {
JSONObject jObject;
List<List<HashMap<String, String>>> routes = null;
try {
jObject = new JSONObject(jsonData[0]);
Log.d("mylog", jsonData[0].toString());
DataParser parser = new DataParser();
Log.d("mylog", parser.toString());
// Starts parsing data
routes = parser.parse(jObject);
Log.d("mylog", "Executing routes");
Log.d("mylog", routes.toString());
} catch (Exception e) {
Log.d("mylog", e.toString());
e.printStackTrace();
}
return routes;
}
// Executes in UI thread, after the parsing process
@Override
protected void onPostExecute(List<List<HashMap<String, String>>> result) {
ArrayList<LatLng> points;
PolylineOptions lineOptions = null;
// Traversing through all the routes
for (int i = 0; i < result.size(); i++) {
points = new ArrayList<>();
lineOptions = new PolylineOptions();
// Fetching i-th route
List<HashMap<String, String>> path = result.get(i);
// Fetching all the points in i-th route
for (int j = 0; j < path.size(); j++) {
HashMap<String, String> point = path.get(j);
double lat = Double.parseDouble(point.get("lat"));
double lng = Double.parseDouble(point.get("lng"));
LatLng position = new LatLng(lat, lng);
points.add(position);
}
// Adding all the points in the route to LineOptions
lineOptions.addAll(points);
if (directionMode.equalsIgnoreCase("walking")) {
lineOptions.width(3);
lineOptions.color(Color.MAGENTA);
} else {
lineOptions.width(3);
lineOptions.color(Color.RED);
}
Log.d("mylog", "onPostExecute lineoptions decoded");
}
// Drawing polyline in the Google Map for the i-th route
if (lineOptions != null) {
//mMap.addPolyline(lineOptions);
taskCallback.onTaskDone(lineOptions);
} else {
Log.d("mylog", "without Polylines drawn");
}
}
}