title: Android Geofence only works with opened app
body: <p>I'm doing a serious research on this topic for many days... I saw many topics here too...
  But unfortunately I couldn't find a solution....</p>
  
  <p>I'm writing an app that uses the new Google API for Geofence...
  Well, I can handle "ins" and "outs" of a geofence, but only if my app is open! Even if I'm with wifi on, gps on, and 3G on, but the app, it does not trigger any event...Just if the app is open...</p>
  
  <p>I'm using exactly the same GeofenceRequester class of the documentation <a href="http://developer.android.com/training/location/geofencing.html">http://developer.android.com/training/location/geofencing.html</a> .</p>
  
  <p>Even the class been the same I'll post the code here:</p>
  
  <pre><code>package br.com.marrs.imhere.geofence;
  import java.util.ArrayList;
  import java.util.List;
  
  import android.app.Activity;
  import android.app.PendingIntent;
  import android.content.Intent;
  import android.content.IntentSender.SendIntentException;
  import android.os.Bundle;
  import android.support.v4.content.LocalBroadcastManager;
  import android.util.Log;
  import br.com.marrs.imhere.services.ReceiveTransitionsIntentService;
  
  import com.google.android.gms.common.ConnectionResult;
  import com.google.android.gms.common.GooglePlayServicesClient;
  import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
  import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
  import com.google.android.gms.location.Geofence;
  import com.google.android.gms.location.LocationClient;
  import com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener;
  import com.google.android.gms.location.LocationStatusCodes;
  
  /**
   * Class for connecting to Location Services and requesting geofences.
   * &lt;b&gt;
   * Note: Clients must ensure that Google Play services is available before requesting geofences.
   * &lt;/b&gt; Use GooglePlayServicesUtil.isGooglePlayServicesAvailable() to check.
   *
   *
   * To use a GeofenceRequester, instantiate it and call AddGeofence(). Everything else is done
   * automatically.
   *
   */
  public class GeofenceRequester
                  implements
                      OnAddGeofencesResultListener,
                      ConnectionCallbacks,
                      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 LocationClient mLocationClient;
  
      /*
       * 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;
          mLocationClient = 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 GooglePlayServicesClient getLocationClient()
      {
          if (mLocationClient == null) {
  
              mLocationClient = new LocationClient(mActivity, this, this);
          }
          return mLocationClient;
  
      }
      /**
       * 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
          mLocationClient.addGeofences(mCurrentGeofences, mGeofencePendingIntent, this);
      }
  
      /*
       * Handle the result of adding the geofences
       */
      @Override
      public void onAddGeofencesResult(int statusCode, String[] geofenceRequestIds) 
      {
          // Create a broadcast Intent that notifies other components of success or failure
          Intent broadcastIntent = new Intent();
  
          // Temp storage for messages
          String msg;
  
          // If adding the geocodes was successful
          if (LocationStatusCodes.SUCCESS == statusCode) 
          {
              // Create a message containing all the geofence IDs added.
              msg = geofenceRequestIds.toString();
  
              // In debug mode, log the result
              Log.d("DEBUG", msg);
  
              // Create an Intent to broadcast to the app
              broadcastIntent.setAction("br.com.marrs.imhere.ACTION_GEOFENCES_ADDED")
                             .addCategory("br.com.marrs.imhere.CATEGORY_LOCATION_SERVICES")
                             .putExtra("br.com.marrs.imhere.EXTRA_GEOFENCE_STATUS", msg);
          // If adding the geofences failed
          } 
          else
          {
  
              /*
               * Create a message containing the error code and the list
               * of geofence IDs you tried to add
               */
              msg = "Erro adicionando geofence";
  
              // Log an error
              Log.e("DEBUG", msg);
  
              // Create an Intent to broadcast to the app
              broadcastIntent.setAction("br.com.marrs.imhere.ACTION_GEOFENCE_ERROR")
                             .addCategory("br.com.marrs.imhere.CATEGORY_LOCATION_SERVICES")
                             .putExtra("br.com.marrs.imhere.EXTRA_GEOFENCE_STATUS", msg);
          }
  
          // Broadcast whichever result occurred
          LocalBroadcastManager.getInstance(mActivity).sendBroadcast(broadcastIntent);
  
          // Disconnect the location client
          requestDisconnection();
      }
  
      /**
       * 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("DEBUG", "GeofenceRequester connected");
  
          // Continue adding the geofences
          continueAddGeofences();
      }
  
      /*
       * 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("DEBUG", "GeofenceRequester disconnected");
  
          // Destroy the current location client
          mLocationClient = 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, 9000);
  
              /*
               * 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("br.com.marrs.imhere.ACTION_CONNECTION_ERROR");
              errorBroadcastIntent.addCategory("br.com.marrs.imhere.CATEGORY_LOCATION_SERVICES")
                                  .putExtra("br.com.marrs.imhere.EXTRA_CONNECTION_ERROR_CODE",
                                          connectionResult.getErrorCode());
              LocalBroadcastManager.getInstance(mActivity).sendBroadcast(errorBroadcastIntent);
          }
      }
  }
  </code></pre>
  
  <p>And the service:</p>
  
  <pre><code>package br.com.marrs.imhere.services;
  import br.com.marrs.imhere.ImHereActivity;
  import br.com.marrs.imhere.R;
  
  import com.google.android.gms.location.Geofence;
  import com.google.android.gms.location.LocationClient;
  
  import android.app.IntentService;
  import android.app.NotificationManager;
  import android.app.PendingIntent;
  import android.content.Context;
  import android.content.Intent;
  import android.support.v4.app.NotificationCompat;
  import android.support.v4.app.TaskStackBuilder;
  import android.support.v4.content.LocalBroadcastManager;
  import android.text.TextUtils;
  import android.util.Log;
  
  import java.util.List;
  
  /**
   * This class receives geofence transition events from Location Services, in the
   * form of an Intent containing the transition type and geofence id(s) that triggered
   * the event.
   */
  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("br.com.marrs.imhere.CATEGORY_LOCATION_SERVICES");
  
          // First check for errors
          if (LocationClient.hasError(intent)) {
  
              // Get the error code
              int errorCode = LocationClient.getErrorCode(intent);
  
  
              // Log the error
              Log.e("DEBUG", "Erro no service LocationClient has error");
  
              // Set the action and error message for the broadcast intent
              broadcastIntent.setAction("br.com.marrs.imhere.ACTION_GEOFENCES_ERROR").putExtra("br.com.marrs.imhere.EXTRA_GEOFENCE_STATUS", "problemas");
  
              // 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 = LocationClient.getGeofenceTransition(intent);
  
              // 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 = LocationClient.getTriggeringGeofences(intent);
                  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(",",geofenceIds);
                  String transitionType = getTransitionString(transition);
  
                  sendNotification(transitionType, ids);
  
                  // Log the transition type and a message
                  Log.d("DEBUG","Ae...n sei pq isso....mas parece que tah ok");
  
              // An invalid transition was reported
              } else {
                  // Always log as an error
                  Log.e("DEBUG","Erro, erro, erro");
              }
          }
      }
  
      /**
       * 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(),ImHereActivity.class);
  
          // Construct a task stack
          TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
  
          // Adds the main Activity to the task stack as the parent
          stackBuilder.addParentStack(ImHereActivity.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.abs__ic_clear)
                 .setContentTitle(ids)
                 .setContentText(transitionType)
                 .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 "Entrando";
  
              case Geofence.GEOFENCE_TRANSITION_EXIT:
                  return "Saindo";
  
              default:
                  return "Desconhecido";
          }
      }
  }
  </code></pre>
  
  <p>And the Broadcast receiver in the Activity:</p>
  
  <pre><code>public class GeofenceSampleReceiver extends BroadcastReceiver 
      {
          /*
           * Define the required method for broadcast receivers
           * This method is invoked when a broadcast Intent triggers the receiver
           */
          @Override
          public void onReceive(Context context, Intent intent) 
          {
  
              // Check the action code and determine what to do
              String action = intent.getAction();
  
              // Intent contains information about errors in adding or removing geofences
              if (TextUtils.equals(action, "br.com.marrs.imhere.ACTION_GEOFENCE_ERROR"))
              {
  
                  handleGeofenceError(context, intent);
  
              // Intent contains information about successful addition or removal of geofences
              } 
              else if (
                      TextUtils.equals(action, "br.com.marrs.imhere.ACTION_GEOFENCES_ADDED")
                      ||
                      TextUtils.equals(action, "br.com.marrs.imhere.ACTION_GEOFENCES_REMOVED")) 
              {
  
                  handleGeofenceStatus(context, intent);
  
              // Intent contains information about a geofence transition
              } else if (TextUtils.equals(action, "br.com.marrs.imhere.ACTION_GEOFENCE_TRANSITION")) 
              {
  
                  handleGeofenceTransition(context, intent);
  
              // The Intent contained an invalid action
              } 
              else 
              {
                  Log.e("DEBUG", "Invalid action detail");
                  Toast.makeText(context, "Invalid action detail", Toast.LENGTH_LONG).show();
              }
          }
  
          /**
           * If you want to display a UI message about adding or removing geofences, put it here.
           *
           * @param context A Context for this component
           * @param intent The received broadcast Intent
           */
          private void handleGeofenceStatus(Context context, Intent intent) {
  
          }
  
          /**
           * Report geofence transitions to the UI
           *
           * @param context A Context for this component
           * @param intent The Intent containing the transition
           */
          private void handleGeofenceTransition(Context context, Intent intent) {
              /*
               * If you want to change the UI when a transition occurs, put the code
               * here. The current design of the app uses a notification to inform the
               * user that a transition has occurred.
               */
          }
  
          /**
           * Report addition or removal errors to the UI, using a Toast
           *
           * @param intent A broadcast Intent sent by ReceiveTransitionsIntentService
           */
          private void handleGeofenceError(Context context, Intent intent) 
          {
              String msg = intent.getStringExtra("br.com.marrs.imhere.EXTRA_GEOFENCE_STATUS");
              Log.e("DEBUG", msg);
              Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
          }
      }
  </code></pre>
  
  <p>And here is the piece of code that I use to create a GEofence before send to GeofenceRequester.</p>
  
  <pre><code>int raio = Integer.parseInt(spinner.getAdapter().getItem(spinner.getSelectedItemPosition()).toString());
              int transitionType = (in.isChecked())?Geofence.GEOFENCE_TRANSITION_ENTER:Geofence.GEOFENCE_TRANSITION_EXIT;
              Geofence geofence = new Geofence.Builder().setRequestId(nomeGeofence.getText().toString()).setTransitionTypes(transitionType).setCircularRegion(lat, lon, raio).setExpirationDuration(Geofence.NEVER_EXPIRE).build();
              geofences.add(geofence);
  
              try 
              {
                  mGeofenceRequester.addGeofences(geofences);
                  addCircleGeofence(raio);
              }
              catch (UnsupportedOperationException e) 
              {
                  Toast.makeText(getActivity(), "Já existe uma requisição de add em andamento",Toast.LENGTH_LONG).show();
              }
  </code></pre>
  
  <p>Any help will be great!
  Thanks!</p>