/**
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.android;
import java.io.DataOutputStream;
import java.io.IOException;
import com.rareventure.android.AndroidPreferenceSet.AndroidPreferences;
import com.rareventure.gps2.GTG;
import com.rareventure.gps2.GTG.GTGEvent;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
public class GpsReader implements DataReader
{
private Object lock = new Object();
private GpsProcessor gpsProcessor;
private GpsDataBuffer gpsDataBuffer;
private ProcessThread processThread;
private LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
//store the location
gpsDataBuffer.lat[gpsDataBuffer.rawReadIndex] = location.getLatitude();
gpsDataBuffer.lon[gpsDataBuffer.rawReadIndex] = location.getLongitude();
gpsDataBuffer.alt[gpsDataBuffer.rawReadIndex] = location.getAltitude();
gpsDataBuffer.timeRead[gpsDataBuffer.rawReadIndex] = System.currentTimeMillis();
synchronized(processThread.lock)
{
gpsDataBuffer.updateReadIndex();
processThread.lock.notify();
}
}
@Override
public void onProviderDisabled(String provider) {
// Log.d(GTG.TAG,"GPS provider disabled: "+provider);
GTG.alert( GTG.GTGEvent.ERROR_GPS_DISABLED);
}
@Override
public void onProviderEnabled(String provider) {
// Log.d(GTG.TAG,"GPS provider enabled: "+provider);
GTG.alert( GTG.GTGEvent.ERROR_GPS_DISABLED, false);
}
@Override
public void onStatusChanged(String provider, int status,
Bundle extras) {
}
};
private LocationManager lm;
private boolean gpsOn;
private Looper looper;
private String tag;
private String providerName;
private DataOutputStream os;
private Context ctx;
public interface GpsProcessor {
void processGpsData(double lon, double lat, double alt, long time);
}
public GpsReader(DataOutputStream os, Context ctx,
GpsProcessor gpsProcessor,
String tag, Looper looper)
{
this.ctx = ctx;
this.os = os;
this.tag = tag;
this.gpsProcessor = gpsProcessor;
this.gpsDataBuffer = new GpsDataBuffer(16);
this.looper = looper;
//TODO 3.2: handle multile levels of accuracy
//basically read from every gps system available
lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setSpeedRequired(false);
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(false);
// criteria.setPowerRequirement(Criteria.POWER_HIGH);
providerName = lm.getBestProvider(criteria, true);
}
@Override
public void setProcessThread(ProcessThread processThread)
{
this.processThread = processThread;
}
@Override
public boolean canProcess() {
return gpsDataBuffer.rawProcessIndex != gpsDataBuffer.rawReadIndex;
}
@Override
public void process() {
gpsProcessor.processGpsData(gpsDataBuffer.lon[gpsDataBuffer.rawProcessIndex],
gpsDataBuffer.lat[gpsDataBuffer.rawProcessIndex],
gpsDataBuffer.alt[gpsDataBuffer.rawProcessIndex],
gpsDataBuffer.timeRead[gpsDataBuffer.rawProcessIndex]);
if(os != null)
writeTestData();
gpsDataBuffer.updateProcessIndex();
}
@Override
public void notifyShutdown() {
turnOff();
}
private void writeTestData() {
synchronized(TestUtil.class)
{
try {
TestUtil.writeMode(os, WriteConstants.MODE_WRITE_GPS_DATA2);
TestUtil.writeDouble("lat",os, gpsDataBuffer.lat[gpsDataBuffer.rawProcessIndex]);
TestUtil.writeDouble("lon",os, gpsDataBuffer.lon[gpsDataBuffer.rawProcessIndex]);
TestUtil.writeDouble("alt",os, gpsDataBuffer.alt[gpsDataBuffer.rawProcessIndex]);
TestUtil.writeLong("time",os, gpsDataBuffer.timeRead[gpsDataBuffer.rawProcessIndex]);
}
catch(IOException e)
{
e.printStackTrace();
throw new IllegalStateException(e); //punt but not a todo because this is test code
}
}
}
public void turnOn() {
synchronized(lock)
{
if(!lm.isProviderEnabled( LocationManager.GPS_PROVIDER))
{
GTG.alert( GTGEvent.ERROR_GPS_DISABLED);
return;
}
if(gpsOn)
return; //already on
gpsOn = true;
lm.requestLocationUpdates(providerName, prefs.gpsRecurringTimeMs, 0,
locationListener, looper);
}
}
public void turnOff() {
synchronized(lock)
{
if(!gpsOn)
return; //already off
gpsOn = false;
lm.removeUpdates(locationListener);
}
//TODO x1: HACK ADDDS FAKE GPS LOCATION DATA
// Location l = new Location("test");
// l.setAltitude(9999);
// l.setLatitude(1);
// l.setLongitude(1);
// l.setBearing(0);
// this.locationListener.onLocationChanged(l);
}
public Preferences prefs = new Preferences();
public static class Preferences implements AndroidPreferences
{
/**
* The time to set the internal android recurring timer for gps measurements.
*/
public long gpsRecurringTimeMs = 1000 * 60;
}
public boolean isGpsOn() {
synchronized(lock)
{
return gpsOn;
}
}
}