Newer
Older
mountainnavigation / app / src / main / java / de / apps4ics / mountainnavigation / MainActivity.java
/**
 * This file is part of MountainNavigation.
 *
 * MountainNavigation is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MountainNavigation 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
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MountainNavigation.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @copyright Copyright (c) 2016 Vinzenz Rosenkanz <vinzenz.rosenkranz@gmail.com>
 *
 * @author Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
 */

package de.apps4ics.mountainnavigation;

import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.IBinder;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.view.GravityCompat;
import android.support.v7.app.ActionBar;
import android.os.Bundle;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.support.v4.widget.DrawerLayout;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.db.chart.listener.OnEntryClickListener;
import com.db.chart.model.LineSet;
import com.db.chart.view.AxisController;
import com.db.chart.view.ChartView;
import com.db.chart.view.LineChartView;
import com.db.chart.view.animation.Animation;

import org.osmdroid.api.IMapController;
import org.osmdroid.bonuspack.overlays.Marker;
import org.osmdroid.bonuspack.overlays.Polyline;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.OverlayItem;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import de.apps4ics.mountainnavigation.adapters.HikeListAdapter;
import de.apps4ics.mountainnavigation.handlers.DatabaseHandler;
import de.apps4ics.mountainnavigation.handlers.HikeHandler;
import de.apps4ics.mountainnavigation.handlers.PoiHandler;
import de.apps4ics.mountainnavigation.handlers.WeatherHandler;
import de.apps4ics.mountainnavigation.pois.AddBiotaDialog;
import de.apps4ics.mountainnavigation.pois.AddPoiDialog;
import de.apps4ics.mountainnavigation.pois.DbGeoPoint;
import de.apps4ics.mountainnavigation.pois.Fountain;
import de.apps4ics.mountainnavigation.pois.Hike;
import de.apps4ics.mountainnavigation.pois.Poi;
import de.apps4ics.mountainnavigation.pois.Types;

public class MainActivity extends AppCompatActivity implements OnSingleWeatherRetrieved, LocationUpdateCallback {

    public static final String TAG = "MountainNavigation";
    /**
     * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
     */

    private CharSequence mTitle;
    private CharSequence mDrawerTitle;
    private static final int GPS_MIN_TIME = 5000;
    private static final int GPS_MIN_DIST = 10;
    private static final int MIN_WEATHER_RELOAD_TIME = 3600000; //1hour, in ms
    private static final int MIN_WEATHER_RELOAD_DIST = 5000; //5km, in m
    private static final int MIN_POI_RELOAD_TIME = 300000; //5min, in ms
    private static final int MIN_POI_RELOAD_DIST = 500; //0.5km, in m
    private long lastWeatherInformation;
    private long lastPoiInformation;
    private static int MAX_POIS_AROUND = 50;
    public static final int MAX_WIFI_LEVELS = 5;
    private static ConnectivityManager cm;
    private static TelephonyManager tm;
    private static WifiManager wm;
    private static PowerManager pm;
    private static AlarmManager am;
    private static NetworkInfo activeNetwork;
    private static int networkStrength;

    private static SharedPreferences sharedPrefs;

    public static SimpleDateFormat df_hm;
    public static SimpleDateFormat df_full;

    private static Resources res;
    private static Context context;
    private FloatingActionButton fab;
    private static String currentImagePath;

    private static DatabaseHandler dbHandler;
    private static PoiHandler poiHandler;
    private static WeatherHandler weatherHandler;
    private static HikeHandler hikeHandler;

    private static MapView mapView;
    private IMapController mapController;
    public static int ZOOM_LEVEL;

    private ActionBarDrawerToggle drawerToggle;
    private DrawerLayout drawerLayout;
    private ExpandableListView poiView;
    private LinearLayout sunLayout;
    private ImageView weatherSymbol;
    private TextView weatherCity;
    private TextView weatherDesc;
    private TextView weatherMinTemp;
    private TextView weatherMaxTemp;
    private TextView weatherSunrise;
    private TextView weatherSunset;

    private Marker currentPosition;

    public static ArrayList<OverlayItem> pathMarkers;
    public static OverlayItem imageMarker;
    private Polyline hikeOverlay;

    private String provider;
    private static Location mLocation;
    private LocationManager locationManager;

    private static List<Location> foundLocations;

    private LocationService locationService;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected");
            LocationService.MyBinder binder = (LocationService.MyBinder) service;
            locationService = binder.getService();
            locationService.setLocationCallback(MainActivity.this);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected");
            locationService = null;
        }
    };

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

        res = getResources();
        context = getApplicationContext();
        pathMarkers = new ArrayList<>();

        cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
        activeNetwork = cm.getActiveNetworkInfo();
        networkStrength = 0;
        tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
        tm.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
        wm = (WifiManager) getSystemService(WIFI_SERVICE);
        pm = (PowerManager) getSystemService(POWER_SERVICE);
        am = (AlarmManager) getSystemService(ALARM_SERVICE);

        sharedPrefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);

        df_hm = new SimpleDateFormat(res.getString(R.string.date_format_hm), Locale.getDefault());
        df_full = new SimpleDateFormat(res.getString(R.string.date_format_full), Locale.getDefault());

        RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.container);
        if(relativeLayout == null) System.exit(0);

        ZOOM_LEVEL = 18;
        mapView = new MapView(getApplicationContext());
        mapView.setTileSource(TileSourceFactory.MAPNIK);
        mapView.setBuiltInZoomControls(true);
        mapView.setMultiTouchControls(true);
        mapController = mapView.getController();
        mapController.setZoom(ZOOM_LEVEL);
        mapController.setCenter(new GeoPoint(48.52, 9.055));

        hikeOverlay = new Polyline(this);
        hikeOverlay.setColor(res.getColor(R.color.polyline_color));
        mapView.getOverlays().add(hikeOverlay);

        dbHandler = new DatabaseHandler(this);
        poiHandler = new PoiHandler(this, res, mapView);
        weatherHandler = new WeatherHandler(this);
        hikeHandler = new HikeHandler(hikeOverlay);

        lastWeatherInformation = lastPoiInformation = 0;

        foundLocations = new ArrayList<>();

        currentPosition = new Marker(mapView);
        currentPosition.setInfoWindow(new ModernInfoWindow(mapView, false));
        currentPosition.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER);
        currentPosition.setTitle(getString(R.string.osm_marker_title));
        currentPosition.setIcon(res.getDrawable(R.drawable.ic_currency_96, null));

        relativeLayout.addView(mapView);

        mTitle = mDrawerTitle = getTitle();

        initGps();

        fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mLocation == null){
                    InformDialog informDialog = new InformDialog();
                    Bundle args = new Bundle();
                    args.putString("title", getString(R.string.inform_title));
                    args.putString("msg", getString(R.string.inform_gps_pos_not_found));
                    informDialog.setArguments(args);
                    informDialog.show(getFragmentManager(), "Inform Dialog");
                    return;
                }
                AddPoiDialog addPoiDialog = poiHandler.createAddPoiDialog();
                addPoiDialog.show(getFragmentManager(), "Add POI Dialog");
            }
        });
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        poiView = (ExpandableListView) findViewById(R.id.poiList);
        weatherSymbol = (ImageView) findViewById(R.id.weather_symbol);
        weatherCity = (TextView) findViewById(R.id.weather_city);
        weatherDesc = (TextView) findViewById(R.id.weather_desc);
        weatherMinTemp = (TextView) findViewById(R.id.weather_min_temp);
        weatherMaxTemp = (TextView) findViewById(R.id.weather_max_temp);
        sunLayout = (LinearLayout) findViewById(R.id.sun_layout);
        weatherSunrise = (TextView) findViewById(R.id.weather_sunrise);
        weatherSunset = (TextView) findViewById(R.id.weather_sunset);

        drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);


        List<String> emptyChild = new ArrayList<>();
        List<Integer> emptyChildImg = new ArrayList<>();
        final List<String> headers = new ArrayList<>();
        final List<String> headerKeys = new ArrayList<>();
        HashMap<String, List<String>> children = new HashMap<>();
        HashMap<String, List<Integer>> childrenImgs = new HashMap<>();

        //Add POI entry
        String layerKey = getString(R.string.drawer_entry_layers);
        headers.add(layerKey);
        headerKeys.add(null); //there is no action for expandable poi layer
        children.put(layerKey, Arrays.asList(PoiHandler.getEntries()));
        childrenImgs.put(layerKey, Arrays.asList(PoiHandler.getEntryImgs()));

        String[] hikeEntries = res.getStringArray(R.array.hikeEntries);
        String[] hikeEntriesKeys = res.getStringArray(R.array.hikeEntriesKeys);
        for(int i=0; i<hikeEntries.length; i++) {
            String entry = hikeEntries[i];
            headers.add(entry);
            headerKeys.add(hikeEntriesKeys[i]);
            children.put(entry, emptyChild);
            childrenImgs.put(entry, emptyChildImg);
        }

        String[] menuEntries = res.getStringArray(R.array.menuEntries);
        String[] menuEntriesKeys = res.getStringArray(R.array.menuEntriesKeys);
        for(int i=0; i<menuEntries.length; i++) {
            String entry = menuEntries[i];
            headers.add(entry);
            headerKeys.add(menuEntriesKeys[i]);
            children.put(entry, emptyChild);
            childrenImgs.put(entry, emptyChildImg);
        }

        ExpandableListAdapter expandableListAdapter = new ExpandableListAdapter(this, headers, children, childrenImgs);
        poiView.setAdapter(expandableListAdapter);
        poiView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                toggleDrawerItems((LinearLayout) v, childPosition);
                return false;
            }
        });
        poiView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView parent, View v, final int groupPosition, long id) {
                String key = headerKeys.get(groupPosition);
                final TextView view = (TextView) v.findViewById(R.id.simple_textview);
                if(key == null) return false;
                if (key.equals(getString(R.string.hike_title_record_key))) {
                    if (hikeHandler.isRecording()) {
                        final ArrayList<HikePoint> hikePoints = (ArrayList<HikePoint>) hikeHandler.getPoints();

                        LayoutInflater inflater = getLayoutInflater();
                        View hikeDialog = inflater.inflate(R.layout.hike_dialog, null, true);
                        final EditText input = (EditText) hikeDialog.findViewById(R.id.hike_name);
                        final Spinner flooring = (Spinner) hikeDialog.findViewById(R.id.hike_flooring_spinner);
                        TextView lengthView = (TextView) hikeDialog.findViewById(R.id.hike_length);
                        final TextView timeView = (TextView) hikeDialog.findViewById(R.id.hike_time);
                        final TextView heightUpView = (TextView) hikeDialog.findViewById(R.id.hike_height_up);
                        final TextView heightDownView = (TextView) hikeDialog.findViewById(R.id.hike_height_down);

                        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(MainActivity.this,
                                R.array.hike_floorings, android.R.layout.simple_spinner_item);
                        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                        flooring.setAdapter(adapter);
                        flooring.setSelection(Features.HIKE_FLOORING_TRAIL);
                        flooring.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                            @Override
                            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                                String key = getResources().getStringArray(R.array.hike_floorings_keys)[position];
                                if (key.equals(getString(R.string.hike_flooring_street_key))) {
                                } else if (key.equals(getString(R.string.hike_flooring_grit_key))) {
                                } else if (key.equals(getString(R.string.hike_flooring_trail_key))) {
                                }
                            }

                            @Override
                            public void onNothingSelected(AdapterView<?> parent) {
                            }
                        });

                        int lengthRest = hikeHandler.getTime();

                        lengthView.setText(String.format(Locale.getDefault(), "Length so far: %.02fm", hikeHandler.getLength()));
                        timeView.setText("Time so far: " + formatTimeIntervalToHms(lengthRest));
                        heightUpView.setText(String.format(Locale.getDefault(), "Up: %.02fm", hikeHandler.getUp()));
                        heightDownView.setText(String.format(Locale.getDefault(), "Down: %.02fm", hikeHandler.getDown()));

                        AlertDialog.Builder saveHikeBuilder = new AlertDialog.Builder(MainActivity.this);
                        saveHikeBuilder.setTitle(R.string.hike_save_title)
                                .setView(hikeDialog)
                                .setPositiveButton(R.string.hike_save_ok_button, new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        String name = input.getText().toString().trim();
                                        if (!name.equals("")) {
                                            hikeHandler.stopRecording();
                                            view.setText(headers.get(groupPosition));
                                            int floor = flooring.getSelectedItemPosition();
                                            long time = System.currentTimeMillis();
                                            long hikeId = poiHandler.addPoi(new Hike(0, hikeHandler.getLength(), hikeHandler.getTime(), (int) (time % 3),
                                                    name, "You", time, hikeHandler.getUp(), hikeHandler.getDown(), floor));
                                            for (HikePoint hp : hikePoints) {
                                                poiHandler.addGp(new DbGeoPoint(hp.getLocation(), hp.getTimestamp(), hikeId, Types.HIKE));
                                            }
                                        }
                                    }
                                })
                                .setNeutralButton(R.string.hike_save_discard, new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        hikeHandler.resetRecording();
                                        view.setText(headers.get(groupPosition));
                                    }
                                })
                                .setNegativeButton(R.string.hike_save_cancel, new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                    }
                                });
                        final AlertDialog saveHikeDialog = saveHikeBuilder.create();
                        saveHikeDialog.show();
                        final Button saveHikeDialogButton = saveHikeDialog.getButton(AlertDialog.BUTTON_POSITIVE);
                        Button discardHikeDialogButton = saveHikeDialog.getButton(AlertDialog.BUTTON_NEUTRAL);
                        Button keepHikeDialogButton = saveHikeDialog.getButton(AlertDialog.BUTTON_NEGATIVE);
                        saveHikeDialogButton.setEnabled(false);
                        saveHikeDialogButton.setTextSize(12);
                        discardHikeDialogButton.setTextSize(12);
                        keepHikeDialogButton.setTextSize(12);

                        input.addTextChangedListener(new TextWatcher() {
                            @Override
                            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                            }

                            @Override
                            public void onTextChanged(CharSequence s, int start, int before, int count) {
                                if (s.length() > 0) saveHikeDialogButton.setEnabled(true);
                                else saveHikeDialogButton.setEnabled(false);
                            }

                            @Override
                            public void afterTextChanged(Editable s) {
                            }
                        });
                    } else {
                        AlertDialog.Builder startHikeBuilder = new AlertDialog.Builder(MainActivity.this);
                        startHikeBuilder
                                .setTitle(R.string.hike_start_question)
                                .setMessage(R.string.hike_start_desc)
                                .setPositiveButton(R.string.hike_start_ok_button, new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        hikeHandler.startRecording();
                                        view.setText(res.getString(R.string.hike_title_stop_rec));
                                        Toaster(res.getString(R.string.hike_is_recording), true);
                                    }
                                })
                                .setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                    }
                                });
                        AlertDialog startHikeDialog = startHikeBuilder.create();
                        startHikeDialog.show();
                    }
                } else if (key.equals(getString(R.string.hike_title_show_key))) {
                    if (mLocation == null) {
                        Toaster("No location found!", true); //TODO dialog
                    } else {
                        final List<Hike> hikes = poiHandler.getHikesAround(mLocation);
                        final List<List<DbGeoPoint>> points = new ArrayList<>();
                        for (Hike hike : hikes) {
                            points.add(dbHandler.getGeoPointsForPoi(hike.getId(), hike.getType()));
                        }
                        AlertDialog.Builder showHikesDialogBuilder = new AlertDialog.Builder(MainActivity.this)
                                .setTitle(R.string.hike_list_title)
                                .setNegativeButton(R.string.close_button, new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                    }
                                });
                        if(hikes.size() > 0) {
                            showHikesDialogBuilder
                                    .setAdapter(new HikeListAdapter(MainActivity.this, hikes, points), new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            Polyline hikePath = new Polyline(MainActivity.this);
                                            Hike hike = hikes.get(which);
                                            List<DbGeoPoint> dbPoints = points.get(which);
                                            List<GeoPoint> pathPoints = new ArrayList<>();
                                            float[] elevationDataPoints = new float[dbPoints.size()];
                                            String[] elevationDataPointsNames = new String[dbPoints.size()];
                                            final String[] elevationDataPointsTimes = new String[dbPoints.size()];
                                            double min = Double.MAX_VALUE;
                                            double max = Double.MIN_VALUE;
                                            long startTime = dbPoints.get(0).getTime();
                                            for (int i = 0; i < dbPoints.size(); i++) {
                                                DbGeoPoint dbGeoPoint = dbPoints.get(i);
                                                elevationDataPointsTimes[i] = formatTimeIntervalToHms((int) (dbGeoPoint.getTime() - startTime));
                                                Log.d(TAG, "formatted: " + elevationDataPointsTimes[i]);
                                                double alt = dbGeoPoint.getAlt();
                                                pathPoints.add(new GeoPoint(dbGeoPoint.getLat(), dbGeoPoint.getLon(), alt));
                                                //TODO REMOVE
                                                alt = (int) (Math.random() * 100) + 40;
                                                elevationDataPoints[i] = (int) alt;
                                                elevationDataPointsNames[i] = (dbGeoPoint.getTime() - startTime) + "s";
                                                if (alt < min) min = alt;
                                                if (alt > max) max = alt;
                                            }
                                            LayoutInflater inflater = getLayoutInflater();
                                            View rowView = inflater.inflate(R.layout.hike_list_detail, null, true);
                                            TextView titleView = (TextView) rowView.findViewById(R.id.hike_list_detail_title);
                                            TextView authorView = (TextView) rowView.findViewById(R.id.hike_list_detail_author);
                                            TextView lengthView = (TextView) rowView.findViewById(R.id.hike_list_detail_length);
                                            TextView timeView = (TextView) rowView.findViewById(R.id.hike_list_detail_time);
                                            TextView difficultyView = (TextView) rowView.findViewById(R.id.hike_list_detail_difficulty);
                                            TextView upView = (TextView) rowView.findViewById(R.id.hike_list_detail_up);
                                            TextView downView = (TextView) rowView.findViewById(R.id.hike_list_detail_down);
                                            LineChartView elevationProfileNew = (LineChartView) rowView.findViewById(R.id.hike_list_detail_elevation_profile);
                                            MapView hikeMap = (MapView) rowView.findViewById(R.id.hike_list_detail_map);
                                            titleView.setText(hike.getName());
                                            authorView.setText(String.format(Locale.getDefault(), res.getString(R.string.hike_list_author), hike.getAuthor()));
                                            lengthView.setText(String.format(Locale.getDefault(), "Length: %.02fm", hike.getLength()));
                                            timeView.setText(String.format(Locale.getDefault(), "Time: %ds", hike.getTime()));
                                            difficultyView.setText(res.getStringArray(R.array.hike_difficulties)[hike.getDifficulty()]);
                                            Drawable difficultyDrawable = null;
                                            switch (hike.getDifficulty()) {
                                                case 0:
                                                    difficultyDrawable = res.getDrawable(R.drawable.difficulty_indicator_easy, null);
                                                    break;
                                                case 1:
                                                    difficultyDrawable = res.getDrawable(R.drawable.difficulty_indicator_medium, null);
                                                    break;
                                                case 2:
                                                    difficultyDrawable = res.getDrawable(R.drawable.difficulty_indicator_hard, null);
                                                    break;
                                            }
                                            difficultyView.setCompoundDrawablesWithIntrinsicBounds(difficultyDrawable, null, null, null);
                                            upView.setText(String.format(Locale.getDefault(), "Up: %.02fm", hike.getHeightUp()));
                                            downView.setText(String.format(Locale.getDefault(), "Down: %.02fm", hike.getHeightDown()));
                                            final LineSet lineSet = new LineSet(elevationDataPointsNames, elevationDataPoints);
                                            lineSet.setDotsColor(res.getColor(R.color.white));
                                            lineSet.setDotsStrokeColor(res.getColor(R.color.elevation_line));
                                            lineSet.setColor(res.getColor(R.color.elevation_line));
                                            lineSet.setFill(res.getColor(R.color.elevation_bg));
                                            lineSet.setDotsRadius(6);
                                            lineSet.setDotsStrokeThickness(3);
                                            lineSet.setThickness(4);
                                            int minDisp = (int) min;
                                            int maxDisp = (int) max;
                                            int padding = (maxDisp - minDisp) / 10;
                                            minDisp = Math.max(0, minDisp - padding);
                                            maxDisp += padding;
                                            minDisp = Math.max(0, minDisp - (minDisp % 10));
                                            maxDisp += (10 - (maxDisp % 10));
                                            int step = (maxDisp - minDisp) / 2;
                                            elevationProfileNew.setAxisBorderValues(minDisp, maxDisp, step);
                                            elevationProfileNew.setXLabels(AxisController.LabelPosition.NONE);
                                            elevationProfileNew.setXAxis(false);
                                            elevationProfileNew.setYAxis(false);
                                            elevationProfileNew.setGrid(ChartView.GridType.HORIZONTAL, new Paint());
                                            elevationProfileNew.addData(lineSet);

                                            elevationProfileNew.setOnEntryClickListener(new OnEntryClickListener() {
                                                @Override
                                                public void onClick(int setIndex, int entryIndex, Rect rect) {
                                                    Toaster(lineSet.getEntry(entryIndex).getValue() + "m @ " + elevationDataPointsTimes[entryIndex], true);
                                                }
                                            });

                                            elevationProfileNew.show(new Animation(1000));
                                            hikeMap.setTileSource(TileSourceFactory.MAPNIK);
                                            hikeMap.setBuiltInZoomControls(true);
                                            hikeMap.setMultiTouchControls(true);
                                            IMapController hikeMapController = hikeMap.getController();
                                            hikeMapController.setZoom(ZOOM_LEVEL);
                                            hikeMapController.setCenter(pathPoints.get(pathPoints.size() / 2));

                                            AlertDialog detailHikeDialog = new AlertDialog.Builder(MainActivity.this)
                                                    .setTitle(String.format(Locale.getDefault(), res.getString(R.string.hike_detail_title), hike.getName()))
                                                    .setView(rowView)
                                                    .setPositiveButton(R.string.hike_start_navigation, new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                        }
                                                    })
                                                    .setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
                                                        @Override
                                                        public void onClick(DialogInterface dialog, int which) {
                                                        }
                                                    })
                                                    .create();
                                            detailHikeDialog.show();
                                            hikePath.setPoints(pathPoints);
                                            hikePath.setColor(res.getColor(R.color.polyline_color));
                                            hikeMap.getOverlays().add(hikePath);
                                            hikeMap.invalidate();
                                        }
                                    });
                        } else {
                            showHikesDialogBuilder.setMessage(R.string.hike_list_no_hikes);
                        }
                        AlertDialog showHikesDialog = showHikesDialogBuilder.create();
                        showHikesDialog.show();
                    }
                } else if(key.equals(getString(R.string.menu_title_about_key))) {
                    Intent about = new Intent(MainActivity.this, AboutActivity.class);
                    startActivity(about);
                } else if(key.equals(getString(R.string.menu_title_settings_key))) {
                    Intent settings = new Intent(MainActivity.this, SettingsActivity.class);
                    startActivity(settings);
                } else if(key.equals(getString(R.string.menu_title_download_key))) {
                    Intent download = new Intent(MainActivity.this, DownloadActivity.class);
                    startActivity(download);
                }
                return false;
            }
        });

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout,
                R.string.navigation_drawer_open,
                R.string.navigation_drawer_close);
        drawerToggle.setDrawerIndicatorEnabled(true);
        drawerLayout.addDrawerListener(drawerToggle);

        double _lat = 48.52;
        double _lon = 9.055;
        double _alt = 350;
        long _time = System.currentTimeMillis() / 1000;
        Fountain fountain = new Fountain(0, 2);
        long f_id = dbHandler.addPoi(fountain);
        DbGeoPoint dbgp = new DbGeoPoint(_lat, _lon, _alt, _time, f_id, Types.FOUNTAIN);
        long gp_id = dbHandler.addPoi(dbgp);
    }

    private void toggleDrawerItems(LinearLayout layout, int position){
        TextView tv = (TextView) layout.findViewById(R.id.toggleEntryDesc);
        int type = getType(position);
        Drawable[] drawables = tv.getCompoundDrawables();
        if(tv.getTag() == null || tv.getTag() == "disabled"){
            drawables[0].setColorFilter(null);
            tv.setTag("");
            tv.setTextColor(res.getColor(R.color.text_color_selected));
            String title = PoiHandler.getEntries()[position];
            poiHandler.enablePois(type, title);
        } else {
            drawables[0].setColorFilter(res.getColor(R.color.icon_unselected_gray), PorterDuff.Mode.DST_OUT);
            tv.setTag("disabled");
            tv.setTextColor(res.getColor(R.color.text_color));
            Toaster("You disabled " + PoiHandler.getEntries()[position]);
            poiHandler.disablePois(type);
            mapView.invalidate();
        }
        tv.setCompoundDrawablesWithIntrinsicBounds(drawables[0], drawables[1], drawables[2], drawables[3]);
    }

    public static SharedPreferences getSharedPrefs() { return sharedPrefs; }

    public static Resources getRes() {
        return res;
    }

    public static boolean showWeatherHints() {
        return sharedPrefs.getBoolean(res.getString(R.string.settings_hint_enable_key), true);
    }

    public static List<Location> getFoundLocations() {
        return foundLocations;
    }

    public static int getPos(int type){
        int pos;
        switch(type){
            case Types.FOUNTAIN:
                pos = 0;
                break;
            case Types.PATH:
                pos = 1;
                break;
            case Types.HUT:
                pos = 2;
                break;
            case Types.PEAK:
                pos = 3;
                break;
            case Types.BREAK_POINT:
                pos = 4;
                break;
            case Types.TRASH_BIN:
                pos = 5;
                break;
            case Types.PIC:
                pos = 6;
                break;
            case Types.CELL_RECEPTION:
                pos = 7;
                break;
            case Types.WIFI:
                pos = 8;
                break;
            case Types.LIFT:
                pos = 9;
                break;
            case Types.BIOTA:
                pos = 10;
                break;
            default:
                pos = 0;
                break;
        }
        return pos;
    }

    public static int getType(int position){
        int type;
        switch (position){
            case 0:
                type = Types.FOUNTAIN;
                break;
            case 1:
                type = Types.PATH;
                break;
            case 2:
                type = Types.HUT;
                break;
            case 3:
                type = Types.PEAK;
                break;
            case 4:
                type = Types.BREAK_POINT;
                break;
            case 5:
                type = Types.TRASH_BIN;
                break;
            case 6:
                type = Types.PIC;
                break;
            case 7:
                type = Types.CELL_RECEPTION;
                break;
            case 8:
                type = Types.WIFI;
                break;
            case 9:
                type = Types.LIFT;
                break;
            case 10:
                type = Types.BIOTA;
                break;
            default:
                type = 0;
                break;
        }
        return type;
    }

    private static String getTypeName(int type){
        String name = "";
        switch(type){
            case Types.FOUNTAIN:
                name = "fountain";
                break;
            case Types.PATH:
                name = "path";
                break;
            case Types.HUT:
                name = "hut";
                break;
            case Types.PEAK:
                name = "peak";
                break;
            case Types.BREAK_POINT:
                name = "break_point";
                break;
            case Types.TRASH_BIN:
                name = "trash_bin";
                break;
            case Types.PIC:
                name = "image";
                break;
            case Types.CELL_RECEPTION:
                name = "cell_reception";
                break;
            case Types.WIFI:
                name = "wifi";
                break;
            case Types.LIFT:
                name = "lift";
                break;
            case Types.HIKE:
                name = "hike";
                break;
            case Types.BIOTA:
                name = "biota";
                break;
        }
        return name;
    }

    public static File createImageFile() throws IOException {
        String ts = new SimpleDateFormat("yyyMMdd_HHmmss").format(new Date());
        String fileName = "JPEG_" + ts + "_";
        File dir = context.getExternalFilesDir(null);
        File image = File.createTempFile(fileName,
                ".jpg",
                dir);
        currentImagePath = image.getAbsolutePath();
        return image;
    }

    public static Drawable convertByteArrayToDrawable(byte[] b, float scaleTo) {
        if(scaleTo <= 0) return new BitmapDrawable(res, BitmapFactory.decodeByteArray(b, 0, b.length));
        Bitmap bitmap = new BitmapDrawable(res, BitmapFactory.decodeByteArray(b, 0, b.length)).getBitmap();
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        float widthScale = scaleTo / width;
        float heightScale = scaleTo / height;
        float scale = Math.min(widthScale, heightScale);
        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);
        Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
        return new BitmapDrawable(res, scaledBitmap);
    }

    public static Drawable convertByteArrayToDrawable(byte[] b) {
        return convertByteArrayToDrawable(b, -1);
    }

    public static byte[] convertDrawableToByteArray(Drawable d) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ((BitmapDrawable) d).getBitmap().compress(Bitmap.CompressFormat.JPEG, 100, stream);
        return stream.toByteArray();
    }

    private void initGps(){
        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
        boolean isLocationEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        if(!isLocationEnabled){
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            startActivity(intent);
        }
    }

    private void Toaster(String text){
        Toaster(text, false);
    }

    private void Toaster(String text, boolean longDuration){
        if(longDuration) Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show();
        else Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
    }

    public static void Toaster(String text, Context context){
        Toaster(text, false, context);
    }

    public static void Toaster(String text, boolean longDuration, Context context) {
        if(longDuration) Toast.makeText(context, text, Toast.LENGTH_LONG).show();
        else Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
    }

    public static Location getLocation() { return mLocation; }

    public static MapView getMapView(){
        return mapView;
    }

    public static DatabaseHandler getDbHandler(){
        return dbHandler;
    }

    public static ArrayList<OverlayItem> getPathMarkers(){
        return pathMarkers;
    }

    public static void setPathMarkers(ArrayList<OverlayItem> al){
        pathMarkers = al;
    }

    private static void setActiveNetwork(){
        activeNetwork = cm.getActiveNetworkInfo();
    }

    public static void setNetworkStrength(int strength){
        networkStrength = strength;
    }

    public static int getNetworkStrength() {
        return networkStrength;
    }

    public static void addPoiToMap(Poi poi) {
        ArrayList<DbGeoPoint> dbGeoPoints = (ArrayList<DbGeoPoint>) dbHandler.getGeoPointsForPoi(poi.getId(), poi.getType());
        if(dbGeoPoints == null || dbGeoPoints.size() == 0) return;
        DbGeoPoint dbGeoPoint = dbGeoPoints.get(0);
        if(dbGeoPoint == null) return;
        GeoPoint gp = new GeoPoint(dbGeoPoint.getLat(), dbGeoPoint.getLon(), dbGeoPoint.getAlt());
        Marker marker = new Marker(mapView);
        marker.setInfoWindow(new ModernInfoWindow(mapView, true));
        marker.setIcon(PoiHandler.createPoiMarker(poi.getType()));
        marker.setTitle(getTypeName(poi.getType()));
        marker.setSnippet(dbGeoPoint.toString() + "\n" + poi.toString());
        marker.setPosition(gp);
        marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
        mapView.getOverlays().add(marker);
        PoiHandler.addPoiMarker(poi.getType(), marker); //add new marker to list (needed to hide poi by type)
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        drawerToggle.syncState();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
    }

    public static PoiHandler getPoiHandler() { return poiHandler; }

    public static WeatherHandler getWeatherHandler() { return weatherHandler; }

    public static NetworkInfo getActiveNetwork() {
        return activeNetwork;
    }

    public static WifiManager getWifiManager() {
        return wm;
    }

    public static TelephonyManager getTelephonyManager() {
        return tm;
    }

    public static boolean hasInternet() {
        setActiveNetwork();
        return activeNetwork != null && activeNetwork.isConnected();
    }

    public static boolean useFahrenheit() {
        return sharedPrefs.getBoolean(res.getString(R.string.settings_use_fahrenheit_key), false);
    }

    public static String formatTimeIntervalToHms(int seconds) {
        int hours = seconds / 3600;
        seconds %= 3600;
        int minutes = seconds / 60;
        seconds %= 60;
        return String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds);
    }

    @Override
    public void onLocationUpdate(Location location) {
        if(mLocation != null && pm.isInteractive()) {
            Location oldLocation = new Location(mLocation);
            long currentTime = System.currentTimeMillis();
            float distance = mLocation.distanceTo(oldLocation);

            if(currentTime - lastWeatherInformation >= MIN_WEATHER_RELOAD_TIME || distance >= MIN_WEATHER_RELOAD_DIST) {
                lastWeatherInformation = currentTime;
                weatherHandler.getCurrentWeather(location, this);
            }
            if(currentTime - lastPoiInformation >= MIN_POI_RELOAD_TIME || distance >= MIN_POI_RELOAD_DIST) { //5 minutes
                lastPoiInformation = currentTime;
                ArrayList<Poi> pois = new ArrayList<>(poiHandler.getPoisAround(location.getLatitude(), location.getLongitude(), MAX_POIS_AROUND));
                Log.d(MainActivity.TAG, "found " + pois.size() + " pois.");
                for(Poi p : pois) {
                    p.display();
                }
            }
        }
        mLocation = location;
        if(mLocation == null) return;
        foundLocations.add(location);

        if(hikeHandler.isRecording()) hikeHandler.addLocation(mLocation);

        double lat = location.getLatitude();
        double lon = location.getLongitude();
        GeoPoint gp = new GeoPoint(lat, lon);

        mapView.getOverlays().remove(currentPosition);
        currentPosition.setPosition(gp);
        currentPosition.setSnippet(String.format(getString(R.string.osm_marker_snippet), gp.getLatitude(), gp.getLongitude(), gp.getAltitude(), 0));
        mapView.getOverlays().add(currentPosition);
        mapView.invalidate();
        mapController.setCenter(gp);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch(requestCode){
            case RequestCodes.SELECT_POI_PHOTO:
                if(resultCode == RESULT_OK){
                    poiHandler.addImagePoi(data.getData());
                }
                break;
            case RequestCodes.SELECT_ENDANGERED_PHOTO:
                if(resultCode == RESULT_OK) {
                    AddBiotaDialog.addImage(data.getData());
                }
                break;
            case RequestCodes.TAKE_ENDANGERED_IMAGE:
                if(resultCode == RESULT_OK) {
                    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
                    bitmapOptions.inJustDecodeBounds = false;
                    Bitmap b = BitmapFactory.decodeFile(currentImagePath, bitmapOptions);
                    AddBiotaDialog.addImage(b);
                }
                break;
        }
    }

    @Override
    public void setTitle(CharSequence title){
        mTitle = title;
        ActionBar actionBar = getSupportActionBar();
        if(actionBar != null) actionBar.setTitle(mTitle);
    }

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

    @Override
    protected void onResume() {
        super.onResume();
        weatherHandler = new WeatherHandler(this);
        Intent service = new Intent(this, LocationService.class);
        bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);
        //startService(service);
        PendingIntent pi = PendingIntent.getService(getApplicationContext(), 0, service, PendingIntent.FLAG_CANCEL_CURRENT);
        am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), GPS_MIN_TIME, pi);
    }

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

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }

    @Override
    public MyWeather postRetrieve(MyWeather weather) {
        weatherSymbol.setImageDrawable(weather.getWeatherCodeImage());
        weatherCity.setText(String.format(Locale.getDefault(), res.getString(R.string.weather_city_display), weather.getCity(), weather.getCountry()));
        weatherDesc.setText(weather.getWeatherDesc());
        String weatherText;
        float minTemp = weather.getMinTemp();
        float maxTemp = weather.getMaxTemp();
        if(useFahrenheit()) {
            weatherText = res.getString(R.string.preferences_n_degree_f_floating);
            minTemp = WeatherHandler.celsiusToFahrenheit(minTemp);
            maxTemp = WeatherHandler.celsiusToFahrenheit(maxTemp);
        } else {
            weatherText = res.getString(R.string.preferences_n_degree_c_floating);
        }
        weatherMinTemp.setText(String.format(Locale.getDefault(), weatherText, minTemp));
        weatherMaxTemp.setText(String.format(Locale.getDefault(), weatherText, maxTemp));
        weatherSunrise.setText(df_hm.format(new Date(weather.getSunrise()*1000)));
        weatherSunset.setText(df_hm.format(new Date(weather.getSunset()*1000)));
        sunLayout.setVisibility(View.VISIBLE);
        if(weather.isSevereWeather()) weatherCity.setCompoundDrawablesWithIntrinsicBounds(null, null, res.getDrawable(R.drawable.ic_warning, null), null);
        else weatherCity.setCompoundDrawables(null, null, null, null);
        weatherHandler.displayHints(weather);
        weatherHandler.displaySevereWeather(weather);
        return null;
    }
}