I have posted about this issue before, and found a few other people who have had the same issue with no solutions found.
I am developing an Android app that submits a JSON query to a server with the obtained GPS coordinates and geocoded Zip Code. For brand new users that have never downloaded the app, GPS does not work whatsoever. It is not until rebooting the phone that GPS will work. After installing the app and then rebooting, the GPS will work every time without problem, even if they restart again.
There is precious little information on this issue, and the only issue I have found refers to using Google Play Location Services, with no further details. Has anyone else had this issue? My development is completely halted until this issue can be resolved.
EDIT:
Here is the link to the MainActivity.java file that calls the geopositioning functions.
Here is the link to the MyLocation.java file that contains the actual logic for multiple sources of geolocation
I have no doubt that there are much better ways of doing GPS. I'm very new to Android development, so any help on this front is very much appreciated.
EDIT 2:
I have wiped my phone with a factory reset, and started from scratch. I still cannot replicate the issue on this device, only on phones using the app for the very first time prior to a restart.
Looks like you're registering both the GPS and NETWORK providers to listen for a location for 10 seconds, and when the timer goes off after 10 seconds you try to get the most recent location from both providers.
There are a few things going on here.
First, you seem to be listening for updates in the wrong method. Your two listeners should look like:
LocationListener locationListenerGps = new LocationListener() {
// This will never be called, its not part of the LocationListener interface - http://developer.android.com/reference/android/location/LocationListener.html
/* public void onStatusChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
} */
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
public void onLocationChanged(Location location) {
// This is the correct method to receive location callbacks
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
Second, I'd use the ScheduledThreadPoolExecutor or Handler instead of Timer.
From the Timer docs:
Prefer ScheduledThreadPoolExecutor for new code...This class does not offer guarantees about the real-time nature of task scheduling.
If a reboot is required to get the app working, its likely something to do with the Timer not firing after 10 seconds. Note that this doesn't necessarily mean that GPS itself isn't working.
Handler should do the job and it's designed for Android, so I'd suggest using it. It looks like:
Handler handler = new Handler();
handler.postDelayed(getLastLocation, 10000);
...and your GetLastLocation would change to:
Runnable getLastLocation = new Runnable() {
#Override
public void run() {
...
}
}
...and your cancel() and other methods would need to reference the Handler.
Also, note that you're declaring the Location object in your MainActivity with a provider type of NETWORK_PROVIDER, and then setting the lat/long in that object.
public Location mUserCoordinates = new Location(LocationManager.NETWORK_PROVIDER);
So, the location type in MainActivity will always appear to be of NETWORK_PROVIDER, no matter the actual source.
Also, doesn't look like your MainActivity needs to implement LocationListener, as its never registered with the LocationManager.
Finally, instead of using two listeners for GPS and NETWORK, I would suggest using the Fused location provider in Google Play Services, as discussed here:
http://developer.android.com/training/location/receive-location-updates.html
You'll be limited to devices Android 2.2 and up with Google Play Services installed, but in my opinion its worth it to avoid dealing with some of the eccentricities of location in the platform and managing more than one provider. For more about Fused location provider and how it differs from listening directly to GPS and NETWORK providers, see this 2013 Google I/O presentation - Beyond the Blue Dot: New Features in Android Location
Why do you use Google Play Services Location API?
The only new feature provided by Play Services is Geofencing. From your answer i assume that you don't want to use Geofencing but just "usual" location requests.
The Android platform provides a great API for such requests which does not requires Google Play Services. I never had the problem you described when using it.
Note that although Google claims the Play Services to be better than the Android API, this is not true since API 9 (Android 2.3), as long as you use the newer LocationManager.requestLocationUpdates methodes that don't require a provider to be specified.
See: http://developer.android.com/guide/topics/location/strategies.html
I had the same issue with the regular Location API earlier. I swiched to Play Services, and it seemed to work. Lately sometimes I experience this issue again with Google Play Services. It is really strange, and based on my experience the probelem is system-wide, so when my app couldn't find location, than the Google Maps app couldn't eather. Note that I use Cyanogenmod, so it can be some bug within it.
Related
I have read a few questions and answers related to this , but none has solved my problem. Please suggest me what should i do. I am using this fused location api in my android background service. And i have provided all the nougat/marshmellow checks also. But i get result location only once or first time, after that , the onLocation result is not called, is it so that only when i change my location it will be called ? please help
heres my simple onCreate of service:
#Override
public void onCreate() {
super.onCreate();
fusedLocationProviderClient= LocationServices.getFusedLocationProviderClient(this);
locationRequest=new LocationRequest();
locationRequest.setInterval(4000);
locationRequest.setFastestInterval(4000);
locationCallback=new LocationCallback(){
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Log.i("serviceTag","onLocationResult called");
}
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)== PackageManager.PERMISSION_GRANTED){
fusedLocationProviderClient.requestLocationUpdates(locationRequest,locationCallback, Looper.myLooper());
}
}
FusedLocationProviderClient provides location updates only in foregrounded state either when an Activity (any not necessarily the one requesting or using location updates) is resumed or when a foreground service associated with location foregroundServiceType is started.
From Android 10, framework developers most likely choose to sub categorize foreground services by a type to ensure not all apps with generic foreground services like media apps gets free access to locations when backgrounded. Given that, it is trivial for application developers to just add this “location” type in manifest for unrelated foreground service to work around the limitation.
https://medium.com/#debuggingisfun/android-foregroundservicetype-8857a36f36b9
I'm trying to detect beacons around me, but with the Nearby API, i can't seem to find them.
I'm using this method to detect nearby devices :
public void startDiscovery(String serviceId, final OnDiscoveryListener l) {
Nearby.Connections.startDiscovery(googleApiClient, serviceId, Connections.DURATION_INDEFINITE, new Connections.EndpointDiscoveryListener() {
#Override
public void onEndpointFound(String endpointId, String deviceId, String serviceId, String endpointName) {
if (l != null) {
l.onEndpointFound(endpointId, deviceId, serviceId, endpointName);
}
}
#Override
public void onEndpointLost(String s) {
if (l != null) {
l.onEndpointLost(s);
}
}
})
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (l != null) {
l.onResult(status);
}
}
});
}
The listener looks like this :
public interface OnDiscoveryListener {
public void onResult(Status status);
public void onEndpointFound(String endpointId, String deviceId, String serviceId, String endpointName);
public void onEndpointLost(String s);
}
But i can't detect anything
I work on the Nearby API at Google. The code snippet above uses the Nearby Connections API--which is actually geared towards different use-cases. To work with Eddystone, use the Nearby Messages API. Here's an example of using Nearby Messages to subscribe to the presence of beacons
Note that you need to first associate a Message payload with the beacon using the Proximity Beacon API.
Even though Google advertised the usage of the Nearby API to detect beacons around us :
The Nearby API for Android and iOS makes it easier for apps to find and communicate with nearby devices and beacons
Source : http://android-developers.blogspot.be/2015/07/lighting-way-with-ble-beacons.html
I wasn't able to use the Nearby API to detect Eddystone beacons. I will describe bellow all the information I have gathered during my research hoping this might save some people some time.
I had setup about the same code as you to detect Estimote beacons but I wasn't able to find the Service ID to provide to Nearby.Connections.startDiscovery() to make it detect my beacon (I tried to use the beacon UUID and some variants without success).
I found on Estimote's website that you need to update the beacon firmware to be able to configure it as an Eddystone beacon : http://developer.estimote.com/eddystone/#configure-estimote-beacons-to-broadcast-eddystone. Mine wasn't so I did it.
Nevertheless, that didn't solve my problem and I was still unable to detect the beacon using the Nearby API. I tried setting it as a Eddystone-UID and a Eddystone-URL and tried several combination (based on the information provided by the Estimote app) as Service ID unsuccessfully.
A more deeper look into the Nearby API's documentation shows that Google doesn't mention anything about beacons nor Eddystone in their Nearby API documentation (https://developers.google.com/nearby/connections/overview) and Google's sample about beacons is not using the Nearby API at all : https://github.com/google/beacon-platform/tree/master/samples/android
Yet, they do mention that Nearby Messages will allow rich interaction such as "collaborative editing, forming a group, voting, or broadcasting a resource" and is coming soon :
Coming Soon: The Nearby Messages API will be available in Google Play service 7.8. This site will be updated with the complete API documentation when the new version is available.
Source : https://developers.google.com/nearby/
My understanding is the support for beacons will be available with the Google Play Services 7.8 since the beacons are broadcasting resources.
In the meantime, if you still wish to be able to detect Eddystone beacons around you, you can use Estimote's Android SDK : https://github.com/estimote/android-sdk#quick-start-for-eddystone
or implement the same code as Google's Beacon Proximity sample :
https://github.com/google/beacon-platform/tree/master/samples/android
This may sound like an odd thing - but try turning you wifi on and off. A lot of cheaper devices are really bad with bluetooth and fail to connect, but for some reason turning wifi off and on fixes it for a while.
I was having a similar problem - everything in my code was correct but not detecting beacons. I even tried with the manufacturers app, and theirs also couldn't detect the beacon (but their iPhone version did). I turned my wifi off, then back on again and the manufacturers app worked and so did mine.
Yes, you can discover Eddystone beacons using the Nearby API. But to detect beacons you have to use the Nearby Messages API not the Nearby Connections API, as #Andrew Bunner also mentions.
To be able to detect the beacons using NearbyMessagesAPI you will have to also register the beacons with Google first, and than configure them to have a message payload associated with them.
You can find all the steps in my blog post or this other answer I posted.
In my app, I've tried two ways of accessing location:
a) Using LocationManager and GPS_PROVIDER. I accept location to be processed if it has accuracy 50 or less. App receives location however most of the time receives no location at all - while Google Maps when I start it to try it out gets my location constantly and more precise than my app.
Here are parts of the source related to this:
Start to listen to locations:
// in service class, function to start listening for locations.
// class implements android.location.LocationListener interface
this.locman = (LocationManager) getApplicationContext().getSystemService(LOCATION_SERVICE);
if( !this.locman.isProviderEnabled(LocationManager.GPS_PROVIDER) ){
Log.d("","GPS is not enabled");
}else{
this.locman.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
this.onLocationChanged( this.locman.getLastKnownLocation(LocationManager.GPS_PROVIDER) );
}
android.location.LocationListener implementation of onLocationChanged function:
#Override
public void onLocationChanged(Location location)
{
... showing provided Location on the map
}
in manifest file:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
This can give me relatively frequent updates, but sometimes has huge gaps. I believe maybe it's problem with connecting with enough satellites, however if I open Google Maps in the same time - it works flawlessly. No time gaps between location updates, and more precise than what I am getting here.
I thought it may be needed to use LocationClient and LocationRequest instead, counting that maybe Google Play API may have some internal interpolation / prediction / whatever that improves precision.
b) Using GooglePlay API with LocationClient and LocationRequest. I've installed Google Play SDK, and also tried Google's sample apps. Here is my code related to this:
// in service class, function to start listening for locations.
// class implements com.google.android.gms.location.LocationListener,
// com.google.android.gms.common.ConnectionResult.OnConnectionFailedListener and
// com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks interface
this.locclient = new LocationClient(this.getApplicationContext(),this,this);
this.locclient.connect();
implementation of onConnected:
#Override
public void onConnected(Bundle dataBundle)
{
LocationRequest req = LocationRequest.create();
req.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
req.setInterval(2000); // 2 sec
req.setFastestInterval(16); // 60 fps
this.locclient.requestLocationUpdates(req, this);
}
And of course onConnectionFailed and onDisconnected is implemented and breakpointed - never gets in, while onConnected is called.
Implementation of com.google.android.gms.location.LocationListener:
#Override
public void onLocationChanged(Location location)
{
... showing provided Location on the map
}
In this case, I get updates immediately, however off for like 200m or more.
In desperation, I tried MyLocation app that is on Google Play and it shows SAME OFFSET!
When I try Google Maps, in the same time, it shows absolute accuracy like 5-6m the most.
Important notice: I am located in Shanghai, China. Not sure if this is related in any way.
How is it possible to have such huge offset between Google Maps and Google's own example of location service (MyLocationDemoActivity.java, provided in google_play_services/samples/maps/)?? To clarify: Google's map demo provided with Google Play Services sample codes, also shows SAME OFFSET (~200m) away from my real location, while in the same time Google Maps app shows precise location.
I'm using Nexus 4 as development platform.
Compiler is ADT (Eclipse). All up-to-date.
Really hope for some quick breakthrough from anyone here!!! Thanks in advance!
P.S.
I have now tried to use LocationRequest.PRIORITY_NO_POWER as setting for location request, to have my app get location update only when another app requested it. I've then started Google Maps, and switched back to my app. It immediately received location. I've copied long/lat into http://maps.googleapis.com/maps/api/staticmap?center=31.229179,121.422615&zoom=16&format=png&sensor=false&size=640x640&maptype=roadmap to test it out, and it is showing SAME OFFSET. While Google Maps on my phone shows exact location.
Is it possible that maps from Google have offset? Or that there is an offset to long/lat received?
I don't have enough reputation to comment yet so I'm writing an answer.
This is most likely related to the China GPS offset problem. The Chinese government insists on not allowing users to record accurate GPS data in some scenarios ("national security something blah blah") and force companies like Apple/Google to abide by the local laws.
Here is a link with some good information on the topic:
http://www.sinosplice.com/life/archives/2013/07/16/a-more-complete-ios-solution-to-the-china-gps-offset-problem
As in above answer, offset is because of China government regulation. However people managed to get transform used at least by GoogleMaps and HEREMaps. It is here written in C#.
Using that you can convert real coordinates to transformed ones with maximum 20 meters error. There are also more accurate implementations.
If you don't want to modify your software, you can use something based on this. It is my simple Xposed module to convert coordinates for all applications using LocationManager.
If I set any ACCURACY to criteria, it takes long time to LocationManager to start updating location:
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
provider = locationManager.getBestProvider(criteria, true);
locationManager.requestLocationUpdates(provider, 0, 0, this);
If I remove ACCURACY flag, it starts immediately but sometimes not accurate.
How can I make it start updating immediately and with good accuracy?
Unfortunately, no way.
If you use ACCURACY_FINE, you will use GPS only, but GPS have "cold start" effect. It means that if you device not used GPS long time, it needs a lot of time for connecting with satellites and download almanac and ephemeris. You can't change this behavior.
If you don't use ACCURACY_FINE, you will use both GPS and network (mobile, wi-fi) signals. So you will receive quick first position from network, because they don't have "cold start" effect, but accuracy of this method is low. When your GPS module will ready, you will start receive updates from it too.
If you care only about accuracy and not things like bearing or altitude I suggest switching to the new fused provider in the LocationClient API from Google.
It is very quick to get the first fix, more accurate than network based and doesn't depend on GPS.
It requires a bit more setup then the built-in LocationManager, so you may read this training article: http://developer.android.com/training/location/receive-location-updates.html
I suspect that at least with ACCURACY_FINE, it's waiting to get an initial GPS fix. You may find that if you've already got GPS turned on for another reason (e.g. if you're in the middle of navigation) that it starts reporting immediately.
It can take a while to get a GPS fix - I think it's just a natural part of how GPS works.
LocationManager is buggy on many phones, since it depends heavily on the customized android open source code for specific hardware. Samsung phones are very buggy when it comes to LocationManager.
You should not use requestLocationUpdates, instead use getLastKnownLocation with a small hack. Just before the getLastKnownLocation call put the following hack and you should be able to use a AlarmManager to get regular updates.
HomeScreen.getLocationManager().requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onLocationChanged(final Location location) {
}
});
LocationClient is the other alternative to LocationManager. It is more accurate, uses a hello a lot less battery.
I am making simple application which based on phone's location. I am using this code for GPS location. In the main() function I am requesting the GPS location and then I am working with it. (I am calculating the sunrise and sunset)
I can get the location, but when I start the application I get the LastKnown location. So, if I want real "new one" location I must wait for GPS lock on and then restart the application.
So, my question is: How can I get a "fresh" location?
Ok. I have an idea.
Can I call MainActivity refresh from another class?
in GPS class I have this
private final Context mContext;
#Override
public void onLocationChanged(Location location) {
startActivity(new Intent(mContext, MainActivity.class));
}
But this doesn't work. Can anyone help?
Here is the overview of location services in Android. Here is the LocationManager class at the heart of location services in Android.
Here is an Android developer tutorial on "Location Strategies". Here is another tutorial that might be usable.
Also, you cannot just ask Android for your current position, since GPS may take quite some time to get a fix. Instead, you need to request location updates and use the first update you get, or similar patterns.