it.unipr.ce.dsg.gamidroid.activities.NAM4JAndroidActivity.java Source code

Java tutorial

Introduction

Here is the source code for it.unipr.ce.dsg.gamidroid.activities.NAM4JAndroidActivity.java

Source

package it.unipr.ce.dsg.gamidroid.activities;

import it.unipr.ce.dsg.gamidroid.R;
import it.unipr.ce.dsg.gamidroid.devicemonitor.DeviceMonitorService;
import it.unipr.ce.dsg.gamidroid.devicemonitor.ResourceMonitor;
import it.unipr.ce.dsg.gamidroid.gaminode.GamiNode;
import it.unipr.ce.dsg.gamidroid.taskmanagerfm.UPCPFTaskDescriptor;
import it.unipr.ce.dsg.gamidroid.utils.Constants;
import it.unipr.ce.dsg.gamidroid.utils.FileManager;
import it.unipr.ce.dsg.gamidroid.utils.LocationUtils;
import it.unipr.ce.dsg.gamidroid.utils.MenuListAdapter;
import it.unipr.ce.dsg.gamidroid.utils.MenuListElement;
import it.unipr.ce.dsg.gamidroid.utils.Utils;
import it.unipr.ce.dsg.gamidroid.utils.Utils.Orientation;
import it.unipr.ce.dsg.s2p.centralized.interfaces.IEventListener;
import it.unipr.ce.dsg.s2p.centralized.message.JoinResponseMessage;
import it.unipr.ce.dsg.s2p.centralized.utils.Resource;
import it.unipr.ce.dsg.s2pchord.msg.MessageListener;
import it.unipr.ce.dsg.s2pchord.msg.PeerListMessage;
import it.unipr.ce.dsg.s2pchord.resource.ResourceDescriptor;
import it.unipr.ce.dsg.s2pchord.resource.ResourceListener;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.graphics.BitmapFactory;
import android.hardware.SensorManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.BatteryManager;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

/**
 * <p>
 * This class represents the main Activity of the Android application.
 * </p>
 * 
 * <p>
 * Copyright (c) 2013, Distributed Systems Group, University of Parma, Italy.
 * Permission is granted to copy, distribute and/or modify this document under
 * the terms of the GNU Free Documentation License, Version 1.3 or any later
 * version published by the Free Software Foundation; with no Invariant
 * Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the
 * license is included in the section entitled "GNU Free Documentation License".
 * </p>
 * 
 * @author Alessandro Grazioli (grazioli@ce.unipr.it)
 * 
 */
public class NAM4JAndroidActivity extends FragmentActivity
        implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener, OnMarkerClickListener,
        ResourceListener, MessageListener, IEventListener {

    /** Shared Preferences */
    SharedPreferences sharedPreferences;

    /** A request to connect to Location Services */
    private LocationRequest mLocationRequest;

    /** Stores the current instantiation of the location client in this object */
    private GoogleApiClient mGoogleApiClient;

    public static String TAG = "NAM4JAndroidActivity";
    final static int MAX_RESULT = 1;

    private FileManager fileManager;

    private UPCPFTaskDescriptor amiTask;

    private GoogleMap map;

    MarkerOptions markerOptions;
    private Marker marker;

    HashMap<String, Marker> ml;

    Context context;

    private RelativeLayout mainRL;
    private RelativeLayout listRL;
    private RelativeLayout titleBarRL;

    private LatLng currentLocation;

    private ProgressDialog dialog;

    private int animationDuration = 300;

    private boolean showingMenu = false;

    Orientation screenOrientation;

    ImageView connectButtonIv;

    /**
     * The boolean is used to decide what to do after a LatLng has been
     * geocoded. If true, it means that the user asked to publish a building so
     * the related function is called. If false, the user asked to look for a
     * resource in the LatLng, so the related function is called.
     */
    private boolean requestPendingForBuilding = false;
    private boolean requestPendingForSensor = false;

    private boolean connected = false;

    /**
     * The first time a location is available, the map is centered on it and the
     * boolean is set to false so that further updates do not move the camera
     */
    private boolean firstLocation = true;

    /** Initial zoom level */
    private int zoom = 15;

    /**
     * Descriptors to set marker colors (blue ones are placed for assigned
     * resources, red for researched resources)
     */
    BitmapDescriptor bitmapDescriptorBlue, bitmapDescriptorRed, blueCircle;

    /** Set to true when the user asks to close the app. */
    private boolean close = false;

    Button menuButton, infoButton, centerButton;

    int screenWidth = 0;
    int screenHeight = 0;

    /** Ratio between the menu size and the screen width */
    double menuWidth = 0.66;

    ListView listView;

    boolean isTablet;

    /** Wi-fi monitor */
    WifiManager wifiManager;

    /** Sensors monitor */
    SensorManager sensorManager;

    LinearLayout cpuBar, memoryBar;

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        context = this;

        isTablet = Utils.isTablet(this);

        // Setting the default network
        sharedPreferences = getSharedPreferences(Constants.PREFERENCES, Context.MODE_PRIVATE);
        Editor editor = sharedPreferences.edit();
        editor.putString(Constants.NETWORK, Constants.DEFAULT_NETWORK);
        editor.commit();

        // Starting the resources monitoring service
        startService(new Intent(this, DeviceMonitorService.class));

        wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);

        // Settings menu elements
        ArrayList<MenuListElement> listElements = new ArrayList<MenuListElement>();

        listElements.add(new MenuListElement(getResources().getString(R.string.connectMenuTitle),
                getResources().getString(R.string.connectMenuSubTitle)));
        listElements.add(new MenuListElement(getResources().getString(R.string.settingsMenuTitle),
                getResources().getString(R.string.settingsMenuSubTitle)));
        listElements.add(new MenuListElement(getResources().getString(R.string.exitMenuTitle),
                getResources().getString(R.string.exitMenuSubTitle)));

        listView = (ListView) findViewById(R.id.ListViewContent);

        MenuListAdapter adapter = new MenuListAdapter(this, R.layout.menu_list_view_row, listElements);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new ListItemClickListener());

        mainRL = (RelativeLayout) findViewById(R.id.rlContainer);
        listRL = (RelativeLayout) findViewById(R.id.listContainer);

        cpuBar = (LinearLayout) findViewById(R.id.CpuBar);
        memoryBar = (LinearLayout) findViewById(R.id.MemoryBar);

        titleBarRL = (RelativeLayout) findViewById(R.id.titleLl);

        // Adding swipe gesture listener to the top bar
        titleBarRL.setOnTouchListener(new SwipeAndClickListener());

        menuButton = (Button) findViewById(R.id.menuButton);
        menuButton.setOnTouchListener(new SwipeAndClickListener());

        infoButton = (Button) findViewById(R.id.infoButton);
        infoButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                AlertDialog dialog = new AlertDialog(NAM4JAndroidActivity.this) {

                    @Override
                    public boolean dispatchTouchEvent(MotionEvent event) {
                        dismiss();
                        return false;
                    }

                };

                String text = getResources().getString(R.string.aboutApp);
                String title = getResources().getString(R.string.nam4j);

                dialog.setMessage(text);
                dialog.setTitle(title);
                dialog.setCanceledOnTouchOutside(true);
                dialog.show();
            }
        });

        centerButton = (Button) findViewById(R.id.centerButton);
        centerButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                centerMap();
            }
        });

        isTablet = Utils.isTablet(context);

        int[] screenSize = Utils.getScreenSize(context, getWindow());
        screenWidth = screenSize[0];
        screenHeight = screenSize[1];

        // Updates the display orientation each time the device is rotated
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
            screenOrientation = Orientation.LANDSCAPE;
        } else {
            screenOrientation = Orientation.PORTRAIT;
        }

        // If the device is portrait, the menu button is displayed, the menu is
        // hidden and the swipe listener is added to the menu bar
        if (screenOrientation == Orientation.PORTRAIT) {

            menuButton.setVisibility(View.VISIBLE);

            // Adding swipe gesture listener to the top bar
            titleBarRL.setOnTouchListener(new SwipeAndClickListener());

            if (isTablet) {
                menuWidth = 0.35;
            } else {
                menuWidth = 0.6;
            }
        } else {
            // If the device is a tablet in landscape, the menu button is
            // hidden, the menu is displayed, the swipe listener is not added to
            // the menu bar and the mainRL width is set to the window's width
            // minus the menu's width
            if (isTablet) {
                menuWidth = 0.2;
                menuButton.setVisibility(View.INVISIBLE);

                RelativeLayout.LayoutParams menuListLP = (LayoutParams) mainRL.getLayoutParams();

                // Setting the main view width as the container width without
                // the menu
                menuListLP.width = (int) (screenWidth * (1 - menuWidth));
                mainRL.setLayoutParams(menuListLP);

                displaySideMenu();
            } else {
                menuWidth = 0.4;
                menuButton.setVisibility(View.VISIBLE);

                // Adding swipe gesture listener to the top bar
                titleBarRL.setOnTouchListener(new SwipeAndClickListener());
            }
        }

        // Check if the device has the Google Play Services installed and
        // updated. They are necessary to use Google Maps
        int code = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);

        if (code != ConnectionResult.SUCCESS) {

            showErrorDialog(code);

            System.out.println("Google Play Services error");

            FrameLayout fl = (FrameLayout) findViewById(R.id.frameId);
            fl.removeAllViews();
        } else {
            // Create a new global location parameters object
            mLocationRequest = new LocationRequest();

            // Set the update interval
            mLocationRequest.setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS);

            // Use high accuracy
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

            // Set the interval ceiling to one minute
            mLocationRequest.setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS);

            bitmapDescriptorBlue = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE);

            blueCircle = BitmapDescriptorFactory
                    .fromBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.blue_circle));

            bitmapDescriptorRed = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED);

            // Create a new location client, using the enclosing class to handle
            // callbacks
            mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this).addApi(LocationServices.API).build();

            map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapview)).getMap();

            if (map != null) {

                // Set default map center and zoom on Parma
                double lat = 44.7950156;
                double lgt = 10.32547;
                map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lgt), 12.0f));

                // Adding listeners to the map respectively for zoom level
                // change and onTap event
                map.setOnCameraChangeListener(getCameraChangeListener());
                map.setOnMapClickListener(getOnMapClickListener());

                // Set map type as normal (i.e. not the satellite view)
                map.setMapType(com.google.android.gms.maps.GoogleMap.MAP_TYPE_NORMAL);

                // Hide traffic layer
                map.setTrafficEnabled(false);

                // Enable the 'my-location' layer, which continuously draws an
                // indication of a user's current location and bearing, and
                // displays UI controls that allow the interaction with the
                // location itself
                // map.setMyLocationEnabled(true);

                ml = new HashMap<String, Marker>();

                // Get file manager for config files
                fileManager = FileManager.getFileManager();
                fileManager.createFiles();

                map.setOnMarkerClickListener(this);

            } else {
                AlertDialog.Builder dialog = new AlertDialog.Builder(this);
                dialog.setMessage("The map cannot be initialized.");
                dialog.setCancelable(true);
                dialog.setPositiveButton(getResources().getString(R.string.ok),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.dismiss();
                            }
                        });
                dialog.show();
            }
        }
    }

    /**
     * Method to display the menu of the app.
     */
    private void displaySideMenu() {

        TranslateAnimation animation = null;

        // If it's a tablet in landscape, the menu is always displayed, else
        // it's activated by the user
        if (!isTablet || (isTablet && screenOrientation == Orientation.PORTRAIT)) {
            if (!showingMenu) {

                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mainRL.getLayoutParams();

                animation = new TranslateAnimation(0, listRL.getMeasuredWidth() - layoutParams.leftMargin, 0, 0);

                animation.setDuration(animationDuration);
                animation.setFillEnabled(true);
                animation.setAnimationListener(new AnimationListener() {

                    @Override
                    public void onAnimationStart(Animation animation) {
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {

                        // At the end, set the final position as the current one
                        RelativeLayout.LayoutParams lpList = (LayoutParams) mainRL.getLayoutParams();
                        lpList.setMargins(listRL.getMeasuredWidth(), 0, -listRL.getMeasuredWidth(), 0);
                        mainRL.setLayoutParams(lpList);

                        showingMenu = true;
                    }
                });

            } else {

                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mainRL.getLayoutParams();

                animation = new TranslateAnimation(0, -layoutParams.leftMargin, 0, 0);
                animation.setDuration(animationDuration);
                animation.setFillEnabled(true);
                animation.setAnimationListener(new AnimationListener() {

                    @Override
                    public void onAnimationStart(Animation animation) {
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {

                        // At the end, set the final position as the current one
                        RelativeLayout.LayoutParams mainContenrLP = (LayoutParams) mainRL.getLayoutParams();
                        mainContenrLP.setMargins(0, 0, 0, 0);
                        mainRL.setLayoutParams(mainContenrLP);

                        showingMenu = false;
                    }
                });
            }

            mainRL.startAnimation(animation);
        }

        else {
            // Showing the menu since the tablet is in landscape orientation
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mainRL.getLayoutParams();

            animation = new TranslateAnimation(0, listRL.getMeasuredWidth() - layoutParams.leftMargin, 0, 0);

            animation.setDuration(animationDuration);
            animation.setFillEnabled(true);
            animation.setAnimationListener(new AnimationListener() {

                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {

                    // At the end, set the final position as the current one
                    RelativeLayout.LayoutParams lpList = (LayoutParams) mainRL.getLayoutParams();
                    lpList.setMargins(listRL.getMeasuredWidth(), 0, -listRL.getMeasuredWidth(), 0);
                    mainRL.setLayoutParams(lpList);

                    showingMenu = true;
                }
            });

            mainRL.startAnimation(animation);
        }
    }

    public OnCameraChangeListener getCameraChangeListener() {
        return new OnCameraChangeListener() {
            @Override
            public void onCameraChange(CameraPosition position) {
                zoom = (int) position.zoom;
            }
        };
    }

    public OnMapClickListener getOnMapClickListener() {
        return new OnMapClickListener() {
            @Override
            public void onMapClick(LatLng arg0) {

                if (connected) {
                    // Reverse geocoding the tapped location
                    new ReverseGeocodingTask(getBaseContext()).execute(arg0);
                } else {
                    Toast.makeText(getApplicationContext(), getResources().getString(R.string.not_connected),
                            Toast.LENGTH_LONG).show();
                }
            }
        };
    }

    @Override
    public void onStop() {

        // If the client is connected
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            stopLocationUpdates();
        }

        // After disconnect() is called, the client is considered "dead".
        if (mGoogleApiClient != null)
            mGoogleApiClient.disconnect();

        stopService(new Intent(context, DeviceMonitorService.class));

        // Unregistering the broadcast receivers
        // unregisterReceiver(bReceiver);
        unregisterReceiver(mConnReceiver);
        unregisterReceiver(wifiReceiver);

        super.onStop();
    }

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

    @Override
    public void onStart() {

        super.onStart();

        if (mGoogleApiClient != null)
            mGoogleApiClient.connect();

        // Registering the broadcast receivers
        //registerReceiver(bReceiver, new IntentFilter(Constants.RECEIVED_RESOURCES_UPDATE));

        registerReceiver(mConnReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));

        registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

        registerReceiver(batteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

    }

    @Override
    public void onResume() {
        super.onResume();

        int[] screenSize = Utils.getScreenSize(context, getWindow());
        screenWidth = screenSize[0];
        screenHeight = screenSize[1];

        final RelativeLayout listRL = (RelativeLayout) findViewById(R.id.listContainer);
        final RelativeLayout listRLContainer = (RelativeLayout) findViewById(R.id.rlListViewContent);
        final RelativeLayout shadowRL = (RelativeLayout) findViewById(R.id.shadowContainer);

        RelativeLayout.LayoutParams menuListLP = (LayoutParams) listRL.getLayoutParams();

        // Setting the ListView width as the container width without the shadow
        // RelativeLayout
        menuListLP.width = (int) (screenWidth * menuWidth);
        listRL.setLayoutParams(menuListLP);

        RelativeLayout.LayoutParams listP = (LayoutParams) listRLContainer.getLayoutParams();
        listP.width = (int) (screenWidth * menuWidth) - shadowRL.getLayoutParams().width;
        listRLContainer.setLayoutParams(listP);

    }

    /**
     * Check if Google Play services are available before making a request.
     * 
     * @return true if Google Play services are available, false otherwise
     */
    private boolean servicesConnected() {

        Log.d(NAM4JAndroidActivity.TAG, this.getString(R.string.checkingGooglePlayServicesAvailability));

        // Check that Google Play services is available
        int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

        if (ConnectionResult.SUCCESS == resultCode) {
            Log.d(NAM4JAndroidActivity.TAG, this.getString(R.string.play_services_availability));
            return true;
        } else {
            showErrorDialog(resultCode);
            return false;
        }
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.d(NAM4JAndroidActivity.TAG, this.getString(R.string.location_services_connected));

        if (servicesConnected()) {

            // Centering map on last known location, if available
            Location mLastLocation = null;
            mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);

            if (mLastLocation != null) {
                if (firstLocation) {
                    firstLocation = false;
                    LatLng myLocation = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude());

                    map.animateCamera(CameraUpdateFactory.newLatLngZoom(myLocation, zoom));
                }
            }

            startLocationUpdates();
        }
    }

    @Override
    public void onConnectionSuspended(int cause) {
        Log.d(NAM4JAndroidActivity.TAG, this.getString(R.string.disconnected_location_services));
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

        // Google Play services can resolve some errors it detects. If the error
        // has a resolution, try sending an Intent to start a Google Play
        // services activity that can resolve error.
        if (connectionResult.hasResolution()) {
            try {
                // Start an Activity that tries to resolve the error
                connectionResult.startResolutionForResult(this,
                        LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
            } catch (IntentSender.SendIntentException e) {
                e.printStackTrace();
            }
        } else {
            // If no resolution is available, display a dialog to the user with
            // the error
            showErrorDialog(connectionResult.getErrorCode());
        }
    }

    /**
     * Report location updates to the UI.
     * 
     * @param location
     *            The updated location.
     */
    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            LatLng myLocation = new LatLng(location.getLatitude(), location.getLongitude());
            currentLocation = myLocation;

            // Center map on current location just the first time a location is
            // available
            if (firstLocation) {
                firstLocation = false;
                map.animateCamera(CameraUpdateFactory.newLatLngZoom(myLocation, zoom));
            }

            if (marker == null) {
                marker = map.addMarker(new MarkerOptions().position(currentLocation).icon(blueCircle));
            } else {
                marker.setPosition(currentLocation);
            }

        } else
            Log.d(NAM4JAndroidActivity.TAG, this.getString(R.string.location_not_available));
    }

    /** Method that centers the map on current user location. */
    private void centerMap() {
        if (currentLocation != null) {
            CameraPosition newCamPos = new CameraPosition(
                    new LatLng(currentLocation.latitude, currentLocation.longitude), zoom,
                    map.getCameraPosition().tilt, // use old tilt
                    map.getCameraPosition().bearing); // use old bearing
            map.animateCamera(CameraUpdateFactory.newCameraPosition(newCamPos), 400, null);
        } else {
            Toast.makeText(context, getResources().getString(R.string.noLocationInfoAvailable), Toast.LENGTH_SHORT)
                    .show();
        }
    }

    /**
     * In response to a request to start updates, send a request to Location
     * Services.
     */
    private void startLocationUpdates() {
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
            Log.d(NAM4JAndroidActivity.TAG, this.getString(R.string.updates_started));
        } else {
            Log.d(NAM4JAndroidActivity.TAG, this.getString(R.string.updates_request_error));
        }
    }

    /**
     * In response to a request to stop updates, send a request to Location
     * Services.
     */
    private void stopLocationUpdates() {
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            Log.d(NAM4JAndroidActivity.TAG, this.getString(R.string.updates_stopped));
        } else {
            Log.d(NAM4JAndroidActivity.TAG, this.getString(R.string.updates_stop_error));
        }
    }

    /**
     * Show a dialog returned by Google Play services for the connection error
     * code
     * 
     * @param errorCode
     *            An error code returned from onConnectionFailed
     */
    private void showErrorDialog(int errorCode) {

        // Get the error dialog from Google Play services
        Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode, this,
                LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);

        // If Google Play services can provide an error dialog
        if (errorDialog != null) {

            // Create a new DialogFragment in which to show the error dialog
            ErrorDialogFragment errorFragment = new ErrorDialogFragment();

            // Set the dialog in the DialogFragment
            errorFragment.setDialog(errorDialog);

            // Show the error dialog in the DialogFragment
            errorFragment.show(getSupportFragmentManager(), NAM4JAndroidActivity.TAG);
        } else {
            Toast.makeText(context, "Incompatible version of Google Play Services", Toast.LENGTH_LONG).show();
        }
    }

    /**
     * Define a DialogFragment to display the error dialog generated in
     * showErrorDialog.
     */
    public static class ErrorDialogFragment extends DialogFragment {

        // Global field to contain the error dialog
        private Dialog mDialog;

        /**
         * Default constructor. Sets the dialog field to null
         */
        public ErrorDialogFragment() {
            super();
            mDialog = null;
        }

        /**
         * Set the dialog to display
         * 
         * @param dialog
         *            An error dialog
         */
        public void setDialog(Dialog dialog) {
            mDialog = dialog;
        }

        /*
         * This method must return a Dialog to the DialogFragment.
         */
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            return mDialog;
        }

        /* Close the app when the user clicks on the dialog button */
        @Override
        public void onDismiss(DialogInterface dialog) {
            super.onDismiss(dialog);

            getActivity().finish();
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        String message = getResources().getString(R.string.exitOnBackButtonPressed);

        if (keyCode == KeyEvent.KEYCODE_BACK) {

            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage(message).setCancelable(false).setPositiveButton(
                    getResources().getString(R.string.yes), new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface iDialog, int id) {

                            stopService(new Intent(context, DeviceMonitorService.class));

                            // Unregistering the broadcast receivers
                            //   unregisterReceiver(bReceiver);
                            unregisterReceiver(mConnReceiver);
                            unregisterReceiver(wifiReceiver);

                            if (connected) {

                                close = true;

                                /*
                                 * The progress dialog is not created by
                                 * the AsyncTask because the peer just
                                 * sends a message to the bootstrap.
                                 * This takes very few time and the
                                 * dialog would disappear almost
                                 * immediately. By showing it before
                                 * executing the AsyncTask, it can stay
                                 * on the screen until the bootstrap
                                 * informs the peer that it is part of
                                 * the network. Thus, the dialog is
                                 * removed from the function listening
                                 * for received messages
                                 * onReceivedMessage(String).
                                 */
                                dialog = new ProgressDialog(NAM4JAndroidActivity.this);
                                dialog.setMessage(NAM4JAndroidActivity.this.getString(R.string.pwLeaving));
                                dialog.show();

                                new LeaveNetwork(null).execute();

                                connected = false;

                            } else {

                                // finish();

                                // AFTER LEAVING THE NETWORK, THE APP GETS CLOSED

                                /*
                                 * Notify the system to finalize and
                                 * collect all objects of the app on
                                 * exit so that the virtual machine
                                 * running the app can be killed by the
                                 * system without causing issues.
                                 * 
                                 * NOTE: If this is set to true then the
                                 * virtual machine will not be killed
                                 * until all of its threads have closed.
                                 */
                                System.runFinalizersOnExit(true);

                                /*
                                 * Force the system to close the app
                                 * down completely instead of retaining
                                 * it in the background. The virtual
                                 * machine that runs the app will be
                                 * killed. The app will be completely
                                 * created as a new app in a new virtual
                                 * machine running in a new process if
                                 * the user starts the app again.
                                 */
                                System.exit(0);
                            }
                        }
                    }).setNegativeButton(getResources().getString(R.string.no),
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    dialog.cancel();
                                }
                            });

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

            return true;
        }

        else if (keyCode == KeyEvent.KEYCODE_MENU) {
            displaySideMenu();
        }

        return super.onKeyDown(keyCode, event);
        // return true;
    }

    /**
     * Method to process a resource descriptor received on the network.
     * 
     * @param resourceDescriptor
     *          The resource descriptor
     */
    private void processResourceDescriptor(String resourceDescriptor, String reason) {

        JSONObject obj;
        try {
            obj = new JSONObject(resourceDescriptor);

            JSONObject locationObj = obj.getJSONObject("location");
            JSONObject locationValue = new JSONObject(locationObj.getString("value"));
            JSONObject building = locationValue.getJSONObject("building");

            // The address to geocode
            String buildingValue = building.getString("value");

            String[] data = new String[] { buildingValue, reason };

            new GeocodeTask(getBaseContext()).execute(data);

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * Method to manage a resource received on the Chord network.
     * 
     * @param rd
     *            The resource descriptor
     * 
     * @param reason
     *            A string defined in {@link Constants} class stating if the
     *            resource has been received upon assignment or search
     */
    @Override
    public void onReceivedResource(ResourceDescriptor rd, String reason) {
        // If the user leaves the network, the node may receive answers to
        // requests sent to the network before leaving it, so a check on
        // connected boolean is performed
        if (connected) {
            if (reason.equalsIgnoreCase(Constants.reasonResearched)) {
                Log.d(NAM4JAndroidActivity.TAG, "Received the researched resource");
                processResourceDescriptor(rd.getAttachment(), Constants.reasonResearched);
            } else if (reason.equalsIgnoreCase(Constants.reasonAssigned)) {
                Log.d(NAM4JAndroidActivity.TAG, "Received a resource for the peer to be its responsible");
                processResourceDescriptor(rd.getAttachment(), Constants.reasonAssigned);
            }
        }
    }

    /**
     * Method to manage a resource received on the Mesh network upon research.
     * 
     * @param resource
     *            The resource descriptor
     */
    @Override
    public void onFoundSearchedResource(Resource resource) {
        // If the user leaves the network, the node may receive answers to
        // requests sent to the network before leaving it, so a check on
        // connected boolean is performed
        if (connected) {
            // Adding a marker on the map for the received resource
            Set<String> keySet = resource.getKeySet();
            for (String k : keySet) {
                processResourceDescriptor(resource.getValue(k), Constants.reasonResearched);
            }
        }
    }

    /**
     * Method to manage a resource received on the Mesh network upon assignment.
     * 
     * @param resource
     *            The resource descriptor
     */
    @Override
    public void onReceivedResourceToBeResponsible(Resource resource) {
        // If the user leaves the network, the node may receive answers to
        // requests sent to the network before leaving it, so a check on
        // connected boolean is performed
        if (connected) {
            // Adding a marker on the map for the received resource
            Set<String> keySet = resource.getKeySet();
            for (String k : keySet) {
                processResourceDescriptor(resource.getValue(k), Constants.reasonAssigned);
            }
        }
    }

    private void startBuildingPublishActivity(String addresses) {
        requestPendingForBuilding = false;
        if (connected) {
            Bundle args = new Bundle();
            args.putParcelable("CurrentLocation", currentLocation);
            Intent i = new Intent(this, BuildingPublishActivity.class);
            i.putExtra("Address", addresses);
            i.putExtra("Bundle", args);
            startActivity(i);
        }
    }

    private void startSensorPublishActivity(String addresses) {
        requestPendingForSensor = false;
        if (connected) {
            Bundle args = new Bundle();
            args.putParcelable("CurrentLocation", currentLocation);
            Intent i = new Intent(this, SensorPublishActivity.class);
            i.putExtra("Address", addresses);
            i.putExtra("Bundle", args);
            startActivity(i);
        }
    }

    private void connect() {
        // The progress dialog is not created by the AsyncTask because the peer
        // just sends a message to the bootstrap. This takes very few time and
        // the dialog would disappear almost immediately. By showing it before
        // executing the AsyncTask, it can stay on the screen until the
        // bootstrap informs the peer that it is part of the network. Thus, the
        // dialog is removed from the function listening for received messages
        // onReceivedMessage(String).
        dialog = new ProgressDialog(NAM4JAndroidActivity.this);
        dialog.setMessage(NAM4JAndroidActivity.this.getString(R.string.pwJoining));
        dialog.show();
        new JoinNetwork(null).execute();
    }

    private void afterConnected() {
        sharedPreferences = getSharedPreferences(Constants.PREFERENCES, Context.MODE_PRIVATE);
        String currentNetwork = sharedPreferences.getString(Constants.NETWORK, "");

        if (currentNetwork.equalsIgnoreCase(Constants.CHORD)) {
            GamiNode.addChordResourceListener(this);
            GamiNode.addChordMessageListener(this);
        } else if (currentNetwork.equalsIgnoreCase(Constants.MESH)) {
            GamiNode.addMeshResourceListener(this);
            GamiNode.addMeshMessageListener(this);
        }

        amiTask = new UPCPFTaskDescriptor("AmITask", "T1");
        amiTask.setState("UNSTARTED");
    }

    private void showSettings() {
        Intent i = new Intent(this, SettingsActivity.class);
        startActivity(i);
    }

    @Override
    public boolean onMarkerClick(Marker marker) {
        LatLng p = marker.getPosition();

        Log.d(NAM4JAndroidActivity.TAG, "Tapped " + p.latitude + " ; " + p.longitude);

        if (connected) {
            // Reverse geocode the tapped location
            new ReverseGeocodingTask(getBaseContext()).execute(p);
        } else {
            Toast.makeText(getApplicationContext(), getResources().getString(R.string.not_connected),
                    Toast.LENGTH_LONG).show();
        }

        return false;
    }

    private void showAddress(final String addressTouch) {

        Log.d(NAM4JAndroidActivity.TAG, "Tapped address: " + addressTouch);

        AlertDialog.Builder dialog = new AlertDialog.Builder(this);
        dialog.setMessage("Do you want to see information about building located in " + addressTouch + " ?");
        dialog.setCancelable(true);
        dialog.setPositiveButton(getResources().getString(R.string.yes), new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                dialog.dismiss();
                Intent intent = new Intent(NAM4JAndroidActivity.this, BuildingLookupActivity.class);

                intent.putExtra("AddressBuilding", addressTouch);
                NAM4JAndroidActivity.this.startActivity(intent);
            }
        });
        dialog.setNegativeButton(getResources().getString(R.string.no), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
                dialog.dismiss();
            }
        });

        dialog.show();
    }

    private void leftNetwork() {
        if (dialog.isShowing()) {
            dialog.dismiss();
        }

        Toast.makeText(getApplicationContext(), getResources().getString(R.string.disconnected_from_network),
                Toast.LENGTH_LONG).show();

        // Settings menu elements
        ArrayList<MenuListElement> listElements = new ArrayList<MenuListElement>();

        listElements.add(new MenuListElement(getResources().getString(R.string.connectMenuTitle),
                getResources().getString(R.string.connectMenuSubTitle)));
        listElements.add(new MenuListElement(getResources().getString(R.string.settingsMenuTitle),
                getResources().getString(R.string.settingsMenuSubTitle)));
        listElements.add(new MenuListElement(getResources().getString(R.string.exitMenuTitle),
                getResources().getString(R.string.exitMenuSubTitle)));

        MenuListAdapter adapter = new MenuListAdapter(this, R.layout.menu_list_view_row, listElements);
        listView.setAdapter(adapter);

        // Cleaning the map and the HashMap containing the known resources
        runOnUiThread(new Runnable() {
            public void run() {
                map.clear();
                ml.clear();
            }
        });
    }

    private void closeApp() {
        if (dialog.isShowing()) {
            dialog.dismiss();
        }

        // finish();
        System.runFinalizersOnExit(true);
        System.exit(0);
    }

    private void addReceivedResourceMarkerOnMap(final LatLng p, final String address, final String reason) {
        if (p != null) {
            if (ml.get(address) == null) {

                Log.d(NAM4JAndroidActivity.TAG, "Added a new marker on the map for position " + p.latitude + " , "
                        + p.longitude + " for the researched resource");

                // The following Runnable is because the only way to interact
                // with the GUI is through the UI thread
                runOnUiThread(new Runnable() {
                    public void run() {

                        Toast.makeText(context, "Added a new marker on the map at address " + address + " ("
                                + p.latitude + ", " + p.longitude + ") for the researched resource",
                                Toast.LENGTH_LONG).show();

                        Marker marker = null;

                        // Creating the marker whose color is set based on the
                        // reason for which the resource has been received
                        if (reason.equalsIgnoreCase(Constants.reasonResearched)) {
                            // Researched resources have a red marker
                            marker = map.addMarker(new MarkerOptions().position(p).icon(bitmapDescriptorRed)
                                    .title(address).snippet(""));

                        } else if (reason.equalsIgnoreCase(Constants.reasonAssigned)) {
                            // Assigned resources have a blue marker
                            marker = map.addMarker(new MarkerOptions().position(p).icon(bitmapDescriptorBlue)
                                    .title(address).snippet(""));
                        }

                        if (marker != null) {
                            ml.put(address, marker);
                        }
                    }
                });

            } else {
                System.out.println("Marker is already present");
            }
        }
    }

    @Override
    public void onReceivedMessage(String msg) {
        System.out.println("Received message of type " + msg);

        // Connected to the network
        if ((msg.equalsIgnoreCase(PeerListMessage.MSG_PEER_LIST) // Chord network join response
                || msg.equalsIgnoreCase(JoinResponseMessage.MSG_KEY)) // Mesh network join response
                && !connected) {

            // Settings menu elements
            ArrayList<MenuListElement> listElements = new ArrayList<MenuListElement>();

            listElements.add(new MenuListElement(getResources().getString(R.string.disconnectMenuTitle),
                    getResources().getString(R.string.disconnectMenuSubTitle)));
            listElements.add(new MenuListElement(getResources().getString(R.string.publishBuildingMenuTitle),
                    getResources().getString(R.string.publishBuildingMenuSubTitle)));
            listElements.add(new MenuListElement(getResources().getString(R.string.publishSensorgMenuTitle),
                    getResources().getString(R.string.publishSensorgMenuSubTitle)));
            listElements.add(new MenuListElement(getResources().getString(R.string.exitMenuTitle),
                    getResources().getString(R.string.exitMenuSubTitle)));

            final MenuListAdapter adapter = new MenuListAdapter(this, R.layout.menu_list_view_row, listElements);

            connected = true;

            runOnUiThread(new Runnable() {
                public void run() {
                    if (dialog.isShowing()) {
                        dialog.dismiss();
                    }

                    Toast.makeText(context, getResources().getString(R.string.connection_started),
                            Toast.LENGTH_LONG).show();
                    listView.setAdapter(adapter);
                }
            });
        }
    }

    // BroadcastReceiver objects used to receive messages informing about
    // changes which occur in the state of the CPU, the memory and the wifi.

    // CPU and memory monitoring BroadcastReceiver (provided by
    // DeviceMonitorService class)
    private final BroadcastReceiver bReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {

            /* Checking if received message is from the monitoring Service */
            if (intent.getAction().equals(Constants.RECEIVED_RESOURCES_UPDATE)) {

                ResourceMonitor rm = (ResourceMonitor) intent.getSerializableExtra("resourceDescriptor");

                float usedCpuPerc = rm.getUsedCpuPerc();
                float availableMem = rm.getAvailableMem();
                float totalMem = rm.getTotalMem();

                float memUsagePerc = (new BigDecimal(Float.toString(availableMem / totalMem)).setScale(2,
                        BigDecimal.ROUND_HALF_UP)).floatValue() * 100;

                /*
                 * String cpuUsageMsg = "CPU usage: " + (usedCpuPerc * 100) +
                 * "%";
                 * 
                 * String memUsageMsg = "Mem usage: " + memUsagePerc +
                 * "% (using " + availableMem + " MB out of " + totalMem +
                 * " MB)";
                 * 
                 * tvCPU.setText(cpuUsageMsg); tvMem.setText(memUsageMsg);
                 */

                LayoutParams memoryLp = (LayoutParams) memoryBar.getLayoutParams();
                memoryLp.height = (int) (10 * Math.ceil(memUsagePerc / 10));
                memoryBar.setLayoutParams(memoryLp);

                LayoutParams barLp = (LayoutParams) cpuBar.getLayoutParams();
                barLp.height = (int) (10 * Math.ceil((usedCpuPerc * 100) / 10));
                cpuBar.setLayoutParams(barLp);
            }
        }
    };

    // Network changes BroadcastReceiver (provided by Android's
    // ConnectivityManager class)
    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {

            String networkStatus = "";

            boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);

            String reason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);

            // No connectivity is available
            if (noConnectivity) {
                networkStatus += "No Connectivity. The reason is: " + reason + "\n";
            }

            NetworkInfo currentNetworkInfo = (NetworkInfo) intent
                    .getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);

            NetworkInfo otherNetworkInfo = (NetworkInfo) intent
                    .getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);

            if (currentNetworkInfo != null)
                networkStatus += "Current Network info: " + currentNetworkInfo.getTypeName() + " ("
                        + currentNetworkInfo.getType() + ") [" + currentNetworkInfo.getState() + "]\n";

            if (otherNetworkInfo != null)
                networkStatus += "Other Network info: " + otherNetworkInfo.getTypeName() + " ("
                        + currentNetworkInfo.getType() + ") [" + currentNetworkInfo.getState() + "]";

            // tvNetwork.setText(networkStatus);
            System.out.println("--- networkStatus = " + networkStatus);
        }
    };

    // Wifi monitoring BroadcastReceiver (provided by Android's WifiManager class)
    private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {

            List<ScanResult> results = wifiManager.getScanResults();

            List<String> networks = new ArrayList<String>();

            ScanResult bestSignal = null;

            String wifiMsg = results.size() + " access points found\n";

            for (ScanResult result : results) {

                if (!networks.contains(result.SSID)) {
                    networks.add(result.SSID);
                }

                wifiMsg += result.SSID + " (strength: " + result.level + "); ";

                if (bestSignal == null || WifiManager.compareSignalLevel(bestSignal.level, result.level) < 0)
                    bestSignal = result;
            }

            wifiMsg += "\nThe strongest is: " + bestSignal.SSID;

            // tvWifi.setText(wifiMsg);
            System.out.println("--- wifiMsg = " + wifiMsg);

        }
    };

    // Battery monitoring broadcast receiver
    private BroadcastReceiver batteryReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
            boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING
                    || status == BatteryManager.BATTERY_STATUS_FULL;

            /*
             * int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED,
             * -1); boolean usbCharge = chargePlug ==
             * BatteryManager.BATTERY_PLUGGED_USB; boolean acCharge = chargePlug
             * == BatteryManager.BATTERY_PLUGGED_AC;
             */

            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);

            float batteryPct = level / (float) scale;

            String batteryStatus = "";

            if (isCharging)
                batteryStatus += "The battery is charging";
            else
                batteryStatus += "The battery is not charging";

            batteryStatus += "\nBattery is " + (batteryPct * 100) + "% charged";

            // tvBattery.setText(batteryStatus);
            System.out.println("--- batteryStatus = " + batteryStatus);
        }
    };

    private class ReverseGeocodingTask extends AsyncTask<LatLng, Void, String> {
        Context mContext;

        public ReverseGeocodingTask(Context context) {
            super();
            mContext = context;
        }

        // Finding address using reverse geocoding
        @Override
        protected String doInBackground(LatLng... params) {

            Geocoder geocoder = new Geocoder(mContext, Locale.getDefault());

            double latitude = params[0].latitude;
            double longitude = params[0].longitude;

            List<Address> addresses = null;
            String addressTouch = null;

            try {
                addresses = geocoder.getFromLocation(latitude, longitude, 1);
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (addresses != null && addresses.size() > 0) {
                addressTouch = addresses.get(0).getAddressLine(0);
            }

            if (addressTouch == null) {

                Log.d(NAM4JAndroidActivity.TAG,
                        "Geocoder service is not available; trying with a http request to Google Maps...");

                HttpURLConnection urlConnection = null;
                try {
                    URL url = new URL("http://maps.googleapis.com/maps/api/geocode/json?latlng=" + latitude + ","
                            + longitude + "&sensor=false");
                    urlConnection = (HttpURLConnection) url.openConnection();

                    InputStream in = new BufferedInputStream(urlConnection.getInputStream());

                    BufferedReader streamReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
                    StringBuilder responseStrBuilder = new StringBuilder();

                    String inputStr;
                    while ((inputStr = streamReader.readLine()) != null)
                        responseStrBuilder.append(inputStr);

                    JSONObject obj = new JSONObject(responseStrBuilder.toString());

                    JSONArray resultsArray = obj.getJSONArray("results");
                    JSONObject resultsArrayFirstElement = resultsArray.getJSONObject(0);

                    String formattedAddress = resultsArrayFirstElement.get("formatted_address").toString();
                    System.out.println("Formatted address: " + formattedAddress);

                    addressTouch = formattedAddress;
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                } catch (JSONException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                finally {
                    if (urlConnection != null)
                        urlConnection.disconnect();
                }

                return addressTouch;
            } else {
                return addressTouch;
            }

        }

        @Override
        protected void onPostExecute(String addresses) {

            if (addresses != null) {
                if (requestPendingForBuilding)
                    startBuildingPublishActivity(addresses);
                else if (requestPendingForSensor)
                    startSensorPublishActivity(addresses);
                else
                    showAddress(addresses);
            } else {
                Toast.makeText(getApplicationContext(), getResources().getString(R.string.geocoder_not_available),
                        Toast.LENGTH_LONG).show();
            }
        }
    }

    private class GeocodeTask extends AsyncTask<String, Void, LatLng> {
        Context mContext;
        String strAddress;
        String reason;

        public GeocodeTask(Context context) {
            super();
            mContext = context;
        }

        // Reverse geocoding current location
        @Override
        protected LatLng doInBackground(String... params) {

            Geocoder coder = new Geocoder(mContext);
            List<Address> addresses = null;
            LatLng p1 = null;

            strAddress = params[0];
            reason = params[1];

            try {
                addresses = coder.getFromLocationName(strAddress, 5);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (addresses != null && addresses.size() > 0) {
                Address location = addresses.get(0);

                p1 = new LatLng((float) (location.getLatitude()), (float) (location.getLongitude()));
            } else {
                Log.d(NAM4JAndroidActivity.TAG,
                        "Geocoder service is not available; trying with a http request to Google Maps...");

                HttpURLConnection urlConnection = null;
                try {
                    URL url = new URL(
                            Constants.GEOCODER_ADDRESS + strAddress.replaceAll("\\s+", "+") + "&sensor=false");
                    urlConnection = (HttpURLConnection) url.openConnection();

                    InputStream in = new BufferedInputStream(urlConnection.getInputStream());

                    BufferedReader streamReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
                    StringBuilder responseStrBuilder = new StringBuilder();

                    String inputStr;
                    while ((inputStr = streamReader.readLine()) != null)
                        responseStrBuilder.append(inputStr);

                    JSONObject obj = new JSONObject(responseStrBuilder.toString());

                    JSONArray resultsArray = obj.getJSONArray("results");
                    JSONObject resultsArrayFirstElement = resultsArray.getJSONObject(0);

                    JSONObject geometryObj = resultsArrayFirstElement.getJSONObject("geometry");
                    JSONObject locationObj = geometryObj.getJSONObject("location");

                    Float lat = Float.parseFloat(locationObj.getString("lat"));
                    Float lng = Float.parseFloat(locationObj.getString("lng"));

                    p1 = new LatLng((double) (lat), (double) (lng));

                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                } catch (JSONException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                finally {
                    urlConnection.disconnect();
                }
            }

            return p1;
        }

        @Override
        protected void onPostExecute(LatLng p) {

            if (p != null) {
                addReceivedResourceMarkerOnMap(p, strAddress, reason);
            } else {
                Toast.makeText(getApplicationContext(), getResources().getString(R.string.geocoder_not_available),
                        Toast.LENGTH_LONG).show();
            }
        }
    }

    private class JoinNetwork extends AsyncTask<Void, Void, Void> {
        public JoinNetwork(Void v) {
            super();
        }

        @Override
        protected Void doInBackground(Void... params) {
            GamiNode.getAndroidGamiNode(context);
            return null;
        }

        @Override
        protected void onPostExecute(Void v) {
            afterConnected();
        }
    }

    private class LeaveNetwork extends AsyncTask<Void, Void, Void> {
        public LeaveNetwork(Void v) {
            super();
        }

        @Override
        protected Void doInBackground(Void... params) {
            GamiNode.disconnect();
            return null;
        }

        @Override
        protected void onPostExecute(Void v) {
            if (close) {
                closeApp();
            } else {
                leftNetwork();
            }
        }
    }

    class ListItemClickListener implements OnItemClickListener {

        @Override
        public void onItemClick(AdapterView<?> clickedList, View clickedElement, final int clickedElementPosition,
                long clickedRowId) {

            if (showingMenu) {

                // If it's a tablet in landscape, the menu is always displayed
                // so no animation is necessary
                if (!isTablet || (isTablet && screenOrientation == Orientation.PORTRAIT)) {

                    final RelativeLayout mainRL = (RelativeLayout) findViewById(R.id.rlContainer);
                    final RelativeLayout listRL = (RelativeLayout) findViewById(R.id.listContainer);

                    TranslateAnimation animation = new TranslateAnimation(0, -listRL.getMeasuredWidth(), 0, 0);

                    animation.setDuration(animationDuration);
                    animation.setFillEnabled(true);
                    animation.setAnimationListener(new AnimationListener() {

                        @Override
                        public void onAnimationStart(Animation animation) {
                        }

                        @Override
                        public void onAnimationRepeat(Animation animation) {
                        }

                        @Override
                        public void onAnimationEnd(Animation animation) {

                            // At the end, set the final position as the current one
                            RelativeLayout.LayoutParams mainContainerLP = (LayoutParams) mainRL.getLayoutParams();
                            mainContainerLP.setMargins(0, 0, 0, 0);
                            mainRL.setLayoutParams(mainContainerLP);

                            showingMenu = false;

                            if (connected) {
                                switch (clickedElementPosition) {
                                case 0:

                                    AlertDialog.Builder bDialog = new AlertDialog.Builder(context);
                                    bDialog.setMessage(getResources().getString(R.string.leave));
                                    bDialog.setCancelable(true);
                                    bDialog.setPositiveButton(getResources().getString(R.string.yes),
                                            new DialogInterface.OnClickListener() {
                                                public void onClick(DialogInterface iDialog, int id) {
                                                    iDialog.dismiss();

                                                    /*
                                                     * The progress dialog is
                                                     * not created by the
                                                     * AsyncTask because the
                                                     * peer just sends a message
                                                     * to the bootstrap. This
                                                     * takes very few time and
                                                     * the dialog would
                                                     * disappear almost
                                                     * immediately. By showing
                                                     * it before executing the
                                                     * AsyncTask, it can stay on
                                                     * the screen until the
                                                     * bootstrap informs the
                                                     * peer that it is part of
                                                     * the network. Thus, the
                                                     * dialog is removed from
                                                     * the function listening
                                                     * for received messages
                                                     * onReceivedMessage
                                                     * (String).
                                                     */
                                                    dialog = new ProgressDialog(NAM4JAndroidActivity.this);
                                                    dialog.setMessage(NAM4JAndroidActivity.this
                                                            .getString(R.string.pwLeaving));
                                                    dialog.show();

                                                    new LeaveNetwork(null).execute();

                                                    connected = false;
                                                }
                                            });
                                    bDialog.setNegativeButton("No", new DialogInterface.OnClickListener() {

                                        @Override
                                        public void onClick(DialogInterface dialog, int id) {
                                            dialog.dismiss();
                                        }
                                    });

                                    bDialog.show();
                                    break;

                                case 1:
                                    if (currentLocation != null) {

                                        // Specifying that the GeoCoder class
                                        // must call the function to start
                                        // publishing by setting the boolean to
                                        // true
                                        requestPendingForBuilding = true;
                                        new ReverseGeocodingTask(getBaseContext()).execute(currentLocation);
                                    } else {
                                        Bundle args = new Bundle();
                                        args.putParcelable("CurrentLocation", null);
                                        Intent i = new Intent(context, BuildingPublishActivity.class);
                                        i.putExtra("Address", "");
                                        i.putExtra("Bundle", args);
                                        startActivity(i);
                                    }
                                    break;

                                case 2:
                                    if (currentLocation != null) {

                                        // Specifying that the GeoCoder class must call the function to start
                                        // publishing by setting the boolean to true
                                        requestPendingForSensor = true;
                                        new ReverseGeocodingTask(getBaseContext()).execute(currentLocation);
                                    } else {
                                        Bundle args = new Bundle();
                                        args.putParcelable("CurrentLocation", null);
                                        Intent i = new Intent(context, SensorPublishActivity.class);
                                        i.putExtra("Address", "");
                                        i.putExtra("Bundle", args);
                                        startActivity(i);
                                    }
                                    break;

                                case 3:
                                    AlertDialog.Builder builder = new AlertDialog.Builder(context);
                                    builder.setMessage(
                                            context.getResources().getString(R.string.exitOnBackButtonPressed))
                                            .setCancelable(false)
                                            .setPositiveButton(getResources().getString(R.string.yes),
                                                    new DialogInterface.OnClickListener() {
                                                        public void onClick(DialogInterface iDialog, int id) {

                                                            stopService(new Intent(context,
                                                                    DeviceMonitorService.class));

                                                            // Unregistering the broadcast receivers
                                                            //unregisterReceiver(bReceiver);
                                                            unregisterReceiver(mConnReceiver);
                                                            unregisterReceiver(wifiReceiver);

                                                            if (connected) {
                                                                close = true;
                                                                dialog = new ProgressDialog(
                                                                        NAM4JAndroidActivity.this);
                                                                dialog.setMessage(NAM4JAndroidActivity.this
                                                                        .getString(R.string.pwLeaving));
                                                                dialog.show();
                                                                new LeaveNetwork(null).execute();
                                                                connected = false;
                                                            } else {
                                                                System.runFinalizersOnExit(true);
                                                                System.exit(0);
                                                            }
                                                        }
                                                    })
                                            .setNegativeButton(getResources().getString(R.string.no),
                                                    new DialogInterface.OnClickListener() {
                                                        public void onClick(DialogInterface dialog, int id) {
                                                            dialog.cancel();
                                                        }
                                                    });

                                    AlertDialog alert = builder.create();
                                    alert.show();
                                    break;
                                }
                            } else {
                                switch (clickedElementPosition) {
                                case 0:
                                    connect();
                                    Log.d(NAM4JAndroidActivity.TAG, context.getString(R.string.menu_connect));
                                    break;

                                case 1:
                                    showSettings();
                                    Log.d(NAM4JAndroidActivity.TAG, context.getString(R.string.menu_settings));
                                    break;

                                case 2:
                                    AlertDialog.Builder builder = new AlertDialog.Builder(context);
                                    builder.setMessage(
                                            context.getResources().getString(R.string.exitOnBackButtonPressed))
                                            .setCancelable(false)
                                            .setPositiveButton(getResources().getString(R.string.yes),
                                                    new DialogInterface.OnClickListener() {
                                                        public void onClick(DialogInterface iDialog, int id) {

                                                            stopService(new Intent(context,
                                                                    DeviceMonitorService.class));

                                                            // Unregistering the broadcast receivers
                                                            //unregisterReceiver(bReceiver);
                                                            unregisterReceiver(mConnReceiver);
                                                            unregisterReceiver(wifiReceiver);

                                                            if (connected) {

                                                                close = true;

                                                                dialog = new ProgressDialog(
                                                                        NAM4JAndroidActivity.this);
                                                                dialog.setMessage(NAM4JAndroidActivity.this
                                                                        .getString(R.string.pwLeaving));
                                                                dialog.show();

                                                                new LeaveNetwork(null).execute();

                                                                connected = false;

                                                            } else {
                                                                System.runFinalizersOnExit(true);

                                                                System.exit(0);
                                                            }
                                                        }
                                                    })
                                            .setNegativeButton(getResources().getString(R.string.no),
                                                    new DialogInterface.OnClickListener() {
                                                        public void onClick(DialogInterface dialog, int id) {
                                                            dialog.cancel();
                                                        }
                                                    });

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

                                default:
                                    break;
                                }
                            }
                        }
                    });

                    mainRL.startAnimation(animation);
                }

                else {
                    switch (clickedElementPosition) {
                    case 0:
                        connect();
                        Log.d(NAM4JAndroidActivity.TAG, context.getString(R.string.menu_connect));
                        break;

                    case 1:
                        showSettings();
                        Log.d(NAM4JAndroidActivity.TAG, context.getString(R.string.menu_settings));
                        break;

                    case 2:
                        AlertDialog.Builder builder = new AlertDialog.Builder(context);
                        builder.setMessage(context.getResources().getString(R.string.exitOnBackButtonPressed))
                                .setCancelable(false).setPositiveButton(getResources().getString(R.string.yes),
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface iDialog, int id) {
                                                stopService(new Intent(context, DeviceMonitorService.class));

                                                // Unregistering the broadcast receivers
                                                // unregisterReceiver(bReceiver);
                                                unregisterReceiver(mConnReceiver);
                                                unregisterReceiver(wifiReceiver);

                                                if (connected) {
                                                    close = true;
                                                    dialog = new ProgressDialog(NAM4JAndroidActivity.this);
                                                    dialog.setMessage(NAM4JAndroidActivity.this
                                                            .getString(R.string.pwLeaving));
                                                    dialog.show();
                                                    new LeaveNetwork(null).execute();
                                                    connected = false;
                                                } else {
                                                    System.runFinalizersOnExit(true);
                                                    System.exit(0);
                                                }
                                            }
                                        })
                                .setNegativeButton(getResources().getString(R.string.no),
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog, int id) {
                                                dialog.cancel();
                                            }
                                        });

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

                    default:
                        break;
                    }
                }
            }
        }
    }

    public class SwipeAndClickListener implements OnTouchListener {

        static final String logTag = "ActivitySwipeDetector";

        int sourceId;

        // To distinguish between click and swipe, set the max duration for a
        // click in milliseconds
        private static final int MAX_CLICK_DURATION = 200;

        // Instant the user clicks
        private long startClickTime;

        boolean isAnimating = false;

        // Change sensitivity based on screen resolution
        static final int MIN_DISTANCE = 50;

        private float downX, downY, upX, upY;

        public SwipeAndClickListener() {
        }

        public void onRightToLeftSwipe() {

            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mainRL.getLayoutParams();

            TranslateAnimation animation = null;

            final RelativeLayout mainRL = (RelativeLayout) findViewById(R.id.rlContainer);

            if (layoutParams.leftMargin >= listRL.getMeasuredWidth() / 2) {
                animation = new TranslateAnimation(0, listRL.getMeasuredWidth() - layoutParams.leftMargin, 0, 0);
            } else {
                animation = new TranslateAnimation(0, -layoutParams.leftMargin, 0, 0);
            }

            animation.setDuration(animationDuration);
            animation.setFillEnabled(true);
            animation.setAnimationListener(new AnimationListener() {

                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {

                    // At the end, set the final position as the current one
                    RelativeLayout.LayoutParams mainContainerLP = (LayoutParams) mainRL.getLayoutParams();

                    if (mainContainerLP.leftMargin >= listRL.getMeasuredWidth() / 2) {
                        mainContainerLP.setMargins(listRL.getMeasuredWidth(), 0, -listRL.getMeasuredWidth(), 0);
                        showingMenu = true;
                    } else {
                        mainContainerLP.setMargins(0, 0, 0, 0);
                        showingMenu = false;
                    }

                    mainRL.setLayoutParams(mainContainerLP);
                    isAnimating = false;
                }
            });

            mainRL.startAnimation(animation);
        }

        public void onLeftToRightSwipe() {
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mainRL.getLayoutParams();

            TranslateAnimation animation = null;

            if (layoutParams.leftMargin >= listRL.getMeasuredWidth() / 2) {
                animation = new TranslateAnimation(0, listRL.getMeasuredWidth() - layoutParams.leftMargin, 0, 0);
            } else {
                animation = new TranslateAnimation(0, -layoutParams.leftMargin, 0, 0);
            }

            animation.setDuration(animationDuration);
            animation.setFillEnabled(true);
            animation.setAnimationListener(new AnimationListener() {

                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {

                    // At the end, set the final position as the current one
                    RelativeLayout.LayoutParams mainContainerLP = (LayoutParams) mainRL.getLayoutParams();

                    if (mainContainerLP.leftMargin >= listRL.getMeasuredWidth() / 2) {
                        mainContainerLP.setMargins(listRL.getMeasuredWidth(), 0, -listRL.getMeasuredWidth(), 0);
                        showingMenu = true;
                    } else {
                        mainContainerLP.setMargins(0, 0, 0, 0);
                        showingMenu = false;
                    }

                    mainRL.setLayoutParams(mainContainerLP);
                    isAnimating = false;
                }
            });

            mainRL.startAnimation(animation);
        }

        public void onTopToBottomSwipe() {
        }

        public void onBottomToTopSwipe() {
        }

        public boolean onTouch(View v, MotionEvent event) {

            sourceId = v.getId();

            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {

                startClickTime = Calendar.getInstance().getTimeInMillis();

                downX = event.getX();
                downY = event.getY();
                return true;
            }
            case MotionEvent.ACTION_UP: {

                long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;

                if (clickDuration < MAX_CLICK_DURATION) {

                    // A click event has occurred

                    // Manage click event just if the button was clicked. If
                    // the user pressed the bar, ignore it
                    if (sourceId == menuButton.getId()) {
                        displaySideMenu();
                    }

                } else {
                    // A swipe event has occurred

                    upX = event.getX();
                    upY = event.getY();

                    float deltaX = downX - upX;
                    float deltaY = downY - upY;

                    if (!isAnimating) {
                        if (!showingMenu) {
                            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mainRL
                                    .getLayoutParams();
                            if (layoutParams.leftMargin > 0) {
                                isAnimating = true;
                                onRightToLeftSwipe();
                            }
                        } else {
                            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mainRL
                                    .getLayoutParams();
                            if (layoutParams.leftMargin < listRL.getMeasuredWidth()) {
                                isAnimating = true;
                                onLeftToRightSwipe();
                            }
                        }
                    }

                    // swipe horizontal?
                    if (Math.abs(deltaX) > MIN_DISTANCE) {

                        // left or right
                        if (deltaX < 0) {
                            // this.onLeftToRightSwipe();
                            return true;
                        }

                        if (deltaX > 0) {
                            // this.onRightToLeftSwipe();
                            return true;
                        }
                    } else {
                    }

                    // swipe vertical?
                    if (Math.abs(deltaY) > MIN_DISTANCE) {
                        // top or down
                        if (deltaY < 0) {
                            this.onTopToBottomSwipe();
                            return true;
                        }
                        if (deltaY > 0) {
                            this.onBottomToTopSwipe();
                            return true;
                        }
                    } else {
                    }

                    // no horizontal nor vertical swipe
                    return false;
                }
            }
            case MotionEvent.ACTION_MOVE: {
                upX = event.getX();
                float deltaX = downX - upX;

                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mainRL.getLayoutParams();

                if (!showingMenu) {
                    if (!isAnimating && ((layoutParams.leftMargin - deltaX >= 0)
                            && (layoutParams.leftMargin - deltaX <= listRL.getMeasuredWidth()))) {
                        layoutParams.leftMargin -= deltaX;
                        layoutParams.rightMargin += deltaX;
                        mainRL.setLayoutParams(layoutParams);
                    }
                } else {
                    if (!isAnimating && ((layoutParams.leftMargin - deltaX <= listRL.getMeasuredWidth())
                            && (layoutParams.leftMargin - deltaX >= 0))) {
                        layoutParams.leftMargin -= deltaX;
                        layoutParams.rightMargin += deltaX;
                        mainRL.setLayoutParams(layoutParams);
                    }
                }
                return false;
            }
            }
            return false;
        }
    }
}