/*
* Copyright (C) 2012 jonas.oreland@gmail.com
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.runnerup.tracker;
import android.Manifest;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.GpsSatellite;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import org.runnerup.util.TickListener;
/**
*
* This is a helper class that is used to determine when the GPS status is good
* enough (isFixed())
*
*/
@TargetApi(Build.VERSION_CODES.FROYO)
public class GpsStatus implements LocationListener,
android.location.GpsStatus.Listener {
static final int HIST_LEN = 3;
boolean mIsFixed = false;
Context context = null;
Location mHistory[] = null;
LocationManager locationManager = null;
TickListener listener = null;
/**
* If we get a location with accurancy <= mFixAccurancy mFixed => true
*/
final float mFixAccurancy = 10;
/**
* If we get fixed satellites >= mFixSatellites mFixed => true
*/
final int mFixSatellites = 2;
/**
* If we get location updates with time difference <= mFixTime mFixed =>
* true
*/
final int mFixTime = 3;
int mKnownSatellites = 0;
int mUsedInLastFixSatellites = 0;
public GpsStatus(Context ctx) {
this.context = ctx;
mHistory = new Location[HIST_LEN];
}
public void start(TickListener listener) {
clear(true);
this.listener = listener;
if (ContextCompat.checkSelfPermission(this.context,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
try {
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
} catch (Exception ex) {
lm = null;
}
if (lm != null) {
locationManager = lm;
locationManager.addGpsStatusListener(this);
}
}
}
public void stop(TickListener listener) {
this.listener = null;
if (locationManager != null) {
locationManager.removeGpsStatusListener(this);
try {
locationManager.removeUpdates(this);
} catch (SecurityException ex) {
//Ignore if user turn off GPS
}
}
locationManager = null;
}
@Override
public void onLocationChanged(Location location) {
System.arraycopy(mHistory, 0, mHistory, 1, HIST_LEN - 1);
mHistory[0] = location;
if (location.hasAccuracy() && location.getAccuracy() < mFixAccurancy) {
mIsFixed = true;
} else if (mHistory[1] != null
&& (location.getTime() - mHistory[1].getTime()) <= (1000 * mFixTime)) {
mIsFixed = true;
} else if (mKnownSatellites >= mFixSatellites) {
mIsFixed = true;
}
if (listener != null)
listener.onTick();
}
@Override
public void onProviderDisabled(String provider) {
if (provider.equalsIgnoreCase("gps")) {
clear(true);
if (listener != null)
listener.onTick();
}
}
@Override
public void onProviderEnabled(String provider) {
if (provider.equalsIgnoreCase("gps")) {
clear(false);
if (listener != null)
listener.onTick();
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
if (provider.equalsIgnoreCase("gps")) {
if (status == LocationProvider.OUT_OF_SERVICE
|| status == LocationProvider.TEMPORARILY_UNAVAILABLE) {
clear(true);
}
if (listener != null)
listener.onTick();
}
}
@Override
public void onGpsStatusChanged(int event) {
if (locationManager == null)
return;
//noinspection MissingPermission
android.location.GpsStatus gpsStatus = locationManager
.getGpsStatus(null);
if (gpsStatus == null)
return;
int cnt0 = 0, cnt1 = 0;
Iterable<GpsSatellite> list = gpsStatus.getSatellites();
for (GpsSatellite satellite : list) {
cnt0++;
if (satellite.usedInFix()) {
cnt1++;
}
}
mKnownSatellites = cnt0;
mUsedInLastFixSatellites = cnt1;
if (listener != null)
listener.onTick();
}
private void clear(boolean resetIsFixed) {
if (resetIsFixed) {
mIsFixed = false;
}
mKnownSatellites = 0;
mUsedInLastFixSatellites = 0;
for (int i = 0; i < HIST_LEN; i++)
mHistory[i] = null;
}
public boolean isLogging() {
return locationManager != null;
}
public boolean isFixed() {
return mIsFixed;
}
public int getSatellitesAvailable() {
return mKnownSatellites;
}
public int getSatellitesFixed() {
return mUsedInLastFixSatellites;
}
public boolean isEnabled() {
LocationManager lm = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
}