forked from funf-org/funf-core-android
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
updated location probe to use fused provider
- Loading branch information
Showing
1 changed file
with
129 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,21 @@ | ||
/** | ||
* | ||
* Funf: Open Sensing Framework | ||
* Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland. | ||
* Acknowledgments: Alan Gardner | ||
* Contact: [email protected] | ||
* | ||
* This file is part of Funf. | ||
* | ||
* Funf is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Lesser General Public License as | ||
* published by the Free Software Foundation, either version 3 of | ||
* the License, or (at your option) any later version. | ||
* | ||
* Funf 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 Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with Funf. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
package edu.mit.media.funf.probe.builtin; | ||
|
||
import java.lang.reflect.Field; | ||
|
||
import android.content.Context; | ||
import android.location.Location; | ||
import android.location.LocationListener; | ||
import android.location.LocationManager; | ||
import android.os.Bundle; | ||
|
||
import com.google.android.gms.common.ConnectionResult; | ||
import com.google.android.gms.common.api.GoogleApiClient; | ||
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; | ||
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; | ||
import com.google.android.gms.location.LocationListener; | ||
import com.google.android.gms.location.LocationRequest; | ||
import com.google.android.gms.location.LocationServices; | ||
import com.google.gson.ExclusionStrategy; | ||
import com.google.gson.FieldAttributes; | ||
import com.google.gson.Gson; | ||
import com.google.gson.JsonObject; | ||
|
||
import android.location.Location; | ||
import android.os.Bundle; | ||
import android.util.Log; | ||
|
||
import edu.mit.media.funf.Schedule; | ||
import edu.mit.media.funf.config.Configurable; | ||
import edu.mit.media.funf.probe.Probe.Base; | ||
|
@@ -46,146 +26,160 @@ | |
import edu.mit.media.funf.probe.Probe.RequiredPermissions; | ||
import edu.mit.media.funf.probe.builtin.ProbeKeys.LocationKeys; | ||
import edu.mit.media.funf.time.DecimalTimeUnit; | ||
import edu.mit.media.funf.util.LogUtil; | ||
|
||
/** | ||
* Sends all location points gathered by system. | ||
* @author alangardner | ||
* | ||
* Updated location probe using fused location provider. | ||
* Supports both active schedule and passive mode. | ||
* @author [email protected] | ||
*/ | ||
@DisplayName("Continuous Location Probe") | ||
@DisplayName("Location Probe") | ||
@RequiredPermissions({android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) | ||
@RequiredFeatures("android.hardware.location") | ||
@Schedule.DefaultSchedule(interval=1800) | ||
public class LocationProbe extends Base implements ContinuousProbe, PassiveProbe, LocationKeys { | ||
public class LocationProbe extends Base implements ContinuousProbe, PassiveProbe, LocationKeys, | ||
ConnectionCallbacks, OnConnectionFailedListener { | ||
|
||
@Configurable | ||
private boolean useGps = true; | ||
|
||
@Configurable | ||
private boolean useNetwork = true; | ||
|
||
private Integer passiveInterval = 60; | ||
|
||
@Configurable | ||
private boolean useCache = true; | ||
private Integer activeInterval = 5; | ||
|
||
private Gson gson; | ||
private LocationManager mLocationManager; | ||
private LocationListener listener = new ProbeLocationListener(); | ||
private LocationListener passiveListener = new ProbeLocationListener(); | ||
|
||
|
||
private LocationRequest mLocationRequest; | ||
private LocationRequest mLocationRequestPassive; | ||
private GoogleApiClient mGoogleApiClient; | ||
private ProbeLocationListener listener = new ProbeLocationListener(); | ||
private ProbeLocationListener passiveListener = new ProbeLocationListener(); | ||
|
||
private boolean toStartActiveMode = false; | ||
|
||
@Override | ||
protected void onEnable() { | ||
super.onEnable(); | ||
gson = getGsonBuilder().addSerializationExclusionStrategy(new LocationExclusionStrategy()).create(); | ||
mLocationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE); | ||
String passiveProvider = getPassiveProvider(); | ||
if (passiveProvider != null) { | ||
mLocationManager.requestLocationUpdates(getPassiveProvider(), 0, 0, passiveListener); | ||
if (mGoogleApiClient == null) { | ||
mGoogleApiClient = new GoogleApiClient.Builder(getContext()) | ||
.addConnectionCallbacks(this) | ||
.addOnConnectionFailedListener(this) | ||
.addApi(LocationServices.API) | ||
.build(); | ||
} | ||
|
||
toStartActiveMode = false; | ||
|
||
mLocationRequestPassive = new LocationRequest(); | ||
mLocationRequestPassive.setInterval(passiveInterval*1000); | ||
mLocationRequestPassive.setFastestInterval(passiveInterval*1000); | ||
mLocationRequestPassive.setPriority(LocationRequest.PRIORITY_NO_POWER); | ||
|
||
mGoogleApiClient.connect(); | ||
|
||
} | ||
|
||
@Override | ||
protected void onStart() { | ||
super.onStart(); | ||
if (useGps) { | ||
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); | ||
private class LocationExclusionStrategy implements ExclusionStrategy { | ||
|
||
public boolean shouldSkipClass(Class<?> cls) { | ||
return false; | ||
} | ||
if (useNetwork) { | ||
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, listener); | ||
|
||
public boolean shouldSkipField(FieldAttributes f) { | ||
String name = f.getName(); | ||
return (f.getDeclaringClass() == Location.class && | ||
(name.equals("mResults") | ||
|| name.equals("mDistance") | ||
|| name.equals("mInitialBearing") | ||
|| name.equals("mLat1") | ||
|| name.equals("mLat2") | ||
|| name.equals("mLon1") | ||
|| name.equals("mLon2") | ||
|| name.equals("mLon2") | ||
|| name.equals("mHasSpeed") | ||
|| name.equals("mHasAccuracy") | ||
|| name.equals("mHasAltitude") | ||
|| name.equals("mHasBearing") | ||
|| name.equals("mHasSpeed") | ||
|| name.equals("mElapsedRealtimeNanos") | ||
) | ||
); | ||
} | ||
if (useCache) { | ||
listener.onLocationChanged(mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)); | ||
listener.onLocationChanged(mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)); | ||
|
||
} | ||
|
||
private class ProbeLocationListener implements LocationListener { | ||
|
||
@Override | ||
public void onLocationChanged(Location location) { | ||
if (location != null) { | ||
JsonObject data = gson.toJsonTree(location).getAsJsonObject(); | ||
data.addProperty(TIMESTAMP, DecimalTimeUnit.MILLISECONDS.toSeconds(data.get("mTime").getAsBigDecimal())); | ||
sendData(gson.toJsonTree(location).getAsJsonObject()); | ||
} | ||
|
||
} | ||
if (!useGps && ! useNetwork) { | ||
stop(); | ||
} | ||
|
||
@Override | ||
protected void onStart() { | ||
super.onStart(); | ||
|
||
toStartActiveMode = true; | ||
|
||
mLocationRequest = new LocationRequest(); | ||
mLocationRequest.setInterval(activeInterval * 1000); | ||
mLocationRequest.setFastestInterval(activeInterval * 1000); | ||
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); | ||
|
||
if (mGoogleApiClient.isConnected()) { | ||
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, | ||
listener); | ||
toStartActiveMode = false; | ||
} else { | ||
mGoogleApiClient.connect(); | ||
} | ||
|
||
|
||
|
||
} | ||
|
||
@Override | ||
protected void onStop() { | ||
super.onStop(); | ||
mLocationManager.removeUpdates(listener); | ||
toStartActiveMode = false; | ||
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, listener); | ||
} | ||
|
||
@Override | ||
protected void onDisable() { | ||
super.onDisable(); | ||
mLocationManager.removeUpdates(passiveListener); | ||
} | ||
|
||
private class ProbeLocationListener implements LocationListener{ | ||
|
||
@Override | ||
public void onLocationChanged(Location location) { | ||
if (location != null) { | ||
String provider = location.getProvider(); | ||
if (provider == null | ||
|| (useGps && LocationManager.GPS_PROVIDER.equals(provider)) | ||
|| (useNetwork && LocationManager.NETWORK_PROVIDER.equals(provider))) { | ||
JsonObject data = gson.toJsonTree(location).getAsJsonObject(); | ||
data.addProperty(TIMESTAMP, DecimalTimeUnit.MILLISECONDS.toSeconds(data.get("mTime").getAsBigDecimal())); | ||
sendData(gson.toJsonTree(location).getAsJsonObject()); | ||
} | ||
} | ||
if (!mGoogleApiClient.isConnected()) { | ||
return; | ||
} | ||
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, passiveListener); | ||
mGoogleApiClient.disconnect(); | ||
} | ||
|
||
@Override | ||
public void onStatusChanged(String provider, int status, Bundle extras) { | ||
@Override | ||
public void onConnected(Bundle bundle) { | ||
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, | ||
mLocationRequestPassive, passiveListener); | ||
if (toStartActiveMode) { | ||
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, | ||
listener); | ||
toStartActiveMode = false; | ||
} | ||
} | ||
|
||
@Override | ||
public void onProviderEnabled(String provider) { | ||
} | ||
@Override | ||
public void onConnectionSuspended(int i) { | ||
|
||
@Override | ||
public void onProviderDisabled(String provider) { | ||
} | ||
|
||
} | ||
|
||
public class LocationExclusionStrategy implements ExclusionStrategy { | ||
|
||
public boolean shouldSkipClass(Class<?> cls) { | ||
return false; | ||
} | ||
|
||
public boolean shouldSkipField(FieldAttributes f) { | ||
String name = f.getName(); | ||
return (f.getDeclaringClass() == Location.class && | ||
(name.equals("mResults") | ||
|| name.equals("mDistance") | ||
|| name.equals("mInitialBearing") | ||
|| name.equals("mLat1") | ||
|| name.equals("mLat2") | ||
|| name.equals("mLon1") | ||
|| name.equals("mLon2") | ||
|| name.equals("mLon2") | ||
|| name.equals("mHasSpeed") | ||
|| name.equals("mHasAccuracy") | ||
|| name.equals("mHasAltitude") | ||
|| name.equals("mHasBearing") | ||
|| name.equals("mHasSpeed") | ||
|| name.equals("mElapsedRealtimeNanos") | ||
) | ||
); | ||
} | ||
|
||
} | ||
|
||
/** | ||
* Supporting API level 7 which does not have PASSIVE provider | ||
* @return | ||
*/ | ||
private String getPassiveProvider() { | ||
try { | ||
Field passiveProviderField = LocationManager.class.getDeclaredField("PASSIVE_PROVIDER"); | ||
return (String)passiveProviderField.get(null); | ||
} catch (SecurityException e) { | ||
} catch (NoSuchFieldException e) { | ||
} catch (IllegalArgumentException e) { | ||
} catch (IllegalAccessException e) { | ||
} | ||
return null; | ||
|
||
@Override | ||
public void onConnectionFailed(ConnectionResult connectionResult) { | ||
|
||
} | ||
|
||
} |