com.markupartist.sthlmtraveling.ViewOnMapActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.markupartist.sthlmtraveling.ViewOnMapActivity.java

Source

/*
 * Copyright (C) 2013 Johan Nilsson <http://markupartist.com>
 *
 * 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 com.markupartist.sthlmtraveling;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.Bundle;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.view.MenuItem;
import android.view.View;

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.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
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.markupartist.sthlmtraveling.data.api.ApiService;
import com.markupartist.sthlmtraveling.data.models.Entrance;
import com.markupartist.sthlmtraveling.data.models.IntermediateStop;
import com.markupartist.sthlmtraveling.data.models.IntermediateResponse;
import com.markupartist.sthlmtraveling.data.models.Leg;
import com.markupartist.sthlmtraveling.data.models.Place;
import com.markupartist.sthlmtraveling.data.models.Route;
import com.markupartist.sthlmtraveling.data.models.Step;
import com.markupartist.sthlmtraveling.data.models.TravelMode;
import com.markupartist.sthlmtraveling.provider.planner.JourneyQuery;
import com.markupartist.sthlmtraveling.provider.site.Site;
import com.markupartist.sthlmtraveling.utils.Analytics;
import com.markupartist.sthlmtraveling.utils.LegUtil;
import com.markupartist.sthlmtraveling.utils.PolyUtil;
import com.markupartist.sthlmtraveling.utils.StringUtils;
import com.markupartist.sthlmtraveling.utils.ViewHelper;

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

import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;

public class ViewOnMapActivity extends BaseFragmentActivity implements OnMapReadyCallback {

    private static final String TAG = "ViewOnMapActivity";
    public static String EXTRA_LOCATION = "com.markupartist.sthlmtraveling.extra.Location";
    public static String EXTRA_JOURNEY_QUERY = "com.markupartist.sthlmtraveling.extra.JourneyQuery";
    public static String EXTRA_TRIP = "com.markupartist.sthlmtraveling.extra.Trip";
    public static String EXTRA_ROUTE = "com.markupartist.sthlmtraveling.extra.Route";

    /**
     * Note that this may be null if the Google Play services APK is not available.
     */
    private GoogleMap mMap;
    private LatLng mFocusedLatLng;
    private Route mTransitRoute;
    private JourneyQuery mJourneyQuery;
    private Route mRoute;
    private ApiService mApiService;

    public static Intent createIntent(Context context, JourneyQuery query, Route route) {
        Intent intent = new Intent(context, ViewOnMapActivity.class);
        intent.putExtra(ViewOnMapActivity.EXTRA_ROUTE, route);
        intent.putExtra(ViewOnMapActivity.EXTRA_JOURNEY_QUERY, query);
        return intent;
    }

    public static Intent createIntent(Context context, Route route, JourneyQuery query, Site location) {
        Intent intent = new Intent(context, ViewOnMapActivity.class);
        intent.putExtra(ViewOnMapActivity.EXTRA_TRIP, route);
        intent.putExtra(ViewOnMapActivity.EXTRA_JOURNEY_QUERY, query);
        intent.putExtra(ViewOnMapActivity.EXTRA_LOCATION, location);
        return intent;
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    public void startActivity(Intent intent) {
        super.startActivity(intent);
        overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Analytics.getInstance(this).registerScreen("View on map");
        setContentView(R.layout.map);

        ActionBar actionBar = getSupportActionBar();
        //actionBar.setBackgroundDrawable(getResources().getDrawableColorInt(R.drawable.ab_bg_black));
        actionBar.setHomeButtonEnabled(true);
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
        actionBar.setDisplayShowHomeEnabled(true);
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setTitle(R.string.route_details_label);

        Bundle extras = getIntent().getExtras();

        mRoute = extras.getParcelable(EXTRA_ROUTE);
        mTransitRoute = extras.getParcelable(EXTRA_TRIP);
        mJourneyQuery = extras.getParcelable(EXTRA_JOURNEY_QUERY);
        final Site focusedLocation = extras.getParcelable(EXTRA_LOCATION);

        mApiService = MyApplication.get(this).getApiService();

        if (focusedLocation != null) {
            mFocusedLatLng = new LatLng(focusedLocation.getLocation().getLatitude(),
                    focusedLocation.getLocation().getLongitude());
        }

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        updateStartAndEndPointViews(mJourneyQuery);
    }

    public void loadIntermediateStops(final Route route) {
        List<String> references = new ArrayList<>();

        for (Leg leg : route.getLegs()) {
            if (leg.getIntermediateStops().isEmpty() && leg.getDetailRef() != null) {
                references.add(leg.getDetailRef());
            }
        }

        if (references.isEmpty()) {
            // If the legs did not have any references there's no need to ask for data.
            return;
        }

        mApiService.getIntermediateStops(references, new Callback<IntermediateResponse>() {
            @Override
            public void success(IntermediateResponse intermediateResponse, Response response) {
                for (Leg leg : route.getLegs()) {
                    if (leg.isTransit()) {
                        leg.setIntermediateStops(intermediateResponse.getStops(leg.getDetailRef()));
                    }
                }
                showTransitRoute(route);
            }

            @Override
            public void failure(RetrofitError error) {
                showTransitRoute(route);
            }
        });
    }

    public void showTransitRoute(Route route) {
        mMap.clear();

        for (Leg leg : route.getLegs()) {
            int legColor = LegUtil.getColor(this, leg);

            float[] hsv = new float[3];
            Color.colorToHSV(legColor, hsv);
            float hueColor = hsv[0];

            LatLng origin = new LatLng(leg.getFrom().getLat(), leg.getFrom().getLon());

            mMap.addMarker(new MarkerOptions().position(origin).title(getLocationName(leg.getFrom()))
                    .snippet(getRouteDescription(leg)).icon(BitmapDescriptorFactory.defaultMarker(hueColor)));

            LatLng destination = new LatLng(leg.getTo().getLat(), leg.getTo().getLon());
            mMap.addMarker(new MarkerOptions().position(destination).title(getLocationName(leg.getTo()))
                    .snippet(DateFormat.getTimeFormat(this).format(leg.getStartTime()))
                    .icon(BitmapDescriptorFactory.defaultMarker(hueColor)));

            if (leg.getGeometry() != null) {
                // If we have a geometry draw that.
                List<LatLng> latLgns = PolyUtil.decode(leg.getGeometry());
                drawPolyline(latLgns, legColor);
            } else {
                // One polyline per leg, different colors.
                PolylineOptions options = new PolylineOptions();
                options.add(origin);

                BitmapDescriptor icon = getColoredMarker(legColor, R.drawable.ic_line_marker);
                for (IntermediateStop stop : leg.getIntermediateStops()) {
                    LatLng intermediateStop = new LatLng(stop.getLocation().getLat(), stop.getLocation().getLon());
                    options.add(intermediateStop);
                    Date date = stop.getTimeRt();
                    if (date == null) {
                        date = stop.getTime();
                    }
                    String time = date != null ? DateFormat.getTimeFormat(this).format(date) : "";
                    mMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).position(intermediateStop)
                            .title(getLocationName(stop.getLocation())).snippet(time).icon(icon));
                }

                options.add(destination);

                mMap.addPolyline(options.width(ViewHelper.dipsToPix(getResources(), 8)).color(legColor));
            }

            if (leg.getFrom().hasEntrances()) {
                showEntrances(leg.getFrom().getEntrances(), false);
            }
            if (leg.getTo().hasEntrances()) {
                showEntrances(leg.getTo().getEntrances(), true);
            }
        }
    }

    public String getRouteDescription(Leg leg) {
        String description;
        if (TravelMode.FOOT.equals(leg.getTravelMode())) {
            description = getString(R.string.trip_map_description_walk,
                    DateFormat.getTimeFormat(this).format(leg.getStartTime()), getLocationName(leg.getTo()));
        } else {
            description = getString(R.string.trip_map_description_normal,
                    DateFormat.getTimeFormat(this).format(leg.getStartTime()), leg.getRouteName(),
                    leg.getHeadsing().getName());
        }
        return description;
    }

    private String getLocationName(Place location) {
        // TODO: Copied from RouteDetailActivity, centralize please!
        if (location == null) {
            return "Unknown";
        }
        if (location.isMyLocation()) {
            return getString(R.string.my_location);
        }
        return location.getName();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onLocationPermissionGranted() {
        //noinspection ResourceType
        mMap.setMyLocationEnabled(true);
    }

    @Override
    public void onLocationPermissionRationale() {
        Snackbar.make(findViewById(R.id.map), R.string.permission_location_needed_maps, Snackbar.LENGTH_INDEFINITE)
                .setAction(R.string.allow, new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        requestLocationPermission();
                    }
                }).show();
    }

    private void setUpMap() {
        if (mTransitRoute != null && mJourneyQuery != null) {
            showTransitRoute(mTransitRoute);
            loadIntermediateStops(mTransitRoute);
            mMap.moveCamera(
                    CameraUpdateFactory.newCameraPosition(CameraPosition.fromLatLngZoom(mFocusedLatLng, 16)));
        } else if (mRoute != null) {
            List<LatLng> latLngs = showRoute(mRoute);
            zoomToFit(latLngs);
        }

        UiSettings settings = mMap.getUiSettings();
        settings.setAllGesturesEnabled(true);
        settings.setMapToolbarEnabled(false);

        verifyLocationPermission();
    }

    private List<LatLng> showRoute(Route route) {
        // If we have geometry parse and all.
        List<LatLng> all = new ArrayList<>();
        for (Leg leg : route.getLegs()) {
            if (leg.getGeometry() != null) {
                List<LatLng> latLgns = PolyUtil.decode(leg.getGeometry());
                drawPolyline(latLgns, ContextCompat.getColor(this, R.color.primary));
                all.addAll(latLgns);

                if (leg.getSteps() != null) {
                    BitmapDescriptor icon = getColoredMarker(ContextCompat.getColor(this, R.color.primary),
                            R.drawable.ic_line_marker);
                    for (Step step : leg.getSteps()) {
                        if ("arrive".equals(step.getCode()) || "depart".equals(step.getCode())
                                || "waypoint".equals(step.getCode())) {
                            mMap.addMarker(new MarkerOptions().position(latLgns.get(step.getPosition()))
                                    .anchor(0.5f, 0.5f).icon(icon));
                        }
                    }
                }

            }
        }
        return all;
    }

    BitmapDescriptor getMarker(@DrawableRes int drawableRes) {
        Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), drawableRes);
        return BitmapDescriptorFactory.fromBitmap(bitmap);
    }

    BitmapDescriptor getColoredMarker(@ColorInt int colorInt, @DrawableRes int drawableRes) {
        Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), drawableRes);
        Bitmap bitmapCopy = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
        Canvas canvas = new Canvas(bitmapCopy);
        Paint paint = new Paint();
        paint.setColorFilter(new PorterDuffColorFilter(colorInt, PorterDuff.Mode.SRC_ATOP));
        canvas.drawBitmap(bitmap, 0f, 0f, paint);
        return BitmapDescriptorFactory.fromBitmap(bitmapCopy);
    }

    private void drawPolyline(List<LatLng> latLngs, @ColorInt int color) {
        Polyline poly = mMap.addPolyline(new PolylineOptions().zIndex(1000).addAll(latLngs)
                .width(ViewHelper.dipsToPix(getResources(), 8)).color(color).geodesic(true));
        poly.setZIndex(Float.MAX_VALUE);
    }

    private void zoomToFit(List<LatLng> latLngs) {
        LatLngBounds.Builder builder = new LatLngBounds.Builder();

        for (LatLng latLng : latLngs) {
            builder.include(latLng);
        }

        LatLngBounds bounds = builder.build();

        // A "random" value for the top padding, fix to fetch from toolbar later on.
        int height = ViewHelper.getDisplayHeight(this) - ViewHelper.dipsToPix(getResources(), 52);
        int width = ViewHelper.getDisplayWidth(this);
        CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width, height,
                getResources().getDimensionPixelSize(R.dimen.padding_large));
        mMap.moveCamera(cu);
        //mMap.animateCamera(cu);
    }

    /**
     * Update the action bar with start and end points.
     * @param journeyQuery the journey query
     */
    protected void updateStartAndEndPointViews(final JourneyQuery journeyQuery) {
        ActionBar ab = getSupportActionBar();
        if (journeyQuery.origin.isMyLocation()) {
            ab.setTitle(StringUtils.getStyledMyLocationString(this));
        } else {
            ab.setTitle(journeyQuery.origin.getName());
        }

        CharSequence via = null;
        if (journeyQuery.hasVia()) {
            via = journeyQuery.via.getName();
        }
        if (journeyQuery.destination.isMyLocation()) {
            if (via != null) {
                ab.setSubtitle(TextUtils.join("  ",
                        new CharSequence[] { via, StringUtils.getStyledMyLocationString(this) }));
            } else {
                ab.setSubtitle(StringUtils.getStyledMyLocationString(this));
            }
        } else {
            if (via != null) {
                ab.setSubtitle(
                        TextUtils.join("  ", new CharSequence[] { via, journeyQuery.destination.getName() }));
            } else {
                ab.setSubtitle(journeyQuery.destination.getName());
            }
        }
    }

    public void showEntrances(List<Entrance> entrances, boolean isExits) {
        BitmapDescriptor icon = getMarker(R.drawable.ic_entrance_exit_12dp);
        for (Entrance entrance : entrances) {
            MarkerOptions markerOptions = new MarkerOptions()
                    .position(new LatLng(entrance.getLat(), entrance.getLon())).anchor(0.5f, 0.5f).icon(icon);
            if (!TextUtils.isEmpty(entrance.getName())) {
                if (isExits) {
                    markerOptions.title(getString(R.string.exit_and_name, entrance.getName()));
                } else {
                    markerOptions.title(getString(R.string.entrance_and_name, entrance.getName()));
                }
            } else {
                if (isExits) {
                    markerOptions.title(getString(R.string.exit));
                } else {
                    markerOptions.title(getString(R.string.entrance));
                }
            }
            mMap.addMarker(markerOptions);
        }
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        setUpMap();
    }
}