com.rareventure.gps2.reviewer.map.GpsLocationOverlay.java Source code

Java tutorial

Introduction

Here is the source code for com.rareventure.gps2.reviewer.map.GpsLocationOverlay.java

Source

/** 
Copyright 2015 Tim Engler, Rareventure LLC
    
This file is part of Tiny Travel Tracker.
    
Tiny Travel Tracker is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
Tiny Travel Tracker is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with Tiny Travel Tracker.  If not, see <http://www.gnu.org/licenses/>.
    
*/
package com.rareventure.gps2.reviewer.map;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Toast;

import com.mapzen.tangram.LngLat;
import com.mapzen.tangram.MapController;
import com.mapzen.tangram.MapData;
import com.rareventure.gps2.R;
import com.rareventure.android.Util;
import com.rareventure.android.AndroidPreferenceSet.AndroidPreferences;
import com.rareventure.gps2.database.cache.AreaPanel;
import com.rareventure.gps2.database.cache.AreaPanelCache;
import com.rareventure.gps2.database.cache.AreaPanelSpaceTimeBox;

//TODO 3: make this use gps service to determine the current location
public class GpsLocationOverlay implements GpsOverlay, LocationListener {
    private OsmMapGpsTrailerReviewerMapActivity activity;
    private long lastLocationReadingMs = 0;
    private float lastLocationAccuracy;

    private MapController mapController;
    private MapData mapData;
    private LngLat lastLoc = new LngLat();
    private Map<String, String> props = new HashMap<>();

    public GpsLocationOverlay(OsmMapGpsTrailerReviewerMapActivity activity) {
        this.activity = activity;

        //TODO 2.5: gps reader should piggyback when any other program starts
        //reading from the gps (if possible)

        //TODO 4: gps reader should start up all location updates, and continue
        // to run until it gets the best location (from the most accurate provider)
        // turning off each provider as soon as it gets a location

        //      locationAnim = AnimationUtils.loadAnimation(activity, R.drawable.location_anim);
    }

    public LngLat getLastLoc() {
        return lastLoc;
    }

    public double getAbsPixelX2(long zoom8BitPrec) {
        double apX = AreaPanel.convertLonToXDouble(lastLoc.longitude);

        return AreaPanel.convertApXToAbsPixelX2(apX, zoom8BitPrec);
    }

    @Override
    public void onLocationChanged(Location location) {
        //if this location is a poorer reading 
        // or the location provider doesn't keep track of accuracy, in case we'll
        // just say screw it and replace it
        //TODO 3: is this the right thing to do?
        if (location.getAccuracy() > lastLocationAccuracy || lastLocationAccuracy == 0) {
            //ignore it if it's within a certain threshold of time
            if (location.getTime() - lastLocationReadingMs <= prefs.maxTimeToKeepBetterAccuracyLocationReadingMs)
                return;
            if (location.getLatitude() == 0 && location.getLongitude() == 0)
                return;
        }

        boolean notifyWeHaveGps = lastLocationReadingMs == 0;

        //NOTE: this may return 0 is the gps provider doesn't keep track of accuracy
        lastLocationAccuracy = location.getAccuracy();
        lastLocationReadingMs = location.getTime();
        lastLoc.latitude = location.getLatitude();
        lastLoc.longitude = location.getLongitude();

        //TODO 2.1 turn off location known when unknown
        if (notifyWeHaveGps) {
            activity.notifyLocationKnown();
            notifyWeHaveGps = false;
        }

        resetMapData();
    }

    private void resetMapData() {
        synchronized (this) {
            if (mapData == null)
                return;
        }
        //props.clear();
        //props.put("rotation", Double.toString(lastCompass));

        //TODO FIXME 1
        //mapData.beginChangeBlock();
        mapData.clear();
        mapData.addPoint(lastLoc, props);
        //mapData.endChangeBlock();

        mapController.requestRender();
    }

    @Override
    public void onProviderDisabled(String provider) {
        //TODO 3: handle this gps location stuff better
    }

    @Override
    public void onProviderEnabled(String provider) {
        //TODO 3: handle this gps location stuff better
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        //TODO 3: handle this gps location stuff better
    }

    private Preferences prefs = new Preferences();
    private float lastCompass;
    private long lastCompassReadingMs;

    @Override
    public void notifyScreenChanged(AreaPanelSpaceTimeBox newStBox) {

    }

    @Override
    public boolean onTap(float x, float y) {
        return false;
    }

    @Override
    public boolean onLongPressMove(float startX, float startY, float endX, float endY) {
        return false;
    }

    @Override
    public boolean onLongPressEnd(float startX, float startY, float endX, float endY) {
        return false;
    }

    @Override
    public void onPause() {
        activity.removeLocationUpdates(this);
    }

    @Override
    public void onResume() {

        activity.setupLocationUpdates(this);
    }

    @Override
    public void startTask(MapController mapController) {
        synchronized (this) {
            this.mapController = mapController;
            mapData = mapController.addDataLayer("mz_current_location");
        }
    }

    public static class Preferences implements AndroidPreferences {

        /**
         * When polling the gps devices, we may get a poorer accuracy reading
         * after a reading with better accuracy. In this case, if the poorer
         * accuracy reading happens within the time threshold specified here
         * (as compared to the more accurate one, we keep the more accurate one)
         */
        public int maxTimeToKeepBetterAccuracyLocationReadingMs = 30 * 1000;
        public float minChangeForRedraw = (float) (5 * Math.PI / 180);
        public int minTimeForRedrawMs = 2000;
    }

}