Android Proximity alert doesn't get fired - android

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

Related

Google location API: request location updates with pending intent?

I have started to implement the Google Location API using this tutorial.
I've managed to get it to work in my application quite fine, it updates my location at the right intervals etc. Now I am working on how to update my location when the device is in sleep mode. According to the documentation, this method is the way to go:
public void requestLocationUpdates (LocationRequest request, PendingIntent callbackIntent);
My question is, how do I set up this PendingIntent, and how do I handle it? I've seen tutorials of how to handle other types of intent, but I am not sure how to apply them to this.
You can either register Broardcast Reciever or Activity through pending intent.Sample Example for registering boardcast reciever:
String proximitys = "ACTION";
IntentFilter filter = new IntentFilter(proximitys);
registerReceiver(mybroadcast, filter);
Intent intent = new Intent(proximitys);
PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
locationManager.requestLocationUpdates(provider, mintime, mindistance,
proximityIntent);
Your Broardcast Reciever:
public class ProximityIntentReceiver extends BroadcastReceiver {
#SuppressWarnings("deprecation")
#Override
public void onReceive(Context arg0, Intent intent) {
//action to be performed
}

requestLocationUpdates with PendingIntent and Broadcast - what broadcasts do I get

I have setup an alarm which is received by a BroadcastReceiver which launches a WakefulIntentService (class LocationMonitor). In the LocationMonitor I have :
private static final int MIN_TIME_BETWEEN_SCANS = 1 * 30 * 1000;
private static final int MIN_DISTANCE = 0;
#Override
protected void doWakefulWork(Intent intent) {
final CharSequence action = intent.getAction();
if (action == null) { // monitor command from the alarm manager
// the call below enables the LocationReceiver
BaseReceiver.enable(this, ENABLE, LocationReceiver.class);
if (lm == null) lm = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
Intent i = new Intent(this, LocationReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, NOT_USED, i,
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
MIN_TIME_BETWEEN_SCANS, MIN_DISTANCE, pi);
} else if (ac_location_data.equals(action)) {
final Bundle extras = intent.getExtras();
if (extras != null) {
final Location loc = (Location) extras
.get(LocationManager.KEY_LOCATION_CHANGED);
if (loc == null) {
w("NULL LOCATION - EXTRAS : " + extras); //Log.w
// while gps is disabled I keep getting this :
// NULL LOCATION - EXTRAS : Bundle[{providerEnabled=false}]
} else {
final double lon = loc.getLongitude();
final double lat = loc.getLatitude();
w("latitude :" + lat + " -- longitude : " + lon);
}
}
}
}
I have several issues with the code above.
If GPS is initially disabled and then I enable it I get a bunch of W/GpsLocationProvider(...): Unneeded remove listener for uid 1000. The warning comes from here. I can't find in the code where is this removing of listeners triggered, nor can I see where they are assigned the uid 1000 (apparently the system server).
When I enable the gps I get the location as expected and then a "RemoteException"
LocationManagerService(...): RemoteException calling onLocationChanged on Receiver{4083ee68 Intent PendingIntent{4084e6b8: PendingIntentRecord{4083ef78 gr.uoa.di.monitoring.android broadcastIntent}}}mUpdateRecords: {gps=UpdateRecord{40838180 mProvider: gps mUid: 10064}}
which is not really a RemoteException, just a PendingIntent.CancelledException - the message is quite misleading. Or so I think : it comes from here which calls this. My question is : why is it reusing the Intent - shouldn't the FLAG_ONE_SHOT dispose of it ?
But the most important question is : when I register a PendingIntent like this what intents do I expect to receive ? And what flags should I use ?
Keep in mind I am using this pattern cause I want to have the phone update its position even when asleep and this achieves it (I do get the location updates). I try to simulate requestSingleUpdate (unavailable in 2.3) using FLAG_ONE_SHOT.
Receiver :
public final class LocationReceiver extends BaseReceiver {
private static final Class<? extends Monitor> MONITOR_CLASS =
LocationMonitor.class;
#Override
public void onReceive(Context context, Intent intent) {
d(intent.toString());
final String action = intent.getAction();
d(action + "");
final Intent i = new Intent(context, MONITOR_CLASS);
i.fillIn(intent, 0); // TODO do I need flags ?
i.setAction(ac_location_data.toString());
WakefulIntentService.sendWakefulWork(context, i);
}
}
To this question:
when I register a PendingIntent like this what intents do I expect to
receive ? And what flags should I use ?
When you register for location updates and pass a PendingIntent, this PendingIntent will be triggered when the LocationManager decides to inform you about a location update. You can provide pretty much whatever you want, depending on what you want to happen when the PendingIntent is triggered. The LocationManager will add an extra to the Intent that is sent. This extra has the bundle key LocationManager.KEY_LOCATION_CHANGED and the object associated with that key is a Location object.
LocationManager will use this PendingIntent again and again to inform your app of location updates, so I think using PendingIntent.FLAG_ONE_SHOT is probably not such a good idea. If you only want a single update, why don't you just unregister after you get one update?
EDIT: Add code to cancel any previously requested updates before registering for updates
Before you call registerLocationUpdates(), do this to cancel any previously registered updates:
Intent i = new Intent(this, LocationReceiver.class);
// Get any existing matching PendingIntent
PendingIntent pi = PendingIntent.getBroadcast(this, NOT_USED, i,
PendingIntent.FLAG_NO_CREATE);
if (pi != null) {
// Cancel any updates for this PendingIntent, because we are about to
// invalidate it
lm.removeUpdates(pi);
}
// Create a new PendingIntent and cancel any previous one
pi = PendingIntent.getBroadcast(this, NOT_USED, i,
PendingIntent.FLAG_CANCEL_CURRENT);
// Now register for location updates...
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
MIN_TIME_BETWEEN_SCANS, MIN_DISTANCE, pi);
NOTE: Actually, I don't know why you need to cancel any previous PendingIntent and create a new one in this case. You can just get a PendingIntent and if you have already registered for location updates with that PendingIntent, I don't think that registering again will cause the PendingIntent to be used multiple times. If you want to try that, all you need to do is to remove PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT from your existing code. I think that is a better/cleaner/clearer solution.

pendingIntent is fire again again in given radius.

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.

Android GPS Proximity Alert when starting within the set proximity

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?

PendingIntents keep caching same object

i ve been facing some problems trying to pass data through intents and pending intents to a BroadcastReceiver, concerning proximity alerts. More specifically, am trying to pass an object, that among others holds the user's constantly changing position. I ve tried various tactics being proposed here (and not only) but none worked, resulting to either null values or same-as-first-time created intents, when the intent is retrieved on the BroadcastReceiver's side. Tactics used:
Flagging the intent that carries the object with:FLAG_ACTIVITY_NEW_TASK+FLAG_ACTIVITY_CLEAR_TOP+FLAG_ACTIVITY_SINGLE_TOP
Result:Null values on the BroadacastReceiver's side
Flagging the pending intent created using the initial intent, with:FLAG_UPDATE_CURRENT or FLAG_CANCEL_CURRENT
Result:Null values on the BroadacastReceiver's side
Acquiring a random ID for intent or the pending intent using System.currentTimeMillis();
Result:Intents are not fired or received at all
Nothing described above. Result:Retrieving the same initial value every time.
Code for the calling method (stripped from any experimentations/producing null values):
private void setProximityAlert(MyCar myCar) {
String locService = Context.LOCATION_SERVICE;
LocationManager locationManager;
locationManager = (LocationManager)getSystemService(locService);
float radius = myCar.getMyCarRadius();
long expiration = myCar.getMyCarExpiration();
myService.setMyDriverLat(userLat);//setting user's position
myService.setMyDriverLng(userLng);//setting user's position
Intent intent = new Intent(myCar.getMyCarName());
intent.putExtra("myCar",myCar);
PendingIntent proximityIntent = PendingIntent.getBroadcast(this, -1, intent, 0);
locationManager.addProximityAlert(myCar.getMyCarLat(), myCar.getMyCarLng(), radius, expiration, proximityIntent);
}
Code for the calling method that sets the intent filter and registers the BroadcastReceiver:
public void addNewCarPoint (MyCar myCar){
IntentFilter filter = new IntentFilter(myCar.getMyCarName());
registerReceiver(new ProximityAlertReceiver(), filter);
setProximityAlert(myCar);
}
Code for the BroadcastReceiver's side:
public class ProximityAlertReceiver extends BroadcastReceiver {
#Override
public void onReceive (Context context, Intent intent) {
MyCar myCar=(MyCar)intent.getParcelableExtra("myCar");
driverLoc=(String)Double.toString(myCar.getMyDriverLat());
Toast.makeText(context, userLoc, Toast.LENGTH_SHORT).show();
Intent i = new Intent(context, MyCarDiscoveryPrompt.class);
context.startActivity(i);//firing intent
}
public void intentDataLoader(){
}
}
Any ideas would be more than welcome.
Thank you in advance.
Hmm i think i ve found something:
I placed the BroadcastReceiver (ProximityAlerReceiver), used to detect proximity alerts in the same class (MyCarTracking.class), where the LocationListener.class is located. This,
provides immediate access to fresh location updates, creating a new intent wrapped in a new pendingIntent to be fired to the BroadcastReceiver (only when the proximity criteria are met).
flags:FLAG_ACTIVITY_NEW_TASK+FLAG_ACTIVITY_SINGLE_TOP and FLAG_CANCEL_CURRENT on intent and pendingIntent, were kept respectively. More specifically:
Code for LocationListener:
private final LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
updateWithNewLocation(location);//update application based on new location
}
public void onProviderDisabled(String provider){
updateWithNewLocation(null);//update application if provider disabled
}
public void onProviderEnabled(String provider){
// Update application if provider enabled
}
public void onStatusChanged(String provider, int status, Bundle extras){
//update application if provider hardware status changed
}
};
Code for setProximityAlert() method:
private void setProximityAlert() {
String locService = Context.LOCATION_SERVICE;
Context context =getApplicationContext();
LocationManager locationManager;
locationManager = (LocationManager)getSystemService(locService);
float radius = myCar.getMyCarRadius();
long expiration = myCar.getMyCarExpiration();
Intent intent = new Intent(CAR_DISCOVERED);
intent.putExtra("myCar",myCar);
locationManager.getLastKnownLocation(provider);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);//flagging intent
PendingIntent proximityIntent = PendingIntent.getBroadcast(context, -1, intent, PendingIntent.FLAG_CANCEL_CURRENT);//flagging pendingIntent
locationManager.addProximityAlert(myCar.getMyCarLat(), myCar.getMyCarLng(), radius, expiration, proximityIntent);//setting proximity alert
}
This solution works producing fresh intents with fresh location updates.
Thank you all for your help and your interest :)
Try adding
intent.setData(uri);
where uri is some unique value for each pending intent
I've been struggling with this problem as well. It took me a whole night to find that a weird bug I had was related to this issue.
Here's a good discussion on google code on the subject: http://groups.google.com/group/android-developers/browse_thread/thread/b2060b27c8934921
I've solved all my problems by (ab)using both the uri in SetData and the (reserved) request code in PendingEvent.GetWhatever.
I'm also using FLAG_CANCEL_CURRENT on my intents and making sure only pendingintents that share the same purpose get the same data, action and uri.
Hope it helps a little bit.

Categories

Resources