Android Geofence cannot call IntentService and cannot work inside BroadcastReceiver - android

I have problem when I'm trying to use geofence with my app. I have succeed to register geofence but I have never get the notification.
First I follow the example that provide in http://developer.android.com/training/location/geofencing.html ,but the code never trigger intent service even I'm walking toward or away from area.
My code for register geofence and calling the intent service as follow :
inside manifest :
<service
android:name="com.example.zukami.apps.blynk.geofence.ReceiveTransitionsIntentService"
android:exported="true" >
</service>
in my MainActivity
private boolean registerGeofence() {
mRequestType = GeofenceUtils.REQUEST_TYPE.ADD;
if (!servicesConnected()) {
return false;
}
SimpleGeofence testGeo = new SimpleGeofence(Flag.GEOFENCE + "_"
+ 1, Double.valueOf("1.317342"),
Double.valueOf("103.841998"), (float) (200),
GEOFENCE_EXPIRATION_IN_HOURS,
Geofence.GEOFENCE_TRANSITION_ENTER);
mPrefs.setGeofence(Flag.GEOFENCE + "_" + 1, testGeo);
mCurrentGeofences.add(testGeo.toGeofence());
SimpleGeofence testGeo2 = new SimpleGeofence(Flag.GEOFENCE + "_"
+ 2, Double.valueOf("1.303961"),
Double.valueOf("103.909356"), (float) (200),
GEOFENCE_EXPIRATION_IN_HOURS,
Geofence.GEOFENCE_TRANSITION_ENTER);
mPrefs.setGeofence(Flag.GEOFENCE + "_" + 2, testGeo2);
mCurrentGeofences.add(testGeo2.toGeofence());
// end deleted this code after testing
try {
mGeofenceRequester.addGeofences(mCurrentGeofences);
Log.e(TAG, "ADDING GEOFENCE ??? YES WE DID IT");
} catch (UnsupportedOperationException e) {
Toast.makeText(this,
R.string.add_geofences_already_requested_error,
Toast.LENGTH_LONG).show();
}
return true;
}
#Override
protected void onResume() {
super.onResume();
// Register the broadcast receiver to receive status updates
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, mIntentFilter);
in my GeofenceRequester
private PendingIntent createRequestPendingIntent() {
Log.e(TAG, "CREATE REQUEST PENDING INTENT");
// If the PendingIntent already exists
if (null != mGeofencePendingIntent) {
Log.e(TAG, "PENDING INTENT NOT NULL");
return mGeofencePendingIntent;
// If no PendingIntent exists
} else {
Log.e(TAG, "PENDING INTENT NULL, LET'S CREATED IT");
// Create an Intent pointing to the IntentService
Intent intent = new Intent(mActivity,
ReceiveTransitionsIntentService.class);
Log.e(TAG,
return PendingIntent.getService(mActivity, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
and in class that subclass from IntentService remain same as an example.
I do search for this problem and found this solutions that describe on this link :
Android Geofence eventually stop getting transition intents ,so I change my code exactly as per suggestion, but still I cannot getting the notification, from my code inside GeofenceReceiver class, the code in this line
LocationClient.getGeofenceTransition(intent);
always return me -1 that means I never enter or leave the area (indicate GEOFENCE NEVER_EXPIRED),so I never get the notification. Please find below my GeofenceReceiver class :
public class GeofenceReceiver extends BroadcastReceiver {
public static String TAG = GeofenceReceiver.class.getCanonicalName();
Context context;
Intent broadcastIntent = new Intent();
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);
if (LocationClient.hasError(intent)) {
handleError(intent);
} else {
handleEnterExit(intent);
}
}
private void handleError(Intent intent) {
int errorCode = LocationClient.getErrorCode(intent);
String errorMessage = LocationServiceErrorMessages.getErrorString(
context, errorCode);
Log.e(GeofenceUtils.APPTAG, context.getString(
R.string.geofence_transition_error_detail, errorMessage));
broadcastIntent.setAction(GeofenceUtils.ACTION_GEOFENCE_ERROR)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, errorMessage);
LocalBroadcastManager.getInstance(context).sendBroadcast(
broadcastIntent);
}
private void handleEnterExit(Intent intent) {
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<Geofence> geofences = LocationClient
.getTriggeringGeofences(intent);
String[] geofenceIds = new String[geofences.size()];
String ids = TextUtils.join(GeofenceUtils.GEOFENCE_ID_DELIMITER,
geofenceIds);
String transitionType = getTransitionString(transition);
for (int index = 0; index < geofences.size(); index++) {
Geofence geofence = geofences.get(index);
geofenceIds[index] = geofences.get(index).getRequestId();
}
sendNotification(transitionType, ids);
// Create an Intent to broadcast to the app
broadcastIntent
.setAction(GeofenceUtils.ACTION_GEOFENCE_TRANSITION)
.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_ID, geofenceIds)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_TRANSITION_TYPE,
transitionType);
LocalBroadcastManager.getInstance(context).sendBroadcast(
broadcastIntent);
// Log the transition type and a message
Log.e(GeofenceUtils.APPTAG, transitionType + ": " + ids);
Log.e(GeofenceUtils.APPTAG, context
.getString(R.string.geofence_transition_notification_text));
Log.e(GeofenceUtils.APPTAG, "transition");
} else {
// Always log as an error
Log.e(TAG, "TRANSITION = " + transition);
}
}
Kindly advise what should I do for fix this code and really appreciate for any kind help.

for me I just changed some lines of code in createPendingIntent method
private PendingIntent createRequestPendingIntent() {
Log.e(TAG, "CREATE REQUEST PENDING INTENT");
// If the PendingIntent already exists
if (null != mGeofencePendingIntent) {
Log.e(TAG, "PENDING INTENT NOT NULL");
return mGeofencePendingIntent;
// If no PendingIntent exists
} else {
Log.e(TAG, "PENDING INTENT NULL, LET'S CREATED IT");
// Create an Intent pointing to the IntentService
Intent intent = new Intent(mActivity,
ReceiveTransitionsIntentService.class);
Log.e(TAG,
return PendingIntent.getService(mActivity, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
So in place of return PendingIntent.getService(mActivity, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
use this piece of cake
return PendingIntent.getBroadcast(mActivity, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
and make sure you have declared your BroadcastReceiver in application manisfest file.Good luck!!!!

Beware: Geofences are indeed being removed when Location Provider Settings change or the device is restarted. Unfortunately the Android documentation doesn't mention this anywhere.
To counter this, you can register for a Boot-Completed Receiver and a Location Provider Changed Receiver:
<!-- Boot Completed Receiver -->
<receiver android:name="com.mydemoapp.geofencing.BootCompleteReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<!-- Location Service Provider Changed Receiver -->
<receiver android:name="com.mydemoapp.geofencing.LocationProviderChangedReceiver">
<intent-filter>
<action android:name="android.location.PROVIDERS_CHANGED" />
</intent-filter>
</receiver>
Inside these two BroadcastReceivers you can implement your logic of re-registering your previously deleted geofences.

In the Manifest you have registered the Service.
<service
android:name="com.example.zukami.apps.blynk.geofence.ReceiveTransitionsIntentService"
android:exported="true" >
</service>
But you have used broadcast receiver so can be an issue there. I am not sure about the broadcast receiver but with ReceiveTransitionIntent it does work as per the documentation.
However now i am stuck because when Location Service is Disabled or When Device is restarted i think Geofences are removed and I am not able to Add the Geofences back in Background.

Related

onHandleWork never receives intent from pending intent Geofencing

I am working on a Geofencing application. The JobIntentService subclass that handles the GeofenceTransitions never receives the intent. I am receiving location updates at one minute interval then creating a new geofence list then adding the geofences based on a user's current location.
Here's my AndroidManifest.xml
........
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<service
android:name=".GeofenceTransitionsService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
<receiver
android:name=".GeofenceBroadcastReceiver"
android:enabled="true"
android:exported="true" />
.............
My GeofenceBroadcastReceiver.java
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
/**
* Receives incoming intents.
*
* #param context the application context.
* #param intent sent by Location Services. This Intent is provided to Location
* Services (inside a PendingIntent) when addGeofences() is called.
*/
#Override
public void onReceive(Context context, Intent intent) {
// Enqueues a JobIntentService passing the context and intent as parameters
GeofenceTransitionsService.enqueueWork(context, intent);
}
}
My GeofenceTransitionsService.java that handles the triggered geofences
public class GeofenceTransitionsService extends JobIntentService {
..........
/**
* Convenience method for enqueuing work in to this service
* Enqueue new work to be dispatched to onHandleWork
*/
public static void enqueueWork(Context context, Intent intent) {
Log.d(TAG, "Received intent: " + intent);
enqueueWork(context, GeofenceTransitionsService.class, JOB_ID, intent);
}
#Override
protected void onHandleWork(Intent intent){
// We have received work to do. The system or framework is already
// holding a wake lock for us at this point, so we can just go.
Log.d(TAG, "Received intent: " + intent);
}
}
Here's part of my code in PointOfInterestMapFragment.java that creates a geofencing request, creates the pending intent and adds the geofences
/* Use the GeofencingRequest class and its nested GeofencingRequestBuilder
* class to specify the geofences to monitor and to set how related geofence events are
* triggered
*/
private GeofencingRequest getGeofencingRequest(){
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
//tell Location services that GEOFENCE_TRANSITION_DWELL should be triggered if the
//device is already inside the geofence
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}//end method getGeofencingRequest
/*Pending intent that starts the IntentService*/
private PendingIntent getGeofencePendingIntent(){
Log.d(TAG, "getPendingIntent()");
//Reuse the pending intent if we already have it
if(mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(getActivity(), GeofenceBroadcastReceiver.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
// calling addGeofences() and removeGeofences().
mGeofencePendingIntent = PendingIntent.getBroadcast(getActivity()
, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;
}//end method PendingIntent
/*Add geofences*/
#SuppressWarnings("MissingPermission")
private void addGeofence(){
if(checkPermissions()){
mGeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "Geofence added");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "Failed to add geofence: " + e.getMessage());
}
})
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
//drawGeofence();
}
});
}else{
requestPermissions();
}
}//end method addGeofence
Here's the part of code in PointOfInterestMapFragment.java where I am receiving the location updates, populating the GeofenceList then adding geofences
/**
* Creates a callback for receiving location events.
*/
private void createLocationCallback() {
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
mCurrentLocation = locationResult.getLastLocation();
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
//populateGeofenceList to reflect the new current location bounds
populateGeofenceList();
addGeofence();
}
};
}
When the app executes, the I get the message in log cat from the line of code Log.d(TAG, "getPendingIntent()"); in getGeofencePendingIntent() but never get the message supposed to be displayed in onHandleWork() method
I had a similar 'problem'. The code is fine. In my case, I thought the code was not working because I had not understood properly how a geofence works. I thought to add the geofences, in your case a call to addGeofence() is the trigger, so I was waiting to see the notifications at that particular point in time. However a call to the method only adds the geofences for monitoring, then an intent is only delivered to the service when any of the filters are satisified (Geofence.GEOFENCE_TRANSITION_DWELL, Geofence.GEOFENCE_TRANSITION_EXIT OR Geofence.GEOFENCE_TRANSITION_ENTER) on an added geofence. You can read more from the documentation here
So, you might receive a Geofence added message in your log cat, but that's what it literally means, the geofences have been added not triggered. Wait for some time after the geofence have been added and if any of the filters are satisfied for a geofence that was added, then the intent is sent. So the solution that worked for me was to wait and I received the intent and notifications after some period of time.
If waiting does not work, you might want to extend the GEOFENCE_RADIUS, say to 3000 metres the check to see whether there is any change. Also, set the expiration duration to a higher value or to Geofence.NEVER_EXPIRE

Send data to BroadcastReceiver (CONNECTIVITY_CHANGE) to access to database from it

I am programming a Geofence app. When user arrives at some point, geofence triggers, and sends a Mail.
This works just perfect. But I need to control the case in which there is no connectivity so that the app sends the mail when connectivity becomes available.
I achieved this, with a Broadcast Receiver, which listens for CONNECTIVITY_CHANGE.
My problem is that I need to retrieve from database the details (receiver of the mail and text), and for that I need an "ID", but I can't find the way to pass this ID to the BroadcastReceiver.
This is my code:
I've an Intent that detects the Geofence, and if there is no Internet, activates the BroacasReceiver:
public class GeofenceIntentService extends IntentService implements com.google.android.gms.location.LocationListener {
[...]
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
extras = intent.getExtras();
Log.e(TAG, String.valueOf(extras.getLong("id")));
ID = extras.getLong("id");
sendMail(ID);
}
}
[...]
private void sendMail(long ID) {
dbHelper = new DBHelper(context);
dbHelper.getWritableDatabase();
cursor = dbHelper.getRegister(ID);
dbHelper.close();
tomail = cursor.getString(cursor.getColumnIndex("tomail"));
where = cursor.getString(cursor.getColumnIndex("where"));
texttosend = cursor.getString(cursor.getColumnIndex("texttosend"));
if (getConnectivityStatus(context) == 1 || getConnectivityStatus(context) == 2) {
Mail m = new Mail("***", "****");
String[] toArr = {tomail};
m.setTo(toArr);
m.setFrom("*****");
m.setSubject(getString(R.string.justtrying));
m.setBody(texttosend);
try {
if (m.send()) {
Log.v(TAG, "Email was sent successfully.");
} else {
Log.v(TAG, "Email was not sent.");
}
} catch (Exception e) {
Log.e("MailApp", "Could not send email", e);
}
} else {
Log.v(TAG, "Waiting for Internet Connection.");
registerForBroadcasts(context);
}
}
public void registerForBroadcasts(Context context) {
ComponentName component = new ComponentName(context, NetworkChangeReceiver.class);
PackageManager pm1 = context.getPackageManager();
pm1.setComponentEnabledSetting(
component,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
An then the receiver on the manifest:
<receiver
android:name=".NetworkChangeReceiver"
android:enabled="false"
android:label="NetworkChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
As I said, this works, but then onReceive, I need to know the ID to get the contact info to send the mail. The Broadcast as an Intent variable, but I don't know how to edit it. This would be the idea:
#Override
public void onReceive(final Context context, final Intent intent) {
final Context mContext = context;
String action = intent.getAction();
extras = intent.getExtras();
ID = extras.getLong("id");
Any ideas? The only alternative I can find is to keep checking for connectivity every 30secs, from the GeofenceIntent, but I think it would be much more effective to listen to Connectivity Change.
EDIT:
Finaly I solved this situation, by adding a "pending" column, on database, and from BroadcastReceiver checking all registers, where Pending = true.
Anyway I still have the doubt if there were any other way.

Android Geofence not triggers once location OFF and ON again [duplicate]

This question already has answers here:
How to check if Location Services are enabled?
(23 answers)
Closed 7 years ago.
I am using Android Geofencing API.After add geofence it works fine when location is ON.But If I OFF location and ON again,afterwards Geofencing not triggers when enter or exit.I have tested on my Moto G with Android 5.0.2 device. Is it Geofence will expire If location is off?
I have seen on Android document as,
In case network location provider is disabled by the user, the
geofence service will stop updating, all registered geofences will be
removed and an intent is generated by the provided pending intent. In
this case, the GeofencingEvent created from this intent represents an
error event, where hasError() returns true and getErrorCode() returns
GEOFENCE_NOT_AVAILABLE.
Document link
Yeap, geofences will be removed once location is switched off.
You should listen for location provider broadcasts using a BroadcastReceiver in your manifest, something like:
<receiver android:name="your.Receiver">
<intent-filter>
<action android:name="android.location.PROVIDERS_CHANGED"/>
</intent-filter>
</receiver>
and then register your geofences again.
public class LocationProviderReceiver extends BroadcastReceiver {
public LocationProviderReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
if (action.equals(LocationManager.PROVIDERS_CHANGED_ACTION)) {
// if location services enabled
// restart geofences
}
}
}
Add this to the manifest:
<receiver android:name="com.aol.android.geofence.GeofenceReceiver"
android:exported="false">
<intent-filter >
<action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/>
</intent-filter>
</receiver>
Then in the GeofenceRequester class you need to change the createRequestPendingIntent method so that it goes to your BroadcastReceiver instead of the ReceiveTransitionsIntentService
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("com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE");
// Intent intent = new Intent(context, 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.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
}
Then I added the GeofenceReceiver class that looks something like this:
public class GeofenceReceiver extends BroadcastReceiver {
Context context;
Intent broadcastIntent = new Intent();
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);
if (LocationClient.hasError(intent)) {
handleError(intent);
} else {
handleEnterExit(intent);
}
}
private void handleError(Intent intent){
// Get the error code
int errorCode = LocationClient.getErrorCode(intent);
// Get the error message
String errorMessage = LocationServiceErrorMessages.getErrorString(
context, errorCode);
// Log the error
Log.e(GeofenceUtils.APPTAG,
context.getString(R.string.geofence_transition_error_detail,
errorMessage));
// Set the action and error message for the broadcast intent
broadcastIntent
.setAction(GeofenceUtils.ACTION_GEOFENCE_ERROR)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, errorMessage);
// Broadcast the error *locally* to other components in this app
LocalBroadcastManager.getInstance(context).sendBroadcast(
broadcastIntent);
}
private void handleEnterExit(Intent intent) {
// 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<Geofence> geofences = LocationClient
.getTriggeringGeofences(intent);
String[] geofenceIds = new String[geofences.size()];
String ids = TextUtils.join(GeofenceUtils.GEOFENCE_ID_DELIMITER,
geofenceIds);
String transitionType = GeofenceUtils
.getTransitionString(transition);
for (int index = 0; index < geofences.size(); index++) {
Geofence geofence = geofences.get(index);
...do something with the geofence entry or exit. I'm saving them to a local sqlite db
}
// Create an Intent to broadcast to the app
broadcastIntent
.setAction(GeofenceUtils.ACTION_GEOFENCE_TRANSITION)
.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_ID, geofenceIds)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_TRANSITION_TYPE,
transitionType);
LocalBroadcastManager.getInstance(MyApplication.getContext())
.sendBroadcast(broadcastIntent);
// Log the transition type and a message
Log.d(GeofenceUtils.APPTAG, transitionType + ": " + ids);
Log.d(GeofenceUtils.APPTAG,
context.getString(R.string.geofence_transition_notification_text));
// In debug mode, log the result
Log.d(GeofenceUtils.APPTAG, "transition");
// An invalid transition was reported
} else {
// Always log as an error
Log.e(GeofenceUtils.APPTAG,
context.getString(R.string.geofence_transition_invalid_type,
transition));
}
}
/**
* 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 locationName) {
// Create an explicit content Intent that starts the main Activity
Intent notificationIntent = new Intent(context, MainActivity.class);
// Construct a task stack
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds 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(
context);
// Set the notification contents
builder.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(transitionType + ": " + locationName)
.setContentText(
context.getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
// Get an instance of the Notification manager
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(0, builder.build());
}
}

not able to get alert in geofencing

I have run a sample of Geofence and I have assigned two set of Lat , Lng and radius and run the sample. When I tap over register geofence I am getting following things in my log
Location Services is available
Client connected
Add Geofences: Success GeofenceRequestIds=[1, 2]
com.example.android.geofence.ACTION_GEOFENCES_ADDED
but nothing happens after that, I don't know what the issue I am passed the current location by enabling gps but no effect.
I don't know when I am gonna get the notification when a fence is crossed, to test it I have passed the same geo coordinates that are in fencing but still no alerts I am getting.
I have tried even replacing getService() by getBroadcast() inside createRequestPendingIntent function after reading few threads over stackoverflow , but no luck.
I have also tried it with
**Geofence #1 and Geofence #2**
Lat : 23.039568000000003
Lng : 72.56600400000002
Radius :1
and I have also set my current position in genymotion to above co ordinates to make it work but no notification.
Even on a real device my 3G is enable and I am moving with the device but no change so far.
you are set radius too small google-play service not give notification for 1 meter when you are increase radius its give better result for that and try it for geo-fencing.
in GeofenceReceiver
Intent broadcastIntent = new Intent();
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);
if (LocationClient.hasError(intent)) {
handleError(intent);
} else {
handleEnterExit(intent);
}
}
private void handleError(Intent intent) {
// Get the error code
int errorCode = LocationClient.getErrorCode(intent);
// Get the error message
String errorMessage = LocationServiceErrorMessages.getErrorString(
context, errorCode);
// Log the error
Log.e(GeofenceUtils.APPTAG, context.getString(
R.string.geofence_transition_error_detail, errorMessage));
// Set the action and error message for the broadcast intent
broadcastIntent.setAction(GeofenceUtils.ACTION_GEOFENCE_ERROR)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, errorMessage);
// Broadcast the error *locally* to other components in this app
LocalBroadcastManager.getInstance(context).sendBroadcast(
broadcastIntent);
}
private void handleEnterExit(Intent intent) {
// 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<Geofence> geofences = LocationClient
.getTriggeringGeofences(intent);
String[] geofenceIds = new String[geofences.size()];
String ids = TextUtils.join(GeofenceUtils.GEOFENCE_ID_DELIMITER,
geofenceIds);
String transitionType = getTransitionString(transition);
sendNotification(transitionType, ids);
for (int index = 0; index < geofences.size(); index++) {
Geofence geofence = geofences.get(index);
}
// Create an Intent to broadcast to the app
broadcastIntent
.setAction(GeofenceUtils.ACTION_GEOFENCE_TRANSITION)
.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);
LocalBroadcastManager.getInstance(sqlitewraper.context)
.sendBroadcast(broadcastIntent);
// Log the transition type and a message
Log.d(GeofenceUtils.APPTAG, transitionType + ": " + ids);
Log.d(GeofenceUtils.APPTAG, context
.getString(R.string.geofence_transition_notification_text));
// In debug mode, log the result
Log.d(GeofenceUtils.APPTAG, "transition");
// An invalid transition was reported
} else {
// Always log as an error
Log.e(GeofenceUtils.APPTAG, context.getString(
R.string.geofence_transition_invalid_type, transition));
}
}
/**
* 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 locationName) {
// Create an explicit content Intent that starts the main Activity
Intent notificationIntent = new Intent(sqlitewraper.context,
MainActivity.class);
// Construct a task stack
TaskStackBuilder stackBuilder = TaskStackBuilder
.create(sqlitewraper.context);
// Adds 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(
sqlitewraper.context);
// Set the notification contents
builder.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(transitionType + ": " + locationName)
.setContentText(
sqlitewraper.context
.getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
// Get an instance of the Notification manager
NotificationManager mNotificationManager = (NotificationManager) sqlitewraper.context
.getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(0, builder.build());
}
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return ("enter geofence");
case Geofence.GEOFENCE_TRANSITION_EXIT:
return ("exit from geofence");
default:
return ("Transisation unknown");
}
}
Change in sample code GeofenceRequester
Intent intent = new Intent("packagename.ACTION_RECEIVE_GEOFENCE");
// Intent intent = new Intent(mActivity, ReceiveTransitionsIntentService.class);
return PendingIntent.getBroadcast(
sqlitewraper.context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
change in Manifest file
<receiver android:name="packagename.GeofenceReceiver"
android:exported="false" >
<intent-filter>
<action android:name="packagename.ACTION_RECEIVE_GEOFENCE" />
<category android:name="packagename" />
</intent-filter>
</receiver>
Hey once check whether access to my location is selected. Ie in setting -> Location access

Remove Geofence after triggered

I use Geofences in my app, everything works fine except the removal of triggered geofences.
I red the guide from the official documentation of Android but they don't explain how to remove a geofence inside of the IntentService.
Here is the code of the event handler of the service:
#Override
protected void onHandleIntent(Intent intent)
{
Log.e("GeofenceIntentService", "Location handled");
if (LocationClient.hasError(intent))
{
int errorCode = LocationClient.getErrorCode(intent);
Log.e("GeofenceIntentService", "Location Services error: " + Integer.toString(errorCode));
}
else
{
int transitionType = LocationClient.getGeofenceTransition(intent);
if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER)
{
List <Geofence> triggerList = LocationClient.getTriggeringGeofences(intent);
String[] triggerIds = new String[triggerList.size()];
for (int i = 0; i < triggerIds.length; i++)
{
// Store the Id of each geofence
triggerIds[i] = triggerList.get(i).getRequestId();
Picture p = PicturesManager.getById(triggerIds[i], getApplicationContext());
/* ... do a lot of work here ... */
}
}
else
Log.e("ReceiveTransitionsIntentService", "Geofence transition error: " + Integer.toString(transitionType));
}
}
How can I delete the geofence after he got triggered ?
You can do something like this:
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient,
// This is the same pending intent that was used in addGeofences().
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
And your getGeofencePendingIntent() method can look like this:
/**
* Gets a PendingIntent to send with the request to add or remove 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 getGeofencePendingIntent() {
Log.d(TAG, "getGeofencePendingIntent()");
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(mContext, GeofenceIntentServiceStub.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// addGeofences() and removeGeofences().
mGeofencePendingIntent = PendingIntent.getService(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;
}
You would proceed as you did when adding Geofences (create a LocationClient and wait for it to connect). Once it is connected, in the onConnected callback method, you would call removeGeofences on the LocationClient instance instead and pass it a list of request IDs you want to remove and an instance of OnRemoveGeofencesResultListener as a callback handler.
Of course, you must use the same request IDs you used when creating the GeoFence with GeoFence.Builder's setRequestId.
#Override
public void onConnected(Bundle arg0) {
locationClient.removeGeofences(requestIDsList,
new OnRemoveGeofencesResultListener() {
...
});

Categories

Resources