es.rczone.tutoriales.gmaps.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for es.rczone.tutoriales.gmaps.MainActivity.java

Source

package es.rczone.tutoriales.gmaps;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.Color;
import android.location.Address;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;

import es.rczone.tutoriales.gmaps.address.AddressActivity;
import es.rczone.tutoriales.gmaps.gps.LocationTracker;
import es.rczone.tutoriales.gmaps.kml.NavigationDataSet;
import es.rczone.tutoriales.gmaps.kml.NavigationSaxHandler;
import es.rczone.tutoriales.gmaps.kml.Placemark;
import es.rczone.tutoriales.gmaps.route.RouteListener;
import es.rczone.tutoriales.gmaps.route.MyAsyncTask;

public class MainActivity extends android.support.v4.app.FragmentActivity
        implements RouteListener, LocationListener {

    private List<Polyline> polylinesList;
    private GoogleMap map;
    private int viewType = 0;

    private Circle circulo_radio;
    private Location currentLocation;

    //Address location
    private List<Marker> markersList;

    //Location tracking
    private LocationTracker locationTracker;
    // Milliseconds per second
    private static final int MILLISECONDS_PER_SECOND = 1000;
    // Update frequency in seconds
    public static final int UPDATE_INTERVAL_IN_SECONDS = 5;
    // Update frequency in milliseconds
    private static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
    // The fastest update frequency, in seconds
    private static final int FASTEST_INTERVAL_IN_SECONDS = 1;
    // A fast frequency ceiling in milliseconds
    private static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;

    private static final int SMALLEST_DISPLACEMENT = 5;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setUpMapIfNeeded();

        polylinesList = new ArrayList<Polyline>();
        markersList = new ArrayList<Marker>();

        map.setMyLocationEnabled(true);

        locationTracker = LocationTracker.getInstance(this);
    }

    private void setUpMapIfNeeded() {
        if (map == null) {

            Log.e("", "Into null map");
            map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();

            if (map != null) {
                Log.e("", "Into full map");
                map.setMyLocationEnabled(true);
                map.getUiSettings().setZoomControlsEnabled(false);
            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_legalnotices:
            showLegalNotice();
            break;

        case R.id.menu_view_type:
            changeTypeView();
            break;

        case R.id.menu_3d_animation:
            animation3DExample();
            break;

        case R.id.menu_camera_position:
            showCameraPosition();
            //this.pos_actual = map.getMyLocation();
            break;

        case R.id.Madrid_Barcelona:
            routeFromMadridToBarcelona();
            break;

        case R.id.enter_address:
            enterAddress();

        case R.id.kml_madrid:
            kmlOfMadrid();
            break;

        case R.id.menu_borrar_polylineas:
            borrarPolylineas();
            break;

        case R.id.menu_mostrar_radio:

            if (currentLocation == null) {
                Toast.makeText(this, "Primero debes consultar tu posicin", Toast.LENGTH_SHORT).show();
                super.onOptionsItemSelected(item);
            }

            if (circulo_radio == null) {
                LatLng pos = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());
                CircleOptions circleOptions = new CircleOptions();
                circleOptions.center(pos);
                circleOptions.radius(500); // In meters
                circleOptions.strokeColor(Color.BLUE);
                circleOptions.fillColor(Color.argb(100, 0, 0, 255));

                circulo_radio = map.addCircle(circleOptions);
            } else {
                LatLng pos = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());
                circulo_radio.setCenter(pos);
                circulo_radio.setRadius(200);
            }
            break;

        }

        return super.onOptionsItemSelected(item);
    }

    private void enterAddress() {
        Intent i = new Intent(this, AddressActivity.class);
        startActivityForResult(i, 1);
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        /**
         * Result for Address activity
         */
        if (requestCode == 1) {

            if (resultCode == RESULT_OK) {
                Address current_location = data.getExtras().getParcelable("result");
                LatLng addressLocation = new LatLng(current_location.getLatitude(),
                        current_location.getLongitude());
                CameraPosition camPos = new CameraPosition.Builder().target(addressLocation) //Center camera in 'Plaza Maestro Villa'
                        .zoom(16) //Set 16 level zoom
                        .build();

                CameraUpdate camUpd3 = CameraUpdateFactory.newCameraPosition(camPos);
                map.animateCamera(camUpd3);
                String description = current_location.getThoroughfare() + " "
                        + current_location.getSubThoroughfare() + ", " + current_location.getLocality() + ", "
                        + current_location.getCountryName();

                Marker m = map.addMarker(new MarkerOptions().position(addressLocation));
                markersList.add(m);

                Toast.makeText(this, description, Toast.LENGTH_LONG).show();
            }
            if (resultCode == RESULT_CANCELED) {
                // Write your code if there's no result
            }
        }
    }// onActivityResult

    private void kmlOfMadrid() {

        cargarKML("Madrid/Alcorcon.kml");
        Toast.makeText(this, "Alcorcon, Madrid", Toast.LENGTH_SHORT).show();
    }

    private void showLegalNotice() {
        String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(this);
        AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(this);
        LicenseDialog.setTitle("Legal Notices");
        LicenseDialog.setMessage(LicenseInfo);
        LicenseDialog.show();
    }

    private void changeTypeView() {
        viewType = (viewType + 1) % 4;

        switch (viewType) {
        case 0:
            map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
            break;
        case 1:
            map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
            break;
        case 2:
            map.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
            break;
        case 3:
            map.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
            break;
        }
    }

    private void animation3DExample() {
        LatLng madrid = new LatLng(40.417325, -3.683081);
        CameraPosition camPos = new CameraPosition.Builder().target(madrid) //Center camera in 'Plaza Maestro Villa'
                .zoom(19) //Set 19 level zoom
                .bearing(45) //Set the orientation to northeast
                .tilt(70) //Set 70 degrees tilt
                .build();

        CameraUpdate camUpd3 = CameraUpdateFactory.newCameraPosition(camPos);
        map.animateCamera(camUpd3);

        Toast.makeText(this, this.getString(R.string.city_3d), Toast.LENGTH_SHORT).show();

    }

    private void showCameraPosition() {
        CameraPosition camPos2 = map.getCameraPosition();
        LatLng cam_pos = camPos2.target;
        Toast.makeText(MainActivity.this, "Lat: " + cam_pos.latitude + " - Lng: " + cam_pos.longitude,
                Toast.LENGTH_LONG).show();

    }

    private void routeFromMadridToBarcelona() {
        //Positions of Madrid and Barcelona
        LatLng Madrid = new LatLng(40.416690900000000000, -3.700345400000060000);
        LatLng Barcelona = new LatLng(41.387917000000000000, 2.169918700000039300);
        String url = makeURL(Madrid.latitude, Madrid.longitude, Barcelona.latitude, Barcelona.longitude);
        new MyAsyncTask(this, url).execute();
    }

    private boolean estaEnElRadio(Location mi_posicion, Location otra_posicion, double radio) {

        double distancia = mi_posicion.distanceTo(otra_posicion);
        // if less than 10 metres
        if (distancia < radio) {
            return true;
        } else {
            return false;
        }
    }

    private void borrarPolylineas() {
        for (Polyline linea : polylinesList) {
            //linea.setVisible(false);
            linea.remove();
        }
    }

    private String makeURL(double sourcelat, double sourcelog, double destlat, double destlog) {
        StringBuilder urlString = new StringBuilder();
        urlString.append("http://maps.googleapis.com/maps/api/directions/json");
        urlString.append("?origin=");// from
        urlString.append(Double.toString(sourcelat));
        urlString.append(",");
        urlString.append(Double.toString(sourcelog));
        urlString.append("&destination=");// to
        urlString.append(Double.toString(destlat));
        urlString.append(",");
        urlString.append(Double.toString(destlog));
        urlString.append("&sensor=false&mode=walking&alternatives=true");
        return urlString.toString();
    }

    public void drawPath(String result) {

        try {
            //Tranform the string into a json object
            final JSONObject json = new JSONObject(result);
            JSONArray routeArray = json.getJSONArray("routes");
            JSONObject routes = routeArray.getJSONObject(0);
            JSONObject overviewPolylines = routes.getJSONObject("overview_polyline");
            String encodedString = overviewPolylines.getString("points");
            List<LatLng> list = decodePoly(encodedString);

            for (int z = 0; z < list.size() - 1; z++) {
                LatLng src = list.get(z);
                LatLng dest = list.get(z + 1);
                Polyline line = map.addPolyline(new PolylineOptions()
                        .add(new LatLng(src.latitude, src.longitude), new LatLng(dest.latitude, dest.longitude))
                        .width(2).color(Color.BLUE).geodesic(true).width(6f));
                polylinesList.add(line);
            }

            //updating camera... just for cosmetic purposes
            LatLng madrid = new LatLng(41.45421586734046, -1.1424993351101875);
            CameraPosition camPos = new CameraPosition.Builder().target(madrid) //Center camera in 'Plaza Maestro Villa'
                    .zoom(6) //Set 6 level zoom
                    .build();

            CameraUpdate camUpd = CameraUpdateFactory.newCameraPosition(camPos);
            map.animateCamera(camUpd);

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * Advice: Don't try to understand this code, does not worth it.
     * 
     * @param encoded text response from google query
     * @return a list of LatLng object that describes the route
     */
    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;
    }

    private void cargarKML(String ruta) {
        try {
            InputStream is_kml = getResources().getAssets().open(ruta);

            // create the factory
            SAXParserFactory factory = SAXParserFactory.newInstance();
            // create a parser
            SAXParser parser;
            parser = factory.newSAXParser();

            // create the reader (scanner)
            XMLReader xmlreader = parser.getXMLReader();
            // instantiate our handler
            NavigationSaxHandler navSaxHandler = new NavigationSaxHandler();
            // assign our handler
            xmlreader.setContentHandler(navSaxHandler);
            // get our data via the url class
            InputSource is = new InputSource(is_kml);
            // perform the synchronous parse           
            xmlreader.parse(is);

            // get the results - should be a fully populated RSSFeed instance, or null on error
            NavigationDataSet ds = navSaxHandler.getParsedData();

            Placemark place = ds.getPlacemarks().get(0);

            ArrayList<String> lista_coordenadas = place.getCoordinates();

            LatLng locationToCamera = null;

            for (String coordenadas : lista_coordenadas) {
                locationToCamera = draw(coordenadas);
            }

            CameraPosition camPos = new CameraPosition.Builder().target(locationToCamera) //Centramos el mapa en Madrid
                    .zoom(9) //Establecemos el zoom en 19
                    .build();

            CameraUpdate camUpd3 = CameraUpdateFactory.newCameraPosition(camPos);

            map.animateCamera(camUpd3);

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private LatLng draw(String coordenadas) {
        List<LatLng> lista = new ArrayList<LatLng>();

        String[] coors = coordenadas.split(" ");
        for (String c : coors) {
            String[] cols = c.split(",");
            double latitude = Double.parseDouble(cols[1].trim());
            double longitude = Double.parseDouble(cols[0].trim());
            LatLng l = new LatLng(latitude, longitude);
            lista.add(l);
        }

        drawPathKML(lista);

        LatLng locationToCamera = lista.get(lista.size() / 2);
        return locationToCamera;
    }

    private void drawPathKML(List<LatLng> list) {
        PolygonOptions opciones = new PolygonOptions().fillColor(Color.argb(100, 0, 0, 255)).strokeWidth(5f)
                .strokeColor(Color.BLUE).geodesic(true);

        for (int z = 0; z < list.size() - 1; z++) {
            LatLng src = list.get(z);
            LatLng dest = list.get(z + 1);
            opciones = opciones.add(new LatLng(src.latitude, src.longitude),
                    new LatLng(dest.latitude, dest.longitude));
        }

        Polygon pol = map.addPolygon(opciones);

    }

    //More about location tracking...

    @Override
    protected void onStart() {
        super.onStart();
        if (!locationTracker.hasLocationUpdatesEnabled())
            locationTracker.setStartUpdates(LocationRequest.PRIORITY_HIGH_ACCURACY, UPDATE_INTERVAL,
                    FASTEST_INTERVAL, SMALLEST_DISPLACEMENT);
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();
        locationTracker.addLocationListener(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        locationTracker.removeLocationListener(this);
    }

    @Override
    public void onLocationChanged(Location location) {
        currentLocation = new Location(location);
    }

}