So this code worked on friday:
public void requestLocationUpdate() {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
Intent updateIntent = new Intent(SINGLE_LOCATION_UPDATE_ACTION);
PendingIntent singleUpdatePI = PendingIntent.getBroadcast(_context, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
IntentFilter locIntentFilter = new IntentFilter(SINGLE_LOCATION_UPDATE_ACTION);
SingleUpdateReceiver receiver = new SingleUpdateReceiver();
getApplicationContext().registerReceiver(receiver, locIntentFilter);
locationManager.requestSingleUpdate(criteria, singleUpdatePI);
}
class SingleUpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// ... never invoked
}
}
Today, onReceive() simply will not be invoked. Is there any reason why this shouldn't work today? The only thing changed is that I'm on a different WiFi router now.
I can see a couple of suspicious lines in LogCat:
06-23 15:10:36.540 709-7716/? D/LocationManagerService﹕ request 430483d8 fused Request[ACCURACY_BLOCK fused requested=+10m0s0ms fastest=+10m0s0ms num=1] from com.nilzor.app(10195)
06-23 15:10:36.540 709-7716/? D/LocationManagerService﹕ provider request: fused ProviderRequest[ON interval=+10m0s0ms]
...don't know if that is relevant?
The documentation of requestSingleUpdate points me to requestLocationUpdates, which again tells me that it might take a while to get the first update. Is that true also for requestSingleUpdate? On friday, the callback fired within a second of the request. Today I've tried 10+ times and it havent fired once. 5 minutes counting as I post now.
When you connect to wi-fi you get coordinates from your router. It does not matter where you are located, in your wi-fi area/place use real gps, or gps spoiler.
Related
I have an android app in which I have used FusedLocationApi to get location updates of the user.
Following is the scenario:
1. I have a singleton Watcher class in which I define the pending intent to get the locations even when app is in background. Following is the code:
private PendingIntent pendingIntent;
private Watcher() {
Intent locationIntent = new Intent(context, Receiver.class);
pendingIntent = PendingIntent.getBroadcast(
context, 007 /*requestcode*/, locationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
Then, when I have successfully connected location services, I request for location updates:
LocationServices.FusedLocationApi.
requestLocationUpdates(googleApiClient, locationRequest, pendingIntent);
Now, whenever Receiver class which extends WakefulBroadcastReceiver gets the location update, it starts the Service.class. The service class extends IntentService.
Following is the code:
#Override
synchronized protected void onHandleIntent(final Intent intent) {
if(LocationResult.hasResult(intent)) {
LocationResult locationResult= LocationResult.extractResult(intent);
Location location = locationResult.getLastLocation();
printLocation(location);
}
So my question is, given the above steps, why does the onHandleIntent gets woken up by the LocationReceiver multiple times within a period of 5 milliseconds. The lat, lng and accuracy are all the same. I have defined the
setFastestInterval(5 seconds); and
setInterval(1 minute);
Also the location accuracy is BALANCED_POWER_ACCURACY;
In my app, the
LocationServices.FusedLocationApi.
requestLocationUpdates(googleApiClient, locationRequest, pendingIntent);
do gets called multiple times. But according to the documentation: "Any previously registered requests that have the same PendingIntent (as defined by equals(Object)) will be replaced by this request." And I am using the same pendingIntent object to call requestLocationUpdates.
Thanks in advance.
Hi Kanika you can set the minimum displacement before passing your location request object this will help you to get updates only when you have certain minimum displacement. you can use below method for doing same.
setSmallestDisplacement(float smallestDisplacementMeters)
Also FYI api reference link , https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest
I can't seem to figure this one out. I have a broadcastReceiver that is registered in the manifest. I ping for gps once a minute, the broadcastReceiver's onReceive fires and starts a service. This service grabs a wakelock just in case, sends the GPS Coords to our server using an ASyncTask and releases the wakelock, and calls stopSelf(). This fires consistantly on my Nexus 6p and an HTC.
However on a Samsung GS5, this only works for so long. The time it stops seems random but usually within 30 mins, sometimes as short as 5 mins. The broadcastReceiver never gets called again, meaning the onReceive just stops firing.
All power saving settings on the samsung are turned off that I can notice. Unless there is a super tricky hidden one, I can't figure out how the Samsung phone can stop this broadcastReceiver, or stop GPS, whichever is happening.
This happens even if the app is not swiped closed. The phone goes idle, screen turns off, and about 5-30 mins later, the phone stops getting coords.
This happens whether I use GPS_PROVIDER or NETWORK_PROVIDER although with network provider it seems to happen even faster.
Here is where I start the GPS.
public void startBackgroundGPS () {
Activity activity = this.cordova.getActivity();
Context context = activity.getApplicationContext();
ComponentName component = new ComponentName(context, LocationReceiver.class);
int status = context.getPackageManager().getComponentEnabledSetting(component);
Log.d(TAG, Integer.toString(status));
if(status == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || status == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
Log.d(TAG, "receiver is enabled");
//getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_DISABLED , PackageManager.DONT_KILL_APP);
} else if(status == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
Log.d(TAG, "receiver is disabled");
context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED , PackageManager.DONT_KILL_APP);
}
Intent intent = new Intent(context, LocationReceiver.class);
intent.setAction("myBroadcast");
intent.putExtra("session_id", session_id);
intent.putExtra("device_id", device_id);
//intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
PendingIntent pendingIntent = PendingIntent.getBroadcast(activity.getApplicationContext(), 58534, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//Register for broadcast intents
locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, pendingIntent);
}
Here is my broadcastReceiver
public class LocationReceiver extends BroadcastReceiver {
//private static boolean semaphore = true;
#Override
public void onReceive(Context context, Intent intent) {
Log.d("DistanceFilterLocationService", intent.getAction());
Location location = (Location) intent.getExtras().get(android.location.LocationManager.KEY_LOCATION_CHANGED);
Intent locationServiceIntent = new Intent(context, DistanceFilterLocationService.class);
locationServiceIntent.putExtra("device_id", intent.getStringExtra("device_id"));
locationServiceIntent.putExtra("session_id", intent.getStringExtra("session_id"));
Double longi = location.getLongitude();
Double lati = location.getLatitude();
locationServiceIntent.putExtra("longitude", longi);
locationServiceIntent.putExtra("latitude", lati);
locationServiceIntent.putExtra("accuracy", location.getAccuracy());
locationServiceIntent.putExtra("time", location.getTime());
context.startService(locationServiceIntent);
}
}
Here is my broadcastreceiver in the manifest.
<receiver android:name="com.mypackage.LocationReceiver">
<intent-filter>
<action android:name="myBroadcast" />
</intent-filter>
</receiver>
Anyone run into something like this? Found a couple similar questions but no answers were given. This one is killing me as it completely destroys the purpose of the app on Samsung phones.
Thanks for any help.
Maybe it is not a good answer, but perhaps the android version could be the problem. Or, maybe some addons from Samsung... did you test on other Samsung phone (maybe another android version)?
I have searched quite a bit and I'm not totally clueless. I have implemented a temporary solution on my end but was wondering if there is a better approach out there.
I have an app that sends a person's location after every 60 seconds to a server. On my dashboard (the main screen that will go to onPause after application starts), I have registered a LocationManager with the following code:
service = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean enabled = service
.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!enabled)
{
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
else
{
Criteria criteria = new Criteria();
provider = service.getBestProvider(criteria, false);
service.requestLocationUpdates(provider, 10000, 50, this);
Location location = service.getLastKnownLocation(provider);
// Initialize the location fields
if (location != null)
{
onLocationChanged(location);
}
else
{
Log.d("Location: ", "No update received");
}
}
However, as I mentioned, this activity will be minimized by the user (by pressing the home button). There is a service that gets called every 60 seconds by an AlarmManager. That service accesses static variables from the Dashboard Activity (lat, lon) and sends it to the server.
My question:
If the activity goes onPause, will the requestLocationUpdates function stop? Or will it keep working?
If it keeps working, it will keep updating the two lat and lon static String objects and the service will keep getting updated values. If they stop, the service will keep getting the same old values again and again.
Also, is there a better way to approach this problem? Using a mix of GPS Provider and Network Provider? (I need fairly accurate values).
EDIT
Here's my Alarm. This code is inside Login Activity
Intent i = new Intent(con, LocationPoller.class);
i.putExtra(LocationPoller.EXTRA_INTENT, new Intent(con,
Login.class));
i.putExtra(LocationPoller.EXTRA_PROVIDER,
LocationManager.GPS_PROVIDER);
gps = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcast(con, 0, i, 0);
gps.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(),
10 * 1000, pi);
Log.d("Service: ",
"GPS Service started and scheduled with AlarmManager");
Here's my receiver (also within Login activity)
private class ReceiveMessages extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Location loc = (Location) intent.getExtras().get(
LocationPoller.EXTRA_LOCATION);
String msg;
if (loc == null)
{
msg = intent.getStringExtra(LocationPoller.EXTRA_ERROR);
}
else
{
msg = loc.toString();
}
if (msg == null)
{
msg = "Invalid broadcast received!";
}
Log.d("GPS Broadcast: ", msg);
}
}
Nothing's happening :s Not getting anything on logcat which means the broadcast isn't being received.
When activity goes on pause, all registered listeners will stop. Better way to implement this is, alarm manager sent a broadcast every 60 seconds, this broadcast receiver starts a service and this service will request a location on Wakeful thread, once location information is retrieved, update the location on server.
There is an Open source library available with an example (courtesy CommonsWare), please refer below link. Its under Apache 2.0 license
Location Polling Library
Please find my sample project using above library. I have modified few things in the above library and created my own version.
Location Polling Demo Application
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 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.