I'm having some trouble getting my proximity alert to work on my Android app that's running on an Emulator. Basically the proximity alert should start an activity that will (for now) print to the log, however when a desired location is set for the alert, and the emulator's location is set at that particular location, nothing happens. Here is the code for the proximity alert:
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Intent intent = new Intent(MY_PROXIMITY_ALERT);
PendingIntent proxIntent = PendingIntent.getActivity(MapActivity.this, 0, intent, 0);
lm.addProximityAlert(latlng.latitude, latlng.longitude, 100, -1, proxIntent);
Now MY_PROXIMITY_ALERT is declared in the manifest as stated below:
<receiver android:name=".myLocationReceiver">
<intent-filter>
<action android:name="PROXIMITY_ALERT"/>
</intent-filter>
</receiver>
And here is my code for myLocationReceiver
public class myLocationReceiver extends BroadcastReceiver{
private static final String TAG = "myLocationReceiver";
#Override
public void onReceive(Context context, Intent intent) {
final String key = LocationManager.KEY_PROXIMITY_ENTERING;
final Boolean entering = intent.getBooleanExtra(key, false);
if(entering) {
Log.d(TAG, "onReceive: Entering proximity of location");
}
}
}
I believe my problem has something to do with the Intent or PendingIntent object but I'm not entirely sure. Also I have heard that usually the GPS will take about a minute to actually register the proximity, but I still do not get a log message even after some time.
Thanks!
You've created an Intent with action MY_PROXIMITY_ALERT and then used PendingIntent.getActivity() to get a PendingIntent to pass to the LocationManager. When the proximity conditions are satisfied, LocationManager will try to start an Activity that is listening for action MY_PROXIMITY_ALERT.
Intent intent = new Intent(MY_PROXIMITY_ALERT);
PendingIntent proxIntent = PendingIntent.getActivity(MapActivity.this, 0, intent, 0);
In your manifest, you've declared a BroadcastReceiver that is listening for action MY_PROXIMITY_ALERT. This won't work.
Since you want the proximity alert to trigger a BroadcastReceiver, you need to get the PendingIntent like this:
Intent intent = new Intent(MY_PROXIMITY_ALERT);
PendingIntent proxIntent = PendingIntent.getBroadcast(MapActivity.this, 0, intent, 0);
Personally, I think it would be better to use an "explicit" Intent instead of an "implicit" Intent. In that case you would do it like this:
Intent intent = new Intent(MapActivity.this, myLocationReceiver.class);
PendingIntent proxIntent = PendingIntent.getBroadcast(MapActivity.this, 0, intent, 0);
You don't need to use the ACTION in the Intent.
Using an "explicit" Intent tells Android exactly what component (class) to launch. If you use an "implicit" Intent, Android has to search for components that advertise that they can handle certain ACTIONs.
Related
I want to fake location in android. In android, there is a way for getting location using PendingIntent. Here is an example:
LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
String proximitys = "ACTION";
IntentFilter filter = new IntentFilter(proximitys);
LocationReceiver mReceiver = new LocationReceiver();
registerReceiver(mReceiver, filter);
Intent intent = new Intent(proximitys);
PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
service.requestLocationUpdates("network", 1000, 0.001f, proximityIntent);
And BroadcastReceiver will receive event when new location change:
public class LocationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Do this when the system sends the intent
Bundle b = intent.getExtras();
Location loc = (Location)b.get(android.location.LocationManager.KEY_LOCATION_CHANGED);
}
}
So, I want to hook this method. But I don't know how to hook this kind of method (that using PendingIntent). because PendingIntent will have data in "some future", and I don't know when it will happen. So hooking both before and after of method requestLocationUpdates seem not work because at that time, PendingIntent doesn't have any data yet.
Please tell me how to do this.
You need to intercept the broadcast receiver, not the pending intent. You can intercept LocationReceiver.onReceive and change the contents of the intent.
To do so intercept the onReceive by defining a beforeHookedMethod. Use its parameter (MethodHookParam params) to retrieve the intent (params.args[1]) and change its extras (intent.replaceExtras(bundle)).
Make sure your new bundle has the same key (android.location.LocationManager.KEY_LOCATION_CHANGED) and as value you can set your own location:
Location loc = new Location("yourprovider");
loc.setLatitude(66.6);
loc.setLongitude(66.6);
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
}
I am currently working on a map app that has points of interest built into it.
These points are supposed to be announced to the user by means of a proximity alert trigger.
Here is the addproximityAlert() code that I'm using
loc.addProximityAlert(lat, longe, radius, -1, PendingIntent.getActivity(
c, 0, new Intent().putExtra(loc_name, loc_name), flag));
The idea is that once the alert fires an alert dialog pops up with a short blurb about the site with the option to either close the alert or get more info(uses WebView).
Thus far I have no run-time or compile-time errors but as I approach each site, nothing happens.
My theory on why nothing happens is that either;
1) I haven't used the PendingIntent correctly, or
2) I haven't set up the BroadcastReceiver correctly
Here is the XML code for the BroadcastRecevier,
<receiver android:name=".ProxyAlertReceiver" >
<intent-filter>
<action android:name="entering" />
</intent-filter>
</receiver>
My current plan to fix this issue is to modify the PendingIntent to use a new Intent like this;
...new Intent(myContext, ProxyAlertReceiver.class)...
and see if I get any results.
Opinions and advice on my issue would be greatly appreciated!
Have you tried PendingIntent.getBroadcast(...)?
Intent locationReachedIntent = new Intent("entering");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1234,
locationReachedIntent, 0);
locationManager.addProximityAlert(longitude, latitude, radius, -1, pendingIntent);
I have the above code working in my application.
Use This
Intent locationIntent = new Intent();
Bundle extras= new Bundle();
extras.putString("loc_name",loc_name);
locationIntent.putExtras(extras);
PendingIntent pendingIntent= new PendingIntent.getActivity(this,0,locationIntent,0);
loc.addProximityAlert(lat, longe, radius, -1, pendingIntent, flag));
I assume your loc_name is a string. This will work.
Implementing a proximity alert depends on more than just calling the addProximity method on a Location Manager.
You must also:
Create a receiver class which will fire when alert is triggered and will receive a status (entering or exiting) and the action name*;
public class ProximityReceiver extends BroadcastReceiver {
public String TAG ="ProxReceiver";
#Override
public void onReceive(Context context, Intent intent) {
/* your code here - sample below */
final String key = LocationManager.KEY_PROXIMITY_ENTERING;
final Boolean entering = intent.getBooleanExtra(key, false);
if (entering) {
Toast.makeText(context, "LocationReminderReceiver entering", Toast.LENGTH_SHORT).show();
Log.v(TAG, "Poi entering");
} else {
Toast.makeText(context, "LocationReminderReceiver exiting", Toast.LENGTH_SHORT).show();
Log.v(TAG, "Poi exiting");
}
Log.v(TAG,"Poi receive intent["+intent.toString()+"]");
Bundle extras = intent.getExtras();
// debugging only
int counterExtras = extras.size();
if (extras != null) {
for (String key : extras.keySet()) {
Object value = extras.get(key);
Log.d(TAG, "Prox Poi extra "+String.format("key[%s] value[%s] class[%s] count[%s]", key,
value.toString(), value.getClass().getName(), String.valueOf(counterExtras)));
}
} else {
Log.v(TAG, "Prox Poi extra empty");
}
}
}
Declare this receiver in your Manifest file;
<receiver android:name=".ProximityReceiver" >
<intent-filter>
<action android:name="my" />
</intent-filter>
</receiver>
Register (associate your pending intents to) this receiver, adding proximity alert(s). Only register your receiver ONCE in your code. If one registers a receiver multiple times, it will fire once for every receiver instance (you reach a POI, which registers a pending intent called "my". **
// create proximity alert
Intent locationIntent = new Intent("my");
ProximityReceiver proximityReceiver = new ProximityReceiver();
PendingIntent pendingIntent = PendingIntent.getBroadcast(mapView.getContext(), <some identifying text>,
locationIntent, 0);
loc.addProximityAlert(lat, longe, radius, -1, PendingIntent.getActivity(
c, 0, new Intent().putExtra(loc_name, loc_name), flag));
IntentFilter filter = new IntentFilter("my");
context.registerReceiver(proximityReceiver, filter);
Where context can be this if running in same activity.
Unless you want to keep on receiving alerts even when in background (or even terminated), you must implement removal and re-creation of proximity alerts in your onPause and onResume methods, like this SO question (jump to the end of the question).
note * In this example, "my" will be the action name (see Intent declaration) for an action and will be passed along with the intent AND a bundle of extras containing, at least, the key entering (LocationManager.KEY_PROXIMITY_ENTERING) with boolean value, which gives you the state of the alert, if one is entering (1) or exiting (0) the proximity radius.
note ** If you have registered the receiver for "my" multiple times, it will fire multiple times for every proximity alert event that calls an intent named "my".
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.
I am trying to use Android's LocationManager requestLocationUpdates. Everything is working until I try to extract the actual location object that in my broadcast receiver. Do I need to specifically define the "extras" to my custom intent so that the Android LocationManager before I pass it to requestLocationUpdates so it knows how to add it into the intent, or will it create the extras-bundle regardless when it passes the fired intent to the broadcast receiver?
My code looks like this:
Intent intent = new Intent("com.myapp.swarm.LOCATION_READY");
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
0, intent, 0);
//Register for broadcast intents
int minTime = 5000;
int minDistance = 0;
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime,
minDistance, pendingIntent);
I have a broadcast receiver that is defined in the manifesto as:
<receiver android:name=".LocationReceiver">
<intent-filter>
<action android:name="com.myapp.swarm.LOCATION_READY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
And the broadcast receiver class as:
public class LocationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Do this when the system sends the intent
Bundle b = intent.getExtras();
Location loc = (Location)b.get("KEY_LOCATION_CHANGED");
Toast.makeText(context, loc.toString(), Toast.LENGTH_SHORT).show();
}
}
My "loc" object is coming up null.
OK, I managed to fix it by changing the KEY_LOCATION_CHANGED in the broadcast receiver code to:
public class LocationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Do this when the system sends the intent
Bundle b = intent.getExtras();
Location loc = (Location)b.get(android.location.LocationManager.KEY_LOCATION_CHANGED);
Toast.makeText(context, loc.toString(), Toast.LENGTH_SHORT).show();
}
}
i ve tried to code and test the solution you proposed, since i am facing similar problems concerning proximity alerts and intents carrying location objects. According the information you provided, you managed to overcome the null object retrieval, on the BroadcastReceiver's side. What you might did not observe is that now you should be receiving the same location as the one your intent was first created (also seen it as: intent caching problem).
In order to overcome this problem, i used FLAG_CANCEL_CURRENT, as being proposed by many people here and it works pretty fine, fetching fresh (and juicy :P) location values. So the line defining your pending intent should look like this:
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
However, you can ignore this if:
your purpose was just to receive a location value once
you managed to overcome it in some other way not visible in your post