I create a proximity alert in this way
private void setProximityAlert(float radius, double lat, double lng, String place)
{
long expiration = -1;
LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Intent intent = new Intent(TREASURE_PROXIMITY_ALERT);
intent.putExtra("lat", lat);
intent.putExtra("lng", lng);
intent.putExtra("place", place);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), -1, intent, 0);
locManager.addProximityAlert(lat, lng, radius, expiration, pendingIntent);
}
and on my activity I registered the receiver in this way
IntentFilter intentFilter = new IntentFilter(TREASURE_PROXIMITY_ALERT);
registerReceiver(new ProximityIntentReceiver(), intentFilter);
setProximityAlert(10, 45.150344, 9.999815, "POINT1");
and my broadcast receiver is correctly called.
So now, I want to add another proximity alert, is it possible? I want that the same boadcast receiver is called by 2 proximity alert.
I made this:
IntentFilter intentFilter1 = new IntentFilter(TREASURE_PROXIMITY_ALERT1);
registerReceiver(new ProximityIntentReceiver(), intentFilter1);
setProximityAlert(200f, 45.143848, 10.039741, "POINT2");
but it does not work, nothing happen. I'm really now on it and I was wondering if it is the right way. My intent is trigger 2 alerts, one when GPS get the position POINT1 and another one at the position POINT2.
Any helps are welcome.
You need to use whatever unique setAction so the system consider the two intents different, as otherwise will tend to reuse the first one.
I have this code:
Intent intent = new Intent(this,PlacesProximityHandlerService.class);
intent.setAction("foo"+objPlace.getId());
intent.putExtra(Poi._ID, objPlace.getId());
intent.putExtra(Poi.LAT, objPlace.getLat());
intent.putExtra(Poi.LON, objPlace.getLon());
PendingIntent sender = PendingIntent.getService(this,0, intent, 0);
LocationUtils.addProximity(this, objPlace.getLat(),objPlace.getLon(), objPlace.getError(), -1,sender);
Also note that the proximity alert works kinda tricky.
User enters the hot ZONE1 based on the signal precision and radius you set. Broadcast is fired for entering=true ZONE1. If you enter another zone ZONE2 that overlap with the current zone you don't get the alert as you are still in ZONE1.
You must leave the ZONE1, so the broadcast will fire again with entering=false. So once now you left ZONE1, if you arrive ZONE2 it will fire the broadcast entering=true ZONE2.
I've tested and it works just fine. Grab Location Spoofer free application from market and mock the location of the phone. You also need to enable mock locations in the phones Setting. And add additional permission to your application:
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
What I would do, set my location far away from me, probably Greenland, then set the position in a zone that triggers ZONE1, broadcast should fire. Then set again my location to Greeland, and set position that triggers ZONE2, broadcast should fire.
The entering flag can be get from the intent extras
Bundle b = intent.getExtras();
Boolean entering = (Boolean) b.get(android.location.LocationManager.KEY_PROXIMITY_ENTERING);
I used the above codes to setup proximity alerts for 100 POIs and all work well.
Related
ios sdk has great region monitoring functions. I need something like that in android and i think we have two alternatives. Geofencing and LocationManager.
Geofencing has really tidy examples and bugs , so i prefered LocationManager. Everyting works fine in LocationManager except one. If you add your current location as ProximityAlert , it immediatly fires "ENTERING" , but it is my current location , it doesnt mean that i entered this region. Because of that , it fires "ENTERING" each time i start my application if i am in region.(Even if i am not moving)
How can i solve this problem and fire event only if user is really ENTERING the region ?
Here is how i am adding PeddingIntents for my locations.
LocationManager locationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
for(Place p : places)
{
Log.e("location", p.location);
Bundle extras = new Bundle();
extras.putString("name", p.displayName);
extras.putString("id", p.id);
Intent intent = new Intent(CommandTypes.PROX_ALERT_INTENT);
intent.putExtra(CommandTypes.PROX_ALERT_INTENT, extras);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,Integer.parseInt(p.id), intent,PendingIntent.FLAG_CANCEL_CURRENT);
float radius = 50f;
locationManager.addProximityAlert(p.lat,
p.lon, radius, 1000000, pendingIntent);
}
Receiver
public class ProximityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final String key = LocationManager.KEY_PROXIMITY_ENTERING;
final Boolean entering = intent.getBooleanExtra(key, false);
Bundle b = intent.getBundleExtra(CommandTypes.PROX_ALERT_INTENT);
String id = b.getString("id");
Log.e("here" + id, "here");
if (entering) {
Log.e(TAG,"entering");
} else {
Log.e(TAG,"leaving");
}
}
Manifest
<receiver android:name=".ProximityReceiver">
<intent-filter>
<action android:name="ACTION_PROXIMITY_ALERT" />
</intent-filter>
</receiver>
Thank you very much
PS: iOS does not have this problem and their documentation explains it so
Monitoring of a geographical region begins immediately after registration for authorized apps. However, do not expect to receive an event right away. Only boundary crossings generate an event. Thus, if at registration time the user’s location is already inside the region, the location manager does not automatically generate an event. Instead, your app must wait for the user to cross the region boundary before an event is generated and sent to the delegate. That said, you can use the requestStateForRegion: method of the CLLocationManager class to check whether the user is already inside the boundary of a region.
EDIT: since i wrote this, there has been a new thing added to the geofence API, 'setInitialTrigger' that allevates this:
https://developers.google.com/android/reference/com/google/android/gms/location/GeofencingRequest.Builder#setInitialTrigger%28int%29
Yeah, this is a nuisance, and is one of the major points where Android and IOS geofencing differs, unfortunately.
Android alerts when you're inside the Geofence if it knows you were outside before OR you added the geofence while inside it.
The way i solve this is with a 'grace period' in my broadcast reciever. Basically, when i create the Geofence, i store away its creation time in sharedpreferences, and i check against that value in onReceive.
By doing this, any 'immediate' hit will be filtered away. Perhaps 3 minutes is too long for someone else, but it works for me based on how i work with the geofences in my app.
private static final Long MIN_PROXALERT_INTERVAL = 18000l; // 3 mins in milliseconds
...
long geofenceCreationTime = session.getPrefs().getCurrentGeofenceCreation();
long elapsedSinceCreation = now - geofenceCreationTime;
if(elapsedSinceCreation < CREATIONTIME_GRACE_PERIOD){
if (ApplicationSession.DEBUG) {
Log.d(TAG, "elapsedSinceCreation;"+elapsedSinceCreation+";less than;"+CREATIONTIME_GRACE_PERIOD+";exiting");
}
return;
}
Hope you see what i'm getting at.
Hope it helps.
I would like to use Android's LocationManager and the addProximityAlert method to setup proximity alerts. For this, I've created a small application that shows a crosshair on top of a map, plus a text field for the proximity alert name and a button to trigger the addition of the alert.
Unfortunately, the BroadcastReceiver that should receive the proximity alerts is not triggered. I've tested the intent alone (not wrapped via a PendingIntent) and that works. Also, I see that once a proximity alert is set, the GPS / location icon appears in the notification bar.
I've found information about proximity alerts a bit confusing - some are telling the alerts cannot be used if the activity is no longer in the foreground. I think it should work, so I assume something else is wrong.
1 Adding a Proximity alert
GeoPoint geo = mapView.getMapCenter();
Toast.makeText(this, geo.toString(), Toast.LENGTH_LONG).show();
Log.d("demo", "Current center location is: " + geo);
PendingIntent pIntent = PendingIntent.getBroadcast(this, 0, getLocationAlertIntent(), 0);
locationManager.addProximityAlert(geo.getLatitudeE6()/1E6, geo.getLongitudeE6()/1E6, 1000f, 8*60*60*1000, pIntent);
The intent itself is here:
private Intent getLocationAlertIntent()
{
Intent intent = new Intent("com.hybris.proxi.LOCATION_ALERT");
intent.putExtra("date", new Date().toString());
intent.putExtra("name", locationName.getEditableText().toString());
return intent;
}
I created a receiver which is supposed to receive the location alerts, registered in AndroidManifest.xml:
<receiver android:name=".LocationAlertReceiver">
<intent-filter>
<action android:name="com.hybris.proxi.LOCATION_ALERT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
The implementation itself is hopefully straightforward. It is supposed to show a notification (and I checked that via directly sending an intent with a test button).
public class LocationAlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context ctx, Intent intent) {
Log.d("demo", "Received Intent!");
String dateString = intent.getStringExtra("date");
String locationName = intent.getStringExtra("name");
boolean isEntering = intent.getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
NotificationManager notificationManager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification.Builder(ctx)
.setContentTitle("LocAlert: " + locationName)
.setContentText(dateString + "|enter: " + isEntering)
.setSmallIcon(R.drawable.ic_stat_loc_notification)
.build();
notificationManager.notify(randomInteger(), notification);
}
private int randomInteger()
{
Random rand = new Random(System.currentTimeMillis());
return rand.nextInt(1000);
}
A few things that I am not 100% sure of, maybe this triggers something in you:
I assume it is OK to register a proximity alert using a pending intent like I do and the Activity that created the proximity alert can later be closed.
Converting from the Map via getCenter returns a GeoPoint with lat/lon as int values. I thnk I am correctly converting them the the double values expected by addProximityAlert by dividing by 1E6
The distance from the center is relatively large - 1000m - I assume that is a nice value.
Examples that I've found online used broadcast receivers registered programmatically. this is not what I want to do. but the book Android 4 Profession Dev by Reto Meier mentions that registering the broadcast receiver in xml is also fine.
Any help greatly appreciated!!
I ran into the same issue. Setting target class of the intent explicitly helped in my case. In your case it should look the following:
private Intent getLocationAlertIntent()
{
Intent intent = new Intent(context, LocationAlertReceiver.class);
intent.setAction("com.hybris.proxi.LOCATION_ALERT"); //not sure if this is needed
intent.putExtra("date", new Date().toString());
intent.putExtra("name", locationName.getEditableText().toString());
return intent;
}
i have set multiple approximate alerts in application. i set notifications in this way :
private void addProximityAlert(double latitude, double longitude) {
try{
LatLonPair latLon;
for(int i = 0; i < mPositions.size(); i++) {
latLon = mPositions.get(i);
Intent intent = new Intent(PROXIMTY_ALERT_INTENT);
intent.putExtra(ProximityIntentReceiver.EVENT_ID_INTENT_EXTRA, i);
intent.putExtra(ProximityIntentReceiver.ITEM_NAME,latLon.getItemName());
intent.putExtra(ProximityIntentReceiver.PLACE_NAME,latLon.getPlaceName());
PendingIntent proximityIntent = PendingIntent.getBroadcast(this, i, intent, 0);
locationManager.addProximityAlert(latLon.getLatitude(), latLon.getLongitude(), radius, expiration, proximityIntent);// alerts set here.
IntentFilter filter = new IntentFilter(PROXIMTY_ALERT_INTENT);
registerReceiver(new ProximityIntentReceiver(), filter);
}
}
catch(Exception ex){
ex.toString();
}
}
all stored location register for proximity Alert at once .now what happened there when one notification is fire and keep firing again again in given radius. i need to help that how i can remove Alert that has fired once do not give notification again and again when device is still in define radius.
in ProximityIntentReceiver unregister the receiver, so that it won't be called again.
See unregisterReceiver
The problem is not removing the alerts. The problem is that you are registering the receiver several times. Do it only once.
I would like to use Android's Proximity Alert for my garage door app. I have a button setup, that when pressed add's the proximity alert and starts tracking location. I want it to track indefinitely until I either enter or exit the proximity. If entering it will open the garage door, if exiting it will close the garage door after which I remove the proximity alert and GPS shuts off. I have it working close to perfectly.
The problem is, when I press the button while in my driveway, hence in the proximity, the intent always fires immediately with the extra KEY_PROXIMITY_ENTERING set to "entering". If I start the tracking outside of the proximity, it acts as expected, only fires once I enter the proximity. How can I get exiting the proximity when starting inside of it working in the same manner? Thanks in advance, here's my code.
In my activity:
float radius = 100f;
double lat = 37.422;
double lon = -122.084;
// Expiration is 10 Minutes
long expiration = 600000;
LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Intent intent = new Intent(proximityIntentAction);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, intent, PendingIntent.FLAG_CANCEL_CURRENT);
locManager.addProximityAlert(lat, lon, radius, expiration, pendingIntent);
And here is my BroadcastReceiver:
public void onReceive(Context context, Intent intent)
{
Log.v("SomeTag","Proximity Alert Intent Received");
String direction = LocationManager.KEY_PROXIMITY_ENTERING;
CharSequence text = direction;
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, "going: "+text, duration);
toast.show();
LocationManager locManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_NO_CREATE);
locManager.removeProximityAlert(pendingIntent);
}
why not put a timer/delay on the firing of the button? For example, why not allow yourself a fixed amount of time to get out of the proximity before your app starts detecting? I think that many home alarms work in the same way. Or, another option might be to detect and ignore your first entry into the proximity and validate any subsequent re-entries to that proximity (i.e. your garage). What do you think?
this is my very first question:
I'm trying to configure proximity alerts that will be feed from a Database and webservice provider; but I have a problem configuring a simple proximity alert for testing. I manage to create the alert but it never gets fired, I'm only trying in the emulator for now and don´t know if I need some extra code to trigger the alerts.
I've read somewhere that the GPS provider to disabled so the network provider can be used in order to trigger the alerts on the emulator.
My code looks like this:
Proximity intent declaration
private String proximityIntentAction = new String("gpsdelivery.gpship.getLocation.GPS_PROXIMITY_ALERT");
Inside onStart() where the parameters of the alerts are set
IntentFilter intentFilter = new IntentFilter(proximityIntentAction);
registerReceiver(new ProximityAlert(), intentFilter);
setProximityAlert(45.150344, 9.999815, -1);
Proximity alert function where the alerts get created
private void setProximityAlert(double lat, double lon, int requestCode)
{
// 100 meter radius
float radius = 100f;
// Expiration is 10 Minutes
long expiration = 600000;
LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Intent intent = new Intent(proximityIntentAction);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
locManager.addProximityAlert(lat, lon, radius, expiration, pendingIntent);
}
And finally my proximity alert class with the Broadcast receiver
public class ProximityAlert extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.v("SomeTag","Proximity alert received");
}
}
Please let me know what I'm missing or what am I doing wrong. Thanks in advance, any source code would be appreciated.
Well, I believe your setProximityAlert(45.150344, 9.999815, -1); is incorrect. Specifically, your -1. It doesn't contain the information needed in the locManager.addProximityAlert(lat, lon, radius, expiration, pendingIntent);.