title: How to keep GPS receiver location updates when the app is in background ( Google Play Service Location API)
body: <p>Sorry this is a long question, but I'm hoping that one of you experts out there can help a novice who is going quietly mad!!</p>
  
  <p>I have an Android app which uses a background service to get GPS fixes (using Google Play Services) every 20 seconds. It compares the latitude and longitude with those in a list, and if it finds a match, it sends a broadcast to a receiver that triggers a foreground activity to alert the user. </p>
  
  <p>I use a background service because typically there are between 2 and 20 minutes between user alerts, and in between, there is no  user interaction. The app uses a foreground activity for the user to choose the options he wants, but then closes all foreground activities leaving only the background activity running.</p>
  
  <p>This worked well on Android 4.3, on my old device, but I am now updating it run on Android 8 (Oreo) (testing it on a Sony Xperia XZ1Compact). I have added</p>
  
  <pre><code>&lt;uses-permission 
  android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/
  </code></pre>
  
  <p>to the manifest, and this caused the app to ask for permission when first run. My device settings then show the app as having a power saving exception allowed.</p>
  
  <p>The code for the background service (sorry there's rather a lot of it but I've included it all in case its relevant!) is as follows</p>
  
  <pre><code>package com.barney.trackgps;
  
  import android.Manifest;
  import android.app.Service;
  import android.content.Intent;
  import android.content.pm.PackageManager;
  import android.location.Location;
  import android.location.LocationListener;
  import android.os.Bundle;
  import android.os.IBinder;
  import android.support.annotation.Nullable;
  import android.support.v4.app.ActivityCompat;
  import android.util.Log;
  
  import com.google.android.gms.common.ConnectionResult;
  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;
  
  
  
  public class ApiTrackService extends Service implements
      GoogleApiClient.ConnectionCallbacks, 
  GoogleApiClient.OnConnectionFailedListener,
      LocationListener {
  
  GoogleApiClient mLocationClient;
  LocationRequest mLocationRequest = new LocationRequest();
  public static final String ACTION_LOCATION_BROADCAST = 
  ApiTrackService.class.getName() + "LocationBroadcast";
  public static final String EXTRA_LATITUDE = "extra_latitude";
  public static final String EXTRA_LONGITUDE = "extra_longitude";
  
  int interval=20; //time between fixes in seconds
  
  
  @Override
  public void onDestroy(){
      super.onDestroy();
      stopSelf();
  }
  
  
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Log.v("sTag","Got to apitrack");
      mLocationClient = new GoogleApiClient.Builder(this)
              .addConnectionCallbacks(this)
              .addOnConnectionFailedListener(this)
              .addApi(LocationServices.API)
              .build();
      mLocationRequest.setInterval(interval*1000);
      mLocationRequest.setFastestInterval(1000);
      int priority = LocationRequest.PRIORITY_HIGH_ACCURACY;
      mLocationRequest.setPriority(priority);
      mLocationClient.connect();
      return START_STICKY;
  }
  
  
  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
      return null;
  }
  
  
  @Override
  public void onConnected(Bundle dataBundle) {
      if (ActivityCompat.checkSelfPermission(this, 
  Manifest.permission.ACCESS_FINE_LOCATION) != 
  PackageManager.PERMISSION_GRANTED &amp;&amp; 
  ActivityCompat.checkSelfPermission(this, 
  Manifest.permission.ACCESS_COARSE_LOCATION) != 
  PackageManager.PERMISSION_GRANTED) {
          return;
      }
  
  LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient, 
  mLocationRequest, this);
  }
  
  
  @Override
  public void onConnectionSuspended(int i) {
  }
  
  
  //to get the location change
  @Override
  public void onLocationChanged(Location location) {
      boolean locFound=false;
      Log.v("sTag","Got a fix");
          /*does stuff to compare latitude and longitude with places in a list 
          and sets locFound=true if it finds a match*/
      if (location != null) {
          GPSLog=GPSLog+"Found";
          if (locFound) {
              Log.v("sTag", "Sending broadcast");
              Intent intent = new Intent();
              intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
              intent.setAction("com.AboutMyJourney.posBroadcast");
              sendBroadcast(intent);
          }
      }
  }
  
  
  @Override
  public void onConnectionFailed(ConnectionResult connectionResult) {
      //Log.d(TAG, "Failed to connect to Google API");
  }
  
  }
  </code></pre>
  
  <p>The app works fine as long as it has one of its foreground activities open and visible. Tracking using logcat shows that background service is getting GPS fixes and the code under onLocationChanged (see code above) is being run every 20 seconds. </p>
  
  <p>The app still works fine, and the onLocationChanged method still gets run every 20 seconds, if I allow my app to close all its foreground activities and run only the background service above, as long as another (completely unrelated) app that is calling for GPS locations is open and visible. </p>
  
  <p>If, however, I don't have any app that uses GPS visible on the screen, then the GPS tracking stops; the onLocationChanged Method is no longer  run and I no longer get GPS fixes. </p>
  
  <p>If I then open one of my app's foreground activities, GPS tracking starts up again, showing that the background service has not been killed.</p>
  
  <p>I am assuming this is something to do with the changes that have been made to implement power saving/DOZE mode, and that I just don't understand it properly. However, all the advice I can find seems to suggest that the background service will go on working as long as it is allowed as an exception in the device's whitelist, but this clearly isn't happening. </p>
  
  <p>It would be my preferred option to make the background service work, as that means the least work to write new code!. However, some responses to similar questions have suggested using a foreground service with a notification instead. Would that meet my requirement to have no User Interface visible (except maybe for a notification) most of the time, only prompting the user to do something every few minutes but leaving him or her free to do other stuff in the meantime? Would it work OK in older versions of Android as well?</p>
  
  <p>Can anyone who understands this better than I do (it's probably not hard to understand it better than I do!) help, please?</p>