org.csp.everyaware.offline.Map.java Source code

Java tutorial

Introduction

Here is the source code for org.csp.everyaware.offline.Map.java

Source

/**
 * AirProbe
 * Air quality application for Android, developed as part of 
 * EveryAware project (<http://www.everyaware.eu>).
 *
 * Copyright (C) 2014 CSP Innovazione nelle ICT. All rights reserved.
 * 
 * This program 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.
 * 
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * For any inquiry please write to <devel@csp.it>
 * 
 * CONTRIBUTORS
 * 
 * This program was made with the contribution of:
 *   Fabio Saracino <fabio.saracino@csp.it>
 *   Patrick Facco <patrick.facco@csp.it>
 * 
 * 
 * SOURCE CODE
 * 
 *  The source code of this program is available at
 *  <https://github.com/CSPICT/airprobe>
 */

package org.csp.everyaware.offline;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.csp.everyaware.ColorHelper;
import org.csp.everyaware.Constants;
import org.csp.everyaware.ExtendedLatLng;
import org.csp.everyaware.KmlParser;
import org.csp.everyaware.R;
import org.csp.everyaware.Start;
import org.csp.everyaware.Utils;
import org.csp.everyaware.bluetooth.BluetoothBroadcastReceiver;
import org.csp.everyaware.bluetooth.BluetoothManager;
import org.csp.everyaware.db.AnnotatedRecord;
import org.csp.everyaware.db.DbManager;
import org.csp.everyaware.db.MapCluster;
import org.csp.everyaware.db.MarkerRecord;
import org.csp.everyaware.db.Record;
import org.csp.everyaware.db.Track;
import org.csp.everyaware.internet.FacebookManager;
import org.csp.everyaware.internet.StoreAndForwardService;
import org.csp.everyaware.internet.TwitterManager;
import org.csp.everyaware.tabactivities.Graph;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.LocationSource.OnLocationChangedListener;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.android.gms.maps.model.VisibleRegion;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnShowListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.CompoundButton.OnCheckedChangeListener;

public class Map extends Activity {
    private MapView mMapView;
    private GoogleMap mGoogleMap;
    private MyLocationSource mLocationSource;

    private Handler mHandler;
    private DbManager mDbManager;

    private List<Record> mRecords = new ArrayList<Record>();

    //opened track
    private Track mTrack;

    //track length button
    private Button mTrackLengthBtn;

    //zoom control custom buttons
    private Button mZoomInBtn, mZoomOutBtn;
    private float mZoom = 15f;

    //insert ann button
    private Button mInsertAnnBtn;

    //share button (log on facebook/twitter)
    private Button mShareBtn;

    //zoom controls (they can show/hide on map)
    private LinearLayout mZoomControls;
    private long mOnMapClickTs;

    //status icons
    private ImageView mGpsStatus;
    private ImageView mInterUplStatus;

    //camera tracking button and boolean flag
    private Button mFollowCamBtn;
    private boolean mCameraTrackOn = true;

    //get bc levels around user from server
    private Button mGetBcLevelsBtn;
    //black carbon legend
    private LinearLayout mSpectrum;

    //array of points of path showed on map
    private List<ExtendedLatLng> mLatLngPoints;

    private ProgressDialog mCancelDialog;
    private ProgressDialog mProgressDialog;
    private ProgressDialog mProgressDialog2;

    private boolean mInitializedView = false;
    private boolean mConnectivityOn;

    //private GetDataThread mGetDataThread;

    private double avg_poll_min = 0;
    private int poll_mult = 35;
    private int poll_base = 25;

    //share section
    private boolean mValidFbSession;
    private boolean mValidTwSession;
    private FacebookManager mFacebookManager;
    private TwitterManager mTwitterManager;
    private Button[] mButtons = new Button[2]; //login buttons (facebook and twitter)

    private Toast mExitToast; //toast showed when user press back button

    private PowerManager mPowerMan;
    private PowerManager.WakeLock mWakeLock;

    private final int BC_MULTIPLIER = 10;

    private KmlParser mKmlParser; //parse server response and returns a list of MapCluster(s)
    private List<MapCluster> mMapClusters; //black carbons level contained in the screen
    private List<Polygon> mMapPolygons;

    private Button mToBeHideBtn;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("Map", "******************************onCreate()******************************");
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.map_container);

        mToBeHideBtn = (Button) findViewById(R.id.startStopBtn);
        mToBeHideBtn.setVisibility(View.GONE);

        mPowerMan = (PowerManager) getSystemService(Context.POWER_SERVICE);
        mWakeLock = mPowerMan.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CPUalwaysOn");

        Utils.setStep(Constants.TRACK_MAP, getApplicationContext());

        mDbManager = DbManager.getInstance(getApplicationContext());
        mDbManager.openDb();

        //it will contain  displayed latlng points
        mLatLngPoints = new ArrayList<ExtendedLatLng>();

        //istantiate custom implementation of LocationSource interface
        mLocationSource = new MyLocationSource();

        //google map initialization
        setUpMapIfNeeded(savedInstanceState);

        //obtaining references to buttons and defining listeners
        getButtonRefs();

        mHandler = new Handler();

        mKmlParser = new KmlParser();

        //starting store'n'forward service and saving reference to it
        Intent serviceIntent = new Intent(getApplicationContext(), StoreAndForwardService.class);
        Utils.storeForwServIntent = serviceIntent;
        startService(serviceIntent);

        //set appropriate colors in all seven black carbon levels under black carbon text box
        setBcLevelColors();
    }

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

        // This verification should be done during onStart() because the system calls
        // this method when the user returns to the activity, which ensures the desired
        // location provider is enabled each time the activity resumes from the stopped state.
        LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        final boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

        if (!gpsEnabled) {
            // Build an alert dialog here that requests that the user enable
            // the location services, then when the user clicks the "OK" button,
            // call enableLocationSettings()
        }
    }

    private void enableLocationSettings() {
        Intent settingsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        startActivity(settingsIntent);
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d("Map", "******************************onStop()******************************");
    }

    @Override
    public void onDestroy() {
        Utils.paused = false;

        mMapView.onDestroy();
        super.onDestroy();
        Log.d("Map", "******************************onDestroy()***************************");

        //release partial wake lock
        if (mWakeLock != null)
            mWakeLock.release();
    }

    @Override
    public void onPause() {
        Utils.paused = true;

        mLocationSource.removeLocUpdates();
        mMapView.onPause();

        Log.d("Map", "******************************onPause()*****************************");

        if (mServiceReceiver != null)
            //unregister receiver for messages from store'n'forward service
            unregisterReceiver(mServiceReceiver);

        if (mGpsServiceReceiver != null)
            //unregister receiver for messages from gps tracking service
            unregisterReceiver(mGpsServiceReceiver);

        //remove polygon heat map from map and clear array of polygons
        if (mMapPolygons != null) {
            for (int i = 0; i < mMapPolygons.size(); i++)
                mMapPolygons.get(i).remove();
            mMapPolygons.clear();
        }

        super.onPause();
    }

    @Override
    public void onResume() {
        Utils.paused = false;
        super.onResume();
        mMapView.onResume();

        //acquire partial wake lock
        if (!mWakeLock.isHeld())
            mWakeLock.acquire();

        mLocationSource.registerLocUpdates();

        if (Utils.uploadOn == Constants.INTERNET_ON_INT)
            mInterUplStatus.setBackgroundResource(R.drawable.internet_on);
        else if (Utils.uploadOn == Constants.INTERNET_OFF_INT)
            mInterUplStatus.setBackgroundResource(R.drawable.internet_off);
        else if (Utils.uploadOn == Constants.UPLOAD_ON_INT)
            mInterUplStatus.setBackgroundResource(R.drawable.upload);

        if (mCameraTrackOn)
            mFollowCamBtn.setBackgroundResource(R.drawable.follow_camera_pressed);
        else
            mFollowCamBtn.setBackgroundResource(R.drawable.follow_camera_not_pressed);

        //register receiver for messages from store'n'forward service
        IntentFilter internetOnFilter = new IntentFilter(Constants.INTERNET_ON);
        registerReceiver(mServiceReceiver, internetOnFilter);
        IntentFilter internetOffFilter = new IntentFilter(Constants.INTERNET_OFF);
        registerReceiver(mServiceReceiver, internetOffFilter);
        IntentFilter uploadOnFilter = new IntentFilter(Constants.UPLOAD_ON);
        registerReceiver(mServiceReceiver, uploadOnFilter);
        IntentFilter uploadOffFilter = new IntentFilter(Constants.UPLOAD_OFF);
        registerReceiver(mServiceReceiver, uploadOffFilter);

        //register receiver for messages from gps tracking service
        IntentFilter phoneGpsOnFilter = new IntentFilter(Constants.PHONE_GPS_ON);
        registerReceiver(mGpsServiceReceiver, phoneGpsOnFilter);
        IntentFilter networkGpsOnFilter = new IntentFilter(Constants.NETWORK_GPS_ON);
        registerReceiver(mGpsServiceReceiver, networkGpsOnFilter);
        IntentFilter phoneGpsOffFilter = new IntentFilter(Constants.PHONE_GPS_OFF);
        registerReceiver(mGpsServiceReceiver, phoneGpsOffFilter);

        //get selected track and draw it on map
        mTrack = Utils.track;

        if (mTrack != null) {
            Log.d("Map", "onCreate()--> shown session id: " + mTrack.mSessionId);

            if (mGoogleMap != null)
                mGoogleMap.clear();

            int divider = 1;

            long trackLength = mTrack.mNumOfRecords;

            Log.d("Map", "onResume()--> track length: " + trackLength);

            if (trackLength > 1800)
                divider = 2;
            if (trackLength > 3600)
                divider = 4;
            if (trackLength > 7200)
                divider = 8;
            if (trackLength > 14400)
                divider = 16;

            mLatLngPoints = mDbManager.loadLatLngPointsBySessionId(mTrack.mSessionId, divider);
            if (mLatLngPoints != null) {
                int size = mLatLngPoints.size();

                if (size > 0) {
                    calcMinAvgPollValue();
                    drawPath();
                    mCameraTrackOn = false;
                    if (mGoogleMap != null)
                        try {
                            mGoogleMap.animateCamera(
                                    CameraUpdateFactory.newLatLng(mLatLngPoints.get(size - 1).mLatLng));
                        } catch (NullPointerException e) {
                            e.printStackTrace();
                        }
                }
            }
        }

        if (mMapPolygons == null)
            mMapPolygons = new ArrayList<Polygon>();

        int color;

        //draw map cluster on the map
        if ((mMapClusters != null) && (mMapClusters.size() > 0)) {
            for (int i = 0; i < mMapClusters.size(); i++) {
                MapCluster mapCluster = mMapClusters.get(i);

                if (mapCluster.mBcLevel != 0) {
                    if ((mapCluster.mBcLevel > 0) && (mapCluster.mBcLevel <= 10))
                        color = ColorHelper.numberToColor(mapCluster.mBcLevel * BC_MULTIPLIER);
                    else
                        color = ColorHelper.numberToColor(100);

                    mMapPolygons.add(mGoogleMap.addPolygon(new PolygonOptions()
                            .add(new LatLng(mapCluster.mMinLat, mapCluster.mMinLon),
                                    new LatLng(mapCluster.mMinLat, mapCluster.mMaxLon),
                                    new LatLng(mapCluster.mMaxLat, mapCluster.mMaxLon),
                                    new LatLng(mapCluster.mMaxLat, mapCluster.mMinLon))
                            .strokeColor(Color.TRANSPARENT)
                            .fillColor(Color.parseColor("#66" + String.format("%06X", 0xFFFFFF & color)))));
                }
            }
        }
    }

    @Override
    public void onBackPressed() {
        closeAppDialog();
        /*
        if(mExitToast != null)
        {      
           if(mExitToast.getView().isShown())
           {
        mExitToast.cancel();
        mExitToast = null;
        closeAppDialog();
           }
           else
           {
        //mExitToast = Toast.makeText(getApplicationContext(), R.string.press_again_to_exit_msg, Toast.LENGTH_SHORT);
        mExitToast.show();   
           }
        }
        else
        {
           mExitToast = Toast.makeText(getApplicationContext(), R.string.press_again_to_exit_msg, Toast.LENGTH_SHORT);
           mExitToast.show();      
        }*/
    }

    /***************************** INIT GOOGLE MAP **********************************************/

    private void setUpMap() {
        mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        mGoogleMap.getUiSettings().setCompassEnabled(false);
        mGoogleMap.getUiSettings().setZoomControlsEnabled(false);

        //assign istance of MyLocationSource to google maps and activate it
        //mGoogleMap.setLocationSource(mLocationSource); 
        //mGoogleMap.setMyLocationEnabled(true);

        //mGoogleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter());

        //animate camera to an initial zoom level 
        try {
            mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(mZoom), 1500, null);
        } catch (NullPointerException e) {
            e.printStackTrace();
        }

        mGoogleMap.setOnMapClickListener(new OnMapClickListener() {
            @Override
            public void onMapClick(LatLng arg0) {
                if (mZoomControls != null) {
                    mOnMapClickTs = new Date().getTime();

                    mZoomControls.setVisibility(View.VISIBLE);

                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if ((new Date().getTime() - mOnMapClickTs) >= 2500)
                                mZoomControls.setVisibility(View.GONE);
                        }

                    }, 3000);
                }
            }
        });

        mGoogleMap.setOnMapLongClickListener(new OnMapLongClickListener() {
            @Override
            public void onMapLongClick(LatLng latLng) {
                double minDistance = 0;
                int index = -1;

                Log.d("Map", "onMapLongClick()--> lat lng: " + latLng.latitude + ", " + latLng.longitude);

                //calculate bounding box around tapped point (tapped point is the center of BB)
                LatLng topLeft = new LatLng(latLng.latitude + 0.01, latLng.longitude - 0.01);
                LatLng bottomRight = new LatLng(latLng.latitude - 0.01, latLng.longitude + 0.01);

                //calculate intersection between BB and path and the point of path inside the intersection that
                //is nearer to tapped point
                //output of the cycle is the index of path point nearest to tapped point
                for (int i = 0; i < mLatLngPoints.size(); i++) {
                    ExtendedLatLng extLatLng = mLatLngPoints.get(i);

                    //if actual path point is inside BB, calculate distance between tapped point and path point and save it 
                    if ((extLatLng.mLatLng.latitude <= topLeft.latitude)
                            && (extLatLng.mLatLng.latitude >= bottomRight.latitude)) {
                        if ((extLatLng.mLatLng.longitude >= topLeft.longitude)
                                && (extLatLng.mLatLng.longitude <= bottomRight.longitude)) {
                            double latDiff = Math.abs(extLatLng.mLatLng.latitude - latLng.latitude);
                            double lonDiff = Math.abs(extLatLng.mLatLng.longitude - latLng.longitude);
                            double distance = Math.sqrt(latDiff * latDiff + lonDiff * lonDiff);

                            if (i == 0) {
                                minDistance = distance;
                                index = 0;
                            } else if (distance < minDistance) {
                                minDistance = distance;
                                index = i;
                            }
                        }
                    }
                }

                //if an index is present, it is the index of the path point inside BB nearest to tapped point
                if (index > -1) {
                    ExtendedLatLng nearestPathLatLng = mLatLngPoints.get(index);
                    insertAnnDialog(nearestPathLatLng);
                } else
                    Toast.makeText(getApplicationContext(), "Path not found", Toast.LENGTH_LONG).show();
            }
        });
    }

    private void setUpMapIfNeeded(Bundle savedInstanceState) {
        // Do a null check to confirm that we have not already instantiated the map.
        if (mMapView == null) {
            mMapView = (MapView) findViewById(R.id.mapView);
            //MapView object has the same life cycle of activity
            mMapView.onCreate(savedInstanceState);

            //get reference to GoogleMap object from MapView
            mGoogleMap = mMapView.getMap();

            if (isGoogleMapsInstalled()) {
                if (mGoogleMap != null) {
                    //CameraUpdateFactory e BitmapDescriptorFactory need initialization now
                    try {
                        MapsInitializer.initialize(this);
                    } catch (GooglePlayServicesNotAvailableException e) {
                        e.printStackTrace();
                    }

                    setUpMap();
                }
            } else {
                Builder builder = new AlertDialog.Builder(this);
                builder.setMessage(getString(R.string.install_google_maps_string));
                builder.setCancelable(false);
                builder.setPositiveButton(R.string.alert_dialog_ok, getGoogleMapsListener());
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        }
    }

    public boolean isGoogleMapsInstalled() {
        try {
            ApplicationInfo info = getPackageManager().getApplicationInfo("com.google.android.apps.maps", 0);
            return true;
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }

    public DialogInterface.OnClickListener getGoogleMapsListener() {
        return new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Intent intent = new Intent(Intent.ACTION_VIEW,
                        Uri.parse("market://details?id=com.google.android.apps.maps"));
                startActivity(intent);

                //Finish the activity so they can't circumvent the check
                finish();
            }
        };
    }

    public final void createLegalNoticesDialog(Activity activity) {
        AlertDialog ad = new AlertDialog.Builder(activity).create();
        ad.setCancelable(false); // This blocks the 'BACK' button  
        ad.setMessage(GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(activity.getApplicationContext()));
        ad.setButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        ad.show();
    }

    /********************************* PERSONALIZED LOCATION SOURCE ******************************************************/

    //to draw user current position on map
    private class MyLocationSource implements LocationListener {
        //private OnLocationChangedListener locChangeListener; //interface of LocationSource
        private LocationManager locManager;

        public MyLocationSource() {
            locManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        }

        public void registerLocUpdates() {
            //register for location updates by gps and network providers
            locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);

            try {
                locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
        }

        public void removeLocUpdates() {
            //remove location updates (all)
            locManager.removeUpdates(this);
        }

        @Override
        public void onProviderDisabled(String provider) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        //method of LocationSource invoked on location update
        @Override
        public void onLocationChanged(Location location) {
            try {
                //center camera on last location update
                if (mCameraTrackOn)
                    mGoogleMap.animateCamera(CameraUpdateFactory
                            .newLatLng(new LatLng(location.getLatitude(), location.getLongitude())));
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
        }
    }

    /****************** OTTIENE RIFERIMENTO AI BOTTONI *********************************/

    public void getButtonRefs() {
        mZoomControls = (LinearLayout) findViewById(R.id.zoomLinearLayout);
        mZoomControls.setVisibility(View.GONE);

        mTrackLengthBtn = (Button) findViewById(R.id.trackLengthBtn);
        mFollowCamBtn = (Button) findViewById(R.id.followCameraBtn);
        mZoomOutBtn = (Button) findViewById(R.id.zoomOutBtn);
        mZoomInBtn = (Button) findViewById(R.id.zoomInBtn);
        mInsertAnnBtn = (Button) findViewById(R.id.insertAnnBtn);
        mShareBtn = (Button) findViewById(R.id.shareBtn);

        mTrackLengthBtn.setVisibility(View.GONE);
        mInsertAnnBtn.setVisibility(View.GONE);

        mZoomOutBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                // Zoom out
                try {
                    mGoogleMap.moveCamera(CameraUpdateFactory.zoomBy(-1f));
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }
                //read and save actual zoom level
                mZoom = mGoogleMap.getCameraPosition().zoom;
            }
        });

        mZoomInBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                // Zoom in
                try {
                    mGoogleMap.moveCamera(CameraUpdateFactory.zoomBy(1f));
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }
                //read and save actual zoom level
                mZoom = mGoogleMap.getCameraPosition().zoom;
            }
        });

        mShareBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                mFacebookManager = FacebookManager.getInstance(Map.this, mFacebookHandler);
                mTwitterManager = TwitterManager.getInstance(Map.this);

                final Dialog dialog = new Dialog(Map.this);
                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
                dialog.setContentView(R.layout.share_dialog);
                //dialog.setTitle("Activate login on...");

                getShareButtonsRef(dialog);

                dialog.show();
            }
        });

        mFollowCamBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                //mCameraTrackOn = !mCameraTrackOn;
                setCameraTracking();

                if (mCameraTrackOn) {
                    try {
                        if (Utils.lastPhoneLocation != null)
                            mGoogleMap.animateCamera(
                                    CameraUpdateFactory.newLatLng(new LatLng(Utils.lastPhoneLocation.getLatitude(),
                                            Utils.lastPhoneLocation.getLongitude())));
                        else if (Utils.lastNetworkLocation != null)
                            mGoogleMap.animateCamera(CameraUpdateFactory
                                    .newLatLng(new LatLng(Utils.lastNetworkLocation.getLatitude(),
                                            Utils.lastNetworkLocation.getLongitude())));
                    } catch (NullPointerException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        mShareBtn.setOnLongClickListener(new OnLongClickListener() {
            @Override
            public boolean onLongClick(View arg0) {
                Toast toast = Toast.makeText(getApplicationContext(),
                        getResources().getString(R.string.share_btn_text), Toast.LENGTH_LONG);
                toast.setGravity(Gravity.TOP | Gravity.RIGHT, 0, 250); //250 from top on a 480x800 screen
                toast.show();
                return false;
            }
        });

        //status icons references
        mGpsStatus = (ImageView) findViewById(R.id.gpsStatusIv);
        mInterUplStatus = (ImageView) findViewById(R.id.interUplStatusIv);

        //gps status icon initialization
        mGpsStatus.setBackgroundResource(R.drawable.gps_off);

        //read network type index on which upload data is allowed: 0 - only wifi; 1 - both wifi and mobile
        int networkTypeIndex = Utils.getUploadNetworkTypeIndex(getApplicationContext());

        //1 - is internet connection available? 
        boolean[] connectivity = Utils.haveNetworkConnection(getApplicationContext());

        //if user wants to upload only on wifi networks, connectivity[0] (network connectivity) must be true
        if (networkTypeIndex == 0) {
            if (connectivity[0])
                mConnectivityOn = true;
            else
                mConnectivityOn = false;
        } else //if user wants to upload both on wifi/mobile networks
            mConnectivityOn = connectivity[0] || connectivity[1];

        //network status icon initialization
        if (mConnectivityOn) {
            mInterUplStatus.setBackgroundResource(R.drawable.internet_on);
            Utils.uploadOn = Constants.INTERNET_ON_INT;
        } else {
            mInterUplStatus.setBackgroundResource(R.drawable.internet_off);
            Utils.uploadOn = Constants.INTERNET_OFF_INT;
        }

        //button to get from server black carbon levels around user
        mGetBcLevelsBtn = (Button) findViewById(R.id.getBcLevelsBtn);
        mGetBcLevelsBtn.setVisibility(View.VISIBLE);
        mGetBcLevelsBtn.setOnClickListener(mGetBcLevelsOnClickListener);

        //bcLayout.addView(mGetBcLevelsBtn);
        mSpectrum = (LinearLayout) findViewById(R.id.spectrumLinearLayout);
        mSpectrum.setVisibility(View.VISIBLE);
    }

    private void setBcLevelColors() {
        TextView[] levelsTv = new TextView[7];
        levelsTv[0] = (TextView) findViewById(R.id.level1Tv);
        levelsTv[1] = (TextView) findViewById(R.id.level2Tv);
        levelsTv[2] = (TextView) findViewById(R.id.level3Tv);
        levelsTv[3] = (TextView) findViewById(R.id.level4Tv);
        levelsTv[4] = (TextView) findViewById(R.id.level5Tv);
        levelsTv[5] = (TextView) findViewById(R.id.level6Tv);
        levelsTv[6] = (TextView) findViewById(R.id.level7Tv);

        levelsTv[0].setBackgroundColor(ColorHelper.numberToColor(5));
        levelsTv[1].setBackgroundColor(ColorHelper.numberToColor(20));
        levelsTv[2].setBackgroundColor(ColorHelper.numberToColor(40));
        levelsTv[3].setBackgroundColor(ColorHelper.numberToColor(70));
        levelsTv[4].setBackgroundColor(ColorHelper.numberToColor(80));
        levelsTv[5].setBackgroundColor(ColorHelper.numberToColor(90));
        levelsTv[6].setBackgroundColor(ColorHelper.numberToColor(100));
    }

    /****************** DISEGNA PATH ****************************************************/

    //draw path from a list of points
    public void drawPath() {
        ExtendedLatLng newLatLng = null;
        ExtendedLatLng precLatLng = null;
        int color = Color.DKGRAY;

        try {
            Log.d("Map", "polyline count: " + mLatLngPoints.size());

            for (int i = 0; i < mLatLngPoints.size(); i++) {
                newLatLng = mLatLngPoints.get(i);
                color = Color.DKGRAY; //color for a segment without bc value

                //10 is upper limit in scale, so a black carbon of 10 (multiplied by 10) must be drawn in dark red
                if ((newLatLng.mBc > 0) && (newLatLng.mBc <= 10))
                    color = ColorHelper.numberToColor(newLatLng.mBc * BC_MULTIPLIER);
                else
                    color = ColorHelper.numberToColor(100);

                //draw segment with appropriate color (dark grey if no bc value is present) 
                if (precLatLng != null)
                    mGoogleMap.addPolyline(new PolylineOptions().add(newLatLng.mLatLng).add(precLatLng.mLatLng)
                            .width(5).color(color));

                String annotation = newLatLng.mUserAnn;

                if (!annotation.equals("")) {
                    BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.annotation_marker);
                    mGoogleMap.addMarker(
                            new MarkerOptions().position(newLatLng.mLatLng).title("AQI: " + newLatLng.mBc)
                                    .snippet("Annotation: " + annotation).icon(icon).anchor(0.25f, 1f)); //Map Markers are 'anchored' by default to the middle of the bottom of layout (i.e., anchor(0.5,1)).
                }

                precLatLng = newLatLng;
            }

            //center camera on last trackn position
            //if((mTrackMode)&&(mCameraTrackOn))
            try {
                mGoogleMap.animateCamera(CameraUpdateFactory
                        .newLatLngZoom(mLatLngPoints.get(mLatLngPoints.size() - 1).mLatLng, mZoom));
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {

        }
    }

    /************************ ALERT DIALOG NO INTERNET AVAILABLE *************************************/

    public void noConnectivityDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(R.string.alert_dialog_no_internet).setIcon(android.R.drawable.ic_dialog_info)
                .setTitle(R.string.app_name).setCancelable(false)
                .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {

                    }
                });

        AlertDialog alert = builder.create();
        alert.show();
    }

    /****************** GESTIONE CAMERA TRACKING SU ULTIMO PUNTO INSERITO ***********************/

    public void setCameraTracking() {
        mCameraTrackOn = !mCameraTrackOn;

        if (mCameraTrackOn)
            mFollowCamBtn.setBackgroundResource(R.drawable.follow_camera_pressed);
        else
            mFollowCamBtn.setBackgroundResource(R.drawable.follow_camera_not_pressed);
    }

    /****************** CALCULATE MINS VALUE FOR POLLUTANTS IN LOADED HISTORY *******************/

    public void calcMinAvgPollValue() {
        double actual_avg_poll = 0;

        //save first avg min
        avg_poll_min = mLatLngPoints.get(0).mAvgValue;

        for (int i = 1; i < mLatLngPoints.size(); i++) {
            actual_avg_poll = mLatLngPoints.get(i).mAvgValue;

            //if actual avg is less then avg min, save it
            if (actual_avg_poll < avg_poll_min)
                avg_poll_min = actual_avg_poll;
        }
        //reduction
        avg_poll_min = avg_poll_min / 2;

        //Log.d("Map", "calcMinAvgPollValue()--> " +avg_poll_min);
    }

    /***************** CALCOLA MEDIE VALORI RECORDS COMPRESI IN INTERVALLO **********************/

    public MarkerRecord calcAvgRecords(int begin, int end) throws IndexOutOfBoundsException {
        int totalRecords = 0;
        long startTs = 0, endTs = 0;

        double avg_poll = 0;

        totalRecords = end - begin;

        Log.d("calcAvgRecords()", "begin: " + begin + " end:" + end + " totalRecords: " + totalRecords);

        for (int i = begin; i < end; i++) {
            if (i == begin)
                startTs = mRecords.get(i).mSysTimestamp;
            if (i == end - 1)
                endTs = mRecords.get(i).mSysTimestamp;

            avg_poll += mRecords.get(i).calcAvgPoll();

        }
        avg_poll = avg_poll / totalRecords;

        return new MarkerRecord(avg_poll, totalRecords, startTs, endTs);
    }

    public MarkerRecord calcAvgRecords(List<ExtendedLatLng> points) throws IndexOutOfBoundsException {
        int totalRecords = 0;
        long startTs = 0, endTs = 0;

        double avg_poll = 0;

        totalRecords = points.size();

        Log.d("calcAvgRecords()", " totalRecords: " + totalRecords);

        for (int i = 0; i < points.size(); i++) {
            if (i == 0)
                startTs = points.get(i).mSysTimestamp;
            if (i == totalRecords - 1)
                endTs = points.get(i).mSysTimestamp;

            avg_poll += points.get(i).calcAvgPoll();

        }
        avg_poll = avg_poll / totalRecords;

        return new MarkerRecord(avg_poll, totalRecords, startTs, endTs);
    }

    /******************************* DIALOGS ****************************************************/

    public void createProgressDialog(String msg, boolean cancelable) {
        mProgressDialog = ProgressDialog.show(Map.this, getResources().getString(R.string.app_name), msg, true,
                true);
    }

    public void createProgressDialog2(String msg, boolean cancelable) {
        mProgressDialog2 = new ProgressDialog(Map.this);
        mProgressDialog2.setTitle(getResources().getString(R.string.app_name));
        mProgressDialog2.setMessage(msg);
        mProgressDialog2.setIndeterminate(true);
        mProgressDialog2.setCancelable(true);
        //mProgressDialog2 = ProgressDialog.show(Map.this, getResources().getString(R.string.app_name), msg, true, true);
        mProgressDialog2.setOnShowListener(new OnShowListener() {
            @Override
            public void onShow(DialogInterface arg0) {
                Log.d("OnShowListener", "onShow()");

                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //clear precedent heat map
                        if (mMapPolygons != null) {
                            for (int i = 0; i < mMapPolygons.size(); i++)
                                mMapPolygons.get(i).remove();

                            mMapPolygons.clear();
                        }

                        if (mMapClusters != null)
                            mMapClusters.clear();

                        //update information about map zoom level
                        mZoom = mGoogleMap.getCameraPosition().zoom;

                        //get viewport min/max coordinates
                        VisibleRegion vr = mGoogleMap.getProjection().getVisibleRegion();
                        double minLong = vr.latLngBounds.southwest.longitude;
                        double maxLat = vr.latLngBounds.northeast.latitude;
                        double maxLong = vr.latLngBounds.northeast.longitude;
                        double minLat = vr.latLngBounds.southwest.latitude;

                        String requestUrl = Constants.GET_BC_LEVELS_ADDR + (Math.round(mZoom) + 1) + "&bbox="
                                + minLong + "," + minLat + "," + maxLong + "," + maxLat; //complete url string      
                        Log.d("Map", "getData()--> request Url: " + requestUrl);

                        new GetDataTask().execute(requestUrl);
                        /*
                        mGetDataThread = new GetDataThread();
                        mGetDataThread.run();*/
                    }
                }, 500);

            }
        });
        mProgressDialog2.show();
    }

    public void closeAppDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(R.string.alert_dialog_close_app).setIcon(android.R.drawable.ic_dialog_info)
                .setTitle(R.string.app_name).setCancelable(false)
                .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        closeApp();
                    }
                }).setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        dialog.dismiss();
                    }
                });

        AlertDialog alert = builder.create();
        alert.show();
    }

    public HashMap<String, ?> createItem(String title, String caption) {
        HashMap<String, String> item = new HashMap<String, String>();
        item.put(Constants.ITEM_TITLE, title);
        item.put(Constants.ITEM_CAPTION, caption);
        return item;
    }

    /*************************** OPTION MENU ***************************************************/

    public boolean onCreateOptionsMenu(Menu menu) {
        String[] menuItems = getResources().getStringArray(R.array.map_optionmenu);

        SubMenu mapSubMenu = menu.addSubMenu("Map Modes").setIcon(android.R.drawable.ic_menu_mapmode);

        mapSubMenu.add(1, Menu.FIRST, Menu.FIRST, "Hybrid").setCheckable(false);
        mapSubMenu.add(1, Menu.FIRST + 1, Menu.FIRST, "Normal").setCheckable(false);
        mapSubMenu.add(1, Menu.FIRST + 2, Menu.FIRST + 2, "Satellite").setCheckable(false);
        mapSubMenu.add(1, Menu.FIRST + 3, Menu.FIRST + 3, "Terrain").setCheckable(false);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int itemId = item.getItemId();

        switch (itemId) {
        case Menu.FIRST:
            mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
            break;
        case Menu.FIRST + 1:
            mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
            break;
        case Menu.FIRST + 2:
            mGoogleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
            break;
        case Menu.FIRST + 3:
            mGoogleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
            break;
        }
        return true;
    }

    /********************** CLOSE APP *************************************************************************/

    public void closeApp() {
        Utils.backToHome = true;

        //stop store'n'forward service
        if (Utils.storeForwServIntent != null)
            stopService(Utils.storeForwServIntent);

        //clear shared prefs
        Utils.deleteSharedPrefs(getApplicationContext());

        Utils.track = null;
        Utils.selectedTrackIndex = -1;

        Intent intent = new Intent(Map.this, Start.class);
        startActivity(intent);
        finish();
    }

    /******************* RECEIVE MESSAGES FROM GPS TRACKING SERVICE ***********************************/

    private BroadcastReceiver mGpsServiceReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (action.equals(Constants.PHONE_GPS_ON)) {
                Log.d("GpsServiceReceiver", "onReceive()--> Phone Gps ON");
                mGpsStatus.setBackgroundResource(R.drawable.gps_on_phone);
            }
            if (action.equals(Constants.NETWORK_GPS_ON)) {
                Log.d("GpsServiceReceiver", "onReceive()--> Network Gps ON");
                mGpsStatus.setBackgroundResource(R.drawable.gps_on_network);

            }
            if (action.equals(Constants.PHONE_GPS_OFF)) {
                Log.d("GpsServiceReceiver", "onReceive()--> Phone Gps OFF");
                mGpsStatus.setBackgroundResource(R.drawable.gps_off);

            }
        }
    };

    /********************* RECEIVES MESSAGES FROM STORE'N'FORWARD SERVICE *****************************/

    private BroadcastReceiver mServiceReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (action.equals(Constants.INTERNET_ON)) {
                Log.d("ServiceReceiver", "Internet is ON");
                mInterUplStatus.setBackgroundResource(R.drawable.internet_on);
            }
            if (action.equals(Constants.INTERNET_OFF)) {
                Log.d("ServiceReceiver", "Internet is OFF");
                mInterUplStatus.setBackgroundResource(R.drawable.internet_off);
            }
            if (action.equals(Constants.UPLOAD_ON)) {
                Log.d("ServiceReceiver", "Upload is ON");
                mInterUplStatus.setBackgroundResource(R.drawable.upload);
            }
            if (action.equals(Constants.UPLOAD_OFF)) {
                Log.d("ServiceReceiver", "Upload is OFF");
                mInterUplStatus.setBackgroundResource(R.drawable.internet_on);
            }
        }
    };

    /********************** CALLS getData() FUNCTION *************************************************/

    private class GetDataTask extends AsyncTask<String, Void, List<MapCluster>> {
        @Override
        protected void onPreExecute() {

        }

        @Override
        protected void onPostExecute(List<MapCluster> param) {
            int color;

            //draw map cluster on the map
            if ((mMapClusters != null) && (mMapClusters.size() > 0)) {
                for (int i = 0; i < mMapClusters.size(); i++) {
                    MapCluster mapCluster = mMapClusters.get(i);

                    if (mapCluster.mBcLevel != 0) {
                        Log.d("GetDataTask",
                                "onPostExecute()--> pos: " + i + " bc level: " + mapCluster.mBcLevel + " coords: "
                                        + mapCluster.mMinLat + ", " + mapCluster.mMinLon + ", " + mapCluster.mMaxLat
                                        + ", " + mapCluster.mMaxLon);

                        if ((mapCluster.mBcLevel > 0) && (mapCluster.mBcLevel <= 10))
                            color = ColorHelper.numberToColor(mapCluster.mBcLevel * BC_MULTIPLIER);
                        else
                            color = ColorHelper.numberToColor(100);

                        mMapPolygons.add(mGoogleMap.addPolygon(new PolygonOptions()
                                .add(new LatLng(mapCluster.mMinLat, mapCluster.mMinLon),
                                        new LatLng(mapCluster.mMinLat, mapCluster.mMaxLon),
                                        new LatLng(mapCluster.mMaxLat, mapCluster.mMaxLon),
                                        new LatLng(mapCluster.mMaxLat, mapCluster.mMinLon))
                                .strokeColor(Color.TRANSPARENT)
                                .fillColor(Color.parseColor("#66" + String.format("%06X", 0xFFFFFF & color)))));
                    }
                }
            }

            if ((mProgressDialog2 != null) && (mProgressDialog2.isShowing()))
                mProgressDialog2.dismiss();

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    int clusterNum = 0;
                    if (mMapClusters != null)
                        clusterNum = mMapClusters.size();

                    Toast.makeText(Map.this, "Found " + clusterNum + " black carbon measures", Toast.LENGTH_LONG)
                            .show();

                }

            });
        }

        @Override
        protected List<MapCluster> doInBackground(String... params) {
            int statusCode = -1;
            InputStream is = null;

            try {
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpGet httpGet = new HttpGet(params[0]);
                HttpResponse response = httpClient.execute(httpGet);

                Log.d("GetDataTask", "doInBackground()--> status line: " + response.getStatusLine());

                //if server response is 'HTTP 200 OK'
                if (response.getStatusLine().getStatusCode() == Constants.STATUS_OK) {
                    if (response.getEntity() != null) {
                        if (mKmlParser == null)
                            mKmlParser = new KmlParser();

                        //get InputStream from response entity
                        is = response.getEntity().getContent();

                        mMapClusters = mKmlParser.parseKml(is);
                    }
                } else {
                    if ((mProgressDialog2 != null) && (mProgressDialog2.isShowing()))
                        mProgressDialog2.dismiss();

                    Toast.makeText(Map.this, response.getStatusLine().toString(), Toast.LENGTH_LONG).show();
                }

            }
            //this exception is invoked when internet connection is up but traffic is not allowed
            //(for example, for networks that needs login but user is not logged)
            catch (HttpHostConnectException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (is != null)
                        is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            Log.d("GetDataTask", "run()--> status code: " + statusCode);

            return mMapClusters;
        }

    }

    /********************** SHARE SECTION ***************************************************************/

    //get button references and set text on them
    private void getShareButtonsRef(Dialog dialog) {
        mValidFbSession = mFacebookManager.isSessionValid();
        mValidTwSession = Utils.getValidTwSession(getApplicationContext());// mTwitterManager.isSessionValid();   

        //if(mButtons[0] == null)
        //{
        mButtons[0] = (Button) dialog.findViewById(R.id.facebook_log_button);
        mButtons[0].setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                //read network type index on which upload data is allowed: 0 - only wifi; 1 - both wifi and mobile
                int networkTypeIndex = Utils.getUploadNetworkTypeIndex(getApplicationContext());

                //1 - is internet connection available? 
                boolean[] connectivity = Utils.haveNetworkConnection(getApplicationContext());

                //if user wants to upload only on wifi networks, connectivity[0] (network connectivity) must be true
                if (networkTypeIndex == 0) {
                    if (connectivity[0])
                        mConnectivityOn = true;
                    else
                        mConnectivityOn = false;
                } else //if user wants to upload both on wifi/mobile networks
                    mConnectivityOn = connectivity[0] || connectivity[1];

                if (mValidFbSession) {
                    mFacebookManager.clearCredentials();
                } else {
                    if (mConnectivityOn) {
                        mFacebookManager.authorizeFbUser();
                    } else {
                        noConnectivityDialog();
                    }
                }
            }
        });
        //}
        //if(mButtons[1] == null)
        //{
        mButtons[1] = (Button) dialog.findViewById(R.id.twitter_log_button);
        mButtons[1].setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                //read network type index on which upload data is allowed: 0 - only wifi; 1 - both wifi and mobile
                int networkTypeIndex = Utils.getUploadNetworkTypeIndex(getApplicationContext());

                //1 - is internet connection available? 
                boolean[] connectivity = Utils.haveNetworkConnection(getApplicationContext());

                //if user wants to upload only on wifi networks, connectivity[0] (network connectivity) must be true
                if (networkTypeIndex == 0) {
                    if (connectivity[0])
                        mConnectivityOn = true;
                    else
                        mConnectivityOn = false;
                } else //if user wants to upload both on wifi/mobile networks
                    mConnectivityOn = connectivity[0] || connectivity[1];

                if (mValidTwSession) {
                    mTwitterManager.shutdown();

                    mValidTwSession = false;
                    mButtons[1].setText(getResources().getString(R.string.login_twitter_text));
                    Utils.setValidTwSession(false, getApplicationContext());
                    Toast.makeText(Map.this, "unauthorized", Toast.LENGTH_SHORT).show();
                } else {
                    if (mConnectivityOn) {
                        mTwitterManager.initTwitter();
                    } else {
                        noConnectivityDialog();
                    }
                }
            }
        });
        //}

        Log.d("Share", "getShareButtonsRef()--> login facebook: " + mValidFbSession);
        Log.d("Share", "getShareButtonsRef()--> login twitter: " + mValidTwSession);

        //display right text (login/logout) on facebook button
        if (mValidFbSession)
            mButtons[0].setText(getResources().getString(R.string.logout_facebook_text));
        else
            mButtons[0].setText(getResources().getString(R.string.login_facebook_text));

        //display text (login/logout) on twitter button
        if (mValidTwSession)
            mButtons[1].setText(getResources().getString(R.string.logout_twitter_text));
        else
            mButtons[1].setText(getResources().getString(R.string.login_twitter_text));
    }

    private Handler mFacebookHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case Constants.LOGIN_COMPLETED:
                Log.d("Share", "FacebookHandler --> Login completed");
                mButtons[0].setText(getResources().getString(R.string.logout_facebook_text));
                mValidFbSession = true;
                Utils.setValidFbSession(true, getApplicationContext());
                break;

            case Constants.LOGIN_CLOSED:
                Log.d("Share", "FacebookHandler --> Login closed");
                mButtons[0].setText(getResources().getString(R.string.login_facebook_text));
                mValidFbSession = false;
                Utils.setValidFbSession(false, getApplicationContext());
                break;

            case Constants.LOGIN_CANCEL:
                Log.d("Share", "FacebookHandler --> Login cancel");
                mValidFbSession = false;
                Utils.setValidFbSession(false, getApplicationContext());
                break;

            case Constants.LOGIN_ERROR:
                Log.d("Share", "FacebookHandler --> Login error");
                mValidFbSession = false;
                Utils.setValidFbSession(false, getApplicationContext());
                break;

            case Constants.LOGIN_FACEBOOK_ERROR:
                Log.d("Share", "FacebookHandler --> Login facebook error");
                mValidFbSession = false;
                Utils.setValidFbSession(false, getApplicationContext());
                break;
            }
        }
    };

    /********************** INVOKED WHEN TwitterLogin RETURNS **********************************************************/

    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);

        if (requestCode == 0) {
            if (resultCode == RESULT_OK) {
                Log.d("Map", "Twitter auth RESULT OK");

                String oauthVerifier = intent.getExtras().getString(Constants.IEXTRA_OAUTH_VERIFIER);
                final boolean result = mTwitterManager.authoriseNewUser(oauthVerifier);

                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (result) {
                            mValidTwSession = true;
                            mButtons[1].setText(getResources().getString(R.string.logout_twitter_text));
                            Utils.setValidTwSession(true, getApplicationContext());
                        } else {
                            mValidTwSession = false;
                            mButtons[1].setText(getResources().getString(R.string.login_twitter_text));
                        }
                    }

                }, 500);
            } else if (resultCode == RESULT_CANCELED) {
                mValidTwSession = false;
                mButtons[1].setText(getResources().getString(R.string.login_twitter_text));
                Utils.setValidTwSession(false, getApplicationContext());
                Log.d("Map", "Twitter auth canceled.");
            }

        }
    }

    private void insertAnnDialog(final ExtendedLatLng annLatLng) {
        final Dialog insertDialog = new Dialog(Map.this);
        insertDialog.setContentView(R.layout.insert_dialog);
        insertDialog.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        insertDialog.setTitle(R.string.annotation_insertion);
        insertDialog.setCancelable(false);

        //get reference to send button
        final Button sendButton = (Button) insertDialog.findViewById(R.id.send_button);
        sendButton.setEnabled(false); //active only if there's text

        //get reference to cancel/close window button
        final Button cancelButton = (Button) insertDialog.findViewById(R.id.cancel_button);
        cancelButton.setEnabled(true); //active all time
        cancelButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                insertDialog.dismiss();
            }
        });

        //get reference to edittext in which user writes annotation
        final EditText editText = (EditText) insertDialog.findViewById(R.id.annotation_editText);
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                //if modified text length is more than 0, activate send button
                if (s.length() > 0)
                    sendButton.setEnabled(true);
                else
                    sendButton.setEnabled(false);
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });

        //get checkbox references
        CheckBox facebookChBox = (CheckBox) insertDialog.findViewById(R.id.facebook_checkBox);
        CheckBox twitterChBox = (CheckBox) insertDialog.findViewById(R.id.twitter_checkBox);

        //activate check boxes depends from log in facebook/twitter
        boolean[] logs = new boolean[2];
        logs[0] = Utils.getValidFbSession(getApplicationContext());
        logs[1] = Utils.getValidTwSession(getApplicationContext());

        facebookChBox.setEnabled(logs[0]);
        twitterChBox.setEnabled(logs[1]);

        //checked on check boxes
        final boolean[] checkeds = Utils.getShareCheckedOn(getApplicationContext());
        if (checkeds[0] == true)
            facebookChBox.setChecked(true);
        else
            facebookChBox.setChecked(false);
        if (checkeds[1] == true)
            twitterChBox.setChecked(true);
        else
            twitterChBox.setChecked(false);

        facebookChBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton arg0, boolean checked) {
                Utils.setShareCheckedOn(checked, checkeds[1], getApplicationContext());
                checkeds[0] = checked;
            }
        });

        twitterChBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton arg0, boolean checked) {
                Utils.setShareCheckedOn(checkeds[0], checked, getApplicationContext());
                checkeds[1] = checked;
            }
        });

        //send annotation to server and on facebook/twitter if user is logged on 
        sendButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //1 - read inserted annotation
                String annotation = editText.getText().toString();

                //2 - update record on db with annotation and save recordId            
                double recordId = annLatLng.mRecordId;

                int result = mDbManager.updateRecordAnnotation(recordId, annotation);

                if (result == 1)
                    Toast.makeText(getApplicationContext(), "Updated record", Toast.LENGTH_LONG).show();
                else
                    Toast.makeText(getApplicationContext(), "Error!", Toast.LENGTH_LONG).show();

                boolean[] checks = Utils.getShareCheckedOn(getApplicationContext());

                //3 - share on facebook is user wants and internet is active now
                if (checks[0] == true) {
                    Record annotatedRecord = mDbManager.loadRecordById(recordId);
                    try {
                        FacebookManager fb = FacebookManager.getInstance(null, null);
                        if (fb != null)
                            fb.postMessageOnWall(annotatedRecord);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                //4 - share on twitter is user wants and internet is active now
                if (checks[1] == true) {
                    Record annotatedRecord = mDbManager.loadRecordById(recordId);

                    try {
                        TwitterManager twManager = TwitterManager.getInstance(null);
                        twManager.postMessage(annotatedRecord);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                //5 - show marker for annotated record
                Record annotatedRecord = mDbManager.loadRecordById(recordId);

                String userAnn = annotatedRecord.mUserData1;

                if (!userAnn.equals("") && (annotatedRecord.mValues[0] != 0)) {
                    BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.annotation_marker);
                    Marker marker = mGoogleMap.addMarker(new MarkerOptions()
                            .position(new LatLng(annotatedRecord.mValues[0], annotatedRecord.mValues[1]))
                            .title("BC: " + String.valueOf(annotatedRecord.mBcMobile) + " "
                                    + getResources().getString(R.string.micrograms))
                            .snippet("Annotation: " + userAnn).icon(icon).anchor(0f, 1f));
                }

                insertDialog.dismiss();
            }
        });

        insertDialog.show();
    }

    /********************* GET DATA FROM SERVER (BC LEVELS AROUND USER CURRENT POSITION) ******************************/

    //on click listener of get black carbon levels around user from server
    private OnClickListener mGetBcLevelsOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View arg0) {
            //VERIFY INTERNET CONNECTION 

            //read network type index on which upload data is allowed: 0 - only wifi; 1 - both wifi and mobile
            //int networkTypeIndex = Utils.getUploadNetworkTypeIndex(getApplicationContext());

            //1 - is internet connection available? 
            boolean[] connectivity = Utils.haveNetworkConnection(getApplicationContext());

            /*
            //if user wants to download only on wifi networks, connectivity[0] (network connectivity) must be true
            if(networkTypeIndex == 0)
            {
               if(connectivity[0])
                  mConnectivityOn = true;
               else
                  mConnectivityOn = false;
            }
            else //if user wants to upload both on wifi/mobile networks
               mConnectivityOn = connectivity[0] || connectivity[1];
            */

            //almost one type of connection (network, mobile) must be available
            mConnectivityOn = connectivity[0] || connectivity[1];

            //if internet connection is not available, inform user and return
            if (!mConnectivityOn) {
                Toast.makeText(getApplicationContext(), getResources().getString(R.string.alert_dialog_no_internet),
                        Toast.LENGTH_LONG).show();
                return;
            }

            //DOWNLOAD DATA
            new Handler().post(new Runnable() {

                @Override
                public void run() {
                    createProgressDialog2(getResources().getString(R.string.progress_dialog_please_wait), true);
                }

            });
        }
    };
}