Location updates using google play and FusedLocationProviderClient services

I want to receive location updates in the "background service" using the latest client of the provider of smooth access. I don't want to use the location listeners and the Google API client that everyone uses. I also need to use the Api location settings provided by google play services to check if the location settings are disabled or included in this "background service". Please, help.

+7
android android-location google-play-services fusedlocationproviderapi google-location-services
source share
5 answers

if we need to use the location of the fusion api, then we need to use the Google API client. For a background service, this is not a problem to use. Below is an example that I used to get a location update in the background. But one more, since Google is introducing DOZE mode with 6.0, so I can’t give the guarantor an update when your device is in "DOZE" mode,

import android.Manifest; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.util.Log; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.location.LocationListener; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationServices; /** * Created By Dhaval Solanki */ public class ConnectionService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { String TAG = "ConnectionService"; private GoogleApiClient mGoogleApiClient; private LocationRequest mLocationRequest; private Location previousLocation; public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 30000; public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2; private Location mLastLocation; private Context context; @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind"); return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { context = getApplicationContext(); Log.i(TAG, "onStartCommand"); if (checkPermsion(context)) { setupLocationService(context); } return Service.START_STICKY; } @Override public void onCreate() { super.onCreate(); ApplicationCLass.isServiceRunning = true; } @Override public boolean onUnbind(Intent intent) { Log.i(TAG, "onUnbind"); ApplicationCLass.isServiceRunning = false; return super.onUnbind(intent); } @Override public void onDestroy() { ApplicationCLass.isServiceRunning = false; super.onDestroy(); } private void setupLocationService(Context context) { if (checkPlayServices()) { mGoogleApiClient = new GoogleApiClient.Builder(context) .addApi(LocationServices.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); createLocationRequest(); } } protected void createLocationRequest() { mLocationRequest = new LocationRequest().create(); mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); mGoogleApiClient.connect(); } public boolean checkPermsion(Context context) { int MyVersion = Build.VERSION.SDK_INT; if (MyVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return false; } else if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return false; } else { return true; } } else { return true; } } private boolean checkPlayServices() { GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance(); int result = googleAPI.isGooglePlayServicesAvailable(this); if (result != ConnectionResult.SUCCESS) { return false; } return true; } private void startLocationUpdates() { if (mGoogleApiClient.isConnected()) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } if (Prefs.getUserLat(context).trim().length() > 0 && Prefs.getUserLong(context).trim().length() > 0) { } else { mLastLocation = LocationServices.FusedLocationApi.getLastLocation( mGoogleApiClient); if (mLastLocation != null) { Prefs.setUserLat(context, String.valueOf(mLastLocation.getLatitude())); Prefs.setUserLong(context, String.valueOf(mLastLocation.getLongitude())); } } LocationServices.FusedLocationApi.requestLocationUpdates( mGoogleApiClient, mLocationRequest, this); } } @Override public void onConnected(@Nullable Bundle bundle) { Log.i(TAG, "Connected to onConnected"); startLocationUpdates(); } @Override public void onConnectionSuspended(int i) { Log.i(TAG, "Connected to onConnectionSuspended"); } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { Log.i(TAG, "Connected to onConnectionFailed"); } @Override public void onLocationChanged(Location location) { try { Logger.print("onLocationChanged", "latitued :" + location.getLatitude() + " ,, Longitude " + location.getLongitude()); } catch (Exception e) { e.printStackTrace(); } } } 

One of the alaram services continues to work or not

 import android.app.ActivityManager; import android.app.IntentService; import android.content.Context; import android.content.Intent; import android.util.Log; public class AlarmService extends IntentService { @Override protected void onHandleIntent(Intent intent) { boolean isServiceRunning = false; ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (ConnectionService.class.getName().equals(service.service.getClassName())) { isServiceRunning = true; break; } } Log.i("AlarmService", "Service is running " + isServiceRunning); if(!isServiceRunning) { startService(new Intent(getApplicationContext(),ConnectionService.class)); } else { ConnectionService.checkConnectionAndConnect(getApplicationContext()); } } /** * Creates an IntentService. Invoked by your subclass constructor. */ public AlarmService() { super("AlaramService"); } } 

And the final start of the service

 private void checkAndStartService() { final ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); new AsyncTask<Void, Void, Boolean>() { boolean isServiceRunning = false; @Override protected Boolean doInBackground(Void... params) { for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (ConnectionService.class.getName().equals(service.service.getClassName())) { isServiceRunning = true; break; } } return isServiceRunning; } @Override protected void onPostExecute(Boolean aBoolean) { super.onPostExecute(aBoolean); Log.i("onPostExecute", "Service running = " + aBoolean); if (!aBoolean) { startService(new Intent(ActivitySplash.this, ConnectionService.class)); Intent i = new Intent(ActivitySplash.this, AlarmService.class); PendingIntent pi = PendingIntent.getService(ActivitySplash.this, 0, i, 0); AlarmManager am = (AlarmManager) ActivitySplash.this.getSystemService(Context.ALARM_SERVICE); am.cancel(pi); // cancel any existing alarms am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60000, pi); } } }.execute(); } 
+2
source share

You can extend the class of service, for example

 public class BackgroundLocationService extends Service implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener 

Here you can check the full source code of BackgroundLocationService.java

To enable location settings

  private void displayLocationSettingsRequest() { GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context) .addApi(LocationServices.API).build(); googleApiClient.connect(); LocationRequest locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); locationRequest.setInterval(10000); locationRequest.setFastestInterval(10000 / 2); LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest); builder.setAlwaysShow(true); PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build()); result.setResultCallback(new ResultCallback<LocationSettingsResult>() { @Override public void onResult(@NonNull LocationSettingsResult result) { final Status status = result.getStatus(); switch (status.getStatusCode()) { case LocationSettingsStatusCodes.SUCCESS: break; case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: try { // Show the dialog by calling startResolutionForResult(), and check the result // in onActivityResult(). status.startResolutionForResult(context, REQUEST_CHECK_SETTINGS); } catch (IntentSender.SendIntentException ignored) { } break; case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: break; } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { // Check for the integer request code originally supplied to startResolutionForResult(). case REQUEST_CHECK_SETTINGS: switch (resultCode) { case Activity.RESULT_OK: //startLocationUpdates(); break; case Activity.RESULT_CANCELED: displayLocationSettingsRequest();//keep asking showToast("Location permission needed"); break; } break; } } 

You can check the location settings from the Service and if the location is turned off,

 LocationManager lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); boolean gps_enabled = false; boolean network_enabled = false; try { gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER); } catch(Exception ex) {} try { network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); } catch(Exception ex) {} if(!gps_enabled && !network_enabled) { // notify user // Either you can display a Notification(Recommended way) or you can show dialog with dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); //It needs SYSTEM_ALERT_WINDOW permission. Add this permission in Manifest. <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> } 
+1
source share

You can write the code for the intent as follows. It was believed that since it runs in the background, we will not show permission dialogs.

 public class GetLocationService extends IntentService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { public static String TAG = GetLocationService.class.getSimpleName(); private GoogleApiClient mGoogleApiClient; public GetLocationService() { super(TAG); } /** * Creates an IntentService. Invoked by your subclass constructor. * * @param name Used to name the worker thread, important only for debugging. */ public GetLocationService(String name) { super(name); } @Override protected void onHandleIntent(Intent intent) { if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { Log.d(TAG, "disconnecting"); mGoogleApiClient.disconnect(); } Log.d(TAG, "onHandleIntent"); mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(LocationServices.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); mGoogleApiClient.connect(); } @Override public void onConnected(@Nullable Bundle bundle) { LocationRequest locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); LocationRequest locationRequestLow = LocationRequest.create(); locationRequestLow.setPriority(LocationRequest.PRIORITY_LOW_POWER); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_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. LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, this); } else { Log.d(TAG, "permission denied"); } } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { } @Override public void onLocationChanged(Location location) { Log.d(TAG, location.toString()); } 

}

+1
source share

Hi, I have a good understanding of location services and how we can use the perfect way in it. Look, I will give you an idea of ​​fused apits.

Just follow the instructions below. This is pretty good and simple. Step 1. Make this class GoogleLocationService.java

 public class GoogleLocationService { private GoogleServicesCallbacks callbacks = new GoogleServicesCallbacks(); LocationUpdateListener locationUpdateListener; Context activity; protected GoogleApiClient mGoogleApiClient; protected LocationRequest mLocationRequest; public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 30000; public GoogleLocationService(Context activity, LocationUpdateListener locationUpdateListener) { this.locationUpdateListener = locationUpdateListener; this.activity = activity; buildGoogleApiClient(); } protected synchronized void buildGoogleApiClient() { //Log.i(TAG, "Building GoogleApiClient"); mGoogleApiClient = new GoogleApiClient.Builder(activity) .addConnectionCallbacks(callbacks) .addOnConnectionFailedListener(callbacks) .addApi(LocationServices.API) .build(); createLocationRequest(); mGoogleApiClient.connect(); } protected void createLocationRequest() { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } private class GoogleServicesCallbacks implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { @Override public void onConnected(Bundle bundle) { startLocationUpdates(); } @Override public void onConnectionSuspended(int i) { mGoogleApiClient.connect(); } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { if (connectionResult.getErrorCode() == ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED) { Toast.makeText(activity, "Google play service not updated", Toast.LENGTH_LONG).show(); } locationUpdateListener.cannotReceiveLocationUpdates(); } @Override public void onLocationChanged(Location location) { if (location.hasAccuracy()) { if (location.getAccuracy() < 30) { locationUpdateListener.updateLocation(location); } } } } private static boolean locationEnabled(Context context) { boolean gps_enabled = false; LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); try { gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER); } catch (Exception ex) { ex.printStackTrace(); } return gps_enabled; } private boolean servicesConnected(Context context) { return isPackageInstalled(GooglePlayServicesUtil.GOOGLE_PLAY_STORE_PACKAGE, context); } private boolean isPackageInstalled(String packagename, Context context) { PackageManager pm = context.getPackageManager(); try { pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES); return true; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return false; } } public void startUpdates() { /* * Connect the client. Don't re-start any requests here; instead, wait * for onResume() */ if (servicesConnected(activity)) { if (locationEnabled(activity)) { locationUpdateListener.canReceiveLocationUpdates(); startLocationUpdates(); } else { locationUpdateListener.cannotReceiveLocationUpdates(); Toast.makeText(activity, "Unable to get your location.Please turn on your device Gps", Toast.LENGTH_LONG).show(); } } else { locationUpdateListener.cannotReceiveLocationUpdates(); Toast.makeText(activity, "Google play service not available", Toast.LENGTH_LONG).show(); } } //stop location updates public void stopUpdates() { stopLocationUpdates(); } //start location updates private void startLocationUpdates() { if (checkSelfPermission(activity, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(activity, ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } if (mGoogleApiClient.isConnected()) { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, callbacks); } } public void stopLocationUpdates() { if (mGoogleApiClient.isConnected()) { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, callbacks); } } public void startGoogleApi() { mGoogleApiClient.connect(); } public void closeGoogleApi() { mGoogleApiClient.disconnect(); } } 

Step2. Make this interface LocationUpdateListener.java

  public interface LocationUpdateListener { /** * Called immediately the service starts if the service can obtain location */ void canReceiveLocationUpdates(); /** * Called immediately the service tries to start if it cannot obtain location - eg the user has disabled wireless and */ void cannotReceiveLocationUpdates(); /** * Called whenever the location has changed (at least non-trivially) * @param location */ void updateLocation(Location location); /** * Called when GoogleLocationServices detects that the device has moved to a new location. * @param localityName The name of the locality (somewhere below street but above area). */ void updateLocationName(String localityName, Location location); } 

Step 3. Make this location service class LocationService.java

 public class LocationService extends Service { private GoogleLocationService googleLocationService; @Override public void onCreate() { super.onCreate(); //start the handler for getting locations //create component updateLocation(getApplicationContext()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return Service.START_STICKY; } //get current location os user private void updateLocation(Context context) { googleLocationService = new GoogleLocationService(context, new LocationUpdateListener() { @Override public void canReceiveLocationUpdates() { } @Override public void cannotReceiveLocationUpdates() { } //update location to our servers for tracking purpose @Override public void updateLocation(Location location) { if (location != null ) { Timber.e("updated location %1$s %2$s", location.getLatitude(), location.getLongitude()); } } @Override public void updateLocationName(String localityName, Location location) { googleLocationService.stopLocationUpdates(); } }); googleLocationService.startUpdates(); } IBinder mBinder = new LocalBinder(); public class LocalBinder extends Binder { public LocationService getServerInstance() { return LocationService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } //stop location updates on stopping the service @Override public void onDestroy() { super.onDestroy(); if (googleLocationService != null) { googleLocationService.stopLocationUpdates(); } } } 

Edited answer:

How to use the service

Start the service in your main action, for example

 startService(new Intent(context, LocationService.class)); 

to stop

 stopService(new Intent(context, LocationService.class)); 

and declare in the manifest as follows:

 <service android:name=".service.location.LocationService" android:enabled="true"></service> 

Note: I did this because I need a place after you killed the application. If you do not want to work with the service. Then you can call directly below the code in the class where you need to update the location and remove the locationervice.

  private GoogleLocationService googleLocationService; googleLocationService = new GoogleLocationService(context, new LocationUpdateListener() { @Override public void canReceiveLocationUpdates() { } @Override public void cannotReceiveLocationUpdates() { } //update location to our servers for tracking purpose @Override public void updateLocation(Location location) { if (location != null ) { Timber.e("updated location %1$s %2$s", location.getLatitude(), location.getLongitude()); } } @Override public void updateLocationName(String localityName, Location location) { googleLocationService.stopLocationUpdates(); } }); googleLocationService.startUpdates(); and call this onDestroy if (googleLocationService != null) { googleLocationService.stopLocationUpdates(); } 

Remember that Locationservice must also be declared in the manifest. In my opinion, this is the best solution. Thank you for helping this.

+1
source share

The question does not seem very specific. It seems that you are having problems starting the location service.

A better idea would probably be to check google samples ( https://github.com/googlesamples/android-play-location ) to better understand the mechanics. I'll probably start by implementing the simplest example ( LocationUpdates ). It uses the FusedLocationProvider and also checks if the settings are enabled, so it should match your needs or at least get started.

If you really need to use the service, you can check LocationUpdatesForegroundService or LocationUpdatesPendingIntent . But I would highly recommend reading and understanding the first example before you do this.

0
source share

All Articles