Java — пытается реализовать посещаемость в Android с помощью геозоны с переполнением стека

Я делаю систему посещаемости в Android, где сотрудник должен иметь возможность выставлять посещаемость только в том случае, если он находится в служебных помещениях с помощью своего мобильного сканера отпечатков пальцев, и я хочу получить такие данные, как имя сотрудника, местоположение, дата, время и сохранить их в коде php, который я кодировал. для геозон, но не знаю, как действовать дальше. Код геозон
Я искал по всему интернету, но не нашел правильного решения, пожалуйста, кто-нибудь, помогите мне, мне действительно нужно это …..

MyGeoFenCIN.java

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<Geofence> 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<>();
}

/***
* 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<>();
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()));
}

}

GeofenceTransitionsIntentService.java

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<Geofence> 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<PlaceBufferResponse>() {
@Override
public void onComplete(@NonNull Task<PlaceBufferResponse> 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<Geofence> triggeringGeofences) {

geofenceTransitionString = getTransitionString(geofenceTransition);


// Get the Ids of each geofence that was triggered.
ArrayList<String> triggeringGeofencesIdsList = new ArrayList<>();
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 >= 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);
}
}
}

Так что здесь я не знаю, как сделать условие, чтобы сотрудник мог ставить посещаемость, только если он находится в служебных помещениях, и после того, как посещаемость хранит данные в php, я видел, как приложения в игровом магазине делают то же самое, но я не знаю, как это сделать. этот

MyPlaceAdapter.java

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<PlaceListAdapter.PlaceViewHolder> {

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);
}

}
}

PlaceProvider.java

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 > 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");
}
}

1

Решение

Я предполагаю, что вы пытаетесь создать приложение, которое сотрудники будут использовать для включения / выключения:

А) сканирование их отпечатков пальцев (с помощью приложения),

и б) нажатием кнопки «ВХОД» или «ВНЕ» (с тем же приложением) ??

Если это так, то вам не нужно геозону. Геозоны — для ситуаций, когда вы хотите, чтобы что-то произошло автоматически когда пользователь входит в обозначенную область.

С другой стороны, ваша ситуация требует, чтобы ваше приложение знать о местонахождении телефона когда пользователь нажимает IN / OUT.

Когда пользователь нажимает IN / OUT, вы просто загружаете широту и долготу, время, ID и т. Д., И сервер определяет, находится ли широта или долгота в пределах границы (вы можете сделать это следующим образом этот).

Если они не находятся на границе, то сервер вернет ошибку … или может быть тихо об этом.

Вам также придется остерегаться поддельные локации.

0

Другие решения

Других решений пока нет …