com.dmsl.anyplace.UnifiedNavigationActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.dmsl.anyplace.UnifiedNavigationActivity.java

Source

/*
 * AnyPlace: A free and open Indoor Navigation Service with superb accuracy!
 *
 * Anyplace is a first-of-a-kind indoor information service offering GPS-less
 * localization, navigation and search inside buildings using ordinary smartphones.
 *
 * Author(s): Timotheos Constambeys, Lambros Petrou
 * 
 * Supervisor: Demetrios Zeinalipour-Yazti
 *
 * URL: http://anyplace.cs.ucy.ac.cy
 * Contact: anyplace@cs.ucy.ac.cy
 *
 * Copyright (c) 2015, Data Management Systems Lab (DMSL), University of Cyprus.
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in the
 * Software without restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the
 * following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

package com.dmsl.anyplace;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.Cursor;
import android.graphics.Color;
import android.location.Location;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.DialogFragment;
import android.text.TextPaint;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;
import com.actionbarsherlock.widget.SearchView;
import com.circlegate.tt.cg.an.lib.map.MapWrapperLayout;
import com.circlegate.tt.cg.an.lib.map.OnInfoWindowElemTouchListener;
import com.dmsl.anyplace.AnyplacePrefs.Action;
import com.dmsl.anyplace.cache.AnyplaceCache;
import com.dmsl.anyplace.cache.BackgroundFetchListener;
import com.dmsl.anyplace.floor.Algo1Radiomap;
import com.dmsl.anyplace.floor.Algo1Server;
import com.dmsl.anyplace.floor.FloorSelector;
import com.dmsl.anyplace.floor.FloorSelector.ErrorAnyplaceFloorListener;
import com.dmsl.anyplace.floor.FloorSelector.FloorAnyplaceFloorListener;
import com.dmsl.anyplace.floor.FloorSelector.NonCriticalError;
import com.dmsl.anyplace.googlemap.AnyPlaceMapTileProvider;
import com.dmsl.anyplace.googlemap.MyBuildingsRenderer;
import com.dmsl.anyplace.googlemap.VisiblePois;
import com.dmsl.anyplace.logger.AnyplaceLoggerActivity;
import com.dmsl.anyplace.nav.*;
import com.dmsl.anyplace.nav.AnyPlaceSeachingHelper.HTMLCursorAdapter;
import com.dmsl.anyplace.nav.AnyPlaceSeachingHelper.SearchTypes;
import com.dmsl.anyplace.nav.BuildingModel.FetchBuildingTaskListener;
import com.dmsl.anyplace.sensors.MovementDetector;
import com.dmsl.anyplace.sensors.SensorsMain;
import com.dmsl.anyplace.sensors.SensorsStepCounter;
import com.dmsl.anyplace.tasks.*;
import com.dmsl.anyplace.tasks.FetchBuildingsTask.FetchBuildingsTaskListener;
import com.dmsl.anyplace.tasks.FetchFloorsByBuidTask.FetchFloorsByBuidTaskListener;
import com.dmsl.anyplace.tasks.FetchPoisByBuidTask.FetchPoisListener;
import com.dmsl.anyplace.tracker.*;
import com.dmsl.anyplace.utils.*;
import com.dmsl.anyplace.wifi.SimpleWifiManager;
import com.flurry.android.FlurryAgent;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.CancelableCallback;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.*;
import com.google.maps.android.clustering.Cluster;
import com.google.maps.android.clustering.ClusterManager;
import com.google.maps.android.clustering.ClusterManager.OnClusterClickListener;
import com.google.maps.android.clustering.ClusterManager.OnClusterItemClickListener;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UnifiedNavigationActivity extends SherlockFragmentActivity
        implements AnyplaceTracker.TrackedLocAnyplaceTrackerListener,
        AnyplaceTracker.WifiResultsAnyplaceTrackerListener, AnyplaceTracker.ErrorAnyplaceTrackerListener,
        GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener,
        LocationListener, FloorAnyplaceFloorListener, ErrorAnyplaceFloorListener, OnSharedPreferenceChangeListener {

    private static final double csLat = 35.144569;
    private static final double csLon = 33.411107;
    private static final float mInitialZoomLevel = 19.0f;
    public static final String SHARED_PREFS_ANYPLACE = "Anyplace_Preferences";

    // Define a request code to send to Google Play services This code is
    // returned in Activity.onActivityResult
    private final static int LOCATION_CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9001;
    private final static int SELECT_PLACE_ACTIVITY_RESULT = 1112;
    private final static int SEARCH_POI_ACTIVITY_RESULT = 1113;
    private final static int PREFERENCES_ACTIVITY_RESULT = 1114;

    // Location API
    private LocationClient mLocationClient;
    // Define an object that holds accuracy and frequency parameters
    private LocationRequest mLocationRequest;

    // UI Elements
    private ProgressBar progressBar;
    private ImageButton btnFloorUp;
    private ImageButton btnFloorDown;
    private TextView textFloor;
    private TextView detectedAPs;
    private ImageButton btnTrackme;
    private TextView textDebug;

    private SearchTypes searchType = SearchTypes.OUTDOOR_MODE;
    private SearchView searchView;
    private AnyplaceSuggestionsTask mSuggestionsTask;

    // <Tasks>
    private DownloadRadioMapTaskBuid downloadRadioMapTaskBuid;
    private boolean floorChangeRequestDialog = false;
    // </Tasks>
    private boolean mAutomaticGPSBuildingSelection;

    /**
     * Note that this may be null if the Google Play services APK is not available.
     */
    private GoogleMap mMap;
    private boolean cameraUpdate = false;
    private float bearing;

    // Navigation
    private AnyUserData userData = null;
    // holds the lines for the navigation route on map
    private Polyline pathLineInside = null;
    private PolylineOptions pathLineOutsideOptions = null;
    private Polyline pathLineOutside = null;

    private AnyplaceCache mAnyplaceCache = null;
    // holds the PoisModels and Markers on map
    private VisiblePois visiblePois = null;
    private ClusterManager<BuildingModel> mClusterManager;

    // AnyplaceTracker
    private SensorsMain sensorsMain; // acceleration and orientation
    private MovementDetector movementDetector; // walking vs standing
    private SensorsStepCounter sensorsStepCounter; // step counter

    private TrackerLogicPlusIMU lpTracker;
    private Algo1Radiomap floorSelector;
    private String lastFloor;

    private boolean isTrackingErrorBackground;
    private Marker userMarker = null;

    /****************************************************************************************************************************/

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_unifiednav);

        detectedAPs = (TextView) findViewById(R.id.detectedAPs);
        textFloor = (TextView) findViewById(R.id.textFloor);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        textDebug = (TextView) findViewById(R.id.textDebug);
        if (AnyplaceAPI.DEBUG_MESSAGES)
            textDebug.setVisibility(View.VISIBLE);

        ActionBar actionBar = getSupportActionBar();
        actionBar.setHomeButtonEnabled(true);

        userData = new AnyUserData();

        SimpleWifiManager.getInstance().startScan();
        sensorsMain = new SensorsMain(getApplicationContext());
        movementDetector = new MovementDetector();
        sensorsMain.addListener(movementDetector);
        sensorsStepCounter = new SensorsStepCounter(getApplicationContext(), sensorsMain);
        lpTracker = new TrackerLogicPlusIMU(movementDetector, sensorsMain, sensorsStepCounter);
        // lpTracker = new TrackerLogic(sensorsMain);
        floorSelector = new Algo1Radiomap(getApplicationContext());

        mAnyplaceCache = AnyplaceCache.getInstance(this);
        visiblePois = new VisiblePois();

        setUpMapIfNeeded();

        // setup the trackme button overlaid in the map
        btnTrackme = (ImageButton) findViewById(R.id.btnTrackme);
        btnTrackme.setImageResource(R.drawable.dark_device_access_location_off);
        isTrackingErrorBackground = true;
        btnTrackme.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                final GeoPoint gpsLoc = userData.getLocationGPSorIP();
                if (gpsLoc != null) {
                    AnyplaceCache mAnyplaceCache = AnyplaceCache.getInstance(UnifiedNavigationActivity.this);
                    mAnyplaceCache.loadWorldBuildings(new FetchBuildingsTaskListener() {

                        @Override
                        public void onSuccess(String result, List<BuildingModel> buildings) {
                            final FetchNearBuildingsTask nearest = new FetchNearBuildingsTask();
                            nearest.run(buildings, gpsLoc.lat, gpsLoc.lng, 200);

                            if (nearest.buildings.size() > 0 && (userData.getSelectedBuildingId() == null
                                    || !userData.getSelectedBuildingId().equals(nearest.buildings.get(0).buid))) {
                                floorSelector.Stop();
                                final FloorSelector floorSelectorAlgo1 = new Algo1Server(getApplicationContext());
                                final ProgressDialog floorSelectorDialog = new ProgressDialog(
                                        UnifiedNavigationActivity.this);

                                floorSelectorDialog.setIndeterminate(true);
                                floorSelectorDialog.setTitle("Detecting floor");
                                floorSelectorDialog.setMessage("Please be patient...");
                                floorSelectorDialog.setCancelable(true);
                                floorSelectorDialog.setCanceledOnTouchOutside(false);
                                floorSelectorDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                                    @Override
                                    public void onCancel(DialogInterface dialog) {
                                        floorSelectorAlgo1.Destoy();
                                        bypassSelectBuildingActivity(nearest.buildings.get(0), "0", false);
                                    }
                                });

                                class Callback implements ErrorAnyplaceFloorListener, FloorAnyplaceFloorListener {

                                    @Override
                                    public void onNewFloor(String floor) {
                                        floorSelectorAlgo1.Destoy();
                                        if (floorSelectorDialog.isShowing()) {
                                            floorSelectorDialog.dismiss();
                                            bypassSelectBuildingActivity(nearest.buildings.get(0), floor, false);
                                        }
                                    }

                                    @Override
                                    public void onFloorError(Exception ex) {
                                        floorSelectorAlgo1.Destoy();
                                        if (floorSelectorDialog.isShowing()) {
                                            floorSelectorDialog.dismiss();
                                            bypassSelectBuildingActivity(nearest.buildings.get(0), "0", false);
                                        }
                                    }

                                }
                                Callback callback = new Callback();
                                floorSelectorAlgo1.addListener((FloorAnyplaceFloorListener) callback);
                                floorSelectorAlgo1.addListener((ErrorAnyplaceFloorListener) callback);

                                // Show Dialog
                                floorSelectorDialog.show();
                                floorSelectorAlgo1.Start(gpsLoc.lat, gpsLoc.lng);
                            } else {
                                focusUserLocation();

                                // Clear cancel request
                                lastFloor = null;
                                floorSelector.RunNow();
                                lpTracker.reset();
                            }
                        }

                        @Override
                        public void onErrorOrCancel(String result) {

                        }

                    }, UnifiedNavigationActivity.this, false);
                } else {
                    focusUserLocation();

                    // Clear cancel request
                    lastFloor = null;
                    floorSelector.RunNow();
                    lpTracker.reset();
                }

            }
        });

        btnFloorUp = (ImageButton) findViewById(R.id.btnFloorUp);
        btnFloorUp.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                if (!userData.isFloorSelected()) {
                    Toast.makeText(getBaseContext(), "Load a map before tracking can be used!", Toast.LENGTH_SHORT)
                            .show();
                    return;
                }

                BuildingModel b = userData.getSelectedBuilding();
                if (b == null) {
                    return;
                }

                if (userData.isNavBuildingSelected()) {
                    // Move to start/destination poi's floor
                    String floor_number;
                    List<PoisNav> puids = userData.getNavPois();
                    // Check start and destination floor number
                    if (!puids.get(puids.size() - 1).floor_number.equals(puids.get(0).floor_number)) {
                        if (userData.getSelectedFloorNumber().equals(puids.get(puids.size() - 1).floor_number)) {
                            floor_number = puids.get(0).floor_number;
                        } else {
                            floor_number = puids.get(puids.size() - 1).floor_number;
                        }

                        FloorModel floor = b.getFloorFromNumber(floor_number);
                        if (floor != null) {
                            bypassSelectBuildingActivity(b, floor);
                            return;
                        }
                    }
                }

                // Move one floor up
                int index = b.getSelectedFloorIndex();

                if (b.checkIndex(index + 1)) {
                    bypassSelectBuildingActivity(b, b.getFloors().get(index + 1));
                }

            }
        });

        btnFloorDown = (ImageButton) findViewById(R.id.btnFloorDown);
        btnFloorDown.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if (!userData.isFloorSelected()) {
                    Toast.makeText(getBaseContext(), "Load a map before tracking can be used!", Toast.LENGTH_SHORT)
                            .show();
                    return;
                }

                BuildingModel b = userData.getSelectedBuilding();
                if (b == null) {
                    return;
                }

                if (userData.isNavBuildingSelected()) {
                    // Move to start/destination poi's floor
                    String floor_number;
                    List<PoisNav> puids = userData.getNavPois();
                    // Check start and destination floor number
                    if (!puids.get(puids.size() - 1).floor_number.equals(puids.get(0).floor_number)) {
                        if (userData.getSelectedFloorNumber().equals(puids.get(puids.size() - 1).floor_number)) {
                            floor_number = puids.get(0).floor_number;
                        } else {
                            floor_number = puids.get(puids.size() - 1).floor_number;
                        }

                        FloorModel floor = b.getFloorFromNumber(floor_number);
                        if (floor != null) {
                            bypassSelectBuildingActivity(b, floor);
                            return;
                        }
                    }
                }

                // Move one floor down
                int index = b.getSelectedFloorIndex();

                if (b.checkIndex(index - 1)) {
                    bypassSelectBuildingActivity(b, b.getFloors().get(index - 1));
                }
            }

        });

        /*
         * Create a new location client, using the enclosing class to handle callbacks.
         */
        // Create the LocationRequest object
        mLocationRequest = LocationRequest.create();
        // Use high accuracy
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        // Set the update interval to 2 seconds
        mLocationRequest.setInterval(2000);
        // Set the fastest update interval to 1 second
        mLocationRequest.setFastestInterval(1000);
        mLocationClient = new LocationClient(this, this, this);
        // declare that this is the first time this Activity launched so make
        // the automatic building selection
        mAutomaticGPSBuildingSelection = true;

        // get/set settings
        PreferenceManager.setDefaultValues(this, SHARED_PREFS_ANYPLACE, MODE_PRIVATE, R.xml.preferences_anyplace,
                true);
        SharedPreferences preferences = getSharedPreferences(SHARED_PREFS_ANYPLACE, MODE_PRIVATE);
        preferences.registerOnSharedPreferenceChangeListener(this);
        lpTracker.setAlgorithm(preferences.getString("TrackingAlgorithm", "WKNN"));

        // handle the search intent
        handleIntent(getIntent());
    }

    private void focusUserLocation() {
        if (userMarker != null) {
            if (AnyPlaceSeachingHelper.getSearchType(mMap.getCameraPosition().zoom) == SearchTypes.OUTDOOR_MODE) {
                cameraUpdate = true;
                mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(userMarker.getPosition(), mInitialZoomLevel),
                        new CancelableCallback() {

                            @Override
                            public void onFinish() {
                                cameraUpdate = false;
                            }

                            @Override
                            public void onCancel() {
                                cameraUpdate = false;
                            }
                        });
            } else {

                cameraUpdate = true;
                mMap.animateCamera(
                        CameraUpdateFactory.newLatLngZoom(userMarker.getPosition(), mMap.getCameraPosition().zoom),
                        new CancelableCallback() {

                            @Override
                            public void onFinish() {
                                cameraUpdate = false;
                            }

                            @Override
                            public void onCancel() {
                                cameraUpdate = false;
                            }
                        });

            }
        }
    }

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

        // Flurry Analytics
        if (AnyplaceAPI.FLURRY_ENABLE) {
            FlurryAgent.onStartSession(this, AnyplaceAPI.FLURRY_APIKEY);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();
        addTrackerListeners();
        // check the Play Services
        checkPlayServices();
        sensorsMain.resume();
        sensorsStepCounter.resume();
        lpTracker.resumeTracking();
        floorSelector.resumeTracking();
    }

    @Override
    protected void onPause() {
        super.onPause();
        lpTracker.pauseTracking();
        floorSelector.pauseTracking();
        sensorsMain.pause();
        sensorsStepCounter.pause();
        removeTrackerListeners();
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Disconnecting the client invalidates it.
        mLocationClient.disconnect();

        // Flurry Analytics
        if (AnyplaceAPI.FLURRY_ENABLE) {
            FlurryAgent.onEndSession(this);
        }
    }

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

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

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getSupportMenuInflater();
        inflater.inflate(R.menu.unified_options_menu, menu);

        // ****************************************** Search View
        // ***************************************************************** /
        // Associate searchable configuration with the SearchView
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        searchView = (SearchView) menu.findItem(R.id.search).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        searchView.setQueryHint("Search outdoor");
        searchView.setAddStatesFromChildren(true);

        // set query change listener
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextChange(final String newText) {
                // return false; // false since we do not handle this call

                if (newText == null || newText.trim().length() < 1) {
                    if (mSuggestionsTask != null && !mSuggestionsTask.isCancelled()) {
                        mSuggestionsTask.cancel(true);
                    }
                    searchView.setSuggestionsAdapter(null);
                    return true;
                }

                if (mSuggestionsTask != null) {
                    mSuggestionsTask.cancel(true);
                }

                if (searchType == SearchTypes.INDOOR_MODE) {
                    if (!userData.isFloorSelected()) {
                        List<IPoisClass> places = new ArrayList<IPoisClass>(1);
                        PoisModel pm = new PoisModel();
                        pm.name = "Load a building first ...";
                        places.add(pm);
                        Cursor cursor = AnyPlaceSeachingHelper.prepareSearchViewCursor(places);
                        showSearchResult(cursor);
                        return true;
                    }
                }

                GeoPoint gp = userData.getLatestUserPosition();

                mSuggestionsTask = new AnyplaceSuggestionsTask(
                        new AnyplaceSuggestionsTask.AnyplaceSuggestionsListener() {
                            @Override
                            public void onSuccess(String result, List<? extends IPoisClass> pois) {
                                showSearchResult(AnyPlaceSeachingHelper.prepareSearchViewCursor(pois, newText));
                            }

                            @Override
                            public void onErrorOrCancel(String result) {
                                Log.d("AnyplaceSuggestions", result);
                            }

                            @Override
                            public void onUpdateStatus(String string, Cursor cursor) {
                                showSearchResult(cursor);
                            }

                        }, UnifiedNavigationActivity.this, searchType,
                        (gp == null) ? new GeoPoint(csLat, csLon) : gp, newText);
                mSuggestionsTask.execute(null, null);

                // we return true to avoid caling the provider set in the xml
                return true;
            }

            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }
        });
        searchView.setSubmitButtonEnabled(true);
        searchView.setQueryRefinementEnabled(false);

        // ****************************************** Select building
        // ***************************************************************** /
        // Select building and floor to start navigating and positioning
        final SubMenu subMenuPlace = menu.addSubMenu("Select Building");
        final MenuItem sPlace = subMenuPlace.getItem();
        sPlace.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        sPlace.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                // start the activity where the user can select the FROM and TO
                // pois he wants to navigate
                GeoPoint gp = userData.getLatestUserPosition();
                loadSelectBuildingActivity(gp, false);
                return true;
            }
        });

        // ********************************** CLEAR NAVIGATION
        // *********************************************** /
        final SubMenu subMenuResetNav = menu.addSubMenu("Clear Navigation");
        final MenuItem ResetNav = subMenuResetNav.getItem();
        ResetNav.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        ResetNav.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                clearLastNavigationInfo();
                return true;
            }
        });

        // ***********************Load Ayplace Logger
        // ************************************** /
        final SubMenu subMenuLoadLogger = menu.addSubMenu("Show Logger");
        final MenuItem LoadLogger = subMenuLoadLogger.getItem();
        LoadLogger.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        LoadLogger.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                Intent intent = new Intent(getApplicationContext(), AnyplaceLoggerActivity.class);
                startActivity(intent);
                return true;
            }
        });

        // ****************************************** preferences
        // ********************************************** /
        final SubMenu subMenuPreferences = menu.addSubMenu("Preferences");
        final MenuItem prefsMenu = subMenuPreferences.getItem();
        prefsMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        prefsMenu.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                Intent i = new Intent(UnifiedNavigationActivity.this, AnyplacePrefs.class);
                startActivityForResult(i, PREFERENCES_ACTIVITY_RESULT);
                return true;
            }
        });

        // ****************************************** about
        // ********************************************** /
        final SubMenu subMenuAbout = menu.addSubMenu("About");
        final MenuItem about = subMenuAbout.getItem();
        about.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        about.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                startActivity(new Intent(UnifiedNavigationActivity.this, AnyplaceAboutActivity.class));
                return true;
            }
        });

        // ****************************************** exit
        // ********************************************** /
        final SubMenu subMenuExit = menu.addSubMenu("Exit");
        final MenuItem Exit = subMenuExit.getItem();
        Exit.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
        Exit.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                finish();
                return true;
            }
        });

        /***************************************** END OF MAIN MENU ***************************************************************/

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        /*
         * case android.R.id.home: // finish(); break;
         */
        default:
            break;
        }
        return super.onOptionsItemSelected(item);
    }

    private void showSearchResult(Cursor cursor) {
        // bind the text data from the results to the
        // custom
        // layout
        String[] from = { SearchManager.SUGGEST_COLUMN_TEXT_1
                // ,SearchManager.SUGGEST_COLUMN_TEXT_2
        };
        int[] to = { android.R.id.text1
                // ,android.R.id.text2
        };
        // add the cursor of the results to the search view
        // SimpleCursorAdapter adapter = new SimpleCursorAdapter(UnifiedNavigationActivity.this, R.layout.queried_pois_item_1_searchbox, cursor, from, to, 0);
        // searchView.setSuggestionsAdapter(adapter);
        // adapter.notifyDataSetChanged();

        AnyPlaceSeachingHelper.HTMLCursorAdapter adapter = new HTMLCursorAdapter(UnifiedNavigationActivity.this,
                R.layout.queried_pois_item_1_searchbox, cursor, from, to);
        searchView.setSuggestionsAdapter(adapter);
        adapter.notifyDataSetChanged();
    }

    public static int getPixelsFromDp(Context context, float dp) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }

    // GOOGLE MAP FUNCTIONS
    /**
     * Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly installed) and the map has not already been instantiated.. This will ensure that we only ever call
     * {@link #setUpMap()} once when {@link #mMap} is not null.
     * <p>
     * If it isn't installed {@link SupportMapFragment} (and {@link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to install/update the Google Play services APK on
     * their device.
     * <p>
     * A user can return to this FragmentActivity after following the prompt and correctly installing/updating/enabling the Google Play services. Since the FragmentActivity may not have been
     * completely destroyed during this process (it is likely that it would only be stopped or paused), {@link #onCreate(Bundle)} may not be called again so we should call this method in
     * {@link #onResume()} to guarantee that it will be called.
     */
    private void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the
        // map.
        if (mMap != null) {
            return;
        }
        // Try to obtain the map from the SupportMapFragment.
        mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
        mClusterManager = new ClusterManager<BuildingModel>(this, mMap);

        // Check if we were successful in obtaining the map.
        if (mMap != null) {

            // http://stackoverflow.com/questions/14123243/google-maps-android-api-v2-interactive-infowindow-like-in-original-android-go
            final MapWrapperLayout mapWrapperLayout = (MapWrapperLayout) findViewById(R.id.map_relative_layout);

            // MapWrapperLayout initialization
            // 39 - default marker height
            // 20 - offset between the default InfoWindow bottom edge and
            // it's content bottom edge
            mapWrapperLayout.init(mMap, getPixelsFromDp(this, 39 + 20));

            final ViewGroup infoWindow;
            final TextView infoTitle;
            final TextView infoSnippet;
            final Button infoButton1;
            final OnInfoWindowElemTouchListener infoButtonListener1;
            Button infoButton2;
            final OnInfoWindowElemTouchListener infoButtonListener2;

            // We want to reuse the info window for all the markers,
            // so let's create only one class member instance
            infoWindow = (ViewGroup) getLayoutInflater().inflate(R.layout.info_window, null);
            infoTitle = (TextView) infoWindow.findViewById(R.id.title);
            infoSnippet = (TextView) infoWindow.findViewById(R.id.snippet);
            infoButton1 = (Button) infoWindow.findViewById(R.id.button1);
            infoButton2 = (Button) infoWindow.findViewById(R.id.button2);

            // Setting custom OnTouchListener which deals with the pressed
            // state
            // so it shows up
            infoButtonListener1 = new OnInfoWindowElemTouchListener(infoButton1,
                    getResources().getDrawable(R.drawable.button_unsel),
                    getResources().getDrawable(R.drawable.button_sel)) {
                @Override
                protected void onClickConfirmed(View v, Marker marker) {

                    PoisModel poi = visiblePois.getPoisModelFromMarker(marker);
                    if (poi != null) {
                        // start the navigation using the clicked marker as
                        // destination
                        startNavigationTask(poi.puid);
                    }

                }
            };
            infoButton1.setOnTouchListener(infoButtonListener1);

            // Setting custom OnTouchListener which deals with the pressed
            // state
            // so it shows up
            infoButtonListener2 = new OnInfoWindowElemTouchListener(infoButton2,
                    getResources().getDrawable(R.drawable.button_unsel),
                    getResources().getDrawable(R.drawable.button_sel)) {
                @Override
                protected void onClickConfirmed(View v, Marker marker) {

                    PoisModel poi = visiblePois.getPoisModelFromMarker(marker);
                    if (poi != null) {
                        if (poi.description.equals("") || poi.description.equals("-")) {
                            // start the navigation using the clicked marker
                            // as destination
                            popup_msg("No description available.", poi.name);
                        } else {
                            popup_msg(poi.description, poi.name);
                        }

                    }

                }
            };
            infoButton2.setOnTouchListener(infoButtonListener2);

            mMap.setInfoWindowAdapter(new InfoWindowAdapter() {
                @Override
                public View getInfoWindow(Marker marker) {
                    return null;
                }

                @Override
                public View getInfoContents(Marker marker) {
                    // Setting up the infoWindow with current's marker info
                    infoTitle.setText(marker.getTitle());
                    infoSnippet.setText(marker.getSnippet());
                    infoButtonListener1.setMarker(marker);
                    infoButtonListener2.setMarker(marker);

                    // We must call this to set the current marker and
                    // infoWindow references
                    // to the MapWrapperLayout
                    mapWrapperLayout.setMarkerWithInfoWindow(marker, infoWindow);
                    return infoWindow;
                }
            });
            setUpMap();
        }

    }

    /**
     * <p>
     * This should only be called once and when we are sure that {@link #mMap} is not null.
     */
    private void setUpMap() {
        initMap();
        // initCamera();
        initListeners();
    }

    private void initMap() {
        // Sets the map type to be NORMAL - ROAD mode
        mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        // mMap.setMyLocationEnabled(true); //displays a button to navigate to
        // the current user's position
        // mMap.setInfoWindowAdapter(new CustomInfoWindowAdapter(this,
        // mPoiMarkersBundle));
        mMap.setBuildingsEnabled(false);
    }

    private void initCamera() {
        // Only for the first time
        if (userMarker != null) {
            return;
        }

        Location gps = mLocationClient.getLastLocation();
        if (gps != null) {
            cameraUpdate = true;
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(gps.getLatitude(), gps.getLongitude()),
                    mInitialZoomLevel), new CancelableCallback() {

                        @Override
                        public void onFinish() {
                            cameraUpdate = false;
                            handleBuildingsOnMap();
                        }

                        @Override
                        public void onCancel() {
                            cameraUpdate = false;
                            handleBuildingsOnMap();
                        }
                    });
        } else {
            AsyncTask<Void, Integer, Void> task = new AsyncTask<Void, Integer, Void>() {

                GeoPoint location;

                @Override
                protected Void doInBackground(Void... params) {
                    try {
                        location = AndroidUtils.getIPLocation();
                    } catch (Exception e) {

                    }
                    return null;
                }

                @Override
                protected void onPostExecute(Void result) {

                    if (location != null && userMarker == null) {
                        userData.setLocationIP(location);
                        updateLocation();
                        cameraUpdate = true;
                        mMap.animateCamera(CameraUpdateFactory
                                .newLatLngZoom(new LatLng(location.dlat, location.dlon), mInitialZoomLevel),
                                new CancelableCallback() {

                                    @Override
                                    public void onFinish() {
                                        cameraUpdate = false;
                                        handleBuildingsOnMap();
                                    }

                                    @Override
                                    public void onCancel() {
                                        cameraUpdate = false;
                                        handleBuildingsOnMap();
                                    }
                                });
                    } else {
                        handleBuildingsOnMap();
                    }

                }

            };

            int currentapiVersion = android.os.Build.VERSION.SDK_INT;
            if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) {
                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            } else {
                task.execute();
            }
        }
    }

    private void initListeners() {
        mMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
            @Override
            public void onCameraChange(CameraPosition position) {

                // change search box message and clear pois
                if (searchType != AnyPlaceSeachingHelper.getSearchType(position.zoom)) {
                    searchType = AnyPlaceSeachingHelper.getSearchType(position.zoom);
                    if (searchType == SearchTypes.INDOOR_MODE) {
                        searchView.setQueryHint("Search indoor");
                        visiblePois.showAll();
                        if (pathLineInside != null)
                            pathLineInside.setVisible(true);
                    } else if (searchType == SearchTypes.OUTDOOR_MODE) {
                        searchView.setQueryHint("Search outdoor");
                        visiblePois.hideAll();
                        if (pathLineInside != null)
                            pathLineInside.setVisible(false);
                    }
                }

                bearing = position.bearing;
                mClusterManager.onCameraChange(position);
            }
        });

        mMap.setOnMarkerClickListener(new OnMarkerClickListener() {

            @Override
            public boolean onMarkerClick(Marker marker) {

                // mClusterManager returns true if is a cluster item
                if (!mClusterManager.onMarkerClick(marker)) {

                    PoisModel poi = visiblePois.getPoisModelFromMarker(marker);
                    if (poi != null) {
                        return false;
                    } else {
                        // Prevent Popup dialog
                        return true;
                    }
                } else {
                    // Prevent Popup dialog
                    return true;
                }
            }
        });

        mClusterManager.setOnClusterClickListener(new OnClusterClickListener<BuildingModel>() {

            @Override
            public boolean onClusterClick(Cluster<BuildingModel> cluster) {
                // Prevent Popup dialog
                return true;
            }
        });

        mClusterManager.setOnClusterItemClickListener(new OnClusterItemClickListener<BuildingModel>() {

            @Override
            public boolean onClusterItemClick(final BuildingModel b) {
                if (b != null) {

                    bypassSelectBuildingActivity(b, "0", false);
                }
                // Prevent Popup dialog
                return true;
            }
        });

    }

    // Select Building Activity based on gps location
    private void loadSelectBuildingActivity(GeoPoint loc, boolean invisibleSelection) {

        Intent placeIntent = new Intent(UnifiedNavigationActivity.this, SelectBuildingActivity.class);
        Bundle b = new Bundle();

        if (loc != null) {
            b.putString("coordinates_lat", String.valueOf(loc.dlat));
            b.putString("coordinates_lon", String.valueOf(loc.dlon));
        }
        b.putSerializable("mode",
                invisibleSelection ? SelectBuildingActivity.Mode.INVISIBLE : SelectBuildingActivity.Mode.NONE);
        placeIntent.putExtras(b);

        // start the activity where the user can select the building he is in
        startActivityForResult(placeIntent, SELECT_PLACE_ACTIVITY_RESULT);
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        switch (requestCode) {
        case LOCATION_CONNECTION_FAILURE_RESOLUTION_REQUEST:
            // If the result code is Activity.RESULT_OK, try to connect again
            switch (resultCode) {
            case Activity.RESULT_OK:
                // Try the request again
                // TODO - check google developers documentation again
                // and implement it correctly
            }

            break;
        case SEARCH_POI_ACTIVITY_RESULT:
            if (resultCode == Activity.RESULT_OK) {
                // search activity finished OK
                if (data == null)
                    return;
                // PoisModel poi_to = (PoisModel)
                // data.getSerializableExtra("pmodel");
                // startNavigationTask(poi_to);

                IPoisClass place = (IPoisClass) data.getSerializableExtra("ianyplace");
                handleSearchPlaceSelection(place);

            } else if (resultCode == Activity.RESULT_CANCELED) {
                // CANCELLED
                if (data == null)
                    return;
                String msg = (String) data.getSerializableExtra("message");
                if (msg != null)
                    Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT).show();
            }
            break;
        case SELECT_PLACE_ACTIVITY_RESULT:
            if (resultCode == Activity.RESULT_OK) {
                if (data == null)
                    return;

                String fpf = data.getStringExtra("floor_plan_path");
                if (fpf == null) {
                    Toast.makeText(getBaseContext(), "You haven't selected both building and floor...!",
                            Toast.LENGTH_SHORT).show();
                    return;
                }

                try {
                    BuildingModel b = mAnyplaceCache.getSpinnerBuildings().get(data.getIntExtra("bmodel", 0));
                    FloorModel f = b.getFloors().get(data.getIntExtra("fmodel", 0));
                    selectPlaceActivityResult(b, f);
                } catch (Exception ex) {
                    Toast.makeText(getBaseContext(), "You haven't selected both building and floor...!",
                            Toast.LENGTH_SHORT).show();
                }

            } else if (resultCode == Activity.RESULT_CANCELED) {
                // CANCELLED
                if (data == null)
                    return;
                String msg = (String) data.getSerializableExtra("message");
                if (msg != null)
                    Toast.makeText(getBaseContext(), msg, Toast.LENGTH_SHORT).show();
            }
            break;
        case PREFERENCES_ACTIVITY_RESULT:
            if (resultCode == RESULT_OK) {
                AnyplacePrefs.Action result = (Action) data.getSerializableExtra("action");

                switch (result) {
                case REFRESH_BUILDING:

                    if (!userData.isFloorSelected()) {
                        Toast.makeText(getBaseContext(), "Load a map before performing this action!",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }

                    if (progressBar.getVisibility() == View.VISIBLE) {
                        Toast.makeText(getBaseContext(), "Building Loading in progress. Please Wait!",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }

                    try {

                        final BuildingModel b = userData.getSelectedBuilding();
                        // clear_floorplans
                        File floorsRoot = new File(AnyplaceUtils.getFloorPlansRootFolder(this), b.buid);
                        // clear radiomaps
                        File radiomapsRoot = AnyplaceUtils.getRadioMapsRootFolder(this);
                        final String[] radiomaps = radiomapsRoot.list(new FilenameFilter() {

                            @Override
                            public boolean accept(File dir, String filename) {
                                if (filename.startsWith(b.buid))
                                    return true;
                                else
                                    return false;
                            }
                        });
                        for (int i = 0; i < radiomaps.length; i++) {
                            radiomaps[i] = radiomapsRoot.getAbsolutePath() + File.separator + radiomaps[i];
                        }

                        floorSelector.Stop();
                        disableAnyplaceTracker();
                        DeleteFolderBackgroundTask task = new DeleteFolderBackgroundTask(
                                new DeleteFolderBackgroundTask.DeleteFolderBackgroundTaskListener() {

                                    @Override
                                    public void onSuccess() {

                                        // clear any markers that might have already
                                        // been added to the map
                                        visiblePois.clearAll();
                                        // clear and resets the cached POIS inside
                                        // AnyplaceCache
                                        mAnyplaceCache.setPois(new HashMap<String, PoisModel>(), "");
                                        mAnyplaceCache.fetchAllFloorsRadiomapReset();

                                        bypassSelectBuildingActivity(b, b.getSelectedFloor());

                                    }
                                }, UnifiedNavigationActivity.this, true);
                        task.setFiles(floorsRoot);
                        task.setFiles(radiomaps);
                        task.execute();
                    } catch (Exception e) {
                        Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                }
                break;
            }
            break;
        }
    }

    private void bypassSelectBuildingActivity(final BuildingModel b, final String floor_number,
            final Boolean force) {
        // Load Building
        b.loadFloors(new FetchFloorsByBuidTaskListener() {

            @Override
            public void onSuccess(String result, List<FloorModel> floors) {

                // Force loading of floor_number
                FloorModel floor;
                if ((floor = b.getFloorFromNumber(floor_number)) != null || !force) {
                    if (floor == null) {
                        floor = b.getSelectedFloor();
                    }

                    ArrayList<BuildingModel> list = new ArrayList<BuildingModel>(1);
                    list.add(b);
                    // Set building for Select Dialog
                    mAnyplaceCache.setSelectedBuildingIndex(0);
                    mAnyplaceCache.setSpinnerBuildings(list);

                    bypassSelectBuildingActivity(b, floor);

                } else {
                    Toast.makeText(getBaseContext(), "Building's Floor Not Found", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onErrorOrCancel(String result) {
                Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();

            }
        }, UnifiedNavigationActivity.this, false, true);
    }

    private void bypassSelectBuildingActivity(final BuildingModel b, final String floor_number, final Boolean force,
            final PoisModel poi) {
        // Load Building
        b.loadFloors(new FetchFloorsByBuidTaskListener() {

            @Override
            public void onSuccess(String result, List<FloorModel> floors) {

                // Force loading of floor_number
                FloorModel floor;
                if ((floor = b.getFloorFromNumber(floor_number)) != null || !force) {
                    if (floor == null) {
                        floor = b.getSelectedFloor();
                    }

                    ArrayList<BuildingModel> list = new ArrayList<BuildingModel>(1);
                    list.add(b);
                    // Set building for Select Dialog
                    mAnyplaceCache.setSelectedBuildingIndex(0);
                    mAnyplaceCache.setSpinnerBuildings(list);

                    bypassSelectBuildingActivity(b, floor, poi);

                } else {
                    Toast.makeText(getBaseContext(), "Building's Floor Not Found", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onErrorOrCancel(String result) {
                Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();

            }
        }, UnifiedNavigationActivity.this, false, true);
    }

    private void bypassSelectBuildingActivity(final BuildingModel b, final FloorModel f) {

        final FetchFloorPlanTask fetchFloorPlanTask = new FetchFloorPlanTask(UnifiedNavigationActivity.this, b.buid,
                f.floor_number);
        fetchFloorPlanTask.setCallbackInterface(new FetchFloorPlanTask.FetchFloorPlanTaskListener() {

            private ProgressDialog dialog;

            @Override
            public void onSuccess(String result, File floor_plan_file) {
                if (dialog != null)
                    dialog.dismiss();
                selectPlaceActivityResult(b, f);
            }

            @Override
            public void onErrorOrCancel(String result) {
                if (dialog != null)
                    dialog.dismiss();
                Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onPrepareLongExecute() {
                dialog = new ProgressDialog(UnifiedNavigationActivity.this);
                dialog.setIndeterminate(true);
                dialog.setTitle("Downloading floor plan");
                dialog.setMessage("Please be patient...");
                dialog.setCancelable(true);
                dialog.setCanceledOnTouchOutside(false);
                dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        fetchFloorPlanTask.cancel(true);
                    }
                });
                dialog.show();
            }
        });
        fetchFloorPlanTask.execute();
    }

    private void bypassSelectBuildingActivity(final BuildingModel b, final FloorModel f, final PoisModel pm) {

        final FetchFloorPlanTask fetchFloorPlanTask = new FetchFloorPlanTask(UnifiedNavigationActivity.this, b.buid,
                f.floor_number);
        fetchFloorPlanTask.setCallbackInterface(new FetchFloorPlanTask.FetchFloorPlanTaskListener() {

            private ProgressDialog dialog;

            @Override
            public void onSuccess(String result, File floor_plan_file) {
                if (dialog != null)
                    dialog.dismiss();
                selectPlaceActivityResult(b, f, pm);
            }

            @Override
            public void onErrorOrCancel(String result) {
                if (dialog != null)
                    dialog.dismiss();
                Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onPrepareLongExecute() {
                dialog = new ProgressDialog(UnifiedNavigationActivity.this);
                dialog.setIndeterminate(true);
                dialog.setTitle("Downloading floor plan");
                dialog.setMessage("Please be patient...");
                dialog.setCancelable(true);
                dialog.setCanceledOnTouchOutside(false);
                dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        fetchFloorPlanTask.cancel(true);
                    }
                });
                dialog.show();
            }
        });
        fetchFloorPlanTask.execute();
    }

    private void selectPlaceActivityResult(final BuildingModel b, final FloorModel f, final PoisModel pm) {

        selectPlaceActivityResult_HELP(b, f);

        fetchPoisByBuidToCache(b.buid, new FetchPoisListener() {

            @Override
            public void onSuccess(String result, Map<String, PoisModel> poisMap) {

                // This should never return null
                if (poisMap.get(pm.puid) == null) {
                    poisMap.put(pm.puid, pm);
                }

                handlePoisOnMap(poisMap.values());
                startNavigationTask(pm.puid);
                selectPlaceActivityResult_HELP2(b, f);
            }

            @Override
            public void onErrorOrCancel(String result) {

                Collection<PoisModel> l = mAnyplaceCache.getPois();
                l.add(pm);
                handlePoisOnMap(l);
                startNavigationTask(pm.puid);

                selectPlaceActivityResult_HELP2(b, f);
            }
        });
    }

    private void selectPlaceActivityResult(final BuildingModel b, final FloorModel f) {

        selectPlaceActivityResult_HELP(b, f);

        fetchPoisByBuidToCache(b.buid, new FetchPoisListener() {

            @Override
            public void onSuccess(String result, Map<String, PoisModel> poisMap) {
                handlePoisOnMap(poisMap.values());
                loadFloorNavRoute();
                selectPlaceActivityResult_HELP2(b, f);
            }

            @Override
            public void onErrorOrCancel(String result) {
                loadFloorNavRoute();
                selectPlaceActivityResult_HELP2(b, f);
            }
        });

    }

    // Help tasks
    private void selectPlaceActivityResult_HELP(final BuildingModel b, final FloorModel f) {
        mAutomaticGPSBuildingSelection = false;
        floorSelector.Stop();
        disableAnyplaceTracker();

        // set the newly selected floor
        b.setSelectedFloor(f.floor_number);
        userData.setSelectedBuilding(b);
        userData.setSelectedFloor(f);
        textFloor.setText(f.floor_name);

        // clean the map in case there are overlays
        mMap.clear();

        // add the Tile Provider that uses our Building tiles over
        // Google Maps
        TileOverlay mTileOverlay = mMap.addTileOverlay(new TileOverlayOptions()
                .tileProvider(new AnyPlaceMapTileProvider(getBaseContext(), b.buid, f.floor_number)));
        mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(b.getPosition(), 19.0f), new CancelableCallback() {

            @Override
            public void onFinish() {
                cameraUpdate = false;
                handleBuildingsOnMap();
                updateLocation();
            }

            @Override
            public void onCancel() {
                cameraUpdate = false;
            }
        });

        // ///////////////////////////////////////////////////////////////
        // we must now change the radio map file since we changed floor
        // RADIO MAP initialization
        try {
            File root = AnyplaceUtils.getRadioMapFoler(this, b.buid, userData.getSelectedFloorNumber());
            lpTracker.setRadiomapFile(
                    new File(root, AnyplaceUtils.getRadioMapFileName(userData.getSelectedFloorNumber()))
                            .getAbsolutePath());
        } catch (Exception e) {
            // exception thrown by GetRootFolder when sdcard is not
            // writable
            Toast.makeText(getBaseContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    // Download RADIOMAP
    private void selectPlaceActivityResult_HELP2(final BuildingModel b, final FloorModel f) {

        String trackedPositionLat = userData.getSelectedBuilding().getLatitudeString();
        String trackedPositionLon = userData.getSelectedBuilding().getLongitudeString();

        // first we should disable the tracker if it's working
        disableAnyplaceTracker();

        class Callback implements DownloadRadioMapTaskBuid.DownloadRadioMapListener, PreviousRunningTask {

            boolean progressBarEnabled = false;
            boolean disableSuccess = false;

            @Override
            public void onSuccess(String result) {
                if (disableSuccess) {
                    onErrorOrCancel("");
                    return;
                }
                // start the tracker
                enableAnyplaceTracker();

                // Download All Building Floors and Radiomaps
                if (AnyplaceAPI.PLAY_STORE) {

                    mAnyplaceCache.fetchAllFloorsRadiomapsRun(new BackgroundFetchListener() {

                        @Override
                        public void onSuccess(String result) {
                            hideProgressBar();
                            if (AnyplaceAPI.DEBUG_MESSAGES) {
                                btnTrackme.setBackgroundColor(Color.YELLOW);
                            }
                            floorSelector.updateFiles(b.buid);
                            floorSelector.Start(b.getLatitudeString(), b.getLongitudeString());
                        }

                        @Override
                        public void onProgressUpdate(int progress_current, int progress_total) {
                            progressBar.setProgress(
                                    (int) ((float) progress_current / progress_total * progressBar.getMax()));
                        }

                        @Override
                        public void onErrorOrCancel(String result, ErrorType error) {
                            // Do not hide progress bar if previous task is running
                            // ErrorType.SINGLE_INSTANCE
                            // Do not hide progress bar because a new task will be created
                            // ErrorType.CANCELLED
                            if (error == ErrorType.EXCEPTION)
                                hideProgressBar();
                        }

                        @Override
                        public void onPrepareLongExecute() {
                            showProgressBar();
                        }

                    }, b);
                }
            }

            @Override
            public void onErrorOrCancel(String result) {
                if (progressBarEnabled) {
                    hideProgressBar();
                }
            }

            @Override
            public void onPrepareLongExecute() {
                progressBarEnabled = true;
                showProgressBar();
                // Set a smaller percentage than fetchAllFloorsRadiomapsOfBUID
                progressBar.setProgress((int) (1.0f / (userData.getSelectedBuilding().getFloors().size() * 2)
                        * progressBar.getMax()));
            }

            @Override
            public void disableSuccess() {
                disableSuccess = true;
            }

        }

        if (downloadRadioMapTaskBuid != null) {
            ((PreviousRunningTask) downloadRadioMapTaskBuid.getCallbackInterface()).disableSuccess();
        }

        downloadRadioMapTaskBuid = new DownloadRadioMapTaskBuid(new Callback(), this, trackedPositionLat,
                trackedPositionLon, userData.getSelectedBuildingId(), userData.getSelectedFloorNumber(), false);

        int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) {
            // Execute task parallel with others and multiple instances of
            // itself
            downloadRadioMapTaskBuid.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        } else {
            downloadRadioMapTaskBuid.execute();
        }
    }

    // LOCATION API FUNCTIONS
    private boolean checkPlayServices() {
        // Check that Google Play services is available
        int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        // If Google Play services is available
        if (ConnectionResult.SUCCESS == resultCode) {
            // In debug mode, log the status
            Log.d("Location Updates", "Google Play services is available.");
            // Continue
            return true;
        } else {
            // Google Play services was not available for some reason

            // GooglePlayServicesUtil.getErrorDialog(resultCode, this,
            // 0).show();
            if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                GooglePlayServicesUtil.getErrorDialog(resultCode, this, PLAY_SERVICES_RESOLUTION_REQUEST).show();
            } else {
                Log.i("AnyplaceNavigator", "This device is not supported.");
                finish();
            }
            return false;
        }
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        // TODO - CHECK HOW THIS WORKS
        Log.d("Google Play Services", "Connection failed");
        // 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, LOCATION_CONNECTION_FAILURE_RESOLUTION_REQUEST);
                // Thrown if Google Play services canceled the original
                // PendingIntent
            } catch (IntentSender.SendIntentException e) {
                // Log the error
                e.printStackTrace();
            }
        } else {
            // If no resolution is available, display a dialog to the
            // user with the error.
            // showErrorDialog(connectionResult.getErrorCode());
            GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 0).show();
        }
    }

    @Override
    public void onConnected(Bundle dataBundle) {
        // THIS IS THE FIRST THINGS LOADED WHEN GOOGLE PLAY SERVICES ARE
        // AVAILABLE
        Log.d("Google Play services", "Connected");

        if (!NetworkUtils.isOnline(UnifiedNavigationActivity.this)) {
            AndroidUtils.showNetworkSettings(this);
        }
        if (checkPlayServices()) {
            initCamera();
            // Get Wifi + GPS Fused Location
            Location currentLocation = mLocationClient.getLastLocation();
            // we must set listener to the get the first location from the API
            // it will trigger the onLocationChanged below when a new location
            // is found or notify the user
            mLocationClient.requestLocationUpdates(mLocationRequest, this);
            if (currentLocation != null) {
                onLocationChanged(currentLocation);
            } else {
                if (mAutomaticGPSBuildingSelection)
                    Toast.makeText(getBaseContext(), "No location available at the moment.", Toast.LENGTH_LONG)
                            .show();
            }
        }
    }

    @Override
    public void onDisconnected() {
        Log.d("Google Play services", "Disconnected. Please re-connect!");
    }

    private void updateLocation() {

        GeoPoint location = userData.getLatestUserPosition();
        if (location != null) {
            // draw the location of the new position
            if (userMarker != null) {
                userMarker.remove();
            }
            MarkerOptions marker = new MarkerOptions();
            marker.position(new LatLng(location.dlat, location.dlon));
            marker.title("User").snippet("Estimated Position");
            marker.icon(BitmapDescriptorFactory.fromResource(R.drawable.icon21));
            marker.rotation(sensorsMain.getRAWHeading() - bearing);
            userMarker = this.mMap.addMarker(marker);
        }
    }

    // location listener
    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            userData.setLocationGPS(location);
            updateLocation();

            if (mAutomaticGPSBuildingSelection) {
                mAutomaticGPSBuildingSelection = false;
                loadSelectBuildingActivity(userData.getLatestUserPosition(), true);
            }

        }
    }

    // *****************************************************************************
    // * NAVIGATION FUNCTIONS
    // *****************************************************************************
    // /

    private void startNavigationTask(String id) {

        if (!NetworkUtils.isOnline(this)) {
            Toast.makeText(this, "No connection available!", Toast.LENGTH_SHORT).show();
            return;
        }

        // show the info window for the destination marker
        Marker marker = visiblePois.getMarkerFromPoisModel(id);
        if (marker != null) {
            marker.showInfoWindow();
        }

        final BuildingModel b = userData.getSelectedBuilding();
        final String floor = userData.getSelectedFloorNumber();

        class Status {
            Boolean task1 = false;
            Boolean task2 = false;
        }
        final Status status = new Status();

        final ProgressDialog dialog;
        dialog = new ProgressDialog(this);
        dialog.setIndeterminate(true);
        dialog.setTitle("Plotting navigation");
        dialog.setMessage("Please be patient...");
        dialog.setCancelable(true);
        dialog.setCanceledOnTouchOutside(false);

        GeoPoint entrance = null;
        GeoPoint pos = userData.getPositionWifi();
        if (pos == null) {
            // Find The nearest building entrance from the destination poi
            PoisModel _entrance = null;
            PoisModel dest = mAnyplaceCache.getPoisMap().get(id);
            double min = Double.MAX_VALUE;
            String currentFloor = userData.getSelectedFloorNumber();
            for (PoisModel pm : mAnyplaceCache.getPoisMap().values()) {
                if (pm.floor_number.equalsIgnoreCase(currentFloor) && pm.is_building_entrance) {
                    double distance = Math.abs(pm.lat() - dest.lat()) + Math.abs(pm.lng() - dest.lng());
                    if (min > distance) {
                        _entrance = pm;
                        min = distance;
                    }
                }
            }

            if (_entrance != null) {
                entrance = new GeoPoint(_entrance.lat(), _entrance.lng());
            } else {
                Toast.makeText(this, "No entrance found!", Toast.LENGTH_SHORT).show();
                return;
            }
        }

        final GeoPoint entrancef = entrance;

        // Does not run if entrance==null or is near the building
        final AsyncTask<Void, Void, String> async1f = new NavDirectionsTask(
                new NavDirectionsTask.NavDirectionsListener() {

                    @Override
                    public void onNavDirectionsSuccess(String result, List<LatLng> points) {
                        onNavDirectionsAboart();

                        if (!points.isEmpty()) {
                            // points.add(new LatLng(entrancef.dlat, entrancef.dlon));
                            pathLineOutsideOptions = new PolylineOptions().addAll(points).width(10).color(Color.RED)
                                    .zIndex(100.0f);
                            pathLineOutside = mMap.addPolyline(pathLineOutsideOptions);
                        }
                    }

                    @Override
                    public void onNavDirectionsErrorOrCancel(String result) {
                        onNavDirectionsAboart();
                        // display the error cause
                        Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onNavDirectionsAboart() {
                        status.task1 = true;
                        if (status.task1 && status.task2)
                            dialog.dismiss();
                        else {
                            // First task executed calls this
                            clearLastNavigationInfo();
                        }
                    }

                }, userData.getLocationGPSorIP(), entrance);

        // start the navigation task
        final AsyncTask<Void, Void, String> async2f = new NavRouteTask(new NavRouteTask.NavRouteListener() {
            @Override
            public void onNavRouteSuccess(String result, List<PoisNav> points) {
                onNavDirectionsAboart();

                // set the navigation building and new points
                userData.setNavBuilding(b);
                userData.setNavPois(points);

                // handle drawing of the points
                handlePathDrawing(points);
            }

            @Override
            public void onNavRouteErrorOrCancel(String result) {
                onNavDirectionsAboart();
                // display the error cause
                Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();
            }

            public void onNavDirectionsAboart() {
                status.task2 = true;
                if (status.task1 && status.task2)
                    dialog.dismiss();
                else {
                    // First task executed calls this
                    clearLastNavigationInfo();
                }
            }
        }, this, id, (pos == null) ? entrancef : pos, floor);

        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                async1f.cancel(true);
                async2f.cancel(true);
            }
        });
        dialog.show();
        async1f.execute();
        async2f.execute();
    }

    private void clearNavOverlays() {
        if (pathLineInside != null) {
            pathLineInside.remove();
        }
        if (pathLineOutside != null) {
            pathLineOutside.remove();
        }
        visiblePois.clearFromMarker();
        visiblePois.clearToMarker();
    }

    private void clearLastNavigationInfo() {
        if (userData != null) {
            userData.clearNav();
        }
        clearNavOverlays();
        btnFloorUp.setVisibility(View.VISIBLE);
        btnFloorDown.setVisibility(View.VISIBLE);
    }

    // Loads the navigation route if any exists for the current floor selected
    // Multi Floor Route ex. DMSL --> Zeina
    private void loadFloorNavRoute() {
        if (userData.isNavBuildingSelected()) {
            clearNavOverlays();
            handlePathDrawing(userData.getNavPois());

            if (pathLineOutsideOptions != null) {
                pathLineOutside = mMap.addPolyline(pathLineOutsideOptions);
            }
        } else {
            btnFloorUp.setVisibility(View.VISIBLE);
            btnFloorDown.setVisibility(View.VISIBLE);
        }
    }

    // draws the navigation route for the loaded floor
    private void handlePathDrawing(List<PoisNav> puids) {
        List<LatLng> p = new ArrayList<LatLng>();
        String selectedFloor = userData.getSelectedFloorNumber();
        for (PoisNav pt : puids) {
            // draw only the route for this floor
            if (pt.floor_number.equalsIgnoreCase(selectedFloor)) {
                // TODO - if this is the first POI for this floor we should add
                // a starting marker, if this floor is not the same with the
                // floor of the starting position which already has a flag
                // marker
                p.add(new LatLng(Double.parseDouble(pt.lat), Double.parseDouble(pt.lon)));
            }
        }
        pathLineInside = mMap
                .addPolyline(new PolylineOptions().addAll(p).width(10).color(Color.RED).zIndex(100.0f));

        if (!puids.isEmpty()) {
            // add markers for starting and ending position
            // starting point
            PoisNav nrpFrom = puids.get(0);
            if (nrpFrom.floor_number.equalsIgnoreCase(selectedFloor))
                visiblePois.setFromMarker(mMap.addMarker(new MarkerOptions()
                        .position(new LatLng(Double.parseDouble(nrpFrom.lat), Double.parseDouble(nrpFrom.lon)))
                        .title("Starting Position")
                        .icon(BitmapDescriptorFactory.fromResource(R.drawable.map_flag_green2_48))));
            // destination point
            PoisNav nrpTo = puids.get(puids.size() - 1);
            if (nrpTo.floor_number.equalsIgnoreCase(selectedFloor))
                visiblePois.setToMarker(mMap.addMarker(new MarkerOptions()
                        .position(new LatLng(Double.parseDouble(nrpTo.lat), Double.parseDouble(nrpTo.lon)))
                        .title("Final Destination")
                        .icon(BitmapDescriptorFactory.fromResource(R.drawable.map_flag_pink2_48))));

            // adjust floor buttons
            if (nrpTo.floor_number.equals(nrpFrom.floor_number)) {
                btnFloorUp.setVisibility(View.VISIBLE);
                btnFloorDown.setVisibility(View.VISIBLE);
            } else {
                // Go to Navigation Destination
                if (Integer.parseInt(nrpTo.floor_number) > Integer.parseInt(selectedFloor)) {
                    btnFloorDown.setVisibility(View.INVISIBLE);
                    btnFloorUp.setVisibility(View.VISIBLE);
                } else if (Integer.parseInt(nrpTo.floor_number) < Integer.parseInt(selectedFloor)) {
                    btnFloorUp.setVisibility(View.INVISIBLE);
                    btnFloorDown.setVisibility(View.VISIBLE);
                } else { // if Navigation Destination Floor Go to Navigation
                         // Start
                    if (Integer.parseInt(nrpFrom.floor_number) > Integer.parseInt(selectedFloor)) {
                        btnFloorDown.setVisibility(View.INVISIBLE);
                        btnFloorUp.setVisibility(View.VISIBLE);
                    } else {
                        btnFloorUp.setVisibility(View.INVISIBLE);
                        btnFloorDown.setVisibility(View.VISIBLE);
                    }
                }
            }

        }
    }

    private void handleBuildingsOnMap() {
        AnyplaceCache mAnyplaceCache = AnyplaceCache.getInstance(UnifiedNavigationActivity.this);
        mAnyplaceCache.loadWorldBuildings(new FetchBuildingsTaskListener() {

            @Override
            public void onSuccess(String result, List<BuildingModel> buildings) {
                List<BuildingModel> collection = new ArrayList<BuildingModel>(buildings);
                mClusterManager.clearItems();
                BuildingModel buid = userData.getSelectedBuilding();
                if (buid != null)
                    collection.remove(buid);
                mClusterManager.addItems(collection);
                mClusterManager.cluster();
                // HACK. This dumps all the cached icons & recreates everything.
                mClusterManager.setRenderer(
                        new MyBuildingsRenderer(UnifiedNavigationActivity.this, mMap, mClusterManager));
            }

            @Override
            public void onErrorOrCancel(String result) {

            }

        }, this, false);
    }

    // </POIS
    // adds markers for the received POIs and stores them inside
    // the structures for later retrieval

    private void handlePoisOnMap(Collection<PoisModel> collection) {

        visiblePois.clearAll();
        String currentFloor = userData.getSelectedFloorNumber();

        // Display part of Description Text Only
        // Make an approximation of available space based on map size
        final int fragmentWidth = (int) (findViewById(R.id.map).getWidth() * 2);
        ViewGroup infoWindow = (ViewGroup) getLayoutInflater().inflate(R.layout.info_window, null);
        TextView infoSnippet = (TextView) infoWindow.findViewById(R.id.snippet);
        TextPaint paint = infoSnippet.getPaint();

        for (PoisModel pm : collection) {
            if (pm.floor_number.equalsIgnoreCase(currentFloor)) {
                String snippet = AndroidUtils.fillTextBox(paint, fragmentWidth, pm.description);
                Marker m = mMap.addMarker(new MarkerOptions()
                        .position(new LatLng(Double.parseDouble(pm.lat), Double.parseDouble(pm.lng))).title(pm.name)
                        .snippet(snippet).icon(BitmapDescriptorFactory.fromResource(R.drawable.pin8)));
                visiblePois.addMarkerAndPoi(m, pm);
            }
        }
    }

    private void fetchPoisByBuidToCache(final String buid, final FetchPoisByBuidTask.FetchPoisListener l) {
        // Check for cahced pois
        if (mAnyplaceCache.checkPoisBUID(buid)) {
            l.onSuccess("Pois read from cache", mAnyplaceCache.getPoisMap());
        } else {
            FetchPoisByBuidTask fetchPoisByBuidFloorTask = new FetchPoisByBuidTask(
                    new FetchPoisByBuidTask.FetchPoisListener() {
                        @Override
                        public void onSuccess(String result, Map<String, PoisModel> poisMap) {
                            mAnyplaceCache.setPois(poisMap, buid);
                            l.onSuccess(result, poisMap);
                        }

                        @Override
                        public void onErrorOrCancel(String result) {
                            // clear any markers that might have already been added to
                            // the map
                            visiblePois.clearAll();
                            // clear and resets the cached POIS inside AnyplaceCache
                            mAnyplaceCache.setPois(new HashMap<String, PoisModel>(), "");
                            l.onErrorOrCancel(result);
                        }
                    }, this, buid);

            fetchPoisByBuidFloorTask.execute();
        }
    }

    // />POIS
    // *****************************************************************************
    // * Activity Listeners
    // *****************************************************************************

    @Override
    public void onNewWifiResults(int aps) {
        // Log.d( "Anyplace Tracker", "wifi res: " + list.size() );
        detectedAPs.setText("AP: " + aps);
    }

    @Override
    public void onNewLocation(final LatLng pos) {
        userData.setPositionWifi(pos.latitude, pos.longitude);
        this.runOnUiThread(new Runnable() {

            @Override
            public void run() {
                if (isTrackingErrorBackground) {
                    isTrackingErrorBackground = false;
                    btnTrackme.setImageResource(R.drawable.dark_device_access_location_searching);
                }

                // update the wifi location of the user
                updateLocation();
            }
        });

    }

    @Override
    public void onTrackerError(final String msg) {
        if (!isTrackingErrorBackground)
            this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    if (!isTrackingErrorBackground) {
                        btnTrackme.setImageResource(R.drawable.dark_device_access_location_off);
                        isTrackingErrorBackground = true;
                    }
                }
            });

    }

    @Override
    public void onFloorError(final Exception ex) {
        if (ex instanceof NonCriticalError)
            return;

        floorSelector.Stop();
        // TODO Auto-generated method stub
        Log.e("Floor Selector", ex.toString());
        Toast.makeText(getBaseContext(), "Floor Selector ecountered an error", Toast.LENGTH_SHORT).show();

    }

    // Change Floor Request on current Building
    @Override
    public void onNewFloor(final String floorNumber) {

        if (floorChangeRequestDialog)
            return;

        final BuildingModel b = userData.getSelectedBuilding();

        if (b == null) {
            Log.e("Unified Activity/onNewFloor", "Floor Number Not found");
            return;
        }

        // Check if the floor is the loaded floor
        if (b.getSelectedFloor().floor_number.equals(floorNumber)) {
            lastFloor = null;
            return;
        }

        // User clicked Cancel
        if (lastFloor != null && lastFloor.equals(floorNumber)) {
            return;
        }

        lastFloor = floorNumber;

        final FloorModel f = b.getFloorFromNumber(floorNumber);
        if (f != null) {

            AlertDialog.Builder alertDialog = new AlertDialog.Builder(UnifiedNavigationActivity.this);
            alertDialog.setTitle("Floor Change Detected");
            alertDialog.setMessage("Floor Number: " + floorNumber + ". Do you want to proceed?");
            alertDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                    floorChangeRequestDialog = false;
                    bypassSelectBuildingActivity(b, f);
                }
            });
            alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                    floorChangeRequestDialog = false;
                }
            });
            alertDialog.show();
            floorChangeRequestDialog = true;
        }
    }

    // *****************************************************************************
    // * HELPER FUNCTIONS
    // *****************************************************************************

    private void enableAnyplaceTracker() {
        // Do not change file wile enabling tracker
        if (lpTracker.trackOn()) {
            btnTrackme.setImageResource(R.drawable.dark_device_access_location_searching);
            isTrackingErrorBackground = false;
        }

    }

    private void disableAnyplaceTracker() {
        lpTracker.trackOff();
        btnTrackme.setImageResource(R.drawable.dark_device_access_location_off);
        isTrackingErrorBackground = true;
    }

    private void addTrackerListeners() {

        // sensorsMain.addListener((SensorsMain.IOrientationListener) this);
        lpTracker.addListener((AnyplaceTracker.WifiResultsAnyplaceTrackerListener) this);
        lpTracker.addListener((AnyplaceTracker.TrackedLocAnyplaceTrackerListener) this);
        lpTracker.addListener((AnyplaceTracker.ErrorAnyplaceTrackerListener) this);
        floorSelector.addListener((FloorSelector.FloorAnyplaceFloorListener) this);
        floorSelector.addListener((FloorSelector.ErrorAnyplaceFloorListener) this);
    }

    private void removeTrackerListeners() {

        // sensorsMain.removeListener((SensorsMain.IOrientationListener) this);
        lpTracker.removeListener((AnyplaceTracker.WifiResultsAnyplaceTrackerListener) this);
        lpTracker.removeListener((AnyplaceTracker.TrackedLocAnyplaceTrackerListener) this);
        lpTracker.removeListener((AnyplaceTracker.ErrorAnyplaceTrackerListener) this);
        floorSelector.removeListener((FloorSelector.FloorAnyplaceFloorListener) this);
        floorSelector.removeListener((FloorSelector.ErrorAnyplaceFloorListener) this);
    }

    private void showProgressBar() {
        progressBar.setVisibility(View.VISIBLE);
    }

    private void hideProgressBar() {
        progressBar.setVisibility(View.GONE);
    }

    // *****************************************************************************
    // * SEARCHING FUNCTIONS
    // *****************************************************************************

    @Override
    protected void onNewIntent(Intent intent) {
        handleIntent(intent);
    }

    // Search Button or URL handle
    private void handleIntent(Intent intent) {

        String action = intent.getAction();
        if (Intent.ACTION_SEARCH.equals(action)) {

            // check what type of search we need
            SearchTypes searchType = AnyPlaceSeachingHelper.getSearchType(mMap.getCameraPosition().zoom);
            String query = intent.getStringExtra(SearchManager.QUERY);
            GeoPoint gp = userData.getLatestUserPosition();

            // manually launch the real search activity
            Intent searchIntent = new Intent(UnifiedNavigationActivity.this, SearchPOIActivity.class);
            // add query to the Intent Extras
            searchIntent.setAction(action);
            searchIntent.putExtra("searchType", searchType);
            searchIntent.putExtra("query", query);
            searchIntent.putExtra("lat", (gp == null) ? csLat : gp.dlat);
            searchIntent.putExtra("lng", (gp == null) ? csLon : gp.dlon);
            startActivityForResult(searchIntent, SEARCH_POI_ACTIVITY_RESULT);

        } else if (Intent.ACTION_VIEW.equals(action)) {
            String data = intent.getDataString();

            if (data != null && data.startsWith("http")) {
                final Uri uri = intent.getData();
                if (uri != null) {
                    String path = uri.getPath();

                    if (path != null && path.equals("/getnavigation")) {
                        String poid = uri.getQueryParameter("poid");
                        if (poid == null || poid.equals("")) {
                            // Share building
                            // http://anyplace.rayzit.com/getnavigation?buid=username_1373876832005&floor=0
                            String buid = uri.getQueryParameter("buid");
                            if (buid == null || buid.equals("")) {
                                Toast.makeText(getBaseContext(), "Buid parameter expected", Toast.LENGTH_SHORT)
                                        .show();
                            } else {
                                mAutomaticGPSBuildingSelection = false;
                                mAnyplaceCache.loadBuilding(buid, new FetchBuildingTaskListener() {

                                    @Override
                                    public void onSuccess(String result, final BuildingModel b) {

                                        bypassSelectBuildingActivity(b, uri.getQueryParameter("floor"), true);

                                    }

                                    @Override
                                    public void onErrorOrCancel(String result) {
                                        Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();

                                    }
                                }, UnifiedNavigationActivity.this);
                            }
                        } else {
                            // Share POI
                            // http://anyplace.rayzit.com/getnavigation?poid=username_username_1373876832005_0_35.14424091022549_33.41139659285545_1382635428093
                            mAutomaticGPSBuildingSelection = false;
                            new FetchPoiByPuidTask(new FetchPoiByPuidTask.FetchPoiListener() {

                                @Override
                                public void onSuccess(String result, final PoisModel poi) {

                                    if (userData.getSelectedBuildingId() != null
                                            && userData.getSelectedBuildingId().equals(poi.buid)) {
                                        // Building is Loaded
                                        startNavigationTask(poi.puid);
                                    } else {
                                        // Load Building
                                        mAnyplaceCache.loadBuilding(poi.buid, new FetchBuildingTaskListener() {

                                            @Override
                                            public void onSuccess(String result, final BuildingModel b) {

                                                bypassSelectBuildingActivity(b, poi.floor_number, true, poi);

                                            }

                                            @Override
                                            public void onErrorOrCancel(String result) {
                                                Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();

                                            }
                                        }, UnifiedNavigationActivity.this);
                                    }
                                }

                                @Override
                                public void onErrorOrCancel(String result) {
                                    Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();
                                }
                            }, this, poid).execute();
                        }
                    }
                }
            } else {

                // Search TextBox results only

                // PoisModel or Place Class
                IPoisClass place_selected = AnyPlaceSeachingHelper.getClassfromJson(data);

                if (place_selected.id() != null) {
                    // hide the search view when a navigation route is drawn
                    if (searchView != null) {
                        searchView.setIconified(true);
                        searchView.clearFocus();
                    }
                    handleSearchPlaceSelection(place_selected);
                }

            }

        }
    } // end of handle intent

    // handle the selected place from the TextBox or search activity
    // either Anyplace POI or a Google Place
    private void handleSearchPlaceSelection(final IPoisClass place) {
        if (place == null)
            return;
        switch (place.type()) {
        case AnyPlacePOI:
            startNavigationTask(place.id());
            break;
        case GooglePlace:

            mAnyplaceCache.loadWorldBuildings(new FetchBuildingsTaskListener() {

                @Override
                public void onSuccess(String result, List<BuildingModel> allBuildings) {
                    FetchNearBuildingsTask nearBuildings = new FetchNearBuildingsTask();
                    nearBuildings.run(allBuildings, place.lat(), place.lng(), 200);

                    if (nearBuildings.buildings.size() > 0) {
                        final BuildingModel b = nearBuildings.buildings.get(0);

                        bypassSelectBuildingActivity(b, "0", false);
                    } else {
                        showGooglePoi(place);
                    }
                }

                @Override
                public void onErrorOrCancel(String result) {
                    showGooglePoi(place);
                }
            }, UnifiedNavigationActivity.this, false);

            break;
        }
    }

    private void showGooglePoi(IPoisClass place) {
        cameraUpdate = true;
        mMap.animateCamera(
                CameraUpdateFactory.newLatLngZoom(new LatLng(place.lat(), place.lng()), mInitialZoomLevel),
                new CancelableCallback() {

                    @Override
                    public void onFinish() {
                        cameraUpdate = false;
                    }

                    @Override
                    public void onCancel() {
                        cameraUpdate = false;
                    }
                });
        // add the marker for this Google Place
        Marker mGooglePlaceMarker = mMap
                .addMarker(new MarkerOptions().position(new LatLng(place.lat(), place.lng()))
                        .icon(BitmapDescriptorFactory.fromResource(R.drawable.pin2)));
        visiblePois.setGooglePlaceMarker(mGooglePlaceMarker, place);
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {

        if (key.equals("TrackingAlgorithm")) {
            lpTracker.setAlgorithm(sharedPreferences.getString("TrackingAlgorithm", "WKNN"));
        }
    }

    private void popup_msg(String msg, String title) {

        AlertDialog.Builder alert_box = new AlertDialog.Builder(this);
        alert_box.setTitle(title);
        alert_box.setMessage(msg);

        alert_box.setNeutralButton("Hide", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

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

    // Define a DialogFragment that displays the error dialog
    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
        public void setDialog(Dialog dialog) {
            mDialog = dialog;
        }

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

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_BACK:
            finish();
            return true;
        case KeyEvent.KEYCODE_FOCUS:
        case KeyEvent.KEYCODE_CAMERA:
        case KeyEvent.KEYCODE_SEARCH:
            // Handle these events so they don't launch the Camera app
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    interface PreviousRunningTask {
        void disableSuccess();
    }
}