Hey everybody,
I am writing an app that uses geolocation to track a user while he is walking from point A to point B. Here is my code so far:
public class LocationTest extends Activity {
private static final String[] S = { "out of service", "temporarily unavailable", "available" };
ArrayList<Location> list = new ArrayList<Location>();
private TextView output;
private String best;
LocationListener locationListener;
LocationManager mgr;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
output = (TextView) findViewById(R.id.output);
mgr = (LocationManager) getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();
best = mgr.getBestProvider(criteria, true);
log("\nBest provider is: " + best);
locationListener = new LocationListener(){
public void onLocationChanged(Location location){
dumpLocation(location);
list.add(location);
}
public void onStatusChanged(String provider, int status, Bundle extras){
log("\nProvider status changed: " + provider + ", status=" + S[status]);
}
public void onProviderEnabled(String provider){
log("\nProvider enabled: " + provider);
}
public void onProviderDisabled(String provider){
log("\nProvider disabled: " + provider);
}
};
}
#Override
protected void onResume(){
super.onResume();
mgr.requestLocationUpdates(best, 120000, 50, locationListener);
}
#Override
protected void onPause(){
super.onPause();
mgr.removeUpdates(locationListener);
log_gen(list);
}
The app currently displays longitude and latitude whenever new fix is obtained. However, the tracking only works when the Activity is displayed on the screen and as soon as the user quits the app the tracking stops. What I want my app to do is keep tracking the user in the background even if he quits the app. Whenever he re-opens an app few minutes later, for example, all the coordinates captured in the background should be displayed on the screen.
From what I researched so far, there are two ways one can go about it: either use a background service to do the tracking or use
requestLocationUpdates (String provider, long minTime, float minDistance, PendingIntent intent)
in combination with BroadcastReceiver to continue getting location updates even if the user quits the app. If I am understanding correct, the second method would continue running in the background. Can someone please show to me in code how to implement BroadcastReceiver with the alternate version of requestLocationUpdates
Many thanks in advance.
Using the below code you can get the periodic location updates well if are concerned for the continuously running service you can customise the interval for getting the location updates also you would need to integrate the google play services in you app in order the following code to work
public class BackgroundLocationService extends Service implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {
IBinder mBinder = new LocalBinder();
private LocationClient mLocationClient;
private LocationRequest mLocationRequest;
// Flag that indicates if a request is underway.
private boolean mInProgress;
private static final String TAG = BackgroundLocationService.class
.getSimpleName();
private Boolean servicesAvailable = false;
public class LocalBinder extends Binder {
public BackgroundLocationService getServerInstance() {
return BackgroundLocationService.this;
}
}
#Override
public void onCreate() {
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(Constants.UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(Constants.FASTEST_INTERVAL);
servicesAvailable = servicesConnected();
/*
* Create a new location client, using the enclosing class to handle
* callbacks.
*/
mLocationClient = new LocationClient(this, this, 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;
}
}
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (!servicesAvailable || mLocationClient.isConnected() || mInProgress)
return START_STICKY;
setUpLocationClientIfNeeded();
if (!mLocationClient.isConnected() || !mLocationClient.isConnecting()
&& !mInProgress) {
mInProgress = true;
mLocationClient.connect();
}
return START_STICKY;
}
/*
* Create a new location client, using the enclosing class to handle
* callbacks.
*/
private void setUpLocationClientIfNeeded() {
if (mLocationClient == null)
mLocationClient = new LocationClient(this, this, this);
}
// Define the callback method that receives location updates
#Override
public void onLocationChanged(final Location location) {
// Report to the UI that the location was updated
String msg = Double.toString(location.getLatitude()) + ","
+ Double.toString(location.getLongitude());
Log.d("debug", msg);
if (location != null) {
// location has the latitude and longitude
}
// Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public String getTime() {
SimpleDateFormat mDateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.US);
return mDateFormat.format(new Date());
}
#Override
public void onDestroy() {
// Turn off the request flag
mInProgress = false;
if (servicesAvailable && mLocationClient != null) {
mLocationClient.removeLocationUpdates(this);
// Destroy the current location client
mLocationClient = null;
}
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new
// Date()) + ": Disconnected. Please re-connect.",
// Toast.LENGTH_SHORT).show();
super.onDestroy();
}
/*
* 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) {
// Request location updates using static settings
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;
// Destroy the current location client
mLocationClient = null;
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new
// Date()) + ": Disconnected. Please re-connect.",
// Toast.LENGTH_SHORT).show();
}
/*
* 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 {
}
}
For integrating google play services please refer here
Related
Background location update using Google Play Services...
Successfully have location updates every 5 minutes in the background.
But, perhaps not surprisingly, if the device is rebooted then the updates stop.
Is it possible to have background location updates survive a phone reboot... and if so, how?
Here is present code in case that helps:
import android.os.Bundle;
import java.util.ArrayList;
public class GPSTracker extends Service implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener {
protected static final String TAG = "Location...";
private Context mContext = this;
/**
* Tracks the status of the location updates request.
*/
public static Boolean mRequestingLocationUpdates;
/**
* Time when the location was updated represented as a String.
*/
protected String mLastUpdateTime;
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mGoogleApiClient;
/**
* Stores parameters for requests to the FusedLocationProviderApi.
*/
protected LocationRequest mLocationRequest;
/**
* Represents a geographical location.
*/
protected Location mCurrentLocation;
public static boolean isEnded = false;
#Override
public void onCreate() {
super.onCreate();
buildGoogleApiClient();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("LOC", "Service init...");
isEnded = false;
mRequestingLocationUpdates = false;
mLastUpdateTime = "";
// buildGoogleApiClient();
if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
startLocationUpdates();
}
return START_STICKY;
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended==");
mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
double latitude = location.getLatitude();
double longitude = location.getLongitude();
StringBuilder stringBuilder = new StringBuilder();
StringBuilder latlong = stringBuilder.append(latitude + "," + longitude);
Calendar cal = Calendar.getInstance();
String zone = TimeZone.getDefault().getDisplayName(false, android.icu.util.TimeZone.SHORT);
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM 'at' h:mm a");
Date date = new Date();
String localtime = (formatter.format(date)).toString();
Date myDate = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
calendar.setTime(myDate);
date = calendar.getTime();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss zz");
dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
String utc = dateFormatter.format(date);
// DateFormat df = DateFormat.getTimeInstance();
// df.setTimeZone(TimeZone.getTimeZone("gmt"));
// String gmtTime = df.format(new Date());
String model = Build.MODEL;
String reqString = Build.VERSION.RELEASE
+ " " + Build.VERSION_CODES.class.getFields()[android.os.Build.VERSION.SDK_INT].getName();
// Date currentTime = Calendar.getInstance().getTime();
// String localtime = currentTime.toString();
PreferencesClass preferencesClass = new PreferencesClass(mContext);
String id = preferencesClass.getFingerPrint();
Data data = null;
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("userId", id);
jsonObject.put("latLon", latlong);
jsonObject.put("timeZone", zone);
jsonObject.put("localTime", localtime);
jsonObject.put("osVersion", reqString);
jsonObject.put("phoneModel", model);
jsonObject.put("utcTime", utc);
data = new Data();
data.setData(jsonObject.toString());
if (data != null) {
if (Utility.isConnectingToInternet(mContext)) {
// boolean isChecked = preferencesClass.getIsChecked();
// if (isChecked){
LocationWebServiceMgr locationWebServiceMgr = new LocationWebServiceMgr();
locationWebServiceMgr.Location(data, new CallBackInterface() {
#Override
public void onResponse(ArrayList<Object> objects, ResponseMetaData responseMetaData) {
Log.d(TAG, "onResponse: Succesfully added the location to server");
// Toast.makeText(getApplicationContext(), "added to server", Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(ResponseMetaData t) {
}
});
// } else {
// Log.d("serverCall", "Location Permission not available ");
// }
} else {
Log.e("serverCall", "Network not available");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
}
/**
* Builds a GoogleApiClient. Uses the {#code #addApi} method to request the
* LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
Log.i(TAG, "Building GoogleApiClient===");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
/**
* Sets up the location request. Android has two location request settings:
* {#code ACCESS_COARSE_LOCATION} and {#code ACCESS_FINE_LOCATION}. These settings control
* the accuracy of the current location. This sample uses ACCESS_FINE_LOCATION, as defined in
* the AndroidManifest.xml.
* <p/>
* When the ACCESS_FINE_LOCATION setting is specified, combined with a fast update
* interval (5 seconds), the Fused Location Provider API returns location updates that are
* accurate to within a few feet.
* <p/>
* These settings are appropriate for mapping applications that show real-time location
* updates.
*/
protected void createLocationRequest() {
mGoogleApiClient.connect();
mLocationRequest = new LocationRequest();
// Sets the desired interval for active location updates. This interval is
// inexact. You may not receive updates at all if no location sources are available, or
// you may receive them slower than requested. You may also receive updates faster than
// requested if other applications are requesting location at a faster interval.
mLocationRequest.setInterval(Constants.UPDATE_INTERVAL_IN_MILLISECONDS);
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
mLocationRequest.setFastestInterval(Constants.FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
// mLocationRequest.setSmallestDisplacement(Constants.DISPLACEMENT);
//mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Requests location updates from the FusedLocationApi.
*/
protected void startLocationUpdates() {
if (!mRequestingLocationUpdates) {
mRequestingLocationUpdates = true;
// The final argument to {#code requestLocationUpdates()} is a LocationListener
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
Log.i(TAG, " startLocationUpdates===");
isEnded = true;
}
}
}
I handled like below it's will helpful for you
RestartReceiver:
public class RestartReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
//started service for update the location of userx
LocationsUpdateRequest.createLocationRequest(context);
//updated in my preference because I need to send data to server if user signed in app only
} catch (Exception e) {
LogUtils.crashlytics(e);
}
}
}
ShutdownReceiver:
public class ShutdownReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
//stop the service when phone is shotdown
LocationsUpdateRequest.getPendingIntent(context).cancel();
//reset flag in preference
} catch (Exception e) {
}
}
}
Manifest:
<receiver android:name=".services.ShutdownReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.QUICKBOOT_POWEROFF" />
</intent-filter>
</receiver>
<receiver android:name=".services.RestartReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
I'm using Nexus 6p with Android 7.1.2. I set the device location accuracy to be HIGH_ACCURACY.
In my code, I have a background service for location update, using the FusedLocation API. As you can see I also set the location request priority to be HIGH_ACCURACY.
Now I've tested it when the device was on my desk without any movements and for most of the time I've got the same LAT/LONG values and sometimes I saw a minor change with the LAT/LONG values even though the device wasn't moving.
So I printed the Location accuracy using the getAccuracy method.
The docs says that if getAccuracy method returns a value >= 68 so it means that there is a high chance that the device (user) is at this location.
So I tried to use this method (another version of the code below) and checked if getAccuracy returns a value >= 68 and then print the location details.
Guess what? it didn't help so much..
The next thing I tried is to rotate the device and I saw that when the device was in landsacpe mode with the back to me, the location lat/long was changed (even though i didn't go anywhere) and the accuracy was increased and in some cases reached to the value of 180.
So I don't understand this:
Why sometimes the device's lat/long values are different even though the device is lying on the desk and doesn't move?
And how the rotations is impact on the location accuracy?!
My Code:
public class LocationUpdateService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener
{
private GoogleApiClient googleApiClient;
private LocationRequest locationRequest;
private boolean playsServiceAvailable;
private String TAG = getClass().getSimpleName();
#Override
public void onCreate()
{
Log.d(TAG,"onCreate");
super.onCreate();
initRequestLocation();
playsServiceAvailable = checkPlayServicesConnection();
setupLocationApiClient();
}
#Nullable
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d(TAG, "onStartCommand");
super.onStartCommand(intent,flags,startId);
if (!playsServiceAvailable || googleApiClient.isConnected())
{
return START_STICKY;
}
setupLocationApiClient();
if (!googleApiClient.isConnected() || !googleApiClient.isConnecting())
{
Log.d(TAG, "onStartCommand: googleApiclient.connect()");
googleApiClient.connect();
}
return START_STICKY;
}
#Override
public void onDestroy()
{
Log.d(TAG, "onDestroy");
if (this.playsServiceAvailable && this.googleApiClient != null)
{
this.googleApiClient.unregisterConnectionCallbacks(this);
this.googleApiClient.unregisterConnectionFailedListener(this);
this.googleApiClient.disconnect();
this.googleApiClient = null;
}
super.onDestroy();
}
#Override
public void onConnected(#Nullable Bundle bundle)
{
try
{
LocationServices.FusedLocationApi.requestLocationUpdates(this.googleApiClient, locationRequest, this);
}
catch (SecurityException e)
{
e.printStackTrace();
}
}
#Override
public void onConnectionSuspended(int i)
{
googleApiClient = null;
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult)
{
}
#Override
public void onLocationChanged(Location currentLocation)
{
Log.d(TAG, "onLocationChanged:\n\t\t\t" +
"CurrentLocation:\n\t\t\t\t" +
"ACCURACY: " + currentLocation.getAccuracy() + "\n\t\t\t\t" +
"LAT: " + currentLocation.getLatitude() + "\n\t\t\t\t" +
"LONG: " + currentLocation.getLongitude() + "\n\t\t\t\t" +
"TIME: " + currentLocation.getTime());
}
private boolean checkPlayServicesConnection ()
{
int resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
if (resultCode != ConnectionResult.SUCCESS)
{
return false;
}
return true;
}
private void initRequestLocation()
{
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(5000)
.setFastestInterval(1000);
}
private void setupLocationApiClient()
{
Log.d(TAG,"setupLocationApiClient");
if (googleApiClient == null)
initGoogleApiClient();
}
private synchronized void initGoogleApiClient()
{
Log.d(TAG,"initGoogleApiClient");
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.build();
}
}
This is GPS In-accuracy this not issue with device. It try to fetch exact location so that's why it move here and there try to improve gps accuracy. Try to set smallest displacement and interval for more accurate result.
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(27);//27 meter
mLocationRequest.setInterval(5000); // Update location every 5 seconds
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
I have developed an application using the Fused location provider. In the onConnected() method, I am requesting for location updates and the application logic will be initiated and onLocationChanged() is called.
Problem : onLocationChanged() method is not called in devices in US . This code works perfectly fine on devices in INDIA but does not work on US. By does not work, I mean that locationClient gets connected but onLocationChanged() is never called.
Code Below:
public class LocationReceiver extends BroadcastReceiver
implements
// GooglePlayServicesClient.ConnectionCallbacks,
// GooglePlayServicesClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
// LocationClient locationclient = null;
GoogleApiClient locationclient = null;
Context contxt;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
#Override
public void onReceive(Context context, Intent intent) {
contxt = context;
// Log.i("locationreciever", "in location rec");,
Log.i("fused", "in location rec");
int resp = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(context);
if (resp == ConnectionResult.SUCCESS) {
// locationclient = new LocationClient(context, this, this);
locationclient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)// (mConnectionCallbacks)
.addOnConnectionFailedListener(this)// (mOnConnectionFailedListener)
.build();
locationclient.connect();
} else {
Log.i("fused", "loc client Google Play Service Error");
}
}
public void updateTransientLocation(Context context, Location loc) {
// Log.i("updateTransientLocation", "in fn");
float lat = (float) loc.getLatitude();
float lon = (float) loc.getLongitude();
float acc = loc.getAccuracy();
float alt = (float) loc.getAltitude();
if (lat > 0 && lon > 0) {
PreferenceForApp prefs = new PreferenceForApp(contxt);
prefs.setTransientLatitude(lat);
prefs.setTransientLongitude(lon);
prefs.setTransientAccuracy(acc);
prefs.setTransientAltitude(alt);
}
}
#Override
public void onLocationChanged(Location location) {
Log.i("fused",
" onLocationChanged Location Request :"
+ location.getLatitude() + ","
+ location.getLongitude() + " acc "
+ location.getAccuracy()+" alt "+location.getAltitude());
//TODO wait for some time to get location
updateTransientLocation(contxt, location);
if (locationclient != null) {
if (locationclient.isConnected()) {
// locationclient.removeLocationUpdates(this);
LocationServices.FusedLocationApi.removeLocationUpdates(
locationclient, this);
locationclient.disconnect();
}
}
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
PreferenceForApp prefs = new PreferenceForApp(contxt);
// if (arg0.hasResolution()) {
// try {
// // Start an Activity that tries to resolve the error
// arg0.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
// } catch (IntentSender.SendIntentException e) {
// e.printStackTrace();
// }}else{
Log.i("fused", "loc client connection failed");
prefs.setGooglePlayServiceErrorCode(arg0.getErrorCode());
}
//}
#Override
public void onConnected(Bundle arg0) {
PreferenceForApp prefs = new PreferenceForApp(contxt);
prefs.setGooglePlayServiceErrorCode(0);
Log.i("fused", "loc client onConnected");
LocationRequest locationrequest = new LocationRequest();
locationrequest
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// PRIORITY_BALANCED_POWER_ACCURACY
// locationclient.requestLocationUpdates(locationrequest, this);
LocationServices.FusedLocationApi.requestLocationUpdates(
locationclient, locationrequest, this); // mLocationListener);
}
// #Override
// public void onDisconnected() {
// Log.i("fused", "loc client disconnected");
// }
#Override
public void onConnectionSuspended(int arg0) {
Log.i("fused", "loc client onConnectionSuspended");
}
}
Can anyone help me out with this issue? Is there something I am missing here?
Maybe it's the fact that the phone can't connect with the service provider?
try using the gps.
String locationProvider = LocationManager.GPS_PROVIDER;
// Or, use GPS location data:
// String locationProvider = LocationManager.NETWORK_PROVIDER;
I think you are using NETWORK_PROVIDER to access/get the location update.
Try to use GPS_PROVIDER or use PASSIVE_PROVIDER to get location from either NETWORK_PROVIDER or GPS_PROVIDER.
Make sure you have permission in manifest to access NETWORK and GPS locations.
If you are using FusedLocationProviderApi, you have the option of using the SettingsApi to check if a device has the location settings required by an application. The SettingsApi and optionally provides a location dialog to update the device's location settings if they are found to be inadequate. You can look at an example. Run the sample with the location turned off in Settings, and you should see the dialog. Your app may be failing because it doesn't have sufficient permissions, and the location dialog could help.
Hi I have a service in which I find the user location co-ordinates. This service is started in onCreate in my MainActivity. however until it finds the values as I know GPS can take some time to find the co-ordinates the screen is black. I have created a splash screen which I would like to show but I am not sure on how to implement. My code will explain more:
My service:
public class LocationService extends Service implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationListener {
public static double curlat;
public static double curlong;
IBinder mBinder = new LocalBinder();
private LocationClient mLocationClient;
private LocationRequest mLocationRequest;
// Flag that indicates if a request is underway.
private boolean mInProgress;
public static final String BROADCAST_ACTION = "com.example.fusedlocation.displayevent";
Intent intent;
private Boolean servicesAvailable = false;
public class LocalBinder extends Binder {
public LocationService getServerInstance() {
return LocationService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
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(Constants.UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(Constants.FASTEST_INTERVAL);
servicesAvailable = servicesConnected();
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
mLocationClient = new LocationClient(this, this, 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;
}
}
public int onStartCommand (Intent intent, int flags, int startId)
{
super.onStartCommand(intent, flags, startId);
if(!servicesAvailable || mLocationClient.isConnected() || mInProgress)
return START_STICKY;
setUpLocationClientIfNeeded();
if(!mLocationClient.isConnected() || !mLocationClient.isConnecting() && !mInProgress)
{
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
mInProgress = true;
mLocationClient.connect();
}
return START_STICKY;
}
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
private void setUpLocationClientIfNeeded()
{
if(mLocationClient == null)
mLocationClient = new LocationClient(this, this, this);
}
// Define the callback method that receives location updates
#Override
public void onLocationChanged(android.location.Location location) {
// Report to the UI that the location was updated
String msg = Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.d("debug", msg);
curlat = location.getLatitude();
curlong = location.getLongitude();
// Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
appendLog(msg, Constants.LOCATION_FILE);
intent.putExtra("Latitude", location.getLatitude());
intent.putExtra("Longitude", location.getLongitude());
sendBroadcast(intent, null);
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public String getTime() {
SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return mDateFormat.format(new Date());
}
public void appendLog(String text, String filename)
{
File logFile = new File(filename);
if (!logFile.exists())
{
try
{
logFile.createNewFile();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try
{
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(text);
buf.newLine();
buf.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onDestroy(){
// Turn off the request flag
mInProgress = false;
if(servicesAvailable && mLocationClient != null) {
mLocationClient.removeLocationUpdates(this);
// Destroy the current location client
mLocationClient = null;
}
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Stopped", Constants.LOG_FILE);
super.onDestroy();
}
/*
* 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) {
// Request location updates using static settings
mLocationClient.requestLocationUpdates(mLocationRequest, this);
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Connected", Constants.LOG_FILE);
}
/*
* 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;
// Destroy the current location client
mLocationClient = null;
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected", Constants.LOG_FILE);
}
/*
* 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 {
}
}
}
MainActivity ( Only the relevant parts):
public class MainActivity extends Activity implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener{
// Google Map & markers
private GoogleMap googleMap;
private Circle mCircle;
private Marker mMarker;
double radiusInMeters;
long start_time, countUp, timeDialogShown = 0;
double latitude, longitude, startLongitude, startLatitude;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Setting the layout
setContentView(R.layout.activity_main);
try {
// Loading map
initilizeMap();
} catch (Exception e) {
e.printStackTrace();
}
startService(new Intent(this, LocationService.class));
} // end onCreate
//Checking the latest location updates
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
latitude = extras.getDouble("Latitude");
longitude = extras.getDouble("Longitude");
LatLng latLng = new LatLng(latitude, longitude);
if (mCircle == null || mMarker == null) {
drawMarkerWithCircle(latLng);
} else {
updateMarkerWithCircle(latLng);
}
getDistance();
//Getting the current weather conditions
//if (condDescr.getText().equals(" ")){
// getWeatherConditions();
//}
//Check if the user has breached the Geofence boundaries
checkBoundaries();
}
};
Check my answer here:
Android SplashScreen
Basically creating a theme background will deal with the black screen till you set the content.
Create a splash_screen activity. Set it as start-up activity.
In this splash_screen activity's onCreate() u can start a service to get location update.
Once u r done with location update, start ur MainAcitivity.class.
protected void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen_layout);
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
// start the service to get location update
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
// start the main activity
}
});
t1.start();
}
I have a LocationService which starts onResume() of the MainActivity and stops onDestroy().
#Override
protected void onResume() {
super.onResume();
//Start the service using alaram manager
//If its not running currently
if (isLocationServiceRunning(this)) {
am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, LocationService.class);
pi = PendingIntent.getService(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pi);
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), 1 * 60 * 1000, pi);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if (isLocationServiceRunning(this)) {
stopService(new Intent(this, LocationService.class));
if (am != null && pi != null) {
am.cancel(pi);
}
}
}
LocationService.java
public class LocationService extends Service implements LocationListener {
public static double curLat = 0.0;
public static double curLng = 0.0;
private LocationManager mgr;
private String best;
private Location location;
private Location currentBestLocation;
private static final int TWO_MINUTES = 1000 * 60 * 2;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mgr = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean gps_enabled = mgr
.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (gps_enabled) {
// If GPS is enabled, set criteria as ACCURACY_FINE
// and get the best provider(which usually will be GPS_PROVIDER)
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
best = mgr.getBestProvider(criteria, true);
// getLastKnownLocation so that user don't need to wait
location = mgr.getLastKnownLocation(best);
if (location == null) {
// request for a single update, and try again.
// Later will request for updates every 10 mins
mgr.requestSingleUpdate(criteria, this, null);
location = mgr
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
if (location != null) {
// If the GPS gives a location, update curLat and curLng
dumpLocation(location);
} else {
// If the location is still null, go for NETWORK_PROVIDER
best = LocationManager.NETWORK_PROVIDER;
location = mgr.getLastKnownLocation(best);
if (location != null) {
// If the NETWORK gives a location, update curLat and curLng
dumpLocation(location);
}
}
// Register the Location Manager for updates, with both the
// providers
// Since GPS updates are expensive, we ask update every 10 mins and
// unregister updates if GPS is disabled in onProviderDisabled
// callback
mgr.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10 * 60 * 1000, 50, this);
// NETWORK_PROVIDER updates every 20 secs
mgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
20 * 1000, 0, this);
return START_NOT_STICKY;
} else {
// If GPS is disables, go with NETWORK_PROVIDER
best = LocationManager.NETWORK_PROVIDER;
location = mgr.getLastKnownLocation(best);
if (location != null) {
dumpLocation(location);
}
// Register NETWORK_PROVIDER for updates every 20 secs
mgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
20 * 1000, 0, this);
return START_NOT_STICKY;
}
}
private void dumpLocation(Location l) {
// Called to update the curLat and curLng.
currentBestLocation = l;
SimpleDateFormat s = new SimpleDateFormat("dd/MM/yyyy:hh:mm:ss",
Locale.ENGLISH);
String format = s.format(l.getTime());
try {
Geocoder coder = new Geocoder(this);
List<Address> address;
Address location = null;
address = coder.getFromLocation(l.getLatitude(), l.getLongitude(),
1);
location = address.get(0);
} catch (Exception e) {
Log.e("Exception while getting address", e.getMessage() + "");
}
curLat = l.getLatitude();
curLng = l.getLongitude();
}
#Override
public void onLocationChanged(Location location) {
// called when location is changed, since we registered Location
// Providers
// for updates
if (isBetterLocation(location, currentBestLocation)) {
dumpLocation(location);
} else {
Log.d("Not a Better Location", "Ignore");
}
}
#Override
public void onProviderDisabled(String provider) {
// Check if best(the currently being used provider) is not null
if (best != null) {
// if best and disabled provider are same, the remove updates
if ((provider.equalsIgnoreCase(LocationManager.GPS_PROVIDER) && best
.equals(LocationManager.GPS_PROVIDER))
|| provider
.equalsIgnoreCase(LocationManager.NETWORK_PROVIDER)
&& best.equals(LocationManager.NETWORK_PROVIDER)) {
if (mgr != null) {
mgr.removeUpdates(this);
}
}
}
}
#Override
public void onProviderEnabled(String provider) {
// This will be taken care in the onStartCommand where if gps_enabled
// case is used.
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// No need to care about, because any thing like OUT_OF_SERVICE occurs,
// location being fetched will be null and such cases are handled above.
if ((provider.equals(LocationManager.GPS_PROVIDER))
&& (LocationProvider.OUT_OF_SERVICE == status)) {
if (mgr != null) {
mgr.removeUpdates(this);
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
// triggered when we call stopService(LocationService);
// which is done in onDestroy of MainActivity
// Because LocationService must be stopped
// when application is closed to avoid data usage
if (mgr != null) {
mgr.removeUpdates(this);
}
}
protected boolean isBetterLocation(Location location,
Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use
// the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be
// worse
} else if (isSignificantlyOlder) {
return false;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Not significantly newer or older, so check for Accuracy
if (isMoreAccurate) {
// If more accurate return true
return true;
} else if (isNewer && !isLessAccurate) {
// Same accuracy but newer, return true
return true;
} else if (isNewer && !isSignificantlyLessAccurate
&& isFromSameProvider) {
// Accuracy is less (not much though) but is new, so if from same
// provider return true
return true;
}
return false;
}
// Checks whether two providers are the same
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
}
The service surely starts and stops as expected and I can see the location details in log, which are fine.
The problem if when I move to a complete different location(300 miles), the curLat and curLng values still remain as that of the old, when I open the application.
Is it because I am not running the service when the device is in motion(because my application is not running)?
Because when I open some other application like FourSquare(which gets the correct location) and then reopen my application, then it shows the correct location.
What else should I do to refresh the location properly.
I think your problem is here
best = mgr.getBestProvider(criteria, true);
// getLastKnownLocation so that user don't need to wait
location = mgr.getLastKnownLocation(best);
if (location == null) {
// request for a single update, and try again.
// Later will request for updates every 10 mins
mgr.requestSingleUpdate(criteria, this, null);
location = mgr
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
because there was previously a location location = mgr.getLastKnownLocation(best); returns that location without starting the provider (see the android documentation. So the location is not null and mgr.requestSingleUpdate(criteria, this, null); is never run.
To get up to date location data a provider must be started.
so a correction could be:
best = mgr.getBestProvider(criteria, true);
// getLastKnownLocation so that user don't need to wait
mgr.requestSingleUpdate(best, this, null);
location = mgr.getLastKnownLocation(best);
Also I'm not sure if it is intended but this service will use the network provider even when GPS data is available and more accurate (due to the 10 minute and 2 minute times chosen for GPS updates and data obsolescence.
P.S. Is there a specific reason you do not want to use FusedLocationProvider that is part of Google Play Services? I have found it to be simpler and it is supposedly optimized for selected best providers and conserving battery.
You code looks perfectly fine if you want to get the location in the foreground. I have gone through in the deep and get to know that in the onDestroy you have stopped the service and alarms also. hence as and when the current app is going to background and the onDestroy is called by system then the code fails to update the location in the background. more over when you launch the application again it will start the service and very first time get the older location which was cached.
when other application updates the location you will get that location according to documentation of the mgr.getLastKnownLocation(best).
Hence to solve this problem do not use alarm here to start service in repeating manner or destory it.
simply start the service and in the onStartCommand ask for the update of the location. and if you want to get rid of the location updates, use removeLocationUpdates(LocationListener) .
Examples are given here http://developer.android.com/training/location/receive-location-updates.html
My best guess is dump "isBetterLocation" and try without it to see what will happen. Based on those checks (which are rather complicated), I think the mistake is either in "isSignificantlyOlder" or in the last return statement (otherwise you would get the new location, correct?)
Have you debugged it to check if the current logic is correct, and if it is, for what distances?
Here is an example to receive location update using Google Play Services
This is MyActivity class
public class MyActivity extends Activity implements
ConnectionCallbacks, OnConnectionFailedListener {
public static final int PLAY_SERVICES_NOT_AVAILABLE_REQUEST = 9000;
public static final int CONNECTION_FAILED_REQUEST = 1000;
private LocationClient mLocationClient;
private LocationRequest mLocationrequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_myactivity);
LocationManager mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mLocationClient = new LocationClient(this, this, this);
boolean isGPSEnabled = mLocationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean isNetworkEnabled = mLocationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
Toast.makeText(this, "GPS: " + isGPSEnabled, Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Network: " + isNetworkEnabled, Toast.LENGTH_SHORT)
.show();
if (isGooglePlayServicesAvailable()) {
mLocationClient.connect();
} else {
// play services not available
}
}
private void defineLocationRequest() {
mLocationrequest = new LocationRequest();
mLocationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(5000);
}
private PendingIntent getCallBackIntent() {
return PendingIntent
.getService(getApplicationContext(), 0, new Intent(this,
MyIntentService.class),
PendingIntent.FLAG_UPDATE_CURRENT);
}
private boolean isGooglePlayServicesAvailable() {
int resultCode = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(this);
if (resultCode == ConnectionResult.SUCCESS) {
Log.d("Car Tracking", "play services available.");
return true;
} else {
Log.d("Car Tracking", "play services not available(resultCode:) "
+ resultCode);
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_NOT_AVAILABLE_REQUEST).show();
return false;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
switch (requestCode) {
case PLAY_SERVICES_NOT_AVAILABLE_REQUEST:
if (resultCode == Activity.RESULT_OK) {
// check again
}
break;
case CONNECTION_FAILED_REQUEST:
if (resultCode == Activity.RESULT_OK) {
// try to connect LocationClient Againg
}
break;
}
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
if (arg0.hasResolution()) {
try {
arg0.startResolutionForResult(this, CONNECTION_FAILED_REQUEST);
} catch (SendIntentException e) {
Log.d("TAG",
"Exception in resolving connection failed: "
+ e.toString());
}
}
}
#Override
public void onConnected(Bundle arg0) {
// TODO Auto-generated method stub
defineLocationRequest();
mLocationClient.requestLocationUpdates(mLocationrequest,
getCallBackIntent());
}
#Override
public void onDisconnected() {
// TODO Auto-generated method stub
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
mLocationClient.removeLocationUpdates(getCallBackIntent());
super.onDestroy();
}
}
Now, this is MyIntentService Class's onHandleIntent Method.
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
if (intent != null) {
Bundle extra = intent.getExtras();
Location location = (Location) extra
.get(LocationClient.KEY_LOCATION_CHANGED);
}
Here, the location object will give you most recent location update
Also add
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
in your manifest
You can use the LocationClient from Google Play Services, its easy to use and proven very efficient.
Here is the link to example
Use Fused Location Provider (new feature available since 4.2 - https://developer.android.com/google/play-services/location.html) - it just gets fast current location and sending updates.
Example: http://www.motta-droid.com/2013/11/location-requests-for-your-app-how-to.html
Just run singleton above in a Service and adjust location update params to your needs.
The only issue You should care about - if it can't determine your current location at all. For example, if just GPS location provider available to your device and you're indoors.
I observed your code..You are updating the location but you are not receiving the updated location information. here is the code how to get the location from a Service
// Send an Intent with an action named "custom-event-name". The Intent sent
// should
// be received by the ReceiverActivity.
private static void sendMessageToActivity(Location l, String msg) {
Intent intent = new Intent("GPSLocationUpdates");
// You can also include some extra data.
intent.putExtra("Status", msg);
Bundle b = new Bundle();
b.putParcelable("Location", l);
intent.putExtra("Location", b);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
in you main activity or which has to receive the location Info write this code.
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mMessageReceiver, new IntentFilter("GPSLocationUpdates"));
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getBundleExtra("Location");
lastKnownLoc = (Location) b.getParcelable("Location");
if (lastKnownLoc != null) {
tvLatitude.setText(String.valueOf(lastKnownLoc.getLatitude()));
tvLongitude
.setText(String.valueOf(lastKnownLoc.getLongitude()));
}
}
};
I hope this will work...
I you do not mind waiting for GPS to achieve a first-fix this might help you. The first-fix should only be a matter of seconds if a fix have been found recently.
I have implemented some code that sends callback as soon as there is a first-fix and on locationchange based on GPSTracker from http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/.
With this implementation you can do:
private GPSTracker gps;
private FirstFixListener firstFixListener;
private LocationUpdateListener locationUpdateListener;
private void startGPS() {
gps = GPSTracker.getInstance(context);
// create listeners
firstFixListener = new MyFirstFixListener();
locationUpdateListener = new MyLocationUpdateListener();
// start the gps
gps.startUsingGPS(firstFixListener, locationUpdateListener);
}
private void stopGPS() {
// stop the gps and unregister callbacks
gps.stopUsingGPS(firstFixListener, locationUpdateListener);
}
private class MyFirstFixListener implements FirstFixListener {
#Override
public void onFirsFixChanged(boolean hasGPSfix) {
if (hasGPSfix == true) {
// accurate position
Location position = gps.getLocation();
}
}
}
private class MyLocationUpdateListener implements LocationUpdateListener {
#Override
public void onLocationChanged(Location location) {
// hand you each new location from the GPS
// you do not need this if you only want to get a single position
}
}
And here is my implementation of GPSTracker:
public class GPSTracker extends Service implements LocationListener {
private static final String TAG = "GPSTracker";
/**
* Register to receive callback on first fix status
*
* #author Morten
*
*/
public interface FirstFixListener {
/**
* Is called whenever gps register a change in first-fix availability
* This is valuable to prevent sending invalid locations to the server.
*
* #param hasGPSfix
*/
public void onFirsFixChanged(boolean hasGPSfix);
}
/**
* Register to receive all location updates
*
* #author Morten
*
*/
public interface LocationUpdateListener {
/**
* Is called every single time the GPS unit register a new location
* The location param will never be null, however, it can be outdated if hasGPSfix is not true.
*
* #param location
*/
public void onLocationChanged(Location location);
}
private Context mContext;
// flag for GPS status
private List<FirstFixListener> firstFixListeners;
private List<LocationUpdateListener> locationUpdateListeners;
boolean isGPSFix = false;
boolean isGPSEnabled = false;
private GPSFixListener gpsListener;
// flag for GPS status
boolean canGetLocation = false;
Location location; // location
double latitude; // latitude
double longitude; // longitude
long mLastLocationMillis;
private boolean logLocationChanges;
// Declaring a Location Manager
protected LocationManager locationManager;
/** removed again as we need multiple instances with different callbacks **/
private static GPSTracker instance;
public static GPSTracker getInstance(Context context) {
if (instance != null) {
return instance;
}
return instance = new GPSTracker(context);
}
private GPSTracker(Context context) {
this.mContext = context;
gpsListener = new GPSFixListener();
firstFixListeners = new ArrayList<GPSTracker.FirstFixListener>();
locationUpdateListeners = new ArrayList<GPSTracker.LocationUpdateListener>();
}
public boolean hasGPSFirstFix() {
return isGPSFix;
}
private void addFirstFixListener(FirstFixListener firstFixListener) {
this.firstFixListeners.add(firstFixListener);
}
private void addLocationUpdateListener(
LocationUpdateListener locationUpdateListener) {
this.locationUpdateListeners.add(locationUpdateListener);
}
private void removeFirstFixListener(FirstFixListener firstFixListener) {
this.firstFixListeners.remove(firstFixListener);
}
private void removeLocationUpdateListener(
LocationUpdateListener locationUpdateListener) {
this.locationUpdateListeners.remove(locationUpdateListener);
}
public void setLogLocationChanges(boolean logLocationChanges) {
this.logLocationChanges = logLocationChanges;
}
public Location getLocation() {
return location;
}
private Location startLocationListener() {
canGetLocation = false;
try {
locationManager = (LocationManager) mContext
.getSystemService(Service.LOCATION_SERVICE);
// getting GPS status
isGPSEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (isGPSEnabled) {
if (location == null) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, this);
locationManager.addGpsStatusListener(gpsListener);
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
} else {
showSettingsAlert();
}
} catch (Exception e) {
e.printStackTrace();
}
return location;
}
public void stopUsingGPS(FirstFixListener firstFixListener,
LocationUpdateListener locationUpdateListener) {
if (firstFixListener != null)
removeFirstFixListener(firstFixListener);
if (locationUpdateListener != null)
removeLocationUpdateListener(locationUpdateListener);
stopUsingGPS();
}
/**
* Stop using GPS listener Calling this function will stop using GPS in your
* app
* */
public void stopUsingGPS() {
Log.d("DEBUG", "GPS stop");
if (locationManager != null) {
locationManager.removeUpdates(GPSTracker.this);
location = null;
if (gpsListener != null) {
locationManager.removeGpsStatusListener(gpsListener);
}
}
isGPSFix = false;
location = null;
}
public void startUsingGPS(FirstFixListener firstFixListener,
LocationUpdateListener locationUpdateListener) {
Log.d("DEBUG", "GPS start");
if (firstFixListener != null)
addFirstFixListener(firstFixListener);
if (locationUpdateListener != null)
addLocationUpdateListener(locationUpdateListener);
startLocationListener();
}
/**
* Function to get latitude
* */
public double getLatitude() {
if (location != null) {
latitude = location.getLatitude();
} else {
Log.e("GPSTracker", "getLatitude location is null");
}
// return latitude
return latitude;
}
/**
* Function to get longitude
* */
public double getLongitude() {
if (location != null) {
longitude = location.getLongitude();
} else {
Log.e("GPSTracker", "getLongitude location is null");
}
// return longitude
return longitude;
}
/**
* Function to check GPS/wifi enabled
*
* #return boolean
* */
public boolean canGetLocation() {
return this.canGetLocation;
}
/**
* Function to show settings alert dialog On pressing Settings button will
* lauch Settings Options
* */
public void showSettingsAlert() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
// Setting Dialog Title
alertDialog.setTitle("GPS settings");
// Setting Dialog Message
alertDialog
.setMessage("GPS is not enabled. Do you want to go to settings menu?");
// On pressing Settings button
alertDialog.setPositiveButton("Settings",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
}
});
// on pressing cancel button
alertDialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
#Override
public void onLocationChanged(Location location) {
if ( location == null)
return;
this.location = location;
mLastLocationMillis = SystemClock.elapsedRealtime();
canGetLocation = true;
if (isGPSFix) {
if (locationUpdateListeners != null) {
for (LocationUpdateListener listener : locationUpdateListeners) {
listener.onLocationChanged(location);
}
}
}
}
#Override
public void onProviderDisabled(String provider) {
canGetLocation = false;
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
private boolean wasGPSFix = false;
// http://stackoverflow.com/questions/2021176/how-can-i-check-the-current-status-of-the-gps-receiver
// answer from soundmaven
private class GPSFixListener implements GpsStatus.Listener {
public void onGpsStatusChanged(int event) {
switch (event) {
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
if (isGPSFix != wasGPSFix) { // only notify on changes
wasGPSFix = isGPSFix;
for (FirstFixListener listener : firstFixListeners) {
listener.onFirsFixChanged(isGPSFix);
}
}
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
// Do something.
break;
}
}
}
}