tm.veriloft.mapsplayground.MapsActivity.java Source code

Java tutorial

Introduction

Here is the source code for tm.veriloft.mapsplayground.MapsActivity.java

Source

/*
 * Copyright 2015. Alashov Berkeli
 *
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package tm.veriloft.mapsplayground;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

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.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import org.apache.http.Header;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class MapsActivity extends AppCompatActivity {

    private GoogleMap mMap; // Might be null if Google Play services APK is not available.

    private ArrayList<Polyline> drawnRoutes = new ArrayList<>(); //all drawn routes in the map, for removing after
    private ArrayList<Marker> addedMarkers = new ArrayList<>(); //all markers in the map, for removing after

    private final String SERVER = "http://router.project-osrm.org/viaroute";
    private final int SERVER_PORT = 80;

    private final String[] drawOptionsStrings = { "Focus to start point after draw", "Add end of point marker",
            "Add requested point marker", "Markers for returned points" };
    private final boolean[] drawOptionsValues = { false, true, true, false };

    private boolean focusAfterRouteDraw = drawOptionsValues[0];
    private boolean endMarkerRouteDraw = drawOptionsValues[1];
    private boolean requestedPointMarkerRouteDraw = drawOptionsValues[2];
    private boolean returnedPointsMarkers = drawOptionsValues[3];

    private final String[] mapTypeStrings = { "Normal", "Hybrid", "Satellite", "Terrain" };
    private int lastMapType = 1;

    private final int ROUTE_WIDTH = 5;
    private final int ROUTE_COLOR = Color.RED;

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

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

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
        case R.id.map_routes_clear:

            //clear them from map
            for (Polyline drawnRoute : drawnRoutes)
                drawnRoute.remove();
            for (Marker marker : addedMarkers)
                marker.remove();

            //clear array
            drawnRoutes.clear();
            addedMarkers.clear();

            break;
        case R.id.map_type:
            AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MapsActivity.this);
            alertDialogBuilder.setTitle("Choose map type");

            alertDialogBuilder.setSingleChoiceItems(mapTypeStrings, lastMapType,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();

                            if (which == lastMapType)
                                return;

                            lastMapType = which;

                            switch (which) {
                            case 0:
                                mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
                                break;
                            case 1:
                                mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
                                break;
                            case 2:
                                mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
                                break;
                            case 3:
                                mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
                                break;
                            }
                        }
                    });
            alertDialogBuilder.setNegativeButton("Cancel", null);
            alertDialogBuilder.show();
            break;
        }
        return true;
    }

    /**
     * Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly
     * installed) and the map has not already been instantiated.. This will ensure that we only ever
     * call {@link #setUpMap()} once when {@link #mMap} is not null.
     * <p>
     * If it isn't installed {@link SupportMapFragment} (and
     * {@link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to
     * install/update the Google Play services APK on their device.
     * <p>
     * A user can return to this FragmentActivity after following the prompt and correctly
     * installing/updating/enabling the Google Play services. Since the FragmentActivity may not
     * have been completely destroyed during this process (it is likely that it would only be
     * stopped or paused), {@link #onCreate(Bundle)} may not be called again so we should call this
     * method in {@link #onResume()} to guarantee that it will be called.
     */
    private void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the map.
        if (mMap == null) {
            // Try to obtain the map from the SupportMapFragment.
            mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
            // Check if we were successful in obtaining the map.
            if (mMap != null) {
                setUpMap();
            }
        }
    }

    /**
     * This is where we can add markers or lines, add listeners or move the camera. In this case, we
     * just add a marker near Africa.
     * <p>
     * This should only be called once and when we are sure that {@link #mMap} is not null.
     */
    private void setUpMap() {
        mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        mMap.setMyLocationEnabled(true);

        mMap.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
            @Override
            public void onMapLongClick(final LatLng latLng) {

                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MapsActivity.this);
                alertDialogBuilder.setTitle("Confirm Route Drawing");

                alertDialogBuilder.setMultiChoiceItems(drawOptionsStrings, drawOptionsValues,
                        new DialogInterface.OnMultiChoiceClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                                drawOptionsValues[which] = isChecked;
                                setDrawOptionsValues();
                            }
                        });

                alertDialogBuilder.setNegativeButton("Nope", null);
                alertDialogBuilder.setPositiveButton("Yes, of coz", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Location location = mMap.getMyLocation();

                        if (location != null) {
                            fetchAndDrawRoute(new LatLng(location.getLatitude(), location.getLongitude()), latLng);
                        } else {
                            showCenteredToast("Your current location currently not available, please wait.");
                        }
                    }
                });
                alertDialogBuilder.show();
            }
        });

        mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng latLng) {
                l("onMapClick, " + latLng.toString());
            }
        });

        focusTo(new LatLng(37.945958662069174, 58.38305085897446), 13); // focus to ashgabat
    }

    private void focusTo(LatLng latLng, float zoomLevel) {
        CameraPosition cameraPosition = CameraPosition.builder().zoom(zoomLevel).target(latLng).build();
        mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
    }

    private void setDrawOptionsValues() {
        focusAfterRouteDraw = drawOptionsValues[0];
        endMarkerRouteDraw = drawOptionsValues[1];
        requestedPointMarkerRouteDraw = drawOptionsValues[2];
        returnedPointsMarkers = drawOptionsValues[3];
    }

    private void fetchAndDrawRoute(final LatLng... latLngs) {
        final AsyncHttpClient asyncHttpClient = new AsyncHttpClient(SERVER_PORT);

        final ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("Loading..");
        progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                asyncHttpClient.cancelRequests(MapsActivity.this, true);
                showCenteredToast("Drawing route got cancelled");
            }
        });

        final RequestParams requestParams = new RequestParams();

        for (LatLng latLng : latLngs) {
            requestParams.add("loc", latLng.latitude + "," + latLng.longitude);
            l("Added latLng to request, " + latLng);
        }

        asyncHttpClient.get(this, SERVER, requestParams, new JsonHttpResponseHandler() {
            @Override
            public void onStart() {
                progressDialog.show();
            }

            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
                try {
                    ArrayList<LatLng> route = MapUtils.decodePoly(response.getString("route_geometry"));
                    PolylineOptions routeOptions = new PolylineOptions();

                    for (int i = 0; i < route.size(); i++) {
                        routeOptions.add(route.get(i));
                        l("Returned point " + route.get(i));
                        if (returnedPointsMarkers)
                            addedMarkers.add(mMap.addMarker(new MarkerOptions().position(route.get(i))
                                    .title("#" + i + " point of #" + drawnRoutes.size())));
                    }

                    routeOptions.width(ROUTE_WIDTH).color(ROUTE_COLOR);
                    drawnRoutes.add(mMap.addPolyline(routeOptions));

                    List<LatLng> points = routeOptions.getPoints();

                    if (focusAfterRouteDraw)
                        focusTo(points.get(0), 13);

                    if (endMarkerRouteDraw) {
                        LatLng trueEndPoint = MapUtils.findTrueEndPoint(latLngs[latLngs.length - 1], route.get(0),
                                route.get(route.size() - 1));
                        addedMarkers.add(mMap.addMarker(
                                new MarkerOptions().position(trueEndPoint).title("End of #" + drawnRoutes.size())));
                    }

                    if (requestedPointMarkerRouteDraw)
                        addedMarkers.add(mMap.addMarker(new MarkerOptions().position(latLngs[latLngs.length - 1])
                                .title("Requested point of #" + drawnRoutes.size())));

                } catch (JSONException exception) {
                    exception.printStackTrace();
                    showCenteredToast("Exception while parsing! Error: " + exception.getLocalizedMessage());
                }
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) {
                showCenteredToast("Network error! Error: " + throwable.getLocalizedMessage());
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                showCenteredToast("Network error! Server returned non-json response, response: " + responseString
                        + ", Error: " + throwable.getLocalizedMessage());
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
                showCenteredToast("Network error! Error: " + throwable.getLocalizedMessage());
            }

            @Override
            public void onFinish() {
                progressDialog.dismiss();
            }
        });
    }

    public void showCenteredToast(String string) {
        if (string == null || string.equals(""))
            string = "null";
        Toast toast = Toast.makeText(this.getApplicationContext(), string, Toast.LENGTH_LONG);
        toast.setGravity(Gravity.CENTER, 0, 0);
        toast.show();
    }

    void l(String l) {
        Log.d("MapPlayground", l);
    }
}