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.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
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.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.support.v4.widget.DrawerLayout;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

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

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import de.apps4ics.mountainnavigation.adapters.ImageListAdapter;
import de.apps4ics.mountainnavigation.handlers.DatabaseHandler;
import de.apps4ics.mountainnavigation.handlers.PoiHandler;
import de.apps4ics.mountainnavigation.handlers.WeatherHandler;
import de.apps4ics.mountainnavigation.pois.AddPoiDialog;
import de.apps4ics.mountainnavigation.pois.DbGeoPoint;
import de.apps4ics.mountainnavigation.pois.Fountain;
import de.apps4ics.mountainnavigation.pois.Poi;
import de.apps4ics.mountainnavigation.pois.Types;

public class MainActivity extends AppCompatActivity implements LocationListener, OnSingleWeatherRetrieved {

    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 = 5;
    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 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 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 FloatingActionButton fab;

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

    private long lastWeatherInformation;
    private long lastPoiInformation;

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

    private ActionBarDrawerToggle drawerToggle;
    private DrawerLayout drawerLayout;
    private LinearLayout poiView;
    private LinearLayout menuView;
    private ImageView weatherSymbol;
    private ImageView weatherWarning;
    private TextView weatherCity;
    private TextView weatherDesc;
    private TextView weatherMinTemp;
    private TextView weatherMaxTemp;

    private Marker currentPosition;

    public static ArrayList<OverlayItem> pathMarkers;
    public static OverlayItem imageMarker;

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

    private static List<Location> foundLocations;

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

        res = getResources();
        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);

        sharedPrefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);

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

        RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.container);

        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));

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

        lastWeatherInformation = lastPoiInformation = 0;

        foundLocations = new ArrayList<>();

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

        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);
        menuView = (LinearLayout) findViewById(R.id.menuList);
        poiView = (LinearLayout) findViewById(R.id.poiList);
        weatherSymbol = (ImageView) findViewById(R.id.weather_symbol);
        weatherWarning = (ImageView) findViewById(R.id.warning_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);

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

//      poiView.setItemsCanFocus(false);
        ImageListAdapter adapter = new ImageListAdapter(MainActivity.this, PoiHandler.getEntries(), PoiHandler.getEntryImgs(), false);
        for(int i=0; i<adapter.getCount(); i++) {
            final TableLayout row = (TableLayout) adapter.getView(i, null, poiView);
            final int position = i;
            row.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    toggleDrawerItems(row, position);
                }
            });
            poiView.addView(row);
        }

        String[] menuEntries = res.getStringArray(R.array.menuEntries);
        ArrayAdapter<String> menuAdapter = new ArrayAdapter<>(MainActivity.this, R.layout.drawer_list_simple, menuEntries);
        for(int i=0; i<menuAdapter.getCount(); i++) {
            final int position = i;
            View view = menuAdapter.getView(i, null, menuView);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String key = res.getStringArray(R.array.menuEntriesKeys)[position];
                    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);
                    }
                }
            });
            menuView.addView(view);
        }

        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.setDrawerListener(drawerToggle);

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

    private void toggleDrawerItems(TableLayout layout, int position){
        TableRow tr = (TableRow) layout.getChildAt(0);
        TextView tv = null;
        ImageView iv = null;
        for(int i=0; i<tr.getChildCount(); ++i){
            View v = tr.getChildAt(i);
            try {
                tv = (TextView) v;
            } catch(ClassCastException cce){
                //Log.e(TAG, "Could not cast " + v.getClass().toString() + " to TextView!");
            }
            try {
                iv = (ImageView) v;
            } catch(ClassCastException cce){
                //Log.e(TAG, "Could not cast " + v.getClass().toString() + " to ImageView!");
            }
        }
        if(tv == null || iv == null){
            Log.e(TAG, "Neither TextView nor ImageView can be null!");
            return;
        }
        int type = getType(position);
        if(iv.getTag() == null || iv.getTag() == "disabled"){
            iv.setColorFilter(null);
            iv.setTag("");
            tv.setTextColor(res.getColor(R.color.text_color_selected));
            String title = PoiHandler.getEntries()[position];
            List<Marker> markers = poiHandler.getPoiIcons(type, title);
            mapView.getOverlays().addAll(markers);
            mapView.invalidate();
        } else {
            iv.setColorFilter(res.getColor(R.color.icon_unselected_gray));
            iv.setTag("disabled");
            tv.setTextColor(res.getColor(R.color.text_color));
            Toaster("You disabled " + PoiHandler.getEntries()[position]);
            poiHandler.disablePois(type);
            mapView.invalidate();
        }
    }

    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;
            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.GP;
                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;
        }
        return name;
    }

    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);
        }
        Criteria criteria = new Criteria();
        provider = locationManager.getBestProvider(criteria, false);
        mLocation = locationManager.getLastKnownLocation(provider);
    }

    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 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;
    }

    private void addSimpleMarker(GeoPoint gp){
        Marker positionMarker = new Marker(mapView);
        positionMarker.setPosition(gp);
        positionMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
        positionMarker.setTitle(getString(R.string.osm_marker_title));
        positionMarker.setSnippet(String.format(getString(R.string.osm_marker_snippet), gp.getLatitude(), gp.getLongitude(), gp.getAltitude(), 0));
        mapView.getOverlays().add(positionMarker);
        mapView.invalidate();
    }

    public static void addPoiToMap(Poi poi) {
        DbGeoPoint dbGeoPoint = poi.getGp();
        GeoPoint gp = new GeoPoint(dbGeoPoint.getLat(), dbGeoPoint.getLon(), dbGeoPoint.getAlt());
        Marker marker = new Marker(mapView);
        marker.setIcon(PoiHandler.createPoiMarker(poi.getType()));
        marker.setTitle(getTypeName(poi.getType()));
        marker.setSnippet(poi.getGp().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
    public void onLocationChanged(Location location) {
        if(mLocation != null) {
            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(TAG, "found " + pois.size() + " pois.");
                for(Poi p : pois) {
                    p.display();
                }
            }
        }
        mLocation = location;
        if(mLocation == null) return;
        foundLocations.add(location);

        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
    public void onStatusChanged(String provider, int status, Bundle extras) {
        Log.d(TAG, "onStatusChanged: " + provider + ", " + status);
    }

    @Override
    public void onProviderEnabled(String provider) {
        Log.d(TAG, "onProviderEnabled: " + provider);
    }

    @Override
    public void onProviderDisabled(String provider) {
        Log.d(TAG, "onProviderDisabled: " + provider);
    }

    @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();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch(requestCode){
            case PoiHandler.SELECT_POI_PHOTO:
                if(resultCode == RESULT_OK){
                    poiHandler.addImagePoi(data.getData());
                }
                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();
        locationManager.requestLocationUpdates(provider, GPS_MIN_TIME, GPS_MIN_DIST, this);
    }

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

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

    @Override
    public MyWeather postRetrieve(MyWeather weather) {
        weatherSymbol.setImageDrawable(weather.getWeatherCodeImage());
        weatherCity.setText(weather.getCity() + ", " + weather.getCountry());
        weatherDesc.setText(weather.getWeatherDesc());
        weatherMinTemp.setText(String.format(res.getString(R.string.preferences_n_degree_floating), weather.getMinTemp()));
        weatherMaxTemp.setText(String.format(res.getString(R.string.preferences_n_degree_floating), weather.getMaxTemp()));
        if(weather.isSevereWeather()) weatherWarning.setImageDrawable(res.getDrawable(R.drawable.ic_warning));
        else weatherWarning.setImageDrawable(null);
        weatherHandler.displayHints(weather);
        weatherHandler.displaySevereWeather(weather);
        return null;
    }
}