From c2f98c526f85ba97dc22b28bc93f7da40df59ca6 Mon Sep 17 00:00:00 2001 From: Ricky Barrette Date: Wed, 17 Sep 2014 20:27:13 -0400 Subject: [PATCH] Updated Location Service to use Google Play Location Service --- .../debug/LocationLibraryConstants.java | 13 ++ .../android/location/GeoUtils.java | 33 ++- .../android/location/LocationService.java | 193 +++++++++++++----- 3 files changed, 183 insertions(+), 56 deletions(-) diff --git a/LocationLib/src/com/TwentyCodes/android/debug/LocationLibraryConstants.java b/LocationLib/src/com/TwentyCodes/android/debug/LocationLibraryConstants.java index f28f819..396d1ea 100644 --- a/LocationLib/src/com/TwentyCodes/android/debug/LocationLibraryConstants.java +++ b/LocationLib/src/com/TwentyCodes/android/debug/LocationLibraryConstants.java @@ -72,6 +72,8 @@ public final class LocationLibraryConstants { public static final String INTENT_EXTRA_LOCATION_CHANGED = LocationManager.KEY_LOCATION_CHANGED; + public static final String INTENT_EXTRA_LOCATION_ATUO = "RockBarrette.action.LocationAuto"; + /** * Used to tell the service how accurate of a location you want reported */ @@ -82,4 +84,15 @@ public final class LocationLibraryConstants { * no data */ public static final long FAIL_SAFE_UPDATE_INVERVAL = AlarmManager.INTERVAL_FIFTEEN_MINUTES; + + // Milliseconds per second + private static final int MILLISECONDS_PER_SECOND = 1000; + // Update frequency in seconds + private static final int UPDATE_INTERVAL_IN_SECONDS = 30; + // Update frequency in milliseconds + public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS; + // The fastest update frequency, in seconds + private static final int FASTEST_INTERVAL_IN_SECONDS = 30; + // A fast frequency ceiling in milliseconds + public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS; } \ No newline at end of file diff --git a/LocationLib/src/com/TwentyCodes/android/location/GeoUtils.java b/LocationLib/src/com/TwentyCodes/android/location/GeoUtils.java index f320a82..e272d71 100644 --- a/LocationLib/src/com/TwentyCodes/android/location/GeoUtils.java +++ b/LocationLib/src/com/TwentyCodes/android/location/GeoUtils.java @@ -133,9 +133,7 @@ public class GeoUtils { * * we are solving this equation for lon2Rad * - * lon2Rad = - * lon1Rad+acos(cos(meters/6371)sec(lat1Rad)sec(lat2Rad)-tan(lat1Rad - * )tan(lat2Rad)) + * lon2Rad = lon1Rad+acos(cos(meters/6371)sec(lat1Rad)sec(lat2Rad)-tan(lat1Rad)tan(lat2Rad)) * * NOTE: sec(x) = 1/cos(x) * @@ -148,10 +146,35 @@ public class GeoUtils { * device, and the distanceKm() from google and has been proven to be * damn close */ - final double lon2Rad = lon1Rad + Math.acos(Math.cos(distance / 6371) * (1 / Math.cos(lat1Rad)) * (1 / Math.cos(lat1Rad)) - Math.tan(lat1Rad) * Math.tan(lat1Rad)); + final double lon2Rad = lon1Rad + Math.acos(Math.cos(distance / 6371) * sec(lat1Rad) * sec(lat1Rad) - Math.tan(lat1Rad) * Math.tan(lat1Rad)); // return a LatLng that is x meters away from the LatLng supplied - return new LatLng(point.latitude, (int) (Math.toDegrees(lon2Rad) * 1e6)); + return new LatLng(point.latitude, Math.toDegrees(lon2Rad)); + } + + public static LatLng distanceFrom(final LatLng point, final double distance, final float bearing) { + final double dist = distance / 6371; + final double brng = Math.toRadians(bearing); + + final double lat1 = Math.toRadians(point.latitude); + final double lon1 = Math.toRadians(point.longitude); + + final double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) + Math.cos(lat1) * Math.sin(dist) * Math.cos(brng)); + + final double lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(lat1), Math.cos(dist) - Math.sin(lat1) * Math.sin(lat2)); + +// if (isNaN(lat2) || isNaN(lon2)) +// return null; + return new LatLng(Math.toDegrees(lat2), Math.toDegrees(lon2)); + } + + /** + * compute secant + * @param theta angle in radians + * @return secant of theta. + */ + public static double sec ( double theta ){ + return 1.0 / Math.cos( theta ); } /** diff --git a/LocationLib/src/com/TwentyCodes/android/location/LocationService.java b/LocationLib/src/com/TwentyCodes/android/location/LocationService.java index 542fd15..c665088 100644 --- a/LocationLib/src/com/TwentyCodes/android/location/LocationService.java +++ b/LocationLib/src/com/TwentyCodes/android/location/LocationService.java @@ -25,16 +25,17 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.location.Location; -import android.location.LocationListener; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.PowerManager; +import android.os.*; import android.os.PowerManager.WakeLock; import android.util.Log; - import com.TwentyCodes.android.debug.Debug; import com.TwentyCodes.android.debug.LocationLibraryConstants; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GooglePlayServicesClient; +import com.google.android.gms.common.GooglePlayServicesUtil; +import com.google.android.gms.location.LocationClient; +import com.google.android.gms.location.LocationListener; +import com.google.android.gms.location.LocationRequest; /** * This service class will be used broadcast the users location either one time, @@ -42,14 +43,25 @@ import com.TwentyCodes.android.debug.LocationLibraryConstants; * * @author ricky barrette */ -public class LocationService extends Service implements LocationListener { +public class LocationService extends Service implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener { public static final String TAG = "LocationService"; private static final int REQUEST_CODE = 7893749; + private IBinder mBinder; + private LocationClient mLocationClient; + private LocationRequest mLocationRequest; + // Flag that indicates if a request is underway. + private boolean mInProgress; + private Boolean servicesAvailable = false; + private WakeLock mWakeLock; + private Location mLocation; + private int mStartId; + private int mRequiredAccuracy; + private Intent mIntent; /** * a convince method for getting an intent to start the service - * + * * @param context * @return a intent that will start the service * @author ricky barrette @@ -60,7 +72,7 @@ public class LocationService extends Service implements LocationListener { /** * a convince method for stopping the service and removing it's alarm - * + * * @param context * @return a runnable that will stop the service * @author ricky barrette @@ -76,14 +88,6 @@ public class LocationService extends Service implements LocationListener { }; } - private WakeLock mWakeLock; - private Location mLocation; - private int mStartId; - private AndroidGPS mLocationManager; - private int mRequiredAccuracy; - - private Intent mIntent; - /* * this runnable will be qued when the service is created. this will be used * as a fail safe @@ -116,20 +120,6 @@ public class LocationService extends Service implements LocationListener { } } - /** - * (non-Javadoc) - * - * @see android.app.Service#onBind(android.content.Intent) - * @param arg0 - * @return - * @author ricky barrette - */ - @Override - public IBinder onBind(final Intent arg0) { - // UNUSED - return null; - } - /** * called when the service is created. this will initialize the location * manager, and acquire a wakelock (non-Javadoc) @@ -139,7 +129,6 @@ public class LocationService extends Service implements LocationListener { */ @Override public void onCreate() { - mLocationManager = new AndroidGPS(this); final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mWakeLock.acquire(); @@ -150,6 +139,24 @@ public class LocationService extends Service implements LocationListener { */ new Handler().postDelayed(failSafe, LocationLibraryConstants.MAX_LOCATION_SERVICE_RUN_TIME); super.onCreate(); + + mInProgress = false; + // Create the LocationRequest object + mLocationRequest = LocationRequest.create(); + // Use high accuracy + mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); + // Set the update interval to 5 seconds + mLocationRequest.setInterval(LocationLibraryConstants.UPDATE_INTERVAL); + // Set the fastest update interval to 1 second + mLocationRequest.setFastestInterval(LocationLibraryConstants.FASTEST_INTERVAL); + + servicesAvailable = servicesConnected(); + + /* + * Create a new location client, using the enclosing class to + * handle callbacks. + */ + mLocationClient = new LocationClient(this, this, this); } /** @@ -162,7 +169,15 @@ public class LocationService extends Service implements LocationListener { @Override public void onDestroy() { broadcastLocation(); - mLocationManager.disableLocationUpdates(); + + // Turn off the request flag + mInProgress = false; + if(servicesAvailable && mLocationClient != null) { + // Destroy the current location client + mLocationClient.removeLocationUpdates(this); + mLocationClient = null; + } + if (mWakeLock.isHeld()) mWakeLock.release(); } @@ -177,18 +192,6 @@ public class LocationService extends Service implements LocationListener { stopSelf(mStartId); } - @Override - public void onProviderDisabled(final String provider) { - // TODO Auto-generated method stub - - } - - @Override - public void onProviderEnabled(final String provider) { - // TODO Auto-generated method stub - - } - /** * This method is called when startService is called. only used in 2.x * android. @@ -203,13 +206,19 @@ public class LocationService extends Service implements LocationListener { parseIntent(intent); - mLocationManager.enableLocationUpdates(this); - return START_STICKY; - } + super.onStartCommand(intent, flags, startId); - @Override - public void onStatusChanged(final String provider, final int status, final Bundle extras) { - // TODO Auto-generated method stub + if(!servicesAvailable || mLocationClient.isConnected() || mInProgress) + return START_STICKY; + + setUpLocationClientIfNeeded(); + if(!mLocationClient.isConnected() || !mLocationClient.isConnecting() && !mInProgress) + { + mInProgress = true; + mLocationClient.connect(); + } + + return START_STICKY; } /** @@ -228,4 +237,86 @@ public class LocationService extends Service implements LocationListener { mRequiredAccuracy = intent.getIntExtra(LocationLibraryConstants.INTENT_EXTRA_REQUIRED_ACCURACY, LocationLibraryConstants.MINIMUM_REQUIRED_ACCURACY); } } + + public class LocalBinder extends Binder { + public LocationService getServerInstance() { + return LocationService.this; + } + } + + private boolean servicesConnected() { + + // Check that Google Play services is available + int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); + + // If Google Play services is available + if (ConnectionResult.SUCCESS == resultCode) { + + return true; + } else { + + return false; + } + } + + /* + * Create a new location client, using the enclosing class to + * handle callbacks. + */ + private void setUpLocationClientIfNeeded() + { + if(mLocationClient == null) + mLocationClient = new LocationClient(this, this, this); + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + /* + * Called by Location Services when the request to connect the + * client finishes successfully. At this point, you can + * request the current location or start periodic updates + */ + @Override + public void onConnected(Bundle bundle) { + + mLocationClient.requestLocationUpdates(mLocationRequest, this); + } + + /* + * Called by Location Services if the connection to the + * location client drops because of an error. + */ + @Override + public void onDisconnected() { + // Turn off the request flag + mInProgress = false; + mLocationClient.removeLocationUpdates(this); + // Destroy the current location client + mLocationClient = null; + } + + /* + * Called by Location Services if the attempt to + * Location Services fails. + */ + @Override + public void onConnectionFailed(ConnectionResult connectionResult) { + mInProgress = false; + + /* + * Google Play services can resolve some errors it detects. + * If the error has a resolution, try sending an Intent to + * start a Google Play services activity that can resolve + * error. + */ + if (connectionResult.hasResolution()) { + + // If no resolution is available, display an error dialog + } else { + + } + } } \ No newline at end of file