title: Why is Google Geofencing not working in my android app?
body: <p>Ive added all the necessary code from the <code>google</code> documentation for implementing <code>Geofencing</code> in android. Although I can more or less understand what is going on, im trying to make the process as minimal as possible. Ideally, the user would pick a location and a <code>geofence</code> gets set around it. Once user enters the area, it should trigger an action. For now I am just trying to hard-code a location and get that working then take it from there. With that being said the button stuff is probably not necessary or the array-list of specified events.</p>
  
  <p>My question is what is the bare minimum code I need to implement this process and what is the best way to go about it? This is my first android app so go easy on the heckling.</p>
  
  <pre><code>public class MapsActivity extends FragmentActivity implements
      GoogleApiClient.ConnectionCallbacks,
      GoogleApiClient.OnConnectionFailedListener,
      LocationListener {
  
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
  
  
          setContentView(R.layout.activity_maps);
  
          // Kick off the request to build GoogleApiClient.
          buildGoogleApiClient();
  
          mGeofencePendingIntent = null;
          // Get the value of mGeofencesAdded from SharedPreferences. Set to false as a default.
          mGeofencesAdded = mSharedPreferences.getBoolean(Constants.GEOFENCES_ADDED_KEY, false);
  
          // Get the geofences used. Geofence data is hard coded in this sample.
          populateGeofenceList();
          getGeofencePendingIntent();
          getGeofencingRequest();
  
          addGeofencesButtonHandler(this);
  
          //Get the UI widgets.
          mAddGeofencesButton = (Button) findViewById(R.id.add_geofences_button);
          mRemoveGeofencesButton = (Button) findViewById(R.id.remove_geofences_button);
  
          mSharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME,
          MODE_PRIVATE);
      }
  
  }
  
  @Override
  public void onConnected(Bundle bundle) {
      mLocationRequest = LocationRequest.create();
      mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
      mLocationRequest.setInterval(1000); // Update location every second
  
      LocationServices.FusedLocationApi.requestLocationUpdates(
              mGoogleApiClient, mLocationRequest, this);
  }
  
  
  @Override
  public void onLocationChanged(Location location) {
  
      double lat = location.getLatitude();
      double lng = location.getLongitude();
  
          myLat = lat;
          myLng = lng;
          mapCenter = new LatLng(myLat, myLng);
          mMap.moveCamera(CameraUpdateFactory.newLatLng(mapCenter));
  }
  
  /**
   * Builds a GoogleApiClient. Uses the {@code #addApi} method to request the LocationServices API.
   */
  protected synchronized void buildGoogleApiClient() {
      mGoogleApiClient = new GoogleApiClient.Builder(this)
              .addConnectionCallbacks(this)
              .addOnConnectionFailedListener(this)
              .addApi(LocationServices.API)
              .build();
  }
  
  private void setUpMap() {
  
      // Enable MyLocation Layer of Google Map
      mMap.setMyLocationEnabled(true);
  
      // Get LocationManager object from System Service LOCATION_SERVICE
      locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
  
      // set map type
      mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
  
      // Get the name of the best provider
      String networkProvider = locationManager.NETWORK_PROVIDER;
      String gpsProvider = locationManager.GPS_PROVIDER;
  
      // Get Best Current Location
      myLocation = locationManager.getLastKnownLocation(networkProvider);
  
          // Get latitude of the current location
          double latitude = myLocation.getLatitude();
  
          // Get longitude of the current location
          double longitude = myLocation.getLongitude();
  
          // Create a LatLng object for the current location
          LatLng latLng = new LatLng(latitude, longitude);
  
          // Show the current location in Google Map
          mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
  
          // Zoom in the Google Map
          mMap.animateCamera(CameraUpdateFactory.zoomTo(14));
  
          //Add Marker For event
          Intent myIntent = getIntent();
          String desc = myIntent.getStringExtra("desc");
          String addr = myIntent.getStringExtra("addr");
          venueLat = myIntent.getDoubleExtra("lat", 0.0);
          venueLng = myIntent.getDoubleExtra("lon", 0.0);
  
          mMap.addMarker(new MarkerOptions().position(new LatLng(venueLat, venueLng)).title(desc).snippet(addr));
      }
  
  }
  
  /*
  *
  *
  *
  *
  * Geofence Stuff
  *
  *
  *
  *
   */
  
  
  private PendingIntent getGeofencePendingIntent() {
      // Reuse the PendingIntent if we already have it.
      if (mGeofencePendingIntent != null) {
          return mGeofencePendingIntent;
      }
      Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
      // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
      // calling addGeofences() and removeGeofences().
      return PendingIntent.getService(this, 0, intent, PendingIntent.
              FLAG_UPDATE_CURRENT);
  }
  
  private GeofencingRequest getGeofencingRequest() {
      GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
      builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
      builder.addGeofences(mGeofenceList);
      return builder.build();
  }
  
  
  /**
   * This sample hard codes geofence data. A real app might dynamically create geofences based on
   * the users location.
   */
  public void populateGeofenceList() {
      for (Map.Entry&lt;String, LatLng&gt; entry : Constants.BAY_AREA_LANDMARKS.entrySet()) {
  
          mGeofenceList.add(new Geofence.Builder()
                  // Set the request ID of the geofence. This is a string to identify this
                  // geofence.
                  .setRequestId(entry.getKey())
  
                          // Set the circular region of this geofence.
                  .setCircularRegion(
                          entry.getValue().latitude,
                          entry.getValue().longitude,
                          Constants.GEOFENCE_RADIUS_IN_METERS
                  )
  
                          // Set the expiration duration of the geofence. This geofence gets automatically
                          // removed after this period of time.
                  .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
  
                          // Set the transition types of interest. Alerts are only generated for these
                          // transition. We track entry and exit transitions in this sample.
                  .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
                          Geofence.GEOFENCE_TRANSITION_EXIT)
  
                          // Create the geofence.
                  .build());
      }
  }
  
  
  
  
  public void addGeofencesButtonHandler(View view) {
      if (!mGoogleApiClient.isConnected()) {
          Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
          return;
      }
  
      try {
          LocationServices.GeofencingApi.addGeofences(
                  mGoogleApiClient,
                  // The GeofenceRequest object.
                  getGeofencingRequest(),
                  // A pending intent that that is reused when calling removeGeofences(). This
                  // pending intent is used to generate an intent when a matched geofence
                  // transition is observed.
                  getGeofencePendingIntent()
          ).setResultCallback((ResultCallback&lt;Status&gt;) this); // Result processed in onResult().
      } catch (SecurityException securityException) {
          // Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
          // logSecurityException(securityException);
      }
  }
  
  
  
  /**
   * Runs when the result of calling addGeofences() and removeGeofences() becomes available.
   * Either method can complete successfully or with an error.
   *
   * Since this activity implements the {@link ResultCallback} interface, we are required to
   * define this method.
   *
   * @param status The Status returned through a PendingIntent when addGeofences() or
   *               removeGeofences() get called.
   */
  public void onResult(Status status) {
      if (status.isSuccess()) {
          // Update state and save in shared preferences.
          mGeofencesAdded = !mGeofencesAdded;
          SharedPreferences.Editor editor = mSharedPreferences.edit();
          editor.putBoolean(Constants.GEOFENCES_ADDED_KEY, mGeofencesAdded);
          editor.commit();
  
          // Update the UI. Adding geofences enables the Remove Geofences button, and removing
          // geofences enables the Add Geofences button.
          setButtonsEnabledState();
  
          Toast.makeText(
                  this,
                  getString(mGeofencesAdded ? R.string.geofences_added :
                          R.string.geofences_removed),
                  Toast.LENGTH_SHORT
          ).show();
      } else {
          // Get the status code for the error and log it using a user-friendly message.
          String errorMessage = GeofenceErrorMessages.getErrorString(this,
                  status.getStatusCode());
          Log.e(TAG, errorMessage);
      }
  }
  
  
  /**
   * Ensures that only one button is enabled at any time. The Add Geofences button is enabled
   * if the user hasnt yet added geofences. The Remove Geofences button is enabled if the
   * user has added geofences.
   */
  private void setButtonsEnabledState() {
      if (mGeofencesAdded) {
          mAddGeofencesButton.setEnabled(false);
          mRemoveGeofencesButton.setEnabled(true);
      } else {
          mAddGeofencesButton.setEnabled(true);
          mRemoveGeofencesButton.setEnabled(false);
      }
  }
  
  
  }
  
  
  
  
  /*
  * ---------------------------------------------------------------------------------------
  */
  
  
  
  public class GeofenceTransitionsIntentService extends IntentService {
  protected static final String TAG = "geofence-transitions-service";
  
  
  /**
   * This constructor is required, and calls the super IntentService(String)
   * constructor with the name for a worker thread.
   */
  public GeofenceTransitionsIntentService() {
      // Use the TAG to name the worker thread.
      super(TAG);
  }
  
  @Override
  public void onCreate() {
      super.onCreate();
  }
  
  /**
   * Handles incoming intents.
   * @param intent sent by Location Services. This Intent is provided to Location
   *               Services (inside a PendingIntent) when addGeofences() is called.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
      if (geofencingEvent.hasError()) {
          String errorMessage = GeofenceErrorMessages.getErrorString(this,
                  geofencingEvent.getErrorCode());
          Log.e(TAG, errorMessage);
          return;
      }
  
      // Get the transition type.
      int geofenceTransition = geofencingEvent.getGeofenceTransition();
  
      // Test that the reported transition was of interest.
      if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
              geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
  
          // Get the geofences that were triggered. A single event can trigger multiple geofences.
          List&lt;Geofence&gt; triggeringGeofences = geofencingEvent.getTriggeringGeofences();
  
          // Get the transition details as a String.
          String geofenceTransitionDetails = getGeofenceTransitionDetails(
                  this,
                  geofenceTransition,
                  triggeringGeofences
          );
  
          // Send notification and log the transition details.
          sendNotification(geofenceTransitionDetails);
         // Toast.makeText(getApplicationContext(), geofenceTransitionDetails, Toast.LENGTH_SHORT).show();
          Log.i(TAG, geofenceTransitionDetails);
      } else {
          // Log the error.
          Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition));
      }
  }
  
  /**
   * Gets transition details and returns them as a formatted string.
   *
   * @param context               The app context.
   * @param geofenceTransition    The ID of the geofence transition.
   * @param triggeringGeofences   The geofence(s) triggered.
   * @return                      The transition details formatted as String.
   */
  private String getGeofenceTransitionDetails(
          Context context,
          int geofenceTransition,
          List&lt;Geofence&gt; triggeringGeofences) {
  
      String geofenceTransitionString = getTransitionString(geofenceTransition);
  
      // Get the Ids of each geofence that was triggered.
      ArrayList triggeringGeofencesIdsList = new ArrayList();
      for (Geofence geofence : triggeringGeofences) {
          triggeringGeofencesIdsList.add(geofence.getRequestId());
      }
      String triggeringGeofencesIdsString = TextUtils.join(", ",  triggeringGeofencesIdsList);
  
      return geofenceTransitionString + ": " + triggeringGeofencesIdsString;
  }
  
  /**
   * Posts a notification in the notification bar when a transition is detected.
   * If the user clicks the notification, control goes to the MainActivity.
   */
  private void sendNotification(String notificationDetails) {
      // Create an explicit content Intent that starts the main Activity.
      Intent notificationIntent = new Intent(getApplicationContext(), MapsActivity.class);
  
      // Construct a task stack.
      TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
  
      // Add the main Activity to the task stack as the parent.
      stackBuilder.addParentStack(MapsActivity.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 thats compatible with platform versions &gt;= 4
      NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
  
      // Define the notification settings.
      builder.setSmallIcon(R.drawable.ic_launcher)
              // In a real app, you may want to use a library like Volley
              // to decode the Bitmap.
              .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                      R.drawable.ic_launcher))
              .setColor(Color.RED)
              .setContentTitle(notificationDetails)
              .setContentText(getString(R.string.geofence_transition_notification_text))
              .setContentIntent(notificationPendingIntent);
  
      // Dismiss notification once the user touches it.
      builder.setAutoCancel(true);
  
      // 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.unknown_geofence_transition);
      }
  }
  }
  
  /*
  * --------------------------------------------------------------------------
  */
  
  
  public class Constants {
  private Constants() {
  }
  
  public static final String PACKAGE_NAME = "com.google.android.gms.location.Geofence";
  
  public static final String SHARED_PREFERENCES_NAME = PACKAGE_NAME + ".SHARED_PREFERENCES_NAME";
  
  public static final String GEOFENCES_ADDED_KEY = PACKAGE_NAME + ".GEOFENCES_ADDED_KEY";
  
  /**
   * Used to set an expiration time for a geofence. After this amount of time Location Services
   * stops tracking the geofence.
   */
  public static final long GEOFENCE_EXPIRATION_IN_HOURS = 12;
  
  /**
   * For this sample, geofences expire after twelve hours.
   */
  public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS =
          GEOFENCE_EXPIRATION_IN_HOURS * 60 * 60 * 1000;
  public static final float GEOFENCE_RADIUS_IN_METERS = 1609; // 1 mile, 1.6 km
  
  /**
   * Map for storing information about airports in the San Francisco bay area.
   */
  public static final HashMap&lt;String, LatLng&gt; BAY_AREA_LANDMARKS = new HashMap&lt;String, LatLng&gt;();
  static {
  
      BAY_AREA_LANDMARKS.put("Home", new LatLng(29.382798, -98.529470));
  
  
      BAY_AREA_LANDMARKS.put("Other Home", new LatLng(29.472491,-98.571244));
  }
  }
  </code></pre>