com.trailbehind.android.iburn.map.MapActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.trailbehind.android.iburn.map.MapActivity.java

Source

package com.trailbehind.android.iburn.map;

import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.apache.http.HttpVersion;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Rect;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.Vibrator;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.nutiteq.BasicMapComponent;
import com.nutiteq.android.MapView;
import com.nutiteq.cache.Cache;
import com.nutiteq.cache.CachingChain;
import com.nutiteq.components.MapPos;
import com.nutiteq.components.PlaceIcon;
import com.nutiteq.components.WgsPoint;
import com.nutiteq.components.ZoomRange;
import com.nutiteq.controls.AndroidKeysHandler;
import com.nutiteq.core.MappingCore;
import com.nutiteq.fs.AndroidFileSystem;
import com.nutiteq.listeners.DelayedMapListener;
import com.nutiteq.location.LocationMarker;
import com.nutiteq.location.NutiteqLocationMarker;
import com.nutiteq.ui.DefaultZoomIndicator;
import com.nutiteq.ui.ThreadDrivenPanning;
import com.trailbehind.android.iburn.BurnApplication;
import com.trailbehind.android.iburn.BurnApplication.AppLocationListener;
import com.trailbehind.android.iburn.BurnApplication.AppLocationProvider;
import com.trailbehind.android.iburn.R;
import com.trailbehind.android.iburn.map.download.MapDownloadThread;
import com.trailbehind.android.iburn.map.download.MapDownloadThread.MapDownloadListerner;
import com.trailbehind.android.iburn.map.source.IMapSource;
import com.trailbehind.android.iburn.util.CompassUtils;
import com.trailbehind.android.iburn.util.CompassUtils.CompassPlaceIcon;
import com.trailbehind.android.iburn.util.FastAndroidFileSystemCache;
import com.trailbehind.android.iburn.util.Globals;
import com.trailbehind.android.iburn.util.IConstants;
import com.trailbehind.android.iburn.util.MapUtils;
import com.trailbehind.android.iburn.util.UIUtils;
import com.trailbehind.android.iburn.util.Utils;
import com.trailbehind.android.iburn.view.CompassView;
import com.trailbehind.android.iburn.view.CustomMapView;
import com.trailbehind.android.iburn.view.MapZoomControls;

public class MapActivity extends Activity implements IConstants {

    /** The Constant DIALOG_ABOUT. */
    final static private int DIALOG_ABOUT = 101;

    /** The Constant DIALOG_SDCARD_NOT_AVAILABLE. */
    final static public int DIALOG_SDCARD_NOT_AVAILABLE = 102;

    /** The Constant DIALOG_NO_INTERNET_DOWNLOAD. */
    final static private int DIALOG_NO_INTERNET_DOWNLOAD = 103;

    /** The Constant DIALOG_CLOSING_RESOURCES. */
    final static private int DIALOG_CLOSING_RESOURCES = 104;

    /** The Constant DIALOG_CLOSING_RESOURCES. */
    final static private int DIALOG_DOWNLOAD_PROGRESS = 105;

    final static private int DIALOG_DOWNLOAD_ERROR = 106;

    // UI views ---------

    /** The map layout. */
    private FrameLayout mMapLayoutView;

    /** The map view. */
    private CustomMapView mMapView;

    /** The compass view. */
    private CompassView mCompassView;

    /** The message panel. */
    private View mMessagePanel;

    // UI controls ---------

    /** The zoom controls. */
    private MapZoomControls mZoomControls;

    /** The progress bar. */
    private ProgressBar mProgressBar;

    /** The message control. */
    private TextView mMessageTextView;

    private ProgressDialog mProgressDialog;

    // menu --------

    /** The menu. */
    private Menu mMenu;

    // map components ---------

    /** The map component. */
    BasicMapComponent mMapComponent;

    /** The saved map cache. */
    private FastAndroidFileSystemCache mSavedMapCache;

    /** The map touch listener. */
    private MapTouchListener mMapTouchListener;

    /** The control keys handler. */
    private AndroidKeysHandler mControlKeysHandler;

    /** The dummy location marker. */
    private LocationMarker mDummyLocationMarker;

    // boolean flags ---------

    /** The locating location. */
    private boolean mGetMyLocation;

    // inner class handles ---------

    /** The map handler. */
    ActivityHandler mActivityHandler = new ActivityHandler();

    // other properties ---------

    /** The wake lock. */
    private PowerManager.WakeLock mWakeLock;

    /** The vibrator. */
    private Vibrator mVibrator;

    private MapDownloadThread[] mMapDownloadThreads;

    private DefaultHttpClient mDefaultHttpClient1;

    /** The file cache writer. */
    private FileCacheWriter mFileCacheWriter;

    private int mErrorMsgId;

    private int mTotalTileCount;

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

        Log.d(TAG, "MapActivity:onCreate called..");

        // set app params
        setActivityParams();

        // setup views
        setupViews();

        setupMapDownload(false);
    }

    private void setupMapDownload(boolean force) {
        if (Utils.isNetworkAvailable(getBaseContext())) {
            if (Utils.isSDCardAvailable()) {
                final boolean mapDownloaded = Globals.sSharedPreferences.getBoolean(PREF_KEY_MAP_DOWNLOADED, false);
                if (!mapDownloaded || force) {
                    showDialog(DIALOG_DOWNLOAD_PROGRESS);
                    mActivityHandler.sendMessageDelayed(
                            mActivityHandler.obtainMessage(ActivityHandler.MESSAGE_START_DOWNLOAD), 50);
                }
            } else {
                showDialog(DIALOG_SDCARD_NOT_AVAILABLE);
            }
        } else {
            showDialog(DIALOG_NO_INTERNET_DOWNLOAD);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.app.Activity#onResume()
     */
    @Override
    protected void onResume() {
        super.onResume();

        checkGPSProvider();
        registerReceivers();
    }

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

        mActivityHandler.removeCallbacksAndMessages(null);
        unregisterReceivers();
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.app.Activity#onDestroy()
     */
    @Override
    public void onDestroy() {
        try {
            if (mDefaultHttpClient1 != null) {
                mDefaultHttpClient1.getConnectionManager().shutdown();
            }
        } catch (Exception e) {
            // we dont care
        }

        getBurnApplication().onDestroy();

        doCleanup();
        System.gc();

        Log.d(TAG, "onDestroy called..");
        super.onDestroy();
    }

    // dialog handler

    /*
     * (non-Javadoc)
     * 
     * @see android.app.Activity#onCreateDialog(int)
     */
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case DIALOG_ABOUT:
            final ScrollView dialogView = (ScrollView) LayoutInflater.from(getBaseContext())
                    .inflate(R.layout.about_dialog, null);
            final TextView aboutText = (TextView) dialogView.findViewById(R.id.message);
            aboutText.setText(Utils.getAboutText(getBaseContext()));

            final String title = getString(R.string.title_dialog_about) + " " + getString(R.string.app_name);
            return new AlertDialog.Builder(this).setView(dialogView).setIcon(R.drawable.icon).setTitle(title)
                    .setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            dialog.dismiss();
                        }
                    }).create();
        case DIALOG_NO_INTERNET_DOWNLOAD:
            return new AlertDialog.Builder(MapActivity.this).setTitle(R.string.title_dialog_error)
                    .setMessage(R.string.error_no_internet_download)
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            removeDialog(DIALOG_NO_INTERNET_DOWNLOAD);
                        }
                    }).create();
        case DIALOG_SDCARD_NOT_AVAILABLE:
            return new AlertDialog.Builder(this).setIcon(R.drawable.ic_dialog_menu_generic)
                    .setTitle(R.string.title_dialog_error).setMessage(R.string.error_sd_not_available)
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            removeDialog(DIALOG_SDCARD_NOT_AVAILABLE);
                        }
                    }).create();
        case DIALOG_DOWNLOAD_PROGRESS:
            mProgressDialog = new ProgressDialog(MapActivity.this);
            mProgressDialog.setTitle(R.string.title_dialog_download);
            mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            mProgressDialog.setButton(getText(android.R.string.cancel), new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    removeDialog(DIALOG_DOWNLOAD_PROGRESS);
                    for (int i = 0, len = mMapDownloadThreads.length; i < len; i++) {
                        MapDownloadThread t = mMapDownloadThreads[i];
                        if (t != null) {
                            t.cancel();
                        }
                        mMapDownloadThreads[i] = null;
                    }

                    mFileCacheWriter.stopRunning();
                    mFileCacheWriter = null;
                }
            });
            return mProgressDialog;
        case DIALOG_DOWNLOAD_ERROR:
            return new AlertDialog.Builder(MapActivity.this).setIcon(R.drawable.ic_dialog_menu_generic)
                    .setTitle(R.string.title_dialog_error).setMessage(mErrorMsgId)
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            removeDialog(DIALOG_SDCARD_NOT_AVAILABLE);
                        }
                    }).create();
        default:
            return null;
        }
    }

    // menu handlers --------

    /*
     * (non-Javadoc)
     * 
     * @see android.app.Activity#onPrepareOptionsMenu(android.view.Menu)
     */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (mMenu == null) {
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.map_menu, menu);
            mMenu = menu;
        }

        return true;
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_mylocation: {
            getMyLocation();
            break;
        }
        case R.id.menu_download: {
            setupMapDownload(true);
            break;
        }
        case R.id.menu_about: {
            showDialog(DIALOG_ABOUT);
            break;
        }
        default:
            return false;
        }
        return true;
    }

    // setup UI ---------

    /**
     * Sets the app params.
     */
    private void setActivityParams() {
        setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
        getWindow().setBackgroundDrawable(null);

        mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
        mActivityHandler.sendMessage(mActivityHandler.obtainMessage(ActivityHandler.MESSAGE_INIT_FILE_SYSTEM_DIR));

        mMapDownloadThreads = new MapDownloadThread[DOWNLOAD_THREAD_COUNT];
    }

    /**
     * Setup views.
     */
    private void setupViews() {
        setContentView(R.layout.map);
        final FrameLayout contentView = (FrameLayout) findViewById(android.R.id.content);
        if (contentView != null) {
            contentView.setBackgroundDrawable(null);
            contentView.setForeground(null);
        }

        // setup top panel
        setupHeaderPanel();

        // setup map component
        setupMapComponent();

        // create map view now
        setupMapView();

        // setup loc source
        mActivityHandler.sendMessageDelayed(
                mActivityHandler.obtainMessage(ActivityHandler.MESSAGE_INIT_LOCATION_SOURCE_N_MAP_LISTENER), 1000);

        // create zoom controls
        setupZoomControls();
    }

    /**
     * Setup map component.
     */
    private void setupMapComponent() {
        if (mMapComponent == null) {
            mMapComponent = new CustomMapComponent(NUTITEQ_LICENSE_KEY, NUTITEQ_VENDOR, NUTITEQ_APP_NAME, 1, 1,
                    BURN_CENTER_POINT, BURN_DEFULT_ZOOM);

            mMapComponent.setMap(BURN_MAP_SOURCE);

            mMapComponent.setPanningStrategy(new ThreadDrivenPanning());

            mControlKeysHandler = new AndroidKeysHandler();
            mMapComponent.setControlKeysHandler(mControlKeysHandler);

            mMapComponent.setZoomLevelIndicator(
                    new DefaultZoomIndicator(BURN_MAP_SOURCE.getMinZoom(), BURN_MAP_SOURCE.getMaxZoom()));
            mMapComponent.setFileSystem(new AndroidFileSystem());
            mMapComponent.setTouchClickTolerance(BasicMapComponent.FINGER_CLICK_TOLERANCE);

            // setup cache
            setupDiskCache();

            // start mapping
            startMapping();
        }
    }

    /**
     * Setup map view.
     */
    private void setupMapView() {
        mMapTouchListener = new MapTouchListener(this);

        // setup map view
        mMapView = new CustomMapView(getBaseContext(), mMapComponent);
        mMapView.setOnTouchListener(mMapTouchListener);
        mMapView.setClickable(true);
        mMapView.setEnabled(true);

        // cache map layout view
        mMapLayoutView = (FrameLayout) findViewById(R.id.map_layout);

        final RelativeLayout.LayoutParams mapViewLayoutParams = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
        mMapLayoutView.addView(mMapView, 0, mapViewLayoutParams);
    }

    /**
     * Setup map listener.
     */
    private void setupMapListener() {
        mMapComponent.setMapListener(new DelayedMapListener(mMapComponent.getMapListener()) {

            @Override
            public void mapMoved() {
                mMapView.post(new Runnable() {

                    @Override
                    public void run() {
                        final AppLocationProvider locProvider = getActiveLocationProvider();
                        if (mGetMyLocation && locProvider != null) {
                            final LocationMarker locationMarker = locProvider.getLocationMarker();
                            locationMarker.setTrackingEnabled(false);

                            mGetMyLocation = false;
                        }
                        mMapTouchListener.mapMoved();
                    }
                });
            }

            @Override
            public void mapClicked(final WgsPoint point) {
                mMapView.post(new Runnable() {

                    @Override
                    public void run() {
                        mMapTouchListener.mapClicked(point);
                    }
                });
            }
        });
    }

    /**
     * Setup disk cache.
     */
    private void setupDiskCache() {
        final boolean fileSystemAvailable = Utils.isSDCardAvailable();
        if (!fileSystemAvailable) {
            showDialog(DIALOG_SDCARD_NOT_AVAILABLE);
        } else {
            final File externalStoragePath = Environment.getExternalStorageDirectory();
            if (externalStoragePath != null) {
                final File appDir = new File(externalStoragePath, APP_DIR_ON_SD_CARD);
                appDir.mkdirs();

                final File cacheDir = new File(appDir, DIR_MAP_CACHE);
                cacheDir.mkdirs();

                mSavedMapCache = new FastAndroidFileSystemCache(getBaseContext(), cacheDir);
                mSavedMapCache.initialize();
                final CachingChain cachingChain = new CachingChain(new Cache[] { mSavedMapCache });

                mMapComponent.setNetworkCache(cachingChain);
            }
        }
    }

    private FastAndroidFileSystemCache getNewSavedMapCache() {
        final File externalStoragePath = Environment.getExternalStorageDirectory();
        if (externalStoragePath != null) {
            final File appDir = new File(externalStoragePath, APP_DIR_ON_SD_CARD);
            appDir.mkdirs();

            final File cacheDir = new File(appDir, DIR_MAP_CACHE);
            cacheDir.mkdirs();

            FastAndroidFileSystemCache savedMapCache = new FastAndroidFileSystemCache(getBaseContext(), cacheDir);
            savedMapCache.initialize();
            return savedMapCache;
        }
        return null;
    }

    /**
     * Setup zoom controls.
     */
    private void setupZoomControls() {
        // Create new ZoomControls
        mZoomControls = (MapZoomControls) findViewById(R.id.zoom_controls);
        mZoomControls.setVisibility(View.GONE);

        mZoomControls.setOnZoomInClickListener(new View.OnClickListener() {
            public void onClick(final View v) {
                zoomIn(1);
            }
        });
        mZoomControls.setOnZoomOutClickListener(new View.OnClickListener() {
            public void onClick(final View v) {
                zoomOut(1);
            }
        });
    }

    /**
     * Sets the location source.
     */
    private void setupLocationSource() {
        final AppLocationProvider locProvider = getActiveLocationProvider();

        locProvider.setLocationMarker(createLocationMarker());
        locProvider.setLocationListener(new AppLocationListener() {

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
                if (LocationManager.GPS_PROVIDER.equalsIgnoreCase(provider)) {
                    if (status == LocationProvider.OUT_OF_SERVICE) {
                        mProgressBar.setVisibility(View.VISIBLE);
                        mMessageTextView.setText(R.string.msg_locating);

                        UIUtils.showPanel(getBaseContext(), mMessagePanel, false);
                    } else {
                        UIUtils.hidePanel(getBaseContext(), mMessagePanel, false);
                    }
                }
            }

            @Override
            public void onProviderEnabled(String provider) {
                if (LocationManager.GPS_PROVIDER.equalsIgnoreCase(provider)) {
                    checkGPSProvider();
                }
            }

            @Override
            public void onProviderDisabled(String provider) {
                if (LocationManager.GPS_PROVIDER.equalsIgnoreCase(provider)) {
                    checkGPSProvider();
                }
            }

            @Override
            public void onLocationChanged(String provider, Location location) {
                if (LocationManager.GPS_PROVIDER.equalsIgnoreCase(provider)) {
                    if (Globals.sCurrentGPSLocation == null) {
                        CompassUtils.updateUserBearing(false, location.getBearing());
                    } else {
                        final boolean hasBearing = location.hasBearing();
                        final float pointBearing = MapUtils.calculateBearing(Globals.sCurrentGPSLocation, location);
                        CompassUtils.updateUserBearing(hasBearing,
                                (hasBearing) ? location.getBearing() : pointBearing);
                    }

                    if (mMessagePanel.getVisibility() == View.VISIBLE) {
                        mProgressBar.setVisibility(View.GONE);
                        UIUtils.hidePanel(getBaseContext(), mMessagePanel, false);
                    }
                } else {
                    CompassUtils.updateUserBearing(false, location.getBearing());

                    if (mGetMyLocation) {
                        final AppLocationProvider locProvider = getActiveLocationProvider();
                        final LocationMarker locationMarker = locProvider.getLocationMarker();
                        locationMarker.updatePosition();
                    }
                }
            }

            @Override
            public void onProviderChanged(String oldProvider, String newProvider) {
                if (LocationManager.GPS_PROVIDER.equalsIgnoreCase(newProvider)) {
                    mMapComponent.removeLocationSource();

                    final AppLocationProvider locProvider = getActiveLocationProvider();
                    final LocationMarker locationMarker = createLocationMarker();

                    locProvider.setLocationMarker(locationMarker);
                    mMapComponent.setLocationSource(locProvider);

                    locationMarker.setTrackingEnabled(mGetMyLocation);
                }
            }
        });

        mMapComponent.setLocationSource(locProvider);
    }

    /**
     * Setup button panel.
     */
    private void setupHeaderPanel() {
        mMessagePanel = (LinearLayout) findViewById(R.id.message_panel);
        mMessageTextView = (TextView) findViewById(R.id.label_message);
        mProgressBar = (ProgressBar) findViewById(R.id.progress_circular);

        mMessageTextView.setOnClickListener(null);

        // Add track location button
        final Button homeButton = (Button) findViewById(R.id.btn_mylocation);
        homeButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                mMapComponent.setMiddlePoint(BURN_CENTER_POINT, BURN_DEFULT_ZOOM);
            }
        });

        mCompassView = (CompassView) findViewById(R.id.compass_view);
        mCompassView.setVisibility(View.VISIBLE);
    }

    /**
     * Check gps provider.
     */
    private void checkGPSProvider() {
        final LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            mProgressBar.setVisibility(View.GONE);
            mMessageTextView.setText(R.string.error_gps_disabled);
            mMessageTextView.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    try {
                        mVibrator.vibrate(50);

                        final Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                        startActivity(intent);
                    } catch (Exception e) {
                        // we dont care
                    }
                }
            });

            UIUtils.showPanel(getBaseContext(), mMessagePanel, false);
        } else if (Globals.sCurrentGPSLocation == null) {
            mProgressBar.setVisibility(View.VISIBLE);
            mMessageTextView.setText(R.string.msg_locating);

            UIUtils.showPanel(getBaseContext(), mMessagePanel, false);
        } else {
            UIUtils.hidePanel(getBaseContext(), mMessagePanel, false);
        }
    }

    /**
     * Start mapping.
     */
    private void startMapping() {
        try {
            // start mapping
            mMapComponent.startMapping();
        } catch (Exception e) {
            try {
                Log.e(TAG, "error starting mapping.. cleaningup first..", e);
                if (mMapView != null) {
                    mMapView.clean();
                    mMapView = null;
                }
                mMapComponent.stopMapping();
                MappingCore.getInstance().setTasksRunner(null);
                final Field field = BasicMapComponent.class.getDeclaredField("taskRunner");
                field.setAccessible(true);
                field.set(mMapComponent, MappingCore.getInstance().getTasksRunner());

                // try to start mapping again
                mMapComponent.startMapping();
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    /**
     * Show zoom level toast.
     */
    private void showZoomLevelToast() {
        UIUtils.showDefaultToast(getBaseContext(),
                String.format(getString(R.string.toast_zoom_level), mMapComponent.getZoom()), false);
    }

    // manage receivers ----------

    /**
     * Register receiver.
     */
    private void registerReceivers() {
        if (mWakeLock == null) {
            final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, TAG);
        }
        mWakeLock.acquire();

        mCompassView.registerReceiver();
    }

    /**
     * Unregister receivers.
     */
    private void unregisterReceivers() {
        mCompassView.unregisterReceiver();

        if (mWakeLock != null) {
            mWakeLock.release();
        }
    }

    /**
     * Zoom in.
     * 
     * @param factor
     *            the factor
     */
    public void zoomIn(int factor) {
        for (int i = 0; i < factor; i++) {
            mMapComponent.zoomIn();
        }
        setZoomControlsEnabled();
        showZoomLevelToast();
    }

    /**
     * Zoom in to point.
     * 
     * @param point
     *            the point
     * @param factor
     *            the factor
     */
    public void zoomInToPoint(WgsPoint point, int factor) {
        mMapComponent.moveMap(point);
        zoomIn(factor);
    }

    /**
     * Zoom out to point.
     * 
     * @param point
     *            the point
     * @param factor
     *            the factor
     */
    public void zoomOutToPoint(WgsPoint point, int factor) {
        mMapComponent.moveMap(point);
        zoomOut(factor);
    }

    /**
     * Zoom out.
     * 
     * @param factor
     *            the factor
     */
    public void zoomOut(int factor) {
        for (int i = 0; i < factor; i++) {
            mMapComponent.zoomOut();
        }
        setZoomControlsEnabled();
        showZoomLevelToast();
    }

    /**
     * Convert screen point to wgs.
     * 
     * @param x
     *            the x
     * @param y
     *            the y
     * 
     * @return the wgs point
     */
    public WgsPoint convertScreenPointToWgs(int x, int y) {
        final int mapZoom = mMapComponent.getZoom();

        final MapPos mapMiddlePos = BURN_MAP_SOURCE.wgsToMapPos(mMapComponent.getMiddlePoint().toInternalWgs(),
                mapZoom);

        final int mapMiddleX = mapMiddlePos.getX() - (mMapView.getWidth() / 2);
        final int mapMiddleY = mapMiddlePos.getY() - (mMapView.getHeight() / 2);

        final MapPos overlayMiddlePos = new MapPos(mapMiddleX + x, mapMiddleY + y, mapZoom);

        return BURN_MAP_SOURCE.mapPosToWgs(overlayMiddlePos).toWgsPoint();
    }

    /**
     * Gets the dummy location marker.
     * 
     * @return the dummy location marker
     */
    public LocationMarker getDummyLocationMarker() {
        if (mDummyLocationMarker == null) {
            mDummyLocationMarker = new NutiteqLocationMarker(
                    new PlaceIcon(com.nutiteq.utils.Utils.createImage(PATH_BLANK_IMAGE)), 3000, false);
        }
        return mDummyLocationMarker;
    }

    // utility methods ----------

    /**
     * Creates the location marker.
     * 
     * @return the location marker
     */
    private LocationMarker createLocationMarker() {
        return new NutiteqLocationMarker(
                new CompassPlaceIcon(com.nutiteq.utils.Utils.createImage(PATH_IMAGE_COMPASS), getBaseContext()),
                3000, false);
    }

    /**
     * Track location.
     */
    private void getMyLocation() {
        final AppLocationProvider locProvider = getActiveLocationProvider();
        if (locProvider != null) {
            final LocationMarker locationMarker = locProvider.getLocationMarker();
            final WgsPoint point = locProvider.getLocation();

            if (point != null) {
                locationMarker.setLocation(point);
                moveMap(locProvider.getLocation());
                locationMarker.updatePosition();

                if (mGetMyLocation) {
                    locationMarker.setTrackingEnabled(false);
                    mGetMyLocation = false;
                }
            } else {
                UIUtils.showDefaultToast(getBaseContext(), R.string.toast_retrieving_current_loc, false);

                if (!mGetMyLocation) {
                    mGetMyLocation = true;
                    locationMarker.setTrackingEnabled(true);
                    locationMarker.updatePosition();
                }
            }
        } else {
            Log.d(TAG, "Get my loc button clicked. Active loc source is null.");
        }
    }

    /**
     * Do cleanup.
     */
    private void doCleanup() {
        try {
            if (mMapView != null) {
                mMapView.clean();
                mMapView = null;
            }

            mMapComponent.stopMapping();
            mMapComponent = null;
        } catch (Exception e) {
            // we don't care if something fails above
        }
    }

    /**
     * Move map.
     * 
     * @param point
     *            the point
     */
    private void moveMap(WgsPoint point) {
        final double lat1 = point.getLat();
        final double lon1 = point.getLon();

        final WgsPoint middlePoint = mMapComponent.getMiddlePoint();
        final double lat0 = middlePoint.getLat();
        final double lon0 = middlePoint.getLon();

        final double latDiff = (lat1 - lat0) / 20;
        final double lonDiff = (lon1 - lon0) / 20;

        for (int i = 1; i < 21; i++) {
            final Bundle bundle = new Bundle();
            if (i != 20) {
                bundle.putDouble(KEY_LAT, (lat0 + (latDiff * i)));
                bundle.putDouble(KEY_LON, (lon0 + (lonDiff * i)));
            } else {
                bundle.putDouble(KEY_LAT, lat1);
                bundle.putDouble(KEY_LON, lon1);
            }

            final Message msg = mActivityHandler.obtainMessage(ActivityHandler.MESSAGE_MOVE_MAP);
            msg.setData(bundle);
            mActivityHandler.sendMessageDelayed(msg, i * 30);
        }
    }

    // package scope methods

    /**
     * Sets the zoom controls enabled.
     */
    void setZoomControlsEnabled() {
        final ZoomRange zoomRange = mMapComponent.getZoomRange();
        final int zoomLevel = mMapComponent.getZoom();
        mZoomControls.setIsZoomInEnabled(zoomRange.getMaxZoom() != zoomLevel);
        mZoomControls.setIsZoomOutEnabled(zoomRange.getMinZoom() != zoomLevel);
    }

    /**
     * Sets the zoom controls visible.
     * 
     * @param visible
     *            the new zoom controls visible
     */
    void setZoomControlsVisible(boolean visible) {
        if (visible) {
            UIUtils.fadeView(mZoomControls, View.VISIBLE, 0f, 1f);
        } else {
            UIUtils.fadeView(mZoomControls, View.GONE, 1f, 0f);
        }
    }

    DefaultHttpClient getHttpClient() {
        // Create and initialize HTTP parameters
        HttpParams params = new BasicHttpParams();
        ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(10));
        ConnManagerParams.setMaxTotalConnections(params, 100);
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setUserAgent(params, "Mozilla");

        HttpConnectionParams.setStaleCheckingEnabled(params, false);

        // Default connection and socket timeout of 20 seconds. Tweak to
        // taste.
        HttpConnectionParams.setConnectionTimeout(params, 30 * 1000);
        HttpConnectionParams.setSoTimeout(params, 30 * 1000);
        HttpConnectionParams.setSocketBufferSize(params, 8192);
        HttpClientParams.setRedirecting(params, true);

        // Create and initialize scheme registry
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));

        // Create an HttpClient with the ThreadSafeClientConnManager.
        // This connection manager must be used if more than one thread will
        // be using the HttpClient.
        ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
        return new DefaultHttpClient(cm, params);
    }

    LinkedList<String> getUrlList() {
        final IMapSource mapSource = BURN_MAP_SOURCE;

        final WgsPoint startPoint = BURN_START_POINT;
        final WgsPoint endPoint = BURN_END_POINT;

        final int tileSize = mapSource.getTileSize();

        final LinkedList<String> urlList = new LinkedList<String>();
        for (int zoom = mapSource.getMinZoom(), endZoom = mapSource
                .getMaxZoom(), i = 0; zoom <= endZoom; zoom++, i++) {
            // switching to coord system
            final MapPos mapStartPos = mapSource.wgsToMapPos(startPoint.toInternalWgs(), zoom);
            final MapPos mapEndPos = mapSource.wgsToMapPos(endPoint.toInternalWgs(), zoom);

            final Rect overlayRect = new Rect();
            overlayRect.left = mapStartPos.getX() / tileSize;
            overlayRect.top = mapStartPos.getY() / tileSize;

            overlayRect.right = mapEndPos.getX() / tileSize;
            overlayRect.bottom = mapEndPos.getY() / tileSize;

            for (int x = overlayRect.left; x <= overlayRect.right; x++) {
                for (int y = overlayRect.top; y <= overlayRect.bottom; y++) {
                    final int tileX = x * tileSize;
                    final int tileY = y * tileSize;

                    urlList.add(mapSource.buildPath(tileX, tileY, zoom));
                }
            }
        }
        return urlList;
    }

    // protected methods ----------

    protected AppLocationProvider getActiveLocationProvider() {
        return getBurnApplication().getActiveLocationProvider();
    }

    protected BurnApplication getBurnApplication() {
        return (BurnApplication) getApplication();
    }

    // inner classes ----------

    /**
     * The Class ActivityHandler.
     */
    private class ActivityHandler extends Handler {

        /** The Constant MESSAGE_MOVE_MAP. */
        private static final int MESSAGE_MOVE_MAP = 0;

        /** The Constant MESSAGE_SAVE_PREF_BOOL. */
        private static final int MESSAGE_SAVE_PREF_BOOL = 1;

        /** The Constant MESSAGE_SAVE_PREF_INT. */
        private static final int MESSAGE_SAVE_PREF_INT = 2;

        /** The Constant MESSAGE_SAVE_PREF_LONG. */
        private static final int MESSAGE_SAVE_PREF_LONG = 3;

        /** The Constant MESSAGE_SAVE_PREF_FLOAT. */
        private static final int MESSAGE_SAVE_PREF_FLOAT = 4;

        /** The Constant MESSAGE_SAVE_PREF_STRING. */
        private static final int MESSAGE_SAVE_PREF_STRING = 5;

        /** The Constant MESSAGE_DO_GRACEFUL_FINISH. */
        private static final int MESSAGE_DO_GRACEFUL_FINISH = 6;

        /** The Constant MESSAGE_TIMEOUT_CLOSING_RESOURCES. */
        private static final int MESSAGE_TIMEOUT_CLOSING_RESOURCES = 7;

        /** The Constant MESSAGE_INIT_FILE_SYSTEM_DIR. */
        private static final int MESSAGE_INIT_FILE_SYSTEM_DIR = 8;

        /** The Constant MESSAGE_INIT_LOCATION_SOURCE_N_MAP_LISTENER. */
        private static final int MESSAGE_INIT_LOCATION_SOURCE_N_MAP_LISTENER = 9;

        /** The Constant MESSAGE_FREE_MAP_COMPONENT_MEMORY. */
        private static final int MESSAGE_FREE_MAP_COMPONENT_MEMORY = 10;

        /** The Constant MESSAGE_REPAINT_MAP_COMPONENT. */
        private static final int MESSAGE_REPAINT_MAP_COMPONENT = 11;

        private static final int MESSAGE_START_DOWNLOAD = 12;

        private static final int MESSAGE_DOWNLOAD_PROGRESS = 13;

        private static final int MESSAGE_DOWNLOAD_ERROR = 14;

        private static final int MESSAGE_END_DOWNLOAD = 15;

        private int mLastCount = 0;

        private long mStartTime = 0;

        /*
         * (non-Javadoc)
         * 
         * @see android.os.Handler#handleMessage(android.os.Message)
         */
        @Override
        public void handleMessage(Message msg) {
            try {
                final Bundle bundle = msg.getData();
                switch (msg.what) {
                case MESSAGE_MOVE_MAP:
                    if (bundle != null) {
                        double lat = bundle.getDouble(KEY_LAT);
                        double lon = bundle.getDouble(KEY_LON);
                        mMapComponent.moveMap(new WgsPoint(lon, lat));
                    }
                    break;
                case MESSAGE_SAVE_PREF_BOOL:
                case MESSAGE_SAVE_PREF_INT:
                case MESSAGE_SAVE_PREF_LONG:
                case MESSAGE_SAVE_PREF_FLOAT:
                case MESSAGE_SAVE_PREF_STRING:
                    if (bundle != null) {
                        final SharedPreferences.Editor editor = Globals.sSharedPreferences.edit();

                        final Set<String> keys = bundle.keySet();
                        for (String key : keys) {
                            switch (msg.what) {
                            case MESSAGE_SAVE_PREF_BOOL:
                                editor.putBoolean(key, bundle.getBoolean(key));
                                break;
                            case MESSAGE_SAVE_PREF_INT:
                                editor.putInt(key, bundle.getInt(key));
                                break;
                            case MESSAGE_SAVE_PREF_LONG:
                                editor.putLong(key, bundle.getLong(key));
                                break;
                            case MESSAGE_SAVE_PREF_FLOAT:
                                editor.putFloat(key, bundle.getFloat(key));
                                break;
                            case MESSAGE_SAVE_PREF_STRING:
                                editor.putString(key, bundle.getString(key));
                                break;
                            default:
                                break;
                            }
                        }

                        editor.commit();
                    }
                    break;
                case MESSAGE_TIMEOUT_CLOSING_RESOURCES: {
                    removeMessages(MESSAGE_DO_GRACEFUL_FINISH);
                    removeDialog(DIALOG_CLOSING_RESOURCES);
                    finish();
                }
                    break;
                case MESSAGE_FREE_MAP_COMPONENT_MEMORY: {
                    removeMessages(MESSAGE_TIMEOUT_CLOSING_RESOURCES);
                    sendMessage(obtainMessage(MESSAGE_TIMEOUT_CLOSING_RESOURCES));
                }
                    break;
                case MESSAGE_INIT_FILE_SYSTEM_DIR: {
                    if (Utils.isSDCardAvailable()) {
                        try {
                            final File file = new File(MapUtils.getSDCardDestinationDir());
                            file.mkdirs();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                    break;
                case MESSAGE_INIT_LOCATION_SOURCE_N_MAP_LISTENER: {
                    setupLocationSource();
                    setupMapListener();
                }
                    break;
                case MESSAGE_REPAINT_MAP_COMPONENT: {
                    if (mMapView != null) {
                        mMapView.needRepaint(true, true);
                    }
                }
                    break;
                case MESSAGE_START_DOWNLOAD: {
                    mLastCount = 0;
                    mStartTime = System.currentTimeMillis();

                    if (mDefaultHttpClient1 == null) {
                        mDefaultHttpClient1 = getHttpClient();
                    }

                    FastAndroidFileSystemCache cache = getNewSavedMapCache();
                    MapDownloadListerner mapDownloadListerner = new MapDownloadListernerImpl();

                    mFileCacheWriter = new FileCacheWriter(cache, mapDownloadListerner);
                    mFileCacheWriter.start();

                    LinkedList<String> urlList = getUrlList();
                    mTotalTileCount = urlList.size();
                    for (int i = 0, len = mMapDownloadThreads.length; i < len; i++) {
                        MapDownloadThread t = new MapDownloadThread(getBaseContext(), cache, mapDownloadListerner,
                                mDefaultHttpClient1, i + 1, mFileCacheWriter, urlList);
                        mMapDownloadThreads[i] = t;
                        t.start();
                    }
                }
                    break;
                case MESSAGE_DOWNLOAD_PROGRESS:
                    ++mLastCount;
                    if (mLastCount % 1000 == 0) {
                        long t = System.currentTimeMillis();
                        Log.d(TAG, "Downloaded 1000 files in " + ((t - mStartTime) / 1000f) + " seconds");
                        mStartTime = t;
                    }
                    mProgressDialog.setProgress(mLastCount);
                    mProgressDialog.setMax(mTotalTileCount);
                    break;
                case MESSAGE_DOWNLOAD_ERROR:
                    for (int i = 0, len = mMapDownloadThreads.length; i < len; i++) {
                        MapDownloadThread t = mMapDownloadThreads[i];
                        if (t != null) {
                            t.cancel();
                        }
                        mMapDownloadThreads[i] = null;
                    }

                    if (mFileCacheWriter != null) {
                        mFileCacheWriter.stopRunning();
                        mFileCacheWriter = null;
                    }

                    removeDialog(DIALOG_DOWNLOAD_PROGRESS);
                    switch (bundle.getInt(KEY_ID)) {
                    case STATUS_FILE_ERROR:
                        mErrorMsgId = R.string.error_download_file_error;
                        break;
                    case STATUS_NETWORK_ERROR:
                        mErrorMsgId = R.string.error_download_network_error;
                        break;
                    case STATUS_SERVER_ERROR:
                        mErrorMsgId = R.string.error_download_server_error;
                        break;
                    default:
                        mErrorMsgId = R.string.error_download_unknown_error;
                        break;
                    }
                    showDialog(DIALOG_DOWNLOAD_ERROR);
                    break;
                case MESSAGE_END_DOWNLOAD:
                    boolean isAnyAlive = false;
                    for (MapDownloadThread t : mMapDownloadThreads) {
                        if (t != null) {
                            if (t.isAlive()) {
                                isAnyAlive = true;
                                break;
                            }
                        }
                    }
                    if (!isAnyAlive) {
                        if (mFileCacheWriter != null) {
                            mFileCacheWriter.stopRunning();
                            mFileCacheWriter = null;
                        }

                        removeDialog(DIALOG_DOWNLOAD_PROGRESS);
                    }
                    break;
                default:
                    break;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    private class MapDownloadListernerImpl implements MapDownloadListerner {

        @Override
        public void notifyProgress() {
            final Message msg = mActivityHandler.obtainMessage(ActivityHandler.MESSAGE_DOWNLOAD_PROGRESS);
            mActivityHandler.sendMessageDelayed(msg, 100);
        }

        @Override
        public void notifyError(int status) {
            final Message msg = mActivityHandler.obtainMessage(ActivityHandler.MESSAGE_DOWNLOAD_ERROR);

            Bundle data = new Bundle();
            data.putInt(KEY_ID, status);

            msg.setData(data);
            mActivityHandler.sendMessageDelayed(msg, 100);
        }

        @Override
        public void notifyComplete() {
            mActivityHandler
                    .sendMessageDelayed(mActivityHandler.obtainMessage(ActivityHandler.MESSAGE_END_DOWNLOAD), 100);
            final Message msg = mActivityHandler.obtainMessage(ActivityHandler.MESSAGE_SAVE_PREF_BOOL);

            Bundle data = new Bundle();
            data.putBoolean(PREF_KEY_MAP_DOWNLOADED, true);

            msg.setData(data);
            mActivityHandler.sendMessageDelayed(msg, 100);
        }

        @Override
        public void notifyCancel() {
            mActivityHandler
                    .sendMessageDelayed(mActivityHandler.obtainMessage(ActivityHandler.MESSAGE_END_DOWNLOAD), 100);
        }
    }

    /**
     * The Class FileCacheWriter.
     */
    static public class FileCacheWriter extends Thread {

        /** The cache. */
        final private FastAndroidFileSystemCache mCache;

        /** The stack. */
        private List<FileCacheInfo> mStack = Collections.synchronizedList(new ArrayList<FileCacheInfo>());

        /** The keep running. */
        private boolean mKeepRunning = true;

        /** The lock. */
        private Object mLock = new Object();

        private MapDownloadListerner mMapDownloadListerner;

        /** The error. */
        public boolean mError;

        /** The exception. */
        public Exception mException;

        /**
         * The Class FileCacheInfo.
         */
        static public class FileCacheInfo {

            /** The url. */
            public String mUrl;

            /** The data. */
            public byte[] mData;
        }

        /**
         * Instantiates a new file cache writer.
         * 
         * @param cache
         *            the cache
         */
        FileCacheWriter(FastAndroidFileSystemCache cache, MapDownloadListerner mapDownloadListerner) {
            mCache = cache;
            mMapDownloadListerner = mapDownloadListerner;
        }

        /**
         * Push.
         * 
         * @param data
         *            the data
         */
        synchronized public void push(FileCacheInfo data) {
            while (mStack.size() >= 300) {
                try {
                    Thread.currentThread().sleep(50);
                } catch (Exception e) {

                }
            }
            mStack.add(data);

            try {
                synchronized (mLock) {
                    mLock.notify();
                }
            } catch (Exception e) {
                Log.e(TAG, "Thread. Error while notifying.", e);
            }
        }

        /**
         * Stop running.
         */
        public void stopRunning() {
            mKeepRunning = false;
            try {
                synchronized (mLock) {
                    mLock.notify();
                }
            } catch (Exception e) {
                Log.e(TAG, "Thread. Error while notifying.", e);
            }
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Thread#run()
         */
        public void run() {
            long startTime = System.currentTimeMillis();
            while (mKeepRunning || !mStack.isEmpty()) {
                // Log.i(TAG, "writer running.. " + mStack.size());
                if (!mStack.isEmpty()) {
                    try {
                        final FileCacheInfo info = mStack.get(0);
                        mStack.remove(info);

                        mCache.cache(info.mUrl, info.mData, Cache.CACHE_LEVEL_PERSISTENT);
                        notifyChange();
                    } catch (Exception e) {
                        mError = true;
                        mException = e;
                        Log.e(TAG, "Thread. Error in writting file.", e);
                    }
                } else {
                    try {
                        // Log.i(TAG, "writer waiting.. " + mStack.size());
                        synchronized (mLock) {
                            mLock.wait();
                        }
                    } catch (Exception e) {
                        Log.e(TAG, "Thread. Error while waiting.", e);
                    }
                }
            }
            long t = System.currentTimeMillis();
            Log.i(TAG,
                    "Thread. FileCacheWriter thread ended. Total time " + ((t - startTime) / 1000f) + " seconds");
        }

        /**
         * Notify change.
         * 
         * @param id
         *            the id
         * @param fileCount
         *            the file count
         */
        private void notifyChange() {
            mMapDownloadListerner.notifyProgress();
        }
    }

    // getters and setters

    /**
     * Gets the map component.
     * 
     * @return the map component
     */
    public BasicMapComponent getMapComponent() {
        return mMapComponent;
    }

    /**
     * Gets the map view.
     * 
     * @return the map view
     */
    public MapView getMapView() {
        return mMapView;
    }
}