I'm trying to implement Geofence
on my APP and the problem is that is not triggering when I'm on the place that I've marked.
The thing that I do is I set the Latitude
& Longitude
from a Place Picker.
The values that I'm getting are fine because I put it on google maps
and the place is the correct one, because I've read many answers that people was setting bad values from lat/long.
I've two classes : GeofenceSingleton.class
and GeofenceTransitionsIntentService
.
The GeofenceSingleton.class
looks like :
public class GeofenceSingleton implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
private GoogleApiClient googleApiClient;
private static GeofenceSingleton _singleInstance;
private static Context appContext;
private static final String ERR_MSG = "Application Context is not set!! " +
"Please call GeofenceSngleton.init() with proper application context";
private PendingIntent mGeofencePendingIntent;
private static ArrayList<Geofence> mGeofenceList;
private GeofenceSingleton() {
if (appContext == null)
throw new IllegalStateException(ERR_MSG);
this.googleApiClient = new GoogleApiClient.Builder(this.appContext)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
this.googleApiClient.connect();
mGeofenceList = new ArrayList<Geofence>();
}
/**
* @param applicationContext
*/
public static void init(Context applicationContext) {
appContext = applicationContext;
}
public static GeofenceSingleton getInstance() {
if (_singleInstance == null)
synchronized (GeofenceSingleton.class) {
if (_singleInstance == null)
_singleInstance = new GeofenceSingleton();
}
return _singleInstance;
}
@Override
public void onConnected(Bundle bundle) {
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
public void addGeofence(Location location, String uid) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(uid)
.setCircularRegion(
location.getLatitude(),
location.getLongitude(),
500
)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.setExpirationDuration(1000000)
.build());
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(appContext, GeofenceSingleton.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// addGeofences() and removeGeofences().
return PendingIntent.getService(appContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public void startGeofencing() {
if (!googleApiClient.isConnected()) {
Toast.makeText(appContext, "API client not connected", Toast.LENGTH_SHORT).show();
return;
}
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
// 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(this); // Result processed in onResult().
Toast.makeText(appContext,"Geofencing started", Toast.LENGTH_LONG).show();
}
public void removeGeofence(){
LocationServices.GeofencingApi.removeGeofences(
googleApiClient,
// This is the same pending intent that was used in addGeofences().
getGeofencePendingIntent()
);
}
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
// Update state and save in shared preferences.
Toast.makeText(
appContext,
"YO",
Toast.LENGTH_SHORT
).show();
} else {
Toast.makeText(
appContext,
"NOO",
Toast.LENGTH_SHORT
).show();
}
}
}
And GeofenceTransitionsIntentService
public class GeofenceTransitionsIntentService extends IntentService {
private static final String TAG = "Geofence-Service";
private Handler handler;
SharedPreferences sp;
SharedPreferences.Editor editor;
String EmailName, MessageEmail;
Context mContext;
Boolean EmailSent = false;
public GeofenceTransitionsIntentService() {
super(TAG);
}
@Override
public void onCreate() {
super.onCreate();
this.mContext = this;
sp = PreferenceManager.getDefaultSharedPreferences(this);
handler = new Handler();
}
@Override
protected void onHandleIntent(Intent intent) {
final GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
Log.e(TAG, "Error in geofencing event");
return;
}
// Get the transition type.
final int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transition was of interest.
if (geofenceTransition == 1) {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "Entered", Toast.LENGTH_SHORT).show();
sendNotification();
}
});
Log.i(TAG, "Entered");
}
else {
// Log the error.
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "Sorry you are out", Toast.LENGTH_SHORT).show();
}
});
Log.e(TAG, String.valueOf(geofenceTransition));
}
}
private void sendNotification() {
Toast.makeText(GeofenceTransitionsIntentService.this, "HEEEEEEEY I'M IN", Toast.LENGTH_SHORT).show();
}
On my MainActivity
I've got this :
GeofenceSingleton.init(this); //If I don't call this the class doesn't work
this.geofenceSingleton = GeofenceSingleton.getInstance();
And then I build a Geofence
as follows :
Location geofence = new Location("");
geofence.setLatitude(Double.parseDouble(latitude));
geofence.setLongitude(Double.parseDouble(longitude));
geofenceSingleton.addGeofence(geofence, GeofenceKey);
geofenceSingleton.startGeofencing();
I've added <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
on my manifest.xml
I declared the service
as <service android:name=".GeofenceTransitionsIntentService"/>
And I added this line on my build.gradle
: compile 'com.google.android.gms:play-services:7.8.0'
It only shows Toast.makeText(appContext,"YO",Toast.LENGTH_SHORT).show();
that's because status is success, and also shows the Toast.makeText(appContext,"Geofencing started", Toast.LENGTH_LONG).show();
means that it's started.
Why my IntentService
is never called?
I tested it putting a Lat
/Long
of my home and since I'm on it should be triggered, isn't it?
It will never work because what you are doing is
Intent intent = new Intent(appContext, GeofenceSingleton.class);
passing intent to GeofenceSingleton ?
What you need to do is
Intent intent = new Intent(appContext, GeofenceTransitionsIntentService.class);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With