com.poguico.palmabici.map.StationMapFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.poguico.palmabici.map.StationMapFragment.java

Source

/*
 * Copyright 2013 Sergio Garcia Villalonga (yayalose@gmail.com)
 *
 * This file is part of PalmaBici.
 *
 *    PalmaBici is free software: you can redistribute it and/or modify
 *    it under the terms of the Affero GNU General Public License version 3
 *    as published by the Free Software Foundation.
 *
 *    PalmaBici is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    Affero GNU General Public License for more details
 *    (https://www.gnu.org/licenses/agpl-3.0.html).
 *    
 */

package com.poguico.palmabici.map;

import java.util.ArrayList;
import java.util.HashMap;

import org.osmdroid.ResourceProxy;
import org.osmdroid.bonuspack.overlays.ExtendedOverlayItem;
import org.osmdroid.bonuspack.overlays.ItemizedOverlayWithBubble;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.tileprovider.util.CloudmadeUtil;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.OverlayItem;
import org.osmdroid.views.overlay.PathOverlay;
import org.osmdroid.views.overlay.ScaleBarOverlay;
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider;
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources.NotFoundException;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.poguico.palmabici.R;
import com.poguico.palmabici.SynchronizableElement;
import com.poguico.palmabici.network.synchronizer.NetworkStationAlarm;
import com.poguico.palmabici.network.synchronizer.NetworkSynchronizer;
import com.poguico.palmabici.synchronizers.LocationSynchronizer;
import com.poguico.palmabici.util.BikeLane;
import com.poguico.palmabici.util.NetworkInformation;
import com.poguico.palmabici.util.Station;
import com.poguico.palmabici.widgets.StationInfoWidget;

public class StationMapFragment extends Fragment implements SynchronizableElement, OpenStreetMapConstants {

    // ===========================================================
    // Fields
    // ===========================================================

    private SharedPreferences mPrefs;
    private MapView mMapView;
    private MyLocationNewOverlay mLocationOverlay;
    private ScaleBarOverlay mScaleBarOverlay;
    private ResourceProxy mResourceProxy;

    private HashMap<Integer, ExtendedOverlayItem> mapMarkers = null;

    private static final String BIKE_LANE_OPTION = "show_bike_lane";

    private ArrayList<PathOverlay> bikeLane = null;
    private SharedPreferences conf;

    private boolean bikeLaneState;

    private LocationSynchronizer locationSynchronizer;
    private NetworkInformation network;
    private ItemizedOverlayWithBubble<OverlayItem> markerOverlay;
    private NetworkSynchronizer networkSync;
    private Context context;

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

        conf = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
        bikeLaneState = conf.getBoolean(BIKE_LANE_OPTION, true);
        locationSynchronizer = LocationSynchronizer.getInstance(this);
        context = this.getActivity().getApplicationContext();
        network = NetworkInformation.getInstance(context);
        networkSync = NetworkSynchronizer.getInstance(context);
        networkSync.addSynchronizableElement(this);

        mPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);

        final SharedPreferences.Editor edit = mPrefs.edit();
        edit.remove(PREFS_SHOWN_MARKER);
        edit.remove(PREFS_SCROLL_X);
        edit.remove(PREFS_SCROLL_Y);
        edit.remove(PREFS_ZOOM_LEVEL);
        edit.commit();

        this.setRetainInstance(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mResourceProxy = new ResourceProxyImpl(inflater.getContext().getApplicationContext());
        mMapView = new MapView(inflater.getContext(), 256, mResourceProxy);
        mMapView.setUseSafeCanvas(true);
        setHardwareAccelerationOff();
        return mMapView;
    }

    private void drawStationMarkers(boolean force) {
        String filename;
        int percentage;

        if (mapMarkers == null || force) {
            mapMarkers = new HashMap<Integer, ExtendedOverlayItem>();
            for (Station station : network.getNetwork()) {
                if (station.getSlots() > 0) {
                    percentage = (int) Math.round((station.getBusySlots() * 10 / station.getSlots()));

                    ExtendedOverlayItem marker = new ExtendedOverlayItem(station.getName(),
                            String.valueOf(station.getId()), new GeoPoint(station.getLat(), station.getLong()),
                            context);
                    try {
                        filename = "marker" + percentage * 10;
                        filename += (NetworkStationAlarm.hasAlarm(station.getId())) ? "_alarm" : "";
                        marker.setMarker(getResources()
                                .getDrawable(R.drawable.class.getDeclaredField(filename).getInt(null)));
                        mapMarkers.put(station.getId(), marker);
                    } catch (NotFoundException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                }
            }

            markerOverlay = new ItemizedOverlayWithBubble<OverlayItem>(this.getActivity(),
                    getResources().getDrawable(R.drawable.marker0), new ArrayList<OverlayItem>(mapMarkers.values()),
                    mMapView, new StationInfoWidget(mMapView, this));

            mMapView.getOverlays().add(markerOverlay);
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void setHardwareAccelerationOff() {
        // Turn off hardware acceleration here, or in manifest
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
            mMapView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        float[] distance = null;
        final DisplayMetrics dm = context.getResources().getDisplayMetrics();

        // only do static initialisation if needed
        if (CloudmadeUtil.getCloudmadeKey().length() == 0) {
            CloudmadeUtil.retrieveCloudmadeKey(context.getApplicationContext());
        }

        this.mLocationOverlay = new MyLocationNewOverlay(context, new GpsMyLocationProvider(context), mMapView);

        mScaleBarOverlay = new ScaleBarOverlay(context);
        mScaleBarOverlay.setCentred(true);
        mScaleBarOverlay.setScaleBarOffset(dm.widthPixels / 2, 10);

        mMapView.setBuiltInZoomControls(true);
        mMapView.setMultiTouchControls(true);
        mMapView.getOverlays().add(this.mScaleBarOverlay);

        Location myLocation = locationSynchronizer.getLocation();

        if (myLocation != null) {
            distance = new float[1];
            Location.distanceBetween(network.getCenter().getLatitude(), network.getCenter().getLongitude(),
                    myLocation.getLatitude(), myLocation.getLongitude(), distance);
        }

        drawBikeLane();
        toggleBikeLane(bikeLaneState);
        mMapView.getController().setZoom(mPrefs.getInt(PREFS_ZOOM_LEVEL, (int) (14 + dm.density)));
        if (distance == null || distance[0] > 10000) {
            mMapView.getController().setCenter(new GeoPoint(39574689, 2651332));
        } else {
            mMapView.getController().setCenter(new GeoPoint(myLocation));
        }
        setHasOptionsMenu(true);
        mMapView.getOverlays().add(this.mLocationOverlay);

        mMapView.scrollTo(mPrefs.getInt(PREFS_SCROLL_X, mMapView.getScrollX()),
                mPrefs.getInt(PREFS_SCROLL_Y, mMapView.getScrollY()));
    }

    @Override
    public void onStart() {
        super.onStart();
        updateStations();
    }

    @Override
    public void onPause() {
        final SharedPreferences.Editor edit = mPrefs.edit();
        edit.putInt(PREFS_SCROLL_X, mMapView.getScrollX());
        edit.putInt(PREFS_SCROLL_Y, mMapView.getScrollY());
        edit.putInt(PREFS_ZOOM_LEVEL, mMapView.getZoomLevel());
        edit.putInt(PREFS_SHOWN_MARKER, markerOverlay.getBubbledItemId());
        edit.putInt(PREFS_SHOWN_STATION, -1);
        edit.commit();
        markerOverlay.hideBubble();

        super.onPause();
    }

    @Override
    public void onResume() {
        int shownBubble;
        Integer activeStation;
        super.onResume();

        shownBubble = mPrefs.getInt(PREFS_SHOWN_MARKER, -1);
        activeStation = mPrefs.getInt(PREFS_SHOWN_STATION, -1);
        if (activeStation >= 0) {
            markerOverlay.showBubbleOnItem(mapMarkers.get(activeStation), mMapView, true);
        } else if (shownBubble >= 0) {
            markerOverlay.showBubbleOnItem(shownBubble, mMapView, true);
        }

        try {
            mMapView.setTileSource(TileSourceFactory.MAPQUESTOSM);
        } catch (final IllegalArgumentException ignore) {
        }

        boolean showBikeLane = conf.getBoolean(BIKE_LANE_OPTION, true);
        if (showBikeLane != bikeLaneState) {
            bikeLaneState = showBikeLane;
            toggleBikeLane(bikeLaneState);
        }
        drawStationMarkers(false);
        this.mLocationOverlay.enableMyLocation();
    }

    @Override
    public void onDestroy() {
        locationSynchronizer.detachSynchronizableElement(this);
        networkSync.detachSynchronizableElement(this);
        super.onDestroy();
    }

    private void updateStations() {
        if (mapMarkers != null) {
            mMapView.getOverlays().remove(markerOverlay);
        }
        drawStationMarkers(true);
    }

    @Override
    public void onSuccessfulNetworkSynchronization() {
        int bubbleId = markerOverlay.getBubbledItemId();
        markerOverlay.hideBubble();
        updateStations();

        if (bubbleId >= 0) {
            markerOverlay.showBubbleOnItem(bubbleId, mMapView, true);
        }
    }

    @Override
    public void onUnsuccessfulNetworkSynchronization() {
        updateStations();
    }

    @Override
    public void onLocationSynchronization() {
        float[] distance;
        Location myLocation;
        if (markerOverlay.getBubbledItemId() < 0) {
            myLocation = locationSynchronizer.getLocation();

            if (myLocation != null) {
                distance = new float[1];
                Location.distanceBetween(network.getCenter().getLatitude(), network.getCenter().getLongitude(),
                        myLocation.getLatitude(), myLocation.getLongitude(), distance);

                if (distance != null && distance[0] <= 10000) {
                    mMapView.getController().animateTo(new GeoPoint(myLocation));
                }
            }
        }
    }

    @Override
    public FragmentActivity getSynchronizableActivity() {
        return this.getActivity();
    }

    private void drawBikeLane() {
        bikeLane = BikeLane.getOSMPaths(this.getActivity(), mMapView);
        for (PathOverlay pathOverlay : bikeLane) {
            mMapView.getOverlays().add(pathOverlay);
        }
    }

    private void toggleBikeLane(boolean visible) {
        for (PathOverlay pathOverlay : bikeLane) {
            pathOverlay.setEnabled(visible);
        }
    }
}