Improving Android GPS performance - java

How do you improve slow GPS signal acquisition on the Android platform?
I'm testing a simple GPS logger based on this open source code, and although it seems to work, it can take up to 10-15 minutes for it to first acquire a signal and start showing GPS coordinates. However, running the Google Maps app on the same device appears to acquire a signal almost instantly (it's even able to detect which direction I'm facing in realtime), while the GPS logger service still says it can't find a signal.
Why is Google Maps so fast at acquiring a GPS signal, while the standard GPS system service takes forever?
The specific code I have that starts the GPS service is:
private void startLoggerService() {
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener = new MyLocationListener();
lm.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
2000,
1,
locationListener);
}

There are a couple of things you should be aware of and definitely take into consideration when it comes to using positional data:
Don't rely on just the GPS sensor. Although GPS can potentially give you the most accurate result, it is relatively slow and quite the battery hog. In stead, also request location updates from the network provider: LocationManager.NETWORK_PROVIDER. In most cases this will give a result accurate enough to use in your app (most devices I've played with seem to yield a worst case accuracy of roughly 60~65m), but more importantly: it's much, much faster. Do note that just as with the GPS, users can enable and disable feature themselves in the system settings. For more details, see Using the Location Manager.
Think about how often you need a location update. If possible, prevent continuous updates (that'll drain the battery in no-time) and release the sensors as soon as you've received the data you require. Also, a good practice is to cache the location to some extend - even if it's not completely accurate, users do get feedback immediately. You can potentially combine this with some logic that takes the time stamp into account.
Use the resources that are already available on the Android Developer website. For example, there is a topic on Location Strategies that will be worth reading. Another good resource will be the blog post by Reto Meier and his open source project that implements his Android Protips for Location. If you have the time, also go over his Google I/O 2011 presentation that discusses best-practices for location-based/location-aware Android apps.
On a side note: the realtime indication of what direction you're facing has nothing to do with locations, but comes from either the magnetic field sensor (read: digital compass) or gyroscope. Both deal with the device's orientation, not position.

The 1 in your code means that the provider will only broadcast the location should your device move by 1 meter. Try setting this to 0.
The API documentation states:
"The frequency of notification may be controlled using the minTime and minDistance parameters. If minTime is greater than 0, the LocationManager could potentially rest for minTime milliseconds between location updates to conserve power. If minDistance is greater than 0, a location will only be broadcasted if the device moves by minDistance meters. To obtain notifications as frequently as possible, set both parameters to 0."

If google maps is showing your direction, it must be using a GPS fix. Google maps must be using the most recent gps fix which you can get using Location.getLastKnownLocation. Presumably if that location is not too old Google maps decides it is way better than nothing and shows it to you while you wait for new GPS fixes.
GPS fixes will often come really slowly or not at all when you are indoors. I assume as you develop you are trying to get GPS fixes? You may have to get up and walk outside.
Many phones have fairly lousy gps receivers. Even in clear outdoor sky I own phones which will take MANY minutes to get the first GPS fix. It sucks and its a rip-off, but its true.

Related

Checking status of GPS Provider in Android App

I have an operational Android app which reports users location within a background service. I want to integrate a feature which will notify the user when GPS signal has been lost.
Our current implementation to commence location updates is:
mLocationListener = LocationListener(LocationManager.GPS_PROVIDER, gpsDeviceCallback)
if (handlerThread?.isAlive == true) {
handlerThread?.quit()
}
handlerThread = HandlerThread("GpsLocationHandler")
handlerThread!!.start()
mLocationManager?.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE.toFloat(),
mLocationListener, handlerThread!!.looper)
with LOCATION_INTERVAL set to 1000 ms and LOCATION_DISTANCE set to 10m.
We get the expected onLocationChanged callbacks under normal operation. However, I would appreciate advice on how to detect a situation where there is a loss of GPS or handset cannot obtain an adequate GPS signal.
We have implemented a solution where we run a time task and determine if onLocationChanged is called during the timer period. The problem with this solution is that if the user handset is stationary during this time then no onLocationChanged callbacks will happen. So this approach will not work as a means of detecting no\inadequate GPS signal.
The user of onStatusChanged as a method of LocationListener is now deprecated so this is not an option either.
Is there some standard solution to this problem ? Perhaps some method which could be called in the case where no onLocationChanged callbacks happen when our check timer expires to test current GPS status?
Thanks!
you can check the current connected satellites and approximate the accuracy see :https://stackoverflow.com/a/10589949

Syncing Two Metronomes In Java using Bluetooth for Android

I have a bit of a unique issue. I'm collaborating with several other Computer Science Majors at my university on an Android Metronome app that allows two users with the app to sync metronomes. Right now, I can send the desired beats per minute of the metronome from one phone to the other and both phones will start to play their respective metronomes. Due to the latency of Bluetooth, the metronomes are only in sync about 20% of the time.
So, here's where the problem is. We're trying to make it so both of the metronomes will start at the exact same time. One way I've thought of doing this is once the first user presses the send button on their phone, a time stamp will be created. This time stamp will be exactly two seconds after the user presses the send button. The time stamp will then be sent to the second phone and the phone will utilize this time stamp to start it's metronome at the same exact time as the first phone. I've tried accomplishing this by putting UTC time in a while loop and then constantly checking the time, to no avail. Does anyone have any ideas as to how we can go about implementing this? I couldn't find any similar problem on StackOverflow, or any other website for that matter.
It's a bit late probably for your project, but if interested. This is a bit long, it's more like a case study.
If your project was about syncing two device clocks remotely, then this won't help you, but if it was about syncing the metronomes, then this may be a start.
First, getting millisecond accurate timings and callbacks in android using java is next to impossible, since android is not a real time system ( All sleep methods and timer might not execute on the exact millisecond you're expecting ). You may want to go with NDK for triggering your beat events, because native threads in android can achieve that, but if you're happy with your single metronome implementation, then that's good enough to read the rest of this .
Full disclosure :
I am the author of JAM the app referenced in the answer I just published a few days ago.
I ran into the same problem when developing the app.
And whether this answer will help you or not, depending on your situation.
and if you're going down the "clock sync" route ( Which I do plan on exploring to improve my app down the road with more features ) but the solution that I found did not involves time sync.
I will mention my approach and then state what I found as advantages/disadvantages for each of the methods .
Instead of syncing clocks ( A very difficult problem, especially for what the app was supposed to do , and that is trigger ticks on multiple devices at the "same" time ) I opted for a subscribe/publish model, where multiple devices can "subscribe" to a host device via bluetooth, and the host device controls and "publishes" the metronome beats.
most times sending a few hundred bytes ( Enough information about each beat ) via bluetooth takes less than 2ms , it could spike up to 10 and sometimes even 30, but that rarely seems to happen .
That approach took care of the syncing problem, now I can send beat events from one device to another in 2ms , and if some sort of delay happened, it will self correct once the interference is gone, because the other event comes in time.
However that approach does require constant connection, you can't start and separate the devices later on, but it's much easier to implement.
Now the interesting part, the problem I never thought of when starting this, and that was the Android 10 millisecond audio path latency problem. I'm not affiliated with superpowered, but I did use their engine in my app to deal with that problem .
To summarize :
Metronome sync over bluetooth in Android has two issues :
1 - triggering beat events simultaneously ( or within acceptable latency )
2 - The beat event should trigger sound events with minimal delay after the beat event is received
#1 is related to the original question, #2 I thought was an important addition to the original problem this question is asking.
I would use (S)NTP to check the clock drift to a public time server. After that I would just send the interval and a start time and let the devices calculate the interval individually. So you just need to sync changes and relay on the clocks of the individual devices. Together with the now known clock drift you can fix this error.

Force GPS to come on

I asked this question (Why Does Map Marker Lurch Around The Map) yesterday. One thing I noticed today is that for an activity that uses LocationManager, but not a map I get the GPS icon (satalite dish beaming signals up) in the status tray. With the activity that has a map fragment and also uses LocationManager I do not get the GPS icon in the tray. I copied and pasted the location manager code from one activity to the other.
Why would the GPS come on some times and not others?
Greg
It depend on global GPS setting - if it's globally on, using LocationManager in your Activity\Fragment will fire "satellite dish". If GPS is globally switched off - using LocationManager will not fire.
The reason is that GPS is a huge power consumerist, and allowing it to run without clear user decision to switch it on will drain the device battery extremely quickly.

What Android methods are called when battery dies?

When the battery on my Android device dies what methods in the Activity and Fragment classes (if any) are called during the "Powering Off" stage of the device?
Also, if a user is currently looking at a screen in my app and they hold the power button and choose switch off, do the events called/not called coincide with when the battery is depleted and shuts down automatically?
OnPause?
OnStop?
OnDestroy?
OnDetach?
Bonus:
Will I have enough time to save a small amount of data to a web server?
To clarify "dies" when the device's battery is 'completely' dead, accepts no more input and a message box/loading screen pops up on the screen stating "Powering Off". Shortly there after the device switches off.
I just need enough time to save a forms state before the phone switches off, I have a strategy to clean the saved data should the phone not switch off, but I want to get as close to the phone switching off as possible (any more than a minute is pointless really).
onDestroy is called on everything when the battery reaches 0.5%
EDIT: There is no specified time that you have to do anything in the shutdown process resulting from low/dead battery, that would be dependent on the specific phone battery and not the system, so you may have enough time to save data to a web server on some phones but not others. Experimentally, I have only been able to write a short line to a file I was already writing to before onDestroy was called and nothing more.
The methods you have mentioned is activity life cycle callback, none of them will be called when battery is low. You need to use a broadcast receiver for this
See this How to detect when the Battery's low : Android?

Android BLE proximity notifications

I've been working on developing an application that interacts with BLE devices. Everything works great, I can scan, connect, and consume services.
I've been reading through all the docs and I do not see anything that gives the developer the option of listening for BLE devices. Basically I would like to trigger a broadcast receiver when the devices enters the range of a BLE device.
I know I could continually scan for this, but battery use is way too high and I would like this to be invoked even when my application is not being used.
Is this feature not supported or am I missing a section of the docs that discuss this?
I have done a project recently, and from what I read in your question it has some similarity to what I did.
I know I could continually scan for this but battery use is way too high and I would like this to be invoked even when my application is not being used.
Regarding battery problem, having Bluetooth on all the time is power consuming, but at the same time you can not detect BLE with out having Bluetooth on.
What I did is two experiments and both are useful but are different and I can not say which one is best, but you need to test it so it fits your requirement.
Having Thread running that turns Bluetooth on and listen to iBeacon and off (with sleeping time) for while programmatically. It can be done many ways.
Using a package called Altbeacon, has a lot of useful features, one of those features is Auto Battery Saving with example code:
public class MyApplication extends Application implements BootstrapNotifier {
private BackgroundPowerSaver backgroundPowerSaver;
public void onCreate() {
super.onCreate();
// Simply constructing this class and holding a reference to it
// in your custom Application class
// enables auto battery saving of about 60%
backgroundPowerSaver = new BackgroundPowerSaver(this);
}
}
We need a broadcast event, that wakes up our app once a BLE-device with a certain Service-UUID is in reach. Maybe now there is a better BLE API available than 2 years ago. The most energy saving and most precise method gets rewarded.
Your other part, it is called triggering actions at a specific distance.
I still use the Altbeacon to check beacon range and triggering action. A sample code is something like
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for (Beacon beacon : beacons) {
if (beacon.getDistance() < 5.0) {
Log.d(TAG, "I see a beacon that is less than 5 meters away.");
// Perform distance-specific action here
}
}
}
So when that said, you can also get distance of specific UUID I build a method based on Altbeacon, looks like this (Look inside the for loop and if statement):
private void startRangeNotifier() {
Log.i(TAG, "Starting range notifier...");
beaconManager.setRangeNotifier(new BeaconRangeListener() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
for (Beacon beacon : beacons) {
Log.d(TAG, "uuid's: " + beacon);
Log.d(TAG, "uuid id1: " + beacon.getId1());
if (beacon.getId1().toString()
.equals("b9407f30-f5f8-466e-aff9-25556b57fe6d")) {
Log.d(TAG, "uuid id1 distance: " + beacon.getDistance());
}
}
}
}
});
try {
beaconManager.startRangingBeaconsInRegion(
new Region(BEACON_MONITORING_ID, null, null, null));
} catch (RemoteException e) {
e.printStackTrace();
}
}
My log output:
D/Main activity:: uuid's: id1: b9407f30-f5f8-466e-aff9-25556b57fe6d id2: 31807 id3: 59251
D/Main activity:: uuid id1: b9407f30-f5f8-466e-aff9-25556b57fe6d
D/Main activity:: uuid id1 distance: 0.2108658568686884
In my answer I wanted to present the concept I used, Beacons project need patience in general. As the other answer mentioned it is also possible to combine the solution here with Geofences and ActivityRecognition.
Note: Since the nature of bluetooth beacon, the distance is proximity and not absolute, and some time even the bluetooth beacon is 1 meter a way it might show 2 meter or 0.5 meter, so have that in mind
Link reference:
https://altbeacon.github.io/android-beacon-library/distance-triggering.html
https://altbeacon.github.io/android-beacon-library/samples.html
https://altbeacon.github.io/android-beacon-library/eddystone-how-to.html
https://github.com/AltBeacon/android-beacon-library-reference
BLE scanning on Android is pretty battery intensive, and it's definitely not something you want to do in the background all the time. If you are working on a background application with stationary bluetooth devices (à la ibeacons) that you know the location of, you can use Geofences to turn scanning on and off when you think you are in the approximate proximity of a device. If you are not careful geofencing can also drain battery.
If you don't know the location of your bluetooth devices I guess you can also play tricks with ActivityRecognition, i.e only scan periodically when the user is walking and stopping it if the user is stationary/running/biking/in vehicle. Again, the activity recognition stuff also takes battery so you are going to have to be judicious.
We need a broadcast event, that wakes up our app once a BLE-device with a certain Service-UUID is in reach.
You probably know how to filter scan results by Service UUID so I won't go into that. About the waking up: if your app is scanning, it is awake by definition. It may or may not be on the foreground, but it is awake.
Maybe now there is a better BLE API available than 2 years ago.
Since SDK version 21, there is a new API that you can use for BLE scanning. To my knowledge, the only difference is the way you access the API and the underlying functionality (regarding power consumption etc.) has not changed.
About the scanning:
It's true that scanning is battery-intensive. Even the docs say so.
The intensity is relative though. It is intensive compared to not scanning at all, but it is not intensive enough that it will hopelessly drain your battery. It's called low energy after all.
An other answer suggest monitoring Geofences and only scan when you know you are in range of BLE devices. While this will lower the battery consumption of the ble scan, it will need that battery power for the GPS, otherwise it can't monitor the Geofences (well, it can, with cellular/wifi data, but then it won't be nearly as accurate).
Depending on how time critical your scanning is (e.g. if there is a device nearby, must you know it right away? or is it okay if it's delayed a couple seconds?) you can implement a pause inbetween scans.
Say you scan for 5 seconds, pause for 5 seconds, scan for 5 seconds again. That way you will be scanning almost all the time, yet only consume roughly half of the battery power. These intervals can be tweaked to match your situation. Maybe you're okay with scanning 3 seconds and pausing for 10. (note that the maximum time between a device's broadcasts is 10.24 seconds).
I have an app with about 50 users that scans with pauses like this (scan for 3 seconds, pause for 3, repeat) 24/7 in the background, and have not received any complaints about excessive battery usage.
If you have a specific BLE peripheral you want to detect, then figure out its advertisement period. If you have different devices, find the longest advertisement period. Scan longer than the advertisement period of the device, so you get at least one advertisement message. Repeat this scanning periodically with the frequency that is suitable for your use case. E.g. Your peripheral is advertising every second once. You would like to detect the device in 5s when it comes to proximity. Then Scan for 1s (or a bit more). Switch off scanning for 4s. This way you can save battery.

Categories