title: Android Geofencing with Google Play Services 6.5.87
body: <p>I have no problem with Google Play Services 6.1.71 (because everything works well) but not the same thing with newer version (6.5.87).</p>
  
  <p>I already know <code>LocationClient</code> class is deprecated in 6.5.87 Google Play Services class and I have little problem with converting <a href="http://developer.android.com/shareables/training/GeofenceDetection.zip" rel="nofollow noreferrer">old GeofenceDetection sample.</a></p>
  
  <ol>
  <li>First issue I have, with new Play Services I haven't find <code>OnAddGeofencesResultListener</code> and <code>OnRemoveGeofencesResultListener</code> that I used to handle errors on console;</li>
  <li>Second issue (main problem) is adding geofence point. When I try to add one to request I receive a pending indefinite...</li>
  </ol>
  
  <p>The code that I have modified is:</p>
  
  <p><strong>ReceiveTransitionsIntentService.java</strong></p>
  
  <pre><code>public class ReceiveTransitionsIntentService extends IntentService {
  
      /**
       * Sets an identifier for this class' background thread
       */
      public ReceiveTransitionsIntentService() {
          super("ReceiveTransitionsIntentService");
      }
  
      /**
       * Handles incoming intents
       *
       * @param intent The Intent sent by Location Services. This Intent is provided
       *               to Location Services (inside a PendingIntent) when you call addGeofences()
       */
      @Override
      protected void onHandleIntent(Intent intent) {
  
          // Create a local broadcast Intent
          Intent broadcastIntent = new Intent();
  
          // Give it the category for all intents sent by the Intent Service
          broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);
          GeofencingEvent geoFenceEvent = GeofencingEvent.fromIntent(intent);
  
          // First check for errors
          if (geoFenceEvent.hasError()) {
              // Get the error code
              int errorCode = geoFenceEvent.getErrorCode();
  
              // Get the error message
              String errorMessage = LocationServiceErrorMessages.getErrorString(this, errorCode);
  
              // Log the error
              Log.e(GeofenceUtils.APPTAG, getString(R.string.geofence_transition_error_detail, errorMessage));
  
              // Set the action and error message for the broadcast intent
              broadcastIntent.setAction(GeofenceUtils.ACTION_GEOFENCE_ERROR).putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, errorMessage);
  
              // Broadcast the error *locally* to other components in this app
              LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);
  
              // If there's no error, get the transition type and create a notification
          } else {
              // Get the type of transition (entry or exit)
              int transition = geoFenceEvent.getGeofenceTransition();
  
              // Test that a valid transition was reported
              if ((transition == Geofence.GEOFENCE_TRANSITION_ENTER) || (transition == Geofence.GEOFENCE_TRANSITION_EXIT)) {
  
                  // Post a notification
                  List&lt;Geofence&gt; geofences = geoFenceEvent.getTriggeringGeofences();
                  String[] geofenceIds = new String[geofences.size()];
                  for (int index = 0; index &lt; geofences.size(); index++) {
                      geofenceIds[index] = geofences.get(index).getRequestId();
                  }
                  String ids = TextUtils.join(GeofenceUtils.GEOFENCE_ID_DELIMITER, geofenceIds);
                  String transitionType = getTransitionString(transition);
  
                  sendNotification(transitionType, ids);
  
                  // Log the transition type and a message
                  Log.d(GeofenceUtils.APPTAG, getString(R.string.geofence_transition_notification_title, transitionType, ids));
                  Log.d(GeofenceUtils.APPTAG, getString(R.string.geofence_transition_notification_text));
  
                  // An invalid transition was reported
              } else {
                  // Always log as an error
                  Log.e(GeofenceUtils.APPTAG,
                          getString(R.string.geofence_transition_invalid_type, transition));
              }
          }
      }
  
      /**
       * Posts a notification in the notification bar when a transition is detected.
       * If the user clicks the notification, control goes to the main Activity.
       *
       * @param transitionType The type of transition that occurred.
       */
      private void sendNotification(String transitionType, String ids) {
  
          // Create an explicit content Intent that starts the main Activity
          Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
  
          // Construct a task stack
          TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
  
          // Adds the main Activity to the task stack as the parent
          stackBuilder.addParentStack(MainActivity.class);
  
          // Push the content Intent onto the stack
          stackBuilder.addNextIntent(notificationIntent);
  
          // Get a PendingIntent containing the entire back stack
          PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
  
          // Get a notification builder that's compatible with platform versions &gt;= 4
          NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
  
          // Set the notification contents
          builder.setSmallIcon(R.drawable.ic_notification)
                  .setContentTitle(getString(R.string.geofence_transition_notification_title, transitionType, ids))
                  .setContentText(getString(R.string.geofence_transition_notification_text))
                  .setContentIntent(notificationPendingIntent);
  
          // Get an instance of the Notification manager
          NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  
          // Issue the notification
          mNotificationManager.notify(0, builder.build());
      }
  
      /**
       * Maps geofence transition types to their human-readable equivalents.
       *
       * @param transitionType A transition type constant defined in Geofence
       * @return A String indicating the type of transition
       */
      private String getTransitionString(int transitionType) {
          switch (transitionType) {
              case Geofence.GEOFENCE_TRANSITION_ENTER:
                  return getString(R.string.geofence_transition_entered);
              case Geofence.GEOFENCE_TRANSITION_EXIT:
                  return getString(R.string.geofence_transition_exited);
              default:
                  return getString(R.string.geofence_transition_unknown);
          }
      }
  }
  </code></pre>
  
  <p><strong>GeofenceRequester.java</strong></p>
  
  <pre><code>public class GeofenceRequester implements
          ConnectionCallbacks,
          OnConnectionFailedListener,
          GoogleApiClient.ConnectionCallbacks,
          GoogleApiClient.OnConnectionFailedListener {
  
      // Storage for a reference to the calling client
      private final Activity mActivity;
  
      // Stores the PendingIntent used to send geofence transitions back to the app
      private PendingIntent mGeofencePendingIntent;
  
      // Stores the current list of geofences
      private ArrayList&lt;Geofence&gt; mCurrentGeofences;
  
      // Stores the current instantiation of the location client
      private GoogleApiClient mGoogleApiClient;
  
      /*
       * Flag that indicates whether an add or remove request is underway. Check this
       * flag before attempting to start a new request.
       */
      private boolean mInProgress;
  
      public GeofenceRequester(Activity activityContext) {
          // Save the context
          mActivity = activityContext;
  
          // Initialize the globals to null
          mGeofencePendingIntent = null;
          mGoogleApiClient = null;
          mInProgress = false;
      }
  
      /**
       * Set the "in progress" flag from a caller. This allows callers to re-set a
       * request that failed but was later fixed.
       *
       * @param flag Turn the in progress flag on or off.
       */
      public void setInProgressFlag(boolean flag) {
          // Set the "In Progress" flag.
          mInProgress = flag;
      }
  
      /**
       * Get the current in progress status.
       *
       * @return The current value of the in progress flag.
       */
      public boolean getInProgressFlag() {
          return mInProgress;
      }
  
      /**
       * Returns the current PendingIntent to the caller.
       *
       * @return The PendingIntent used to create the current set of geofences
       */
      public PendingIntent getRequestPendingIntent() {
          return createRequestPendingIntent();
      }
  
      /**
       * Start adding geofences. Save the geofences, then start adding them by requesting a
       * connection
       *
       * @param geofences A List of one or more geofences to add
       */
      public void addGeofences(List&lt;Geofence&gt; geofences) throws UnsupportedOperationException {
  
          /*
           * Save the geofences so that they can be sent to Location Services once the
           * connection is available.
           */
          mCurrentGeofences = (ArrayList&lt;Geofence&gt;) geofences;
  
          // If a request is not already in progress
          if (!mInProgress) {
              // Toggle the flag and continue
              mInProgress = true;
  
              // Request a connection to Location Services
              requestConnection();
  
              // If a request is in progress
          } else {
  
              // Throw an exception and stop the request
              throw new UnsupportedOperationException();
          }
      }
  
      /**
       * Request a connection to Location Services. This call returns immediately,
       * but the request is not complete until onConnected() or onConnectionFailure() is called.
       */
      private void requestConnection() {
          getLocationClient().connect();
      }
  
      /**
       * Get the current location client, or create a new one if necessary.
       *
       * @return A LocationClient object
       */
      private GoogleApiClient getLocationClient() {
          if (mGoogleApiClient == null) {
  
              mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
                      .addApi(LocationServices.API)
                      .addConnectionCallbacks(this)
                      .addOnConnectionFailedListener(this)
                      .build();
          }
          return mGoogleApiClient;
  
      }
  
      /**
       * Once the connection is available, send a request to add the Geofences
       */
      private void continueAddGeofences() {
  
          // Get a PendingIntent that Location Services issues when a geofence transition occurs
          mGeofencePendingIntent = createRequestPendingIntent();
  
          // Send a request to add the current geofences
          LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, mCurrentGeofences, mGeofencePendingIntent);
      }
  
      /**
       * Get a location client and disconnect from Location Services
       */
      private void requestDisconnection() {
  
          // A request is no longer in progress
          mInProgress = false;
  
          getLocationClient().disconnect();
      }
  
      /*
       * Called by Location Services once the location client is connected.
       *
       * Continue by adding the requested geofences.
       */
      @Override
      public void onConnected(Bundle arg0) {
          // If debugging, log the connection
          Log.d(GeofenceUtils.APPTAG, mActivity.getString(R.string.connected));
  
          // Continue adding the geofences
          continueAddGeofences();
      }
  
      @Override
      public void onConnectionSuspended(int i) {
  
      }
  
      /*
       * Called by Location Services once the location client is disconnected.
       */
      @Override
      public void onDisconnected() {
          // Turn off the request flag
          mInProgress = false;
  
          // In debug mode, log the disconnection
          Log.d(GeofenceUtils.APPTAG, mActivity.getString(R.string.disconnected));
  
          // Destroy the current location client
          mGoogleApiClient = null;
      }
  
      /**
       * Get a PendingIntent to send with the request to add Geofences. Location Services issues
       * the Intent inside this PendingIntent whenever a geofence transition occurs for the current
       * list of geofences.
       *
       * @return A PendingIntent for the IntentService that handles geofence transitions.
       */
      private PendingIntent createRequestPendingIntent() {
  
          // If the PendingIntent already exists
          if (null != mGeofencePendingIntent) {
  
              // Return the existing intent
              return mGeofencePendingIntent;
  
              // If no PendingIntent exists
          } else {
  
              // Create an Intent pointing to the IntentService
              Intent intent = new Intent(mActivity, ReceiveTransitionsIntentService.class);
              /*
               * Return a PendingIntent to start the IntentService.
               * Always create a PendingIntent sent to Location Services
               * with FLAG_UPDATE_CURRENT, so that sending the PendingIntent
               * again updates the original. Otherwise, Location Services
               * can't match the PendingIntent to requests made with it.
               */
              return PendingIntent.getService(
                      mActivity,
                      0,
                      intent,
                      PendingIntent.FLAG_UPDATE_CURRENT);
          }
      }
  
      /*
       * Implementation of OnConnectionFailedListener.onConnectionFailed
       * If a connection or disconnection request fails, report the error
       * connectionResult is passed in from Location Services
       */
      @Override
      public void onConnectionFailed(ConnectionResult connectionResult) {
  
          // Turn off the request flag
          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()) {
  
              try {
                  // Start an Activity that tries to resolve the error
                  connectionResult.startResolutionForResult(mActivity,
                          GeofenceUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
  
                  /*
                   * Thrown if Google Play services canceled the original
                   * PendingIntent
                   */
              } catch (SendIntentException e) {
                  // Log the error
                  e.printStackTrace();
              }
  
              /*
               * If no resolution is available, put the error code in
               * an error Intent and broadcast it back to the main Activity.
               * The Activity then displays an error dialog.
               * is out of date.
               */
          } else {
  
              Intent errorBroadcastIntent = new Intent(GeofenceUtils.ACTION_CONNECTION_ERROR);
              errorBroadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES)
                      .putExtra(GeofenceUtils.EXTRA_CONNECTION_ERROR_CODE,
                              connectionResult.getErrorCode());
              LocalBroadcastManager.getInstance(mActivity).sendBroadcast(errorBroadcastIntent);
          }
      }
  }
  </code></pre>