Android number of satellites problem [duplicate] - android

I'm using a GPS provider and LocationListener.onLocationChanged(Location location) to receive location fixes.
Documentation says, that Location.getExtras() contains next key/value pair:
satellites - the number of satellites used to derive the fix
but on practice I'm getting an empty extra object - there is no any data there.
Does it means that I'm getting the A-GPS fixes and not GPS?

To get the number of satellites used by the GPS engine you need to implement android.location.GpsStatus.Listener and implement its method onGpsStatusChanged().
Example...
public void onGpsStatusChanged(int event) {
int satellites = 0;
int satellitesInFix = 0;
int timetofix = locationManager.getGpsStatus(null).getTimeToFirstFix();
Log.i(TAG, "Time to first fix = " + timetofix);
for (GpsSatellite sat : locationManager.getGpsStatus(null).getSatellites()) {
if(sat.usedInFix()) {
satellitesInFix++;
}
satellites++;
}
Log.i(TAG, satellites + " Used In Last Fix ("+satellitesInFix+")");
}

I use Location.getExtras().getInt("satellites"), and it give the number of satellites in use.

Since Android API 24 GpsStatus is deprecated and one should use GnssStatus. Let us have an activity or a service processing Gps data and a LocationManager already created.
private GnssStatus.Callback gnssCallback;
public void initCallbacks() {
....
gnssCallback = new GnssStatus.Callback() {
#Override
public void onSatelliteStatusChanged(#NonNull GnssStatus status) {
final int satelliteCount = status.getSatelliteCount();
int usedCount = 0;
for (int i = 0; i < satelliteCount; ++i)
if (status.usedInFix(i))
++usedCount;
Log.d("MyServiceTag", "satellites count = " + satelliteCount + ", used = " + usedCount);
}
};
locationManager.registerGnssStatusCallback(gnssCallback, new Handler(Looper.myLooper()));
....
}
public void deinitCallbacks() {
....
locationManager.unregisterGnssStatusCallback(gnssCallback);
....
}
initCallbacks() should be called after locationManager initialization. deinitCallbacks() should be called when information on the number of satellites is no longer needed, e.g. in onDestroy(). GnssStatus.getSatelliteCount() returns total number of known satellites, GnssStatus.usedInFix(int i) tells whether i-th satellite had been used in the most actual location capture.

Nope it means that your phone manufacturer decided not to implement this. (Or you could be using the NETWORK_PROVIDER which does not use satellites)
Use a NmeaListener and parse the sentences to know the number of satellites visible or used.

Related

Getting the Speed of the User - getSpeed and casting

I am currently trying to get the speed of a user using the GPS (Google Play Location Services).
However, the problem with my code is that the speed is stuck on a very small number - going down to 1.9^E18, basically 0. This value doesn't change even though I move around.
I am currently trying to calculate the speed of the user manually through using speed and time stamps. However, I have also found a function called getSpeed(). I was considering to use it, but there were many complaints I found here that said that it always returned zero.
Firstly - is getSpeed() only used for mock locations, or can it be used safely with location objects obtained by the GPS?
Secondly if getSpeed does not work, I will need to continue obtaining the speed manually. I believe there may be problems with the casting. Can someone help in finding the problem of my current method?
public void onLocationChanged(Location location) {
location.getLatitude();
Toast.makeText(this, "Location Changed", Toast.LENGTH_SHORT).show();
if (settings == null) {
settings = getSharedPreferences(PREFS_NAME, 0);
}
int TimeDifference = (int) (location.getTime() - OldLocation.getTime());
int distance = (int) OldLocation.distanceTo(location);
double speed = distance / TimeDifference;
if (LowerLimit < speed && speed < UpperLimit) {
TimeInstance += TimeDifference;
}
if (TimeInstance>TimeLimit) {
if (!dialogShown) {
dialogShown = true;
ViolationMessage();
TimeInstance = 0;
}
else {
TimeInstance = 0;
}
}
OldLocation = location;
}

Location.getBearing always 0.0

I'm using LocationListener and returned Location always has Bearing as 0.0
Is there anything else I need to do?
I also noticed that with 4.0.3 update I rarely have speed reported. Now I just get positions and accuracy/elevation
public void onLocationChanged(Location loc)
{
Log.d(LOG_TAG, "onLocationChanged");
Position position = new Position();
position.PositionGKey = UUID.randomUUID();
position.GPSTime = new Date(loc.getTime());
position.DeviceTime = new Date();
position.Latitude = loc.getLatitude();
position.Longitude = loc.getLongitude();
position.Altitude = loc.getAltitude();
position.Speed = loc.hasSpeed() ? loc.getSpeed() * 2.23693629 : 0;
position.Accuracy = (int)loc.getAccuracy();
position.Bearing = loc.hasBearing() ? loc.getBearing() : 0;
// There was cases with speed reported 1000+. Just make it real here, round of obvious errors.
if (position.Speed > 120)
{
position.Speed = 0.0;
}
PositionData.InsertPosition(getApplicationContext(), position);
}
When using the GPS provider, Bearing is usually not updated / returned unless the device physically moves and gains speed (check getSpeed()). In practice, speed above 1m/s should produce accurate bearings. I've also found that I have had to occasionally poll and check for the last known location on the GPS provider and grab it's updated bearings to get proper readings.

gps approximate alters on bunch of locations stored in sqlite database

im new in android im stuck at a point, i have stored locations in sqlite database and retrieve using a cursor.i want to use these locations for proximity alert/notification.eg
i have stored a shopping mall when i will be near enough of this mall a notification pop up on screen. unbale to start how to get alters on multiple locations and how to keep alive tracking for updated location and get notify after application is closed.please give me any start.
i have got all stored locations in variable :
private void refreshLocations() {
try{
String pla_key = String.valueOf(listforkey2);
locationcursor=sql.ListWithPlaceonmap(pla_key);
if (locationcursor.moveToFirst())
do {
Lati = (int) (locationcursor.getDouble(locationcursor.getColumnIndex("Place_liti")));
Longi = (int) (locationcursor.getDouble(locationcursor.getColumnIndex("Place_longi")));
} while(locationcursor.moveToNext());
}
catch(Exception ex){
ex.toString();
}
i m also getting locations updated continually :
public void startButton(View view) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
i have an other method in my activity for updated locations:
public void recordLocation(Location loc) {
Toast.makeText(tracking_to_do.this,"Lat: " + String.valueOf(loc.getLatitude()) + " Long: " + String.valueOf(loc.getLongitude()),Toast.LENGTH_SHORT).show();
}
how i can arrange things for setting the alerts .

Getting the number of satellites from Location object

I'm using a GPS provider and LocationListener.onLocationChanged(Location location) to receive location fixes.
Documentation says, that Location.getExtras() contains next key/value pair:
satellites - the number of satellites used to derive the fix
but on practice I'm getting an empty extra object - there is no any data there.
Does it means that I'm getting the A-GPS fixes and not GPS?
To get the number of satellites used by the GPS engine you need to implement android.location.GpsStatus.Listener and implement its method onGpsStatusChanged().
Example...
public void onGpsStatusChanged(int event) {
int satellites = 0;
int satellitesInFix = 0;
int timetofix = locationManager.getGpsStatus(null).getTimeToFirstFix();
Log.i(TAG, "Time to first fix = " + timetofix);
for (GpsSatellite sat : locationManager.getGpsStatus(null).getSatellites()) {
if(sat.usedInFix()) {
satellitesInFix++;
}
satellites++;
}
Log.i(TAG, satellites + " Used In Last Fix ("+satellitesInFix+")");
}
I use Location.getExtras().getInt("satellites"), and it give the number of satellites in use.
Since Android API 24 GpsStatus is deprecated and one should use GnssStatus. Let us have an activity or a service processing Gps data and a LocationManager already created.
private GnssStatus.Callback gnssCallback;
public void initCallbacks() {
....
gnssCallback = new GnssStatus.Callback() {
#Override
public void onSatelliteStatusChanged(#NonNull GnssStatus status) {
final int satelliteCount = status.getSatelliteCount();
int usedCount = 0;
for (int i = 0; i < satelliteCount; ++i)
if (status.usedInFix(i))
++usedCount;
Log.d("MyServiceTag", "satellites count = " + satelliteCount + ", used = " + usedCount);
}
};
locationManager.registerGnssStatusCallback(gnssCallback, new Handler(Looper.myLooper()));
....
}
public void deinitCallbacks() {
....
locationManager.unregisterGnssStatusCallback(gnssCallback);
....
}
initCallbacks() should be called after locationManager initialization. deinitCallbacks() should be called when information on the number of satellites is no longer needed, e.g. in onDestroy(). GnssStatus.getSatelliteCount() returns total number of known satellites, GnssStatus.usedInFix(int i) tells whether i-th satellite had been used in the most actual location capture.
Nope it means that your phone manufacturer decided not to implement this. (Or you could be using the NETWORK_PROVIDER which does not use satellites)
Use a NmeaListener and parse the sentences to know the number of satellites visible or used.

Detecting "use only 2G networks" setting

Is there a way of returning the value of Android's mobile network setting for "use only 2G networks"?
The app being developed measures the internet speed at a certain location, but in order for this to be relevant, it must know if the user is deliberately restricting mobile internet to 2G.
I've taken a look at ConnectivityManager, but it only provides information about the background data setting or all networks. Iterating through them reveals that despite the setting being enabled, HSPA and UMTS return true for isAvailable():
for (NetworkInfo netInfo : cm.getAllNetworkInfo()) {
Log.i(TAG, netInfo.getSubtypeName() + ": " + netInfo.isAvailable());
}
The only hint I've found amidst all this is that netInfo.getReason() returns "connectionDisabled" on HSPA and UMTS when the setting is enabled. The trouble is, when the setting is disabled, those network types don't necessarily appear in the list at all. It doesn't seem right to me to use a string comparison specifically on HSPA and UMTS for "connectionDisabled".
What's the right way of tackling this?
For a small subset of devices (specifically for the LG Optimus 2X Speed, LG-P990), an answer seems to be:
int enabled = Settings.Secure.getInt(getContentResolver(),
"preferred_network_mode", -1);
Log.d("MYAPP", "2G only enabled: " + enabled);
Where the "use only 2G networks" setting is specified as:
0 indicates the setting is disabled
1 indicates the setting is enabled
-1 indicates the setting is not set (some devices?)
How I discovered this? I gathered all the key/value pairs from Settings.Secure using the following:
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(Settings.Secure.CONTENT_URI, null, null, null, null);
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
Log.d("MYAPP", "cursor: "
+ cursor.getString(0) + ", "
+ cursor.getString(1) + ", "
+ cursor.getString(2));
cursor.moveToNext();
}
}
I compared results between enabling and disabling the setting, and sure enough I got:
07-08 00:15:20.991: DEBUG/MYAPP(13813): cursor: 5154, preferred_network_mode, 1
Do NOT use the index column (5154 in the example above), as I've noticed it changes between toggling the setting.
Although this correlates with some documentation for Settings.Secure I found online, this value isn't respected by all phones.
If your device returns -1, perhaps listing the key value pairs will reveal which setting you need. Please comment if you encounter it!
As far as I can tell, there is no documented way of getting value for that setting. But there is a Use2GOnlyCheckBoxPreference class that can be used as an example. It uses internal Phone and PhoneFactory classes to obtain the current value of prefer_2g setting.
You can use Phone and PhoneFactory classes via reflection. But of cause this is undocumented and is on your own risk. Here is relevant code from Use2GOnlyCheckBoxPreference:
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
public class Use2GOnlyCheckBoxPreference extends CheckBoxPreference {
private Phone mPhone;
private MyHandler mHandler;
public Use2GOnlyCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPhone = PhoneFactory.getDefaultPhone();
mHandler = new MyHandler();
mPhone.getPreferredNetworkType(
mHandler.obtainMessage(MyHandler.MESSAGE_GET_PREFERRED_NETWORK_TYPE));
}
private class MyHandler extends Handler {
private static final int MESSAGE_GET_PREFERRED_NETWORK_TYPE = 0;
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_GET_PREFERRED_NETWORK_TYPE:
handleGetPreferredNetworkTypeResponse(msg);
break;
}
}
private void handleGetPreferredNetworkTypeResponse(Message msg) {
AsyncResult ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
int type = ((int[])ar.result)[0];
Log.i(LOG_TAG, "get preferred network type="+type);
setChecked(type == Phone.NT_MODE_GSM_ONLY);
} else {
// Weird state, disable the setting
Log.i(LOG_TAG, "get preferred network type, exception="+ar.exception);
setEnabled(false);
}
}
}
}

Categories

Resources