title: trying to implement attendance in android using geofence with php
body: <p>I'm making an attendance system in android where employee should be able to put attendance only if he is in office premises through his mobile fingerprint scanner and I want to retrieve data like employee_name, location, date, time and save it in php I coded for geofencing but don't know how to proceed further below is code for geofencing
  I searched all over the internet but didn't find a proper solution please anyone help me I really need this.....</p>
  
  <p><strong>MyGeoFenCIN.java</strong></p>
  
  <pre><code>import android.app.PendingIntent;
  import android.content.Context;
  import android.content.Intent;
  import android.support.annotation.NonNull;
  import android.util.Log;
  
  import com.google.android.gms.common.api.GoogleApiClient;
  import com.google.android.gms.common.api.Result;
  import com.google.android.gms.common.api.ResultCallback;
  import com.google.android.gms.location.Geofence;
  import com.google.android.gms.location.GeofencingRequest;
  import com.google.android.gms.location.LocationServices;
  import com.google.android.gms.location.places.Place;
  import com.google.android.gms.location.places.PlaceBuffer;
  
  import java.util.ArrayList;
  import java.util.List;
  
  public class Geofencing implements ResultCallback {
  
      // Constants
      public static final String TAG = Geofencing.class.getSimpleName();
      private static final float GEOFENCE_RADIUS = 1606; // 50 meters
      private static final long GEOFENCE_TIMEOUT = 24 * 60 * 60 * 1000; // 24 hours
  
      private List&lt;Geofence&gt; mGeofenceList;
      private PendingIntent mGeofencePendingIntent;
      private GoogleApiClient mGoogleApiClient;
      private Context mContext;
  
      public Geofencing(Context context, GoogleApiClient client) {
          mContext = context;
          mGoogleApiClient = client;
          mGeofencePendingIntent = null;
          mGeofenceList = new ArrayList&lt;&gt;();
      }
  
      /***
       * Registers the list of Geofences specified in mGeofenceList with Google Place Services
       * Uses {@code #mGoogleApiClient} to connect to Google Place Services
       * Uses {@link #getGeofencingRequest} to get the list of Geofences to be registered
       * Uses {@link #getGeofencePendingIntent} to get the pending intent to launch the IntentService
       * when the Geofence is triggered
       * Triggers {@link #onResult} when the geofences have been registered successfully
       */
      public void registerAllGeofences() {
          // Check that the API client is connected and that the list has Geofences in it
          if (mGoogleApiClient == null || !mGoogleApiClient.isConnected() ||
                  mGeofenceList == null || mGeofenceList.size() == 0) {
              return;
          }
          try {
              LocationServices.GeofencingApi.addGeofences(
                      mGoogleApiClient,
                      getGeofencingRequest(),
                      getGeofencePendingIntent()
              ).setResultCallback(this);
          } catch (SecurityException securityException) {
              // Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
              Log.e(TAG, securityException.getMessage());
          }
      }
  
      /***
       * Unregisters all the Geofences created by this app from Google Place Services
       * Uses {@code #mGoogleApiClient} to connect to Google Place Services
       * Uses {@link #getGeofencePendingIntent} to get the pending intent passed when
       * registering the Geofences in the first place
       * Triggers {@link #onResult} when the geofences have been unregistered successfully
       */
      public void unRegisterAllGeofences() {
          if (mGoogleApiClient == null || !mGoogleApiClient.isConnected()) {
              return;
          }
          try {
              LocationServices.GeofencingApi.removeGeofences(
                      mGoogleApiClient,
                      // This is the same pending intent that was used in registerGeofences
                      getGeofencePendingIntent()
              ).setResultCallback(this);
          } catch (SecurityException securityException) {
              // Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
              Log.e(TAG, securityException.getMessage());
          }
      }
  
  
      /***
       * Updates the local ArrayList of Geofences using data from the passed in list
       * Uses the Place ID defined by the API as the Geofence object Id
       *
       * @param places the PlaceBuffer result of the getPlaceById call
       */
      public void updateGeofencesList(PlaceBuffer places) {
          mGeofenceList = new ArrayList&lt;&gt;();
          if (places == null || places.getCount() == 0) return;
          for (Place place : places) {
              // Read the place information from the DB cursor
              String placeUID = place.getId();
              double placeLat = place.getLatLng().latitude;
              double placeLng = place.getLatLng().longitude;
              // Build a Geofence object
              Geofence geofence = new Geofence.Builder()
                      .setRequestId(placeUID)
                      .setExpirationDuration(GEOFENCE_TIMEOUT)
                      .setCircularRegion(placeLat, placeLng, GEOFENCE_RADIUS)
                      .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
                      .build();
              // Add it to the list
              mGeofenceList.add(geofence);
          }
      }
  
      /***
       * Creates a GeofencingRequest object using the mGeofenceList ArrayList of Geofences
       * Used by {@code #registerGeofences}
       *
       * @return the GeofencingRequest object
       */
      private GeofencingRequest getGeofencingRequest() {
          GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
          builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
          builder.addGeofences(mGeofenceList);
          return builder.build();
      }
  
      /***
       * Creates a PendingIntent object using the GeofenceTransitionsIntentService class
       * Used by {@code #registerGeofences}
       *
       * @return the PendingIntent object
       */
      private PendingIntent getGeofencePendingIntent() {
          // Reuse the PendingIntent if we already have it.
          if (mGeofencePendingIntent != null) {
              return mGeofencePendingIntent;
          }
  
          Intent intent = new Intent(mContext, GeofenceTransitionsIntentService.class);
          mGeofencePendingIntent = PendingIntent.getService(mContext, 0, intent, PendingIntent.
                  FLAG_UPDATE_CURRENT);
          return mGeofencePendingIntent;
      }
  
      @Override
      public void onResult(@NonNull Result result) {
          Log.e(TAG, String.format("Error adding/removing geofence : %s",
                  result.getStatus().toString()));
      }
  
  }
  </code></pre>
  
  <p><strong>GeofenceTransitionsIntentService.java</strong></p>
  
  <pre><code>import android.app.AlarmManager;
  import android.app.IntentService;
  import android.app.NotificationManager;
  import android.app.PendingIntent;
  import android.content.Context;
  import android.content.Intent;
  import android.content.SharedPreferences;
  import android.graphics.BitmapFactory;
  import android.graphics.Color;
  import android.net.Uri;
  import android.preference.PreferenceManager;
  import android.support.annotation.NonNull;
  import android.support.v4.app.NotificationCompat;
  import android.support.v4.app.TaskStackBuilder;
  import android.text.TextUtils;
  import android.util.Log;
  import android.widget.Toast;
  
  import com.google.android.gms.common.api.PendingResult;
  import com.google.android.gms.common.api.ResultCallback;
  import com.google.android.gms.location.Geofence;
  import com.google.android.gms.location.GeofencingEvent;
  import com.google.android.gms.location.places.GeoDataClient;
  import com.google.android.gms.location.places.Place;
  import com.google.android.gms.location.places.PlaceBuffer;
  import com.google.android.gms.location.places.PlaceBufferResponse;
  import com.google.android.gms.location.places.Places;
  import com.google.android.gms.tasks.OnCompleteListener;
  import com.google.android.gms.tasks.Task;
  
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Calendar;
  import java.util.List;
  import java.util.Map;
  
  /**
   * Listener for geofence transition changes.
   *
   * Receives geofence transition events from Location Services in the form of an Intent containing
   * the transition type and geofence id(s) that triggered the transition. Creates a notification
   * as the output.
   */
  public class GeofenceTransitionsIntentService extends IntentService {
  
      private static final String TAG = "GeofenceTransitionsIS";
  
      private GeoDataClient mGeoDataClient;
      String geofenceTransitionString;
  
      /**
       * 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);
  
  
  
      }
  
      /**
       * 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(geofenceTransition,
                      triggeringGeofences);
  
              mGeoDataClient = Places.getGeoDataClient(this, null);
  
              mGeoDataClient.getPlaceById(geofenceTransitionDetails).addOnCompleteListener(new OnCompleteListener&lt;PlaceBufferResponse&gt;() {
                  @Override
                  public void onComplete(@NonNull Task&lt;PlaceBufferResponse&gt; task) {
                      if (task.isSuccessful()) {
                          PlaceBufferResponse places = task.getResult();
                          Place myPlace = places.get(0);
                          Log.i(TAG, "Place found: " + myPlace.getName());
                          CharSequence name = myPlace.getName();
                          String placeName = name.toString();
                          places.release();
  
                          Calendar currentTime = Calendar.getInstance();
                          SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
                          String formattedDate = df.format(currentTime.getTime());
  
                          sendNotification(geofenceTransitionString + ": " + placeName + " " + formattedDate);
                      } else {
                          Log.e(TAG, "Place not found.");
                      }
                  }
              });
              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 geofenceTransition    The ID of the geofence transition.
           * @param triggeringGeofences   The geofence(s) triggered.
           * @return                      The transition details formatted as String.
           */
          private String getGeofenceTransitionDetails(
                  int geofenceTransition,
                  List&lt;Geofence&gt; triggeringGeofences) {
  
              geofenceTransitionString = getTransitionString(geofenceTransition);
  
  
              // Get the Ids of each geofence that was triggered.
              ArrayList&lt;String&gt; triggeringGeofencesIdsList = new ArrayList&lt;&gt;();
              for (Geofence geofence : triggeringGeofences) {
                  triggeringGeofencesIdsList.add(geofence.getRequestId());
  
  
              }
              String triggeringGeofencesIdsString = TextUtils.join(", ",  triggeringGeofencesIdsList);
  
  
  
              return 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(), MainActivity.class);
  
              // Construct a task stack.
              TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
  
              // Add 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);
  
              // Define the notification settings.
              builder.setSmallIcon(R.mipmap.ic_launcher)
                      // In a real app, you may want to use a library like Volley
                      // to decode the Bitmap.
                      .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                              R.mipmap.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);
              }
          }
      }
  </code></pre>
  
  <p>So here I don't know how to make a condition that employee can put attendance only if he is in office premises and after attendance storing data in php I have seen apps on play store doing the same but I don't know how to do this</p>
  
  <p><strong>MyPlaceAdapter.java</strong>    </p>
  
  <pre><code>import android.content.Context;
  import android.support.v7.widget.RecyclerView;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.TextView;
  
  import com.locationgeo.R;
  import com.google.android.gms.location.places.PlaceBuffer;
  
  public class PlaceListAdapter extends RecyclerView.Adapter&lt;PlaceListAdapter.PlaceViewHolder&gt; {
  
      private Context mContext;
      private PlaceBuffer mPlaces;
  
  
      public PlaceListAdapter(Context context, PlaceBuffer places) {
          this.mContext = context;
          this.mPlaces = places;
      }
  
  
      @Override
      public PlaceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
          // Get the RecyclerView item layout
          LayoutInflater inflater = LayoutInflater.from(mContext);
          View view = inflater.inflate(R.layout.item_place_card, parent, false);
          return new PlaceViewHolder(view);
      }
  
  
      @Override
      public void onBindViewHolder(PlaceViewHolder holder, int position) {
          String placeName = mPlaces.get(position).getName().toString();
          String placeAddress = mPlaces.get(position).getAddress().toString();
          holder.nameTextView.setText(placeName);
          holder.addressTextView.setText(placeAddress);
      }
  
      public void swapPlaces(PlaceBuffer newPlaces){
          mPlaces = newPlaces;
          if (mPlaces != null) {
              // Force the RecyclerView to refresh
              this.notifyDataSetChanged();
          }
      }
  
  
      @Override
      public int getItemCount() {
          if(mPlaces==null) return 0;
          return mPlaces.getCount();
      }
  
      /**
       * PlaceViewHolder class for the recycler view item
       */
      class PlaceViewHolder extends RecyclerView.ViewHolder {
  
          TextView nameTextView;
          TextView addressTextView;
  
          public PlaceViewHolder(View itemView) {
              super(itemView);
              nameTextView = (TextView) itemView.findViewById(R.id.name_text_view);
              addressTextView = (TextView) itemView.findViewById(R.id.address_text_view);
          }
  
      }
  }
  </code></pre>
  
  <p><strong>PlaceProvider.java</strong>    </p>
  
  <pre><code>import android.content.ContentProvider;
  import android.content.ContentUris;
  import android.content.ContentValues;
  import android.content.Context;
  import android.content.UriMatcher;
  import android.database.Cursor;
  import android.database.sqlite.SQLiteDatabase;
  import android.net.Uri;
  import android.support.annotation.NonNull;
  
  
  public class PlaceContentProvider extends ContentProvider {
  
  
      public static final int PLACES = 100;
      public static final int PLACE_WITH_ID = 101;
  
      // Declare a static variable for the Uri matcher that you construct
      private static final UriMatcher sUriMatcher = buildUriMatcher();
      private static final String TAG = PlaceContentProvider.class.getName();
  
      // Define a static buildUriMatcher method that associates URI's with their int match
      public static UriMatcher buildUriMatcher() {
          // Initialize a UriMatcher
          UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
          // Add URI matches
          uriMatcher.addURI(PlaceContract.AUTHORITY, PlaceContract.PATH_PLACES, PLACES);
          uriMatcher.addURI(PlaceContract.AUTHORITY, PlaceContract.PATH_PLACES + "/#", PLACE_WITH_ID);
          return uriMatcher;
      }
  
      // Member variable for a PlaceDbHelper that's initialized in the onCreate() method
      private PlaceDbHelper mPlaceDbHelper;
  
      @Override
      public boolean onCreate() {
          Context context = getContext();
          mPlaceDbHelper = new PlaceDbHelper(context);
          return true;
      }
  
      /***
       * Handles requests to insert a single new row of data
       *
       * @param uri
       * @param values
       * @return
       */
      @Override
      public Uri insert(@NonNull Uri uri, ContentValues values) {
          final SQLiteDatabase db = mPlaceDbHelper.getWritableDatabase();
  
          // Write URI matching code to identify the match for the places directory
          int match = sUriMatcher.match(uri);
          Uri returnUri; // URI to be returned
          switch (match) {
              case PLACES:
                  // Insert new values into the database
                  long id = db.insert(PlaceContract.PlaceEntry.TABLE_NAME, null, values);
                  if (id &gt; 0) {
                      returnUri = ContentUris.withAppendedId(PlaceContract.PlaceEntry.CONTENT_URI, id);
                  } else {
                      throw new android.database.SQLException("Failed to insert row into " + uri);
                  }
                  break;
              // Default case throws an UnsupportedOperationException
              default:
                  throw new UnsupportedOperationException("Unknown uri: " + uri);
          }
  
          // Notify the resolver if the uri has been changed, and return the newly inserted URI
          getContext().getContentResolver().notifyChange(uri, null);
  
          // Return constructed uri (this points to the newly inserted row of data)
          return returnUri;
      }
  
  
      @Override
      public Cursor query(@NonNull Uri uri, String[] projection, String selection,
                          String[] selectionArgs, String sortOrder) {
  
          // Get access to underlying database (read-only for query)
          final SQLiteDatabase db = mPlaceDbHelper.getReadableDatabase();
  
          // Write URI match code and set a variable to return a Cursor
          int match = sUriMatcher.match(uri);
          Cursor retCursor;
  
          switch (match) {
              // Query for the places directory
              case PLACES:
                  retCursor = db.query(PlaceContract.PlaceEntry.TABLE_NAME,
                          projection,
                          selection,
                          selectionArgs,
                          null,
                          null,
                          sortOrder);
                  break;
              // Default exception
              default:
                  throw new UnsupportedOperationException("Unknown uri: " + uri);
          }
  
          // Set a notification URI on the Cursor and return that Cursor
          retCursor.setNotificationUri(getContext().getContentResolver(), uri);
  
          // Return the desired Cursor
          return retCursor;
      }
  
  
      @Override
      public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
          // Get access to the database and write URI matching code to recognize a single item
          final SQLiteDatabase db = mPlaceDbHelper.getWritableDatabase();
          int match = sUriMatcher.match(uri);
          // Keep track of the number of deleted places
          int placesDeleted; // starts as 0
          switch (match) {
              // Handle the single item case, recognized by the ID included in the URI path
              case PLACE_WITH_ID:
                  // Get the place ID from the URI path
                  String id = uri.getPathSegments().get(1);
                  // Use selections/selectionArgs to filter for this ID
                  placesDeleted = db.delete(PlaceContract.PlaceEntry.TABLE_NAME, "_id=?", new String[]{id});
                  break;
              default:
                  throw new UnsupportedOperationException("Unknown uri: " + uri);
          }
          // Notify the resolver of a change and return the number of items deleted
          if (placesDeleted != 0) {
              // A place (or more) was deleted, set notification
              getContext().getContentResolver().notifyChange(uri, null);
          }
          // Return the number of places deleted
          return placesDeleted;
      }
  
  
      @Override
      public int update(@NonNull Uri uri, ContentValues values, String selection,
                        String[] selectionArgs) {
          // Get access to underlying database
          final SQLiteDatabase db = mPlaceDbHelper.getWritableDatabase();
          int match = sUriMatcher.match(uri);
          // Keep track of the number of updated places
          int placesUpdated;
  
          switch (match) {
              case PLACE_WITH_ID:
                  // Get the place ID from the URI path
                  String id = uri.getPathSegments().get(1);
                  // Use selections/selectionArgs to filter for this ID
                  placesUpdated = db.update(PlaceContract.PlaceEntry.TABLE_NAME, values, "_id=?", new String[]{id});
                  break;
              // Default exception
              default:
                  throw new UnsupportedOperationException("Unknown uri: " + uri);
          }
  
          // Notify the resolver of a change and return the number of items updated
          if (placesUpdated != 0) {
              // A place (or more) was updated, set notification
              getContext().getContentResolver().notifyChange(uri, null);
          }
          // Return the number of places deleted
          return placesUpdated;
      }
  
  
      @Override
      public String getType(@NonNull Uri uri) {
          throw new UnsupportedOperationException("Not yet implemented");
      }
  }
  </code></pre>