title: android - Get location and send data to remote server ONLY while condition is true
body: <p>I am building an app that needs to send the user's location to a remote server (Pusher in this case). The goal is to update their location on a map in near real-time but <strong>only</strong> when they are on a job, otherwise the app will not need to track their location.</p>
  
  <p>I need the location updates to remain active if they leave the activity where they accepted the job (and therefore were placed on the map) and if they leave the app altogether. Once they have reached their destination, I wish to stop this background tracking.</p>
  
  <p>I have been looking at Android's <code>Service</code> component but I am not sure if it is what I need for this. The updates should occur in the background indefinitely but only while the user is assigned to a Job (updates start when they accept a job, end when they reach their destination). </p>
  
  <p>Would a Bound service be the best for this? If so, some code as it relates to this problem would be <strong>GREATLY</strong> appreciated, as much of what I can find is generic and does things like return random integers.</p>
  
  <p>Here is the code I wish to execute in the background:</p>
  
  <pre><code>package com.example.locationtester;
  
  import android.content.Context;
  import android.location.Location;
  import android.location.LocationListener;
  import android.location.LocationManager;
  import android.os.Bundle;
  import android.support.v7.app.AppCompatActivity;
  import android.util.Log;
  import android.widget.TextView;
  import android.widget.Toast;
  
  import com.pusher.client.Pusher;
  import com.pusher.client.PusherOptions;
  import com.pusher.client.channel.PrivateChannel;
  import com.pusher.client.channel.PrivateChannelEventListener;
  import com.pusher.client.connection.ConnectionEventListener;
  import com.pusher.client.connection.ConnectionState;
  import com.pusher.client.connection.ConnectionStateChange;
  import com.pusher.client.util.HttpAuthorizer;
  
  import org.json.JSONException;
  import org.json.JSONObject;
  
  public class MainActivity extends AppCompatActivity {
  
      private TextView mLatLabel;
      private TextView mLongLabel;
      private TextView mAccuracy;
  
      private Double mLat;
      private Double mLong;
      private boolean isSubscribed = false;
  
      private Pusher mPusher;
      private PrivateChannel mChannel;
  
      private static final long MIN_TIME_BW_UPDATES = 1000 * 60;
      private static final String TAG = "GPSTest";
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
  
          mLatLabel = (TextView) findViewById(R.id.latLabel);
          mLongLabel = (TextView) findViewById(R.id.longLabel);
          mAccuracy = (TextView) findViewById(R.id.accuracyLabel);
  
          HttpAuthorizer authorizer = new HttpAuthorizer("http://example.com");
          PusherOptions options = new PusherOptions().setAuthorizer(authorizer).setEncrypted(true);
          mPusher = new Pusher("PUSHER_API_KEY", options);
          mPusher.connect(new ConnectionEventListener() {
              @Override
              public void onConnectionStateChange(ConnectionStateChange change) {
                  Log.d(TAG, "State changed to " + change.getCurrentState() +
                          " from " + change.getPreviousState());
              }
  
              @Override
              public void onError(String message, String code, Exception e) {
                  Log.d(TAG, "There was a problem connecting! " + e.toString());
              }
          }, ConnectionState.ALL);
  
          mChannel = mPusher.subscribePrivate("private-location", new PrivateChannelEventListener() {
              @Override
              public void onAuthenticationFailure(String message, Exception e) {
                  Log.e(TAG, "Error " + message);
              }
  
              @Override
              public void onSubscriptionSucceeded(String channelName) {
                  Log.d(TAG, "Subscribed to " + channelName);
                  isSubscribed = true;
              }
  
              @Override
              public void onEvent(String channelName, String eventName, String data) {
  
              }
          });
  
  
          LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
  
          LocationListener locationListener = new LocationListener() {
              @Override
              public void onLocationChanged(Location location) {
                  handleLocationUpdate(location);
              }
  
              @Override
              public void onStatusChanged(String provider, int status, Bundle extras) {
                  Toast.makeText(getApplicationContext(), "GPS Status Changed " + provider, Toast.LENGTH_LONG).show();
              }
  
              @Override
              public void onProviderEnabled(String provider) {
                  Toast.makeText(getApplicationContext(), "GPS Provider Enabled " + provider, Toast.LENGTH_LONG).show();
              }
  
              @Override
              public void onProviderDisabled(String provider) {
  
              }
          };
  
          // Register the listener with the Location Manager to receive location updates
          locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, 0, locationListener);
      }
  
      private void handleLocationUpdate(Location location) {
          mLat = location.getLatitude();
          mLong = location.getLongitude();
  
          mLatLabel.setText("Long: " + location.getLongitude());
          mLongLabel.setText("Lat: " + location.getLatitude());
          mAccuracy.setText("Accuracy: " + location.getAccuracy() + " at " + location.getTime());
          Log.d(TAG, mLat + "");
  
          if (isSubscribed)
          {
              JSONObject json = new JSONObject();
              try {
                  json.put("lat", mLat);
                  json.put("long", mLong);
                  json.put("time", location.getTime());
                  json.put("accuracy", location.getAccuracy());
                  mChannel.trigger("client-location-changed", json.toString());
              } catch (JSONException e) {
                  Log.e(TAG, "Problem adding JSON");
              }
          }
  
      }
  }
  </code></pre>
  
  <p><strong>UPDATE</strong></p>
  
  <p>This is what I came up with after switching to Google Play Service's Location API. I have tested leaving this activity (and the app in general) and everything keeps running smoothly, proving location updates until I click on the button to make them stop.</p>
  
  <p>Feedback would be appreciated on this code:</p>
  
  <pre><code>public class MainActivity extends AppCompatActivity implements
          GoogleApiClient.ConnectionCallbacks,
          GoogleApiClient.OnConnectionFailedListener,
          LocationListener {
  
      private GoogleApiClient mGoogleApiClient;
      private LocationRequest mLocationRequest;
  
      public static final String TAG = MainActivity.class.getSimpleName();
      public static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
  
      private boolean isSubscribed = false;
  
      private Pusher mPusher;
      private PrivateChannel mChannel;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
  
          Button startTracking = (Button) findViewById(R.id.btnStartTracking);
          Button stopTracking = (Button) findViewById(R.id.btnStopTracking);
          final Button startActivity = (Button) findViewById(R.id.btnStartActivity);
  
          HttpAuthorizer authorizer = new HttpAuthorizer("http://example.com");
          PusherOptions options = new PusherOptions().setAuthorizer(authorizer).setEncrypted(true);
          mPusher = new Pusher("API_KEY", options);
          mPusher.connect(new ConnectionEventListener() {
              @Override
              public void onConnectionStateChange(ConnectionStateChange change) {
                  Log.d(TAG, "State changed to " + change.getCurrentState() +
                          " from " + change.getPreviousState());
              }
  
              @Override
              public void onError(String message, String code, Exception e) {
                  Log.d(TAG, "There was a problem connecting! " + e.toString());
              }
          }, ConnectionState.ALL);
  
          mChannel = mPusher.subscribePrivate("private-location", new PrivateChannelEventListener() {
              @Override
              public void onAuthenticationFailure(String message, Exception e) {
                  Log.e(TAG, "Error " + message);
              }
  
              @Override
              public void onSubscriptionSucceeded(String channelName) {
                  Log.d(TAG, "Subscribed to " + channelName);
                  isSubscribed = true;
              }
  
              @Override
              public void onEvent(String channelName, String eventName, String data) {
  
              }
          });
  
          // Build the Google Api Client and set the API for LocationServices
          mGoogleApiClient = new GoogleApiClient.Builder(this)
                  .addConnectionCallbacks(this)
                  .addOnConnectionFailedListener(this)
                  .addApi(LocationServices.API)
                  .build();
  
          // Create the LocationRequest object
          mLocationRequest = LocationRequest.create()
                  .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                  .setInterval(20 * 1000) // 3 seconds, in MS
                  .setFastestInterval(1000); // 1 second, in MS
  
  
          startTracking.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  if (!mGoogleApiClient.isConnected())
                  {
                      mGoogleApiClient.connect();
                  }
              }
          });
  
          stopTracking.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  if (mGoogleApiClient.isConnected())
                  {
                      mGoogleApiClient.disconnect();
                  }
              }
          });
  
          startActivity.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  Intent intent = new Intent(getApplicationContext(), Activity2.class);
                  startActivity(intent);
              }
          });
      }
  
      @Override
      protected void onResume()
      {
          super.onResume();
  
          if (!mGoogleApiClient.isConnected())
          {
              mGoogleApiClient.connect();
          }
      }
  
      @Override
      public void onConnected(Bundle bundle) {
          Log.i(TAG, "Location services connected");
  
          LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
      }
  
      private void handleNewLocation(Location location) {
          Log.d(TAG, location.toString());
  
          double currentLatitude = location.getLatitude();
          double currentLongitude = location.getLongitude();
  
          LatLng latLng = new LatLng(currentLatitude, currentLongitude);
  
          int speed = (int) (location.getSpeed() * 2.2369);
  
          if (isSubscribed) {
              JSONObject json = new JSONObject();
              try {
                  json.put("lat", currentLatitude);
                  json.put("long", currentLongitude);
                  json.put("time", location.getTime());
                  json.put("accuracy", location.getAccuracy());
                  json.put("speed", speed);
                  json.put("latLng", latLng);
                  mChannel.trigger("client-location-changed", json.toString());
              } catch (JSONException e) {
                  Log.e(TAG, "Problem adding JSON");
              }
          }
      }
  
      @Override
      public void onConnectionSuspended(int i) {
          Log.i(TAG, "Location services suspended. Please reconnect");
      }
  
      @Override
      public void onLocationChanged(Location location) {
          handleNewLocation(location);
      }
  
      @Override
      public void onConnectionFailed(ConnectionResult connectionResult) {
          if (connectionResult.hasResolution()) {
              try {
                  // Start an Activity that tries to resolve the error
                  connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
              } catch (IntentSender.SendIntentException e) {
                  e.printStackTrace();
              }
          } else {
              Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
          }
      }
  }
  </code></pre>