forked from organicmaps/organicmaps
Location service refactoring.
This commit is contained in:
parent
b7d3967f39
commit
6b00af612e
9 changed files with 218 additions and 309 deletions
|
@ -70,7 +70,7 @@ public class DownloadActivity extends MapsWithMeBaseListActivity implements MapS
|
|||
if (getDownloadAdapter().onCountryStatusChanged(idx) == MapStorage.DOWNLOAD_FAILED)
|
||||
{
|
||||
// Show wireless settings page if no connection found.
|
||||
if (ConnectionState.getState(this) == ConnectionState.NOT_CONNECTED)
|
||||
if (!ConnectionState.isConnected(this))
|
||||
{
|
||||
final DownloadActivity activity = this;
|
||||
final String country = getDownloadAdapter().mStorage.countryName(idx);
|
||||
|
|
|
@ -38,7 +38,7 @@ import java.util.regex.Pattern;
|
|||
|
||||
@SuppressLint("StringFormatMatches")
|
||||
public class DownloadResourcesActivity extends MapsWithMeBaseActivity
|
||||
implements LocationService.Listener, MapStorage.Listener
|
||||
implements LocationService.LocationListener, MapStorage.Listener
|
||||
{
|
||||
private static final String TAG = "DownloadResourcesActivity";
|
||||
|
||||
|
@ -384,7 +384,7 @@ public class DownloadResourcesActivity extends MapsWithMeBaseActivity
|
|||
{
|
||||
setAction(DOWNLOAD);
|
||||
|
||||
if (ConnectionState.getState(this) == ConnectionState.CONNECTED_BY_WIFI)
|
||||
if (ConnectionState.isWifiConnected(this))
|
||||
onDownloadClicked(mButton);
|
||||
}
|
||||
}
|
||||
|
@ -601,11 +601,19 @@ public class DownloadResourcesActivity extends MapsWithMeBaseActivity
|
|||
@Override
|
||||
public void onCompassUpdated(long time, double magneticNorth, double trueNorth, double accuracy)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrivingHeadingUpdated(long time, double heading)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationError(int errorCode)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
private class GeoIntentProcessor implements IntentProcessor
|
||||
|
|
|
@ -48,6 +48,7 @@ import com.mapswithme.maps.widget.MapInfoView.OnVisibilityChangedListener;
|
|||
import com.mapswithme.maps.widget.MapInfoView.State;
|
||||
import com.mapswithme.util.ConnectionState;
|
||||
import com.mapswithme.util.Constants;
|
||||
import com.mapswithme.util.LocationUtils;
|
||||
import com.mapswithme.util.ShareAction;
|
||||
import com.mapswithme.util.UiUtils;
|
||||
import com.mapswithme.util.Utils;
|
||||
|
@ -60,7 +61,7 @@ import java.util.Locale;
|
|||
import java.util.Stack;
|
||||
|
||||
public class MWMActivity extends NvEventQueueActivity
|
||||
implements LocationService.Listener,
|
||||
implements LocationService.LocationListener,
|
||||
OnBalloonListener,
|
||||
OnVisibilityChangedListener, OnClickListener
|
||||
{
|
||||
|
@ -505,7 +506,7 @@ public class MWMActivity extends NvEventQueueActivity
|
|||
|
||||
private void checkFacebookDialog()
|
||||
{
|
||||
if ((ConnectionState.getState(this) != ConnectionState.NOT_CONNECTED) &&
|
||||
if (ConnectionState.isConnected(this) &&
|
||||
mApplication.shouldShowDialog(MWMApplication.FACEBOOK) &&
|
||||
!isChinaRegion())
|
||||
{
|
||||
|
@ -540,7 +541,7 @@ public class MWMActivity extends NvEventQueueActivity
|
|||
private void checkBuyProDialog()
|
||||
{
|
||||
if (!mApplication.isProVersion() &&
|
||||
(ConnectionState.getState(this) != ConnectionState.NOT_CONNECTED) &&
|
||||
(ConnectionState.isConnected(this)) &&
|
||||
mApplication.shouldShowDialog(MWMApplication.BUYPRO))
|
||||
{
|
||||
showDialogImpl(MWMApplication.BUYPRO, R.string.pro_version_available,
|
||||
|
@ -881,7 +882,7 @@ public class MWMActivity extends NvEventQueueActivity
|
|||
public void onCompassUpdated(long time, double magneticNorth, double trueNorth, double accuracy)
|
||||
{
|
||||
final double angles[] = {magneticNorth, trueNorth};
|
||||
getLocationService().correctCompassAngles(getWindowManager().getDefaultDisplay(), angles);
|
||||
LocationUtils.correctCompassAngles(getWindowManager().getDefaultDisplay(), angles);
|
||||
nativeCompassUpdated(time, angles[0], angles[1], accuracy);
|
||||
final double north = (angles[1] >= 0.0 ? angles[1] : angles[0]);
|
||||
|
||||
|
@ -889,6 +890,13 @@ public class MWMActivity extends NvEventQueueActivity
|
|||
mInfoView.updateAzimuth(north);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrivingHeadingUpdated(long time, double heading)
|
||||
{
|
||||
if (mInfoView.getState() != State.HIDDEN)
|
||||
mInfoView.updateAzimuth(heading);
|
||||
}
|
||||
|
||||
public void onCompassStatusChanged(int newStatus)
|
||||
{
|
||||
if (newStatus == 1)
|
||||
|
|
|
@ -39,7 +39,7 @@ import com.mapswithme.util.Utils;
|
|||
import com.mapswithme.util.statistics.Statistics;
|
||||
|
||||
|
||||
public class SearchActivity extends MapsWithMeBaseListActivity implements LocationService.Listener, OnClickListener
|
||||
public class SearchActivity extends MapsWithMeBaseListActivity implements LocationService.LocationListener, OnClickListener
|
||||
{
|
||||
public static final String EXTRA_QUERY = "search_query";
|
||||
/// @name These constants should be equal with
|
||||
|
@ -754,14 +754,6 @@ public class SearchActivity extends MapsWithMeBaseListActivity implements Locati
|
|||
getSearchAdapter().updateCategories();
|
||||
}
|
||||
|
||||
/*
|
||||
private void runSearch(int mode)
|
||||
{
|
||||
mSearchMode = mode;
|
||||
runSearch();
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onLocationUpdated(final Location l)
|
||||
{
|
||||
|
@ -777,33 +769,19 @@ public class SearchActivity extends MapsWithMeBaseListActivity implements Locati
|
|||
@Override
|
||||
public void onCompassUpdated(long time, double magneticNorth, double trueNorth, double accuracy)
|
||||
{
|
||||
/*
|
||||
if (doShowCategories())
|
||||
return;
|
||||
//
|
||||
}
|
||||
|
||||
// We don't want to update view too often, it is slow
|
||||
// and breaks click listeners
|
||||
if (System.currentTimeMillis() - mLastCompassUpdate < COMPASS_DELTA)
|
||||
return;
|
||||
else
|
||||
mLastCompassUpdate = System.currentTimeMillis();
|
||||
|
||||
final double north[] = { magneticNorth, trueNorth };
|
||||
mLocation.correctCompassAngles(getWindowManager().getDefaultDisplay(), north);
|
||||
final double ret = (north[1] >= 0.0 ? north[1] : north[0]);
|
||||
|
||||
// if difference is more than 1 degree
|
||||
if (mNorth == -1 || Math.abs(mNorth - ret) > 0.02)
|
||||
{
|
||||
mNorth = ret;
|
||||
updateDistanceAndAzimut();
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
public void onDrivingHeadingUpdated(long time, double heading)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationError(int errorCode)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
private boolean isCurrentResult(int id)
|
||||
|
|
|
@ -26,7 +26,7 @@ import java.util.Map;
|
|||
|
||||
|
||||
public class BookmarkListAdapter extends BaseAdapter
|
||||
implements LocationService.Listener
|
||||
implements LocationService.LocationListener
|
||||
{
|
||||
private final Activity mContext;
|
||||
private final BookmarkCategory mCategory;
|
||||
|
@ -159,9 +159,16 @@ public class BookmarkListAdapter extends BaseAdapter
|
|||
// We don't show any arrows for bookmarks any more.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrivingHeadingUpdated(long time, double heading)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationError(int errorCode)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
private class PinHolder
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.mapswithme.maps.location;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.hardware.GeomagneticField;
|
||||
import android.hardware.Sensor;
|
||||
|
@ -8,14 +7,9 @@ import android.hardware.SensorEvent;
|
|||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GooglePlayServicesClient;
|
||||
|
@ -24,7 +18,7 @@ import com.google.android.gms.location.LocationClient;
|
|||
import com.google.android.gms.location.LocationRequest;
|
||||
import com.mapswithme.maps.MWMApplication;
|
||||
import com.mapswithme.util.ConnectionState;
|
||||
import com.mapswithme.util.Utils;
|
||||
import com.mapswithme.util.LocationUtils;
|
||||
import com.mapswithme.util.log.Logger;
|
||||
import com.mapswithme.util.log.SimpleLogger;
|
||||
import com.mapswithme.util.statistics.Statistics;
|
||||
|
@ -36,7 +30,7 @@ import java.util.List;
|
|||
|
||||
|
||||
public class LocationService implements
|
||||
LocationListener, SensorEventListener, WifiLocationScanner.Listener,
|
||||
android.location.LocationListener, SensorEventListener, WifiLocationScanner.Listener,
|
||||
GooglePlayServicesClient.ConnectionCallbacks,
|
||||
GooglePlayServicesClient.OnConnectionFailedListener,
|
||||
com.google.android.gms.location.LocationListener
|
||||
|
@ -47,7 +41,6 @@ public class LocationService implements
|
|||
private static final double DEFAULT_SPEED_MPS = 5;
|
||||
private static final float DISTANCE_TO_RECREATE_MAGNETIC_FIELD_M = 1000;
|
||||
private static final float MIN_SPEED_CALC_DIRECTION_MPS = 1;
|
||||
private static final long LOCATION_EXPIRATION_TIME_MILLIS = 5 * 60 * 1000;
|
||||
private static final String GS_LOCATION_PROVIDER = "fused";
|
||||
|
||||
/// These constants should correspond to values defined in platform/location.hpp
|
||||
|
@ -56,53 +49,42 @@ public class LocationService implements
|
|||
public static final int ERROR_DENIED = 2;
|
||||
public static final int ERROR_GPS_OFF = 3;
|
||||
|
||||
public interface Listener
|
||||
public interface LocationListener
|
||||
{
|
||||
public void onLocationUpdated(final Location l);
|
||||
|
||||
public void onCompassUpdated(long time, double magneticNorth, double trueNorth, double accuracy);
|
||||
|
||||
public void onDrivingHeadingUpdated(long time, double heading);
|
||||
|
||||
public void onLocationError(int errorCode);
|
||||
}
|
||||
|
||||
private final HashSet<Listener> mObservers = new HashSet<Listener>(10);
|
||||
private final HashSet<LocationListener> mListeners = new HashSet<LocationListener>();
|
||||
|
||||
/// Last accepted location
|
||||
private Location mLastLocation = null;
|
||||
/// System timestamp for the last location
|
||||
private long mLastLocationTime;
|
||||
/// Current heading if we are moving (-1.0 otherwise)
|
||||
private double mDrivingHeading = -1.0;
|
||||
private boolean mIsGPSOff;
|
||||
|
||||
private WifiLocationScanner mWifiScanner = null;
|
||||
|
||||
private final SensorManager mSensorManager;
|
||||
private Sensor mAccelerometer = null;
|
||||
private Sensor mMagnetometer = null;
|
||||
/// To calculate true north for compass
|
||||
private GeomagneticField mMagneticField = null;
|
||||
private LocationProvider mLocationProvider;
|
||||
|
||||
private MWMApplication mApplication = null;
|
||||
|
||||
// Main location provider.
|
||||
private LocationProvider mLocationProvider;
|
||||
|
||||
private double mLastNorth;
|
||||
private static final double NOISE_THRESHOLD = 3;
|
||||
|
||||
private void createLocationProvider()
|
||||
{
|
||||
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(mApplication) == ConnectionResult.SUCCESS)
|
||||
{
|
||||
mLocationProvider = new GoogleFusedLocationProvider();
|
||||
mLogger.d("Using Google Provider");
|
||||
}
|
||||
else
|
||||
{
|
||||
mLocationProvider = new AndroidNativeLocationProvider();
|
||||
mLogger.d("Using native location provider");
|
||||
}
|
||||
}
|
||||
private float[] mGravity = null;
|
||||
private float[] mGeomagnetic = null;
|
||||
private final float[] mR = new float[9];
|
||||
private final float[] mI = new float[9];
|
||||
private final float[] mOrientation = new float[3];
|
||||
|
||||
public LocationService(MWMApplication application)
|
||||
{
|
||||
|
@ -112,7 +94,6 @@ public class LocationService implements
|
|||
mLocationProvider.setUp();
|
||||
|
||||
mSensorManager = (SensorManager) mApplication.getSystemService(Context.SENSOR_SERVICE);
|
||||
|
||||
if (mSensorManager != null)
|
||||
{
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
|
@ -120,52 +101,58 @@ public class LocationService implements
|
|||
}
|
||||
}
|
||||
|
||||
private void createLocationProvider()
|
||||
{
|
||||
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(mApplication) == ConnectionResult.SUCCESS)
|
||||
mLocationProvider = new GoogleFusedLocationProvider();
|
||||
else
|
||||
mLocationProvider = new AndroidNativeLocationProvider();
|
||||
}
|
||||
|
||||
public Location getLastKnown() { return mLastLocation; }
|
||||
|
||||
private void notifyLocationUpdated(final Location l)
|
||||
{
|
||||
final Iterator<Listener> it = mObservers.iterator();
|
||||
final Iterator<LocationListener> it = mListeners.iterator();
|
||||
while (it.hasNext())
|
||||
it.next().onLocationUpdated(l);
|
||||
}
|
||||
|
||||
private void notifyCompassUpdated(long time, double magneticNorth, double trueNorth, double accuracy)
|
||||
{
|
||||
final Iterator<Listener> it = mObservers.iterator();
|
||||
final Iterator<LocationListener> it = mListeners.iterator();
|
||||
while (it.hasNext())
|
||||
it.next().onCompassUpdated(time, magneticNorth, trueNorth, accuracy);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private static boolean isNotExpired(Location l, long t)
|
||||
private void notifyDrivingHeadingUpdated(long time, double heading)
|
||||
{
|
||||
long timeDiff;
|
||||
if (Utils.apiEqualOrGreaterThan(Build.VERSION_CODES.JELLY_BEAN_MR1))
|
||||
timeDiff = (SystemClock.elapsedRealtimeNanos() - l.getElapsedRealtimeNanos()) / 1000000;
|
||||
else
|
||||
timeDiff = System.currentTimeMillis() - t;
|
||||
return (timeDiff <= LOCATION_EXPIRATION_TIME_MILLIS);
|
||||
final Iterator<LocationListener> it = mListeners.iterator();
|
||||
while (it.hasNext())
|
||||
it.next().onDrivingHeadingUpdated(time, heading);
|
||||
}
|
||||
|
||||
public void startUpdate(Listener observer)
|
||||
public void startUpdate(LocationListener listener)
|
||||
{
|
||||
mLogger.d("Start update for listener: ", observer);
|
||||
mObservers.add(observer);
|
||||
mListeners.add(listener);
|
||||
mLocationProvider.startUpdates(listener);
|
||||
}
|
||||
|
||||
mLocationProvider.startUpdates(observer);
|
||||
public void stopUpdate(LocationListener listener)
|
||||
{
|
||||
mListeners.remove(listener);
|
||||
if (mListeners.size() == 0)
|
||||
mLocationProvider.stopUpdates();
|
||||
}
|
||||
|
||||
private void startWifiLocationUpdate()
|
||||
{
|
||||
final boolean isWifiEnabled = ((WifiManager) mApplication.getSystemService(Context.WIFI_SERVICE)).isWifiEnabled();
|
||||
if (isWifiEnabled &&
|
||||
Statistics.INSTANCE.isStatisticsEnabled(mApplication) &&
|
||||
ConnectionState.isConnected(mApplication))
|
||||
if (Statistics.INSTANCE.isStatisticsEnabled(mApplication) &&
|
||||
ConnectionState.isWifiConnected(mApplication))
|
||||
{
|
||||
if (mWifiScanner == null)
|
||||
mWifiScanner = new WifiLocationScanner();
|
||||
|
||||
mLogger.d("Invoke WiFi scanner.");
|
||||
mWifiScanner.startScan(mApplication, this);
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +168,6 @@ public class LocationService implements
|
|||
{
|
||||
if (mSensorManager != null)
|
||||
{
|
||||
// How often compass is updated (may be SensorManager.SENSOR_DELAY_UI)
|
||||
final int COMPASS_REFRESH_MKS = SensorManager.SENSOR_DELAY_NORMAL;
|
||||
|
||||
if (mAccelerometer != null)
|
||||
|
@ -191,52 +177,32 @@ public class LocationService implements
|
|||
}
|
||||
}
|
||||
|
||||
public void stopUpdate(Listener observer)
|
||||
private void updateDrivingHeading(Location l)
|
||||
{
|
||||
mLogger.d("Stop update for listener: ", observer);
|
||||
|
||||
mObservers.remove(observer);
|
||||
|
||||
// Stop only if no more observers are subscribed
|
||||
if (mObservers.size() == 0)
|
||||
mLocationProvider.stopUpdates();
|
||||
}
|
||||
|
||||
private void calcDirection(Location l)
|
||||
{
|
||||
// Try to calculate direction if we are moving
|
||||
if (l.getSpeed() >= MIN_SPEED_CALC_DIRECTION_MPS && l.hasBearing())
|
||||
mDrivingHeading = bearingToHeading(l.getBearing());
|
||||
mDrivingHeading = LocationUtils.bearingToHeading(l.getBearing());
|
||||
else
|
||||
mDrivingHeading = -1.0;
|
||||
}
|
||||
|
||||
private void emitLocation(Location l)
|
||||
{
|
||||
mLogger.d("Location accepted: ", l);
|
||||
|
||||
mLastLocation = l;
|
||||
mLastLocationTime = System.currentTimeMillis();
|
||||
|
||||
notifyLocationUpdated(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location l)
|
||||
{
|
||||
mLogger.d("Location changed: ", l);
|
||||
|
||||
// Completely ignore locations without lat and lon
|
||||
if (l.getAccuracy() <= 0.0)
|
||||
return;
|
||||
|
||||
if (mLocationProvider.isLocationBetter(l))
|
||||
if (mLocationProvider.isLocationBetterThanCurrent(l))
|
||||
{
|
||||
mLogger.d("Location accepted: " + l);
|
||||
updateDrivingHeading(l);
|
||||
|
||||
calcDirection(l);
|
||||
|
||||
// Used for more precise compass updates
|
||||
if (mSensorManager != null)
|
||||
{
|
||||
// Recreate magneticField if location has changed significantly
|
||||
|
@ -252,27 +218,10 @@ public class LocationService implements
|
|||
}
|
||||
}
|
||||
|
||||
private native float[] nativeUpdateCompassSensor(int ind, float[] arr);
|
||||
|
||||
private float[] updateCompassSensor(int ind, float[] arr)
|
||||
{
|
||||
final float[] ret = nativeUpdateCompassSensor(ind, arr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private float[] mGravity = null;
|
||||
private float[] mGeomagnetic = null;
|
||||
private final float mR[] = new float[9];
|
||||
private final float mI[] = new float[9];
|
||||
private final float[] mOrientation = new float[3];
|
||||
|
||||
private boolean mIsGPSOff;
|
||||
|
||||
private void emitCompassResults(long time, double north, double trueNorth, double offset)
|
||||
{
|
||||
if (mDrivingHeading >= 0.0)
|
||||
notifyCompassUpdated(time, mDrivingHeading, mDrivingHeading, 0.0);
|
||||
notifyDrivingHeadingUpdated(time, mDrivingHeading);
|
||||
else
|
||||
{
|
||||
if (Math.abs(Math.toDegrees(north - mLastNorth)) < NOISE_THRESHOLD)
|
||||
|
@ -291,16 +240,15 @@ public class LocationService implements
|
|||
@Override
|
||||
public void onSensorChanged(SensorEvent event)
|
||||
{
|
||||
// Get the magnetic north (orientation contains azimut, pitch and roll).
|
||||
boolean hasOrientation = false;
|
||||
|
||||
switch (event.sensor.getType())
|
||||
{
|
||||
case Sensor.TYPE_ACCELEROMETER:
|
||||
mGravity = updateCompassSensor(0, event.values);
|
||||
mGravity = nativeUpdateCompassSensor(0, event.values);
|
||||
break;
|
||||
case Sensor.TYPE_MAGNETIC_FIELD:
|
||||
mGeomagnetic = updateCompassSensor(1, event.values);
|
||||
mGeomagnetic = nativeUpdateCompassSensor(1, event.values);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -315,7 +263,7 @@ public class LocationService implements
|
|||
|
||||
if (hasOrientation)
|
||||
{
|
||||
final double magneticHeading = correctAngle(mOrientation[0], 0.0);
|
||||
final double magneticHeading = LocationUtils.correctAngle(mOrientation[0], 0.0);
|
||||
|
||||
if (mMagneticField == null)
|
||||
{
|
||||
|
@ -325,67 +273,15 @@ public class LocationService implements
|
|||
else
|
||||
{
|
||||
// positive 'offset' means the magnetic field is rotated east that much from true north
|
||||
final double offset = mMagneticField.getDeclination() * Math.PI / 180.0;
|
||||
final double trueHeading = correctAngle(magneticHeading, offset);
|
||||
final double offset = Math.toRadians(mMagneticField.getDeclination());
|
||||
final double trueHeading = LocationUtils.correctAngle(magneticHeading, offset);
|
||||
|
||||
emitCompassResults(event.timestamp, magneticHeading, trueHeading, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @name Angle correct functions.
|
||||
//@{
|
||||
@SuppressWarnings("deprecation")
|
||||
public void correctCompassAngles(Display display, double angles[])
|
||||
{
|
||||
// Do not do any corrections if heading is from GPS service.
|
||||
if (mDrivingHeading >= 0.0)
|
||||
return;
|
||||
|
||||
// Correct compass angles due to orientation.
|
||||
double correction = 0;
|
||||
switch (display.getOrientation())
|
||||
{
|
||||
case Surface.ROTATION_90:
|
||||
correction = Math.PI / 2.0;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
correction = Math.PI;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
correction = (3.0 * Math.PI / 2.0);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < angles.length; ++i)
|
||||
{
|
||||
if (angles[i] >= 0.0)
|
||||
{
|
||||
// negative values (like -1.0) should remain negative (indicates that no direction available)
|
||||
angles[i] = correctAngle(angles[i], correction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static private double correctAngle(double angle, double correction)
|
||||
{
|
||||
angle += correction;
|
||||
|
||||
final double twoPI = 2.0 * Math.PI;
|
||||
angle = angle % twoPI;
|
||||
|
||||
// normalize angle into [0, 2PI]
|
||||
if (angle < 0.0)
|
||||
angle += twoPI;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
static private double bearingToHeading(double bearing)
|
||||
{
|
||||
return correctAngle(0.0, bearing * Math.PI / 180.0);
|
||||
}
|
||||
//@}
|
||||
private native float[] nativeUpdateCompassSensor(int ind, float[] arr);
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy)
|
||||
|
@ -393,22 +289,13 @@ public class LocationService implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider)
|
||||
{
|
||||
mLogger.d("Disabled location provider: ", provider);
|
||||
}
|
||||
public void onProviderDisabled(String provider) { }
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider)
|
||||
{
|
||||
mLogger.d("Enabled location provider: ", provider);
|
||||
}
|
||||
public void onProviderEnabled(String provider) { }
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras)
|
||||
{
|
||||
mLogger.d("Status changed for location provider: ", provider, status);
|
||||
}
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) { }
|
||||
|
||||
@Override
|
||||
public void onWifiLocationUpdated(Location l)
|
||||
|
@ -423,30 +310,22 @@ public class LocationService implements
|
|||
return mLocationProvider.getLastGPSLocation();
|
||||
}
|
||||
|
||||
|
||||
// Location providers: Android native or Google Play Services
|
||||
private abstract class LocationProvider
|
||||
{
|
||||
protected LocationService mHost;
|
||||
protected boolean mIsActive;
|
||||
protected static final long LOCATION_UPDATE_INTERVAL = 500;
|
||||
|
||||
protected LocationProvider()
|
||||
{
|
||||
mIsActive = false;
|
||||
// I don't like Something.this syntax
|
||||
mHost = LocationService.this;
|
||||
}
|
||||
protected boolean mIsActive;
|
||||
|
||||
protected abstract void setUp();
|
||||
|
||||
protected abstract void startUpdates(Listener l);
|
||||
protected abstract void startUpdates(LocationListener l);
|
||||
|
||||
protected void stopUpdates()
|
||||
{
|
||||
stopWifiLocationUpdate();
|
||||
|
||||
if (mSensorManager != null)
|
||||
mSensorManager.unregisterListener(mHost);
|
||||
mSensorManager.unregisterListener(LocationService.this);
|
||||
|
||||
// Reset current parameters to force initialize in the next startUpdate
|
||||
mMagneticField = null;
|
||||
|
@ -456,7 +335,7 @@ public class LocationService implements
|
|||
|
||||
protected abstract Location getLastGPSLocation();
|
||||
|
||||
protected boolean isLocationBetter(Location l)
|
||||
protected boolean isLocationBetterThanCurrent(Location l)
|
||||
{
|
||||
if (l == null)
|
||||
return false;
|
||||
|
@ -464,7 +343,7 @@ public class LocationService implements
|
|||
return true;
|
||||
|
||||
final double s = Math.max(DEFAULT_SPEED_MPS, (l.getSpeed() + mLastLocation.getSpeed()) / 2.0);
|
||||
return (l.getAccuracy() < (mLastLocation.getAccuracy() + s * getLocationTimeDiffS(l)));
|
||||
return (l.getAccuracy() < (mLastLocation.getAccuracy() + s * getDiffWithLastLocation(l)));
|
||||
}
|
||||
|
||||
private boolean isSameLocationProvider(String p1, String p2)
|
||||
|
@ -474,10 +353,13 @@ public class LocationService implements
|
|||
return p1.equals(p2);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private double getLocationTimeDiffS(Location l)
|
||||
/**
|
||||
* @param l new location
|
||||
* @return diff with mLastLocation in seconds
|
||||
*/
|
||||
private double getDiffWithLastLocation(Location l)
|
||||
{
|
||||
if (Utils.apiEqualOrGreaterThan(Build.VERSION_CODES.JELLY_BEAN_MR1))
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
return (l.getElapsedRealtimeNanos() - mLastLocation.getElapsedRealtimeNanos()) * 1.0E-9;
|
||||
else
|
||||
{
|
||||
|
@ -498,18 +380,16 @@ public class LocationService implements
|
|||
|
||||
private class AndroidNativeLocationProvider extends LocationProvider
|
||||
{
|
||||
// Meat
|
||||
private volatile LocationManager mLocationManager;
|
||||
|
||||
@Override
|
||||
protected void startUpdates(Listener listener)
|
||||
protected void startUpdates(LocationListener listener)
|
||||
{
|
||||
if (!mIsActive)
|
||||
{
|
||||
mIsGPSOff = false;
|
||||
|
||||
final List<String> providers = getFilteredProviders();
|
||||
mLogger.d("Enabled providers count = ", providers.size());
|
||||
|
||||
startWifiLocationUpdate();
|
||||
|
||||
|
@ -520,34 +400,18 @@ public class LocationService implements
|
|||
mIsActive = true;
|
||||
|
||||
for (final String provider : providers)
|
||||
{
|
||||
mLogger.d("Connected to provider = ", provider);
|
||||
|
||||
// Half of a second is more than enough, I think ...
|
||||
mLocationManager.requestLocationUpdates(provider, 500, 0, mHost);
|
||||
}
|
||||
mLocationManager.requestLocationUpdates(provider, LOCATION_UPDATE_INTERVAL, 0, LocationService.this);
|
||||
|
||||
registerSensorListeners();
|
||||
|
||||
// Choose best location from available
|
||||
final Location l = getBestLastLocation(providers);
|
||||
mLogger.d("Last location: ", l);
|
||||
|
||||
if (isLocationBetter(l))
|
||||
{
|
||||
// get last better location
|
||||
final Location l = findBestLocation(providers);
|
||||
if (isLocationBetterThanCurrent(l))
|
||||
emitLocation(l);
|
||||
}
|
||||
else if (mLastLocation != null && isNotExpired(mLastLocation, mLastLocationTime))
|
||||
{
|
||||
// notify UI about last valid location
|
||||
notifyLocationUpdated(mLastLocation);
|
||||
}
|
||||
else if (mLastLocation != null && !LocationUtils.isExpired(mLastLocation, mLastLocationTime))
|
||||
notifyLocationUpdated(mLastLocation); // notify UI about last valid location
|
||||
else
|
||||
{
|
||||
// forget about old location
|
||||
mLastLocation = null;
|
||||
}
|
||||
mLastLocation = null; // forget about old location
|
||||
}
|
||||
|
||||
if (mIsGPSOff)
|
||||
|
@ -558,7 +422,7 @@ public class LocationService implements
|
|||
@Override
|
||||
protected void stopUpdates()
|
||||
{
|
||||
mLocationManager.removeUpdates(mHost);
|
||||
mLocationManager.removeUpdates(LocationService.this);
|
||||
super.stopUpdates();
|
||||
}
|
||||
|
||||
|
@ -568,14 +432,13 @@ public class LocationService implements
|
|||
mLocationManager = (LocationManager) mApplication.getSystemService(Context.LOCATION_SERVICE);
|
||||
}
|
||||
|
||||
// Trash
|
||||
private Location getBestLastLocation(List<String> providers)
|
||||
private Location findBestLocation(List<String> providers)
|
||||
{
|
||||
Location res = null;
|
||||
for (final String pr : providers)
|
||||
{
|
||||
final Location l = mLocationManager.getLastKnownLocation(pr);
|
||||
if (l != null && isNotExpired(l, l.getTime()))
|
||||
if (l != null && !LocationUtils.isExpired(l, l.getTime()))
|
||||
{
|
||||
if (res == null || res.getAccuracy() > l.getAccuracy())
|
||||
res = l;
|
||||
|
@ -601,15 +464,10 @@ public class LocationService implements
|
|||
continue;
|
||||
}
|
||||
|
||||
if (Utils.apiLowerThan(11) &&
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB &&
|
||||
LocationManager.NETWORK_PROVIDER.equals(prov) &&
|
||||
!ConnectionState.isConnected(mApplication))
|
||||
{
|
||||
// Do not use WiFi location provider.
|
||||
// It returns very old last saved locations with the current time stamp.
|
||||
mLogger.d("Disabled network location as a device isn't online.");
|
||||
continue;
|
||||
}
|
||||
|
||||
acceptedProviders.add(prov);
|
||||
}
|
||||
|
@ -632,26 +490,22 @@ public class LocationService implements
|
|||
@Override
|
||||
protected void setUp()
|
||||
{
|
||||
mLocationClient = new LocationClient(mApplication, mHost, mHost);
|
||||
mLocationClient = new LocationClient(mApplication, LocationService.this, LocationService.this);
|
||||
mLocationClient.connect();
|
||||
|
||||
mLocationRequest = LocationRequest.create();
|
||||
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
|
||||
mLocationRequest.setInterval(500);
|
||||
mLocationRequest.setFastestInterval(250);
|
||||
|
||||
mLogger.d("SetUp for GP provider.");
|
||||
mLocationRequest.setInterval(LOCATION_UPDATE_INTERVAL);
|
||||
mLocationRequest.setFastestInterval(LOCATION_UPDATE_INTERVAL / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUpdates(Listener listener)
|
||||
protected void startUpdates(LocationListener listener)
|
||||
{
|
||||
if (!mLocationClient.isConnected())
|
||||
{
|
||||
mLogger.e("LocationClient is disconnected");
|
||||
// Connection is asynchronous process
|
||||
// We need to be connected before call LocationClient.requestLocationUpdates()
|
||||
|
||||
if (!mLocationClient.isConnecting())
|
||||
mLocationClient.connect();
|
||||
|
||||
|
@ -660,12 +514,9 @@ public class LocationService implements
|
|||
|
||||
if (!mIsActive)
|
||||
{
|
||||
mLocationClient.requestLocationUpdates(mLocationRequest, mHost);
|
||||
mLocationClient.requestLocationUpdates(mLocationRequest, LocationService.this);
|
||||
|
||||
// Sensors
|
||||
registerSensorListeners();
|
||||
|
||||
// WiFi
|
||||
startWifiLocationUpdate();
|
||||
|
||||
final Location l = mLocationClient.getLastLocation();
|
||||
|
@ -680,13 +531,13 @@ public class LocationService implements
|
|||
protected void stopUpdates()
|
||||
{
|
||||
if (mLocationClient.isConnected())
|
||||
mLocationClient.removeLocationUpdates(mHost);
|
||||
mLocationClient.removeLocationUpdates(LocationService.this);
|
||||
|
||||
super.stopUpdates();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isLocationBetter(Location l)
|
||||
protected boolean isLocationBetterThanCurrent(Location l)
|
||||
{
|
||||
if (l == null)
|
||||
return false;
|
||||
|
@ -699,38 +550,22 @@ public class LocationService implements
|
|||
if (GS_LOCATION_PROVIDER.equalsIgnoreCase(mLastLocation.getProvider()))
|
||||
return false;
|
||||
|
||||
return super.isLocationBetter(l);
|
||||
return super.isLocationBetterThanCurrent(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Location getLastGPSLocation()
|
||||
{
|
||||
// there is no possibility to return precise provider
|
||||
// using LocationClient. Everything is 'fused'
|
||||
return mLocationClient.getLastLocation();
|
||||
}
|
||||
|
||||
// End of inner class GoogleFusedLP
|
||||
}
|
||||
|
||||
|
||||
// Google Play callbacks
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult arg0)
|
||||
{
|
||||
mLogger.d("onConnectionFailed " + arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected(Bundle arg0)
|
||||
{
|
||||
mLogger.d("onConnected " + arg0);
|
||||
}
|
||||
public void onConnectionFailed(ConnectionResult connectionResult) { }
|
||||
|
||||
@Override
|
||||
public void onDisconnected()
|
||||
{
|
||||
mLogger.d("onDisconnected");
|
||||
}
|
||||
public void onConnected(Bundle arg0) { }
|
||||
|
||||
@Override
|
||||
public void onDisconnected() { }
|
||||
}
|
||||
|
|
|
@ -452,7 +452,7 @@ public class MapInfoView extends LinearLayout implements View.OnClickListener
|
|||
mDistanceText = (TextView) mGeoLayout.findViewById(R.id.info_box_geo_distance);
|
||||
mAvDirection = (ArrowView) mGeoLayout.findViewById(R.id.av_direction);
|
||||
mAvDirection.setDrawCircle(true);
|
||||
mAvDirection.setVisibility(View.GONE); // should be hidden until first compas update
|
||||
mAvDirection.setVisibility(View.GONE); // should be hidden until first compass update
|
||||
mTvCoords = (TextView) mGeoLayout.findViewById(R.id.info_box_geo_location);
|
||||
mTvCoords.setOnClickListener(this);
|
||||
|
||||
|
@ -559,14 +559,14 @@ public class MapInfoView extends LinearLayout implements View.OnClickListener
|
|||
private void fillPlacePagePoi(MapObject poi)
|
||||
{
|
||||
mPlacePageContainer.removeAllViews();
|
||||
final View poiView = mInflater.inflate(R.layout.info_box_poi, null);
|
||||
final View poiView = mInflater.inflate(R.layout.info_box_poi, this, false);
|
||||
mPlacePageContainer.addView(poiView);
|
||||
}
|
||||
|
||||
private void fillPlacePageBookmark(final Bookmark bmk)
|
||||
{
|
||||
mPlacePageContainer.removeAllViews();
|
||||
final View bmkView = mInflater.inflate(R.layout.info_box_bookmark, null);
|
||||
final View bmkView = mInflater.inflate(R.layout.info_box_bookmark, this, false);
|
||||
bmkView.setOnClickListener(this);
|
||||
|
||||
// Description of BMK
|
||||
|
@ -593,14 +593,14 @@ public class MapInfoView extends LinearLayout implements View.OnClickListener
|
|||
private void fillPlacePageLayer(SearchResult sr)
|
||||
{
|
||||
mPlacePageContainer.removeAllViews();
|
||||
final View addLayerView = mInflater.inflate(R.layout.info_box_additional_layer, null);
|
||||
final View addLayerView = mInflater.inflate(R.layout.info_box_additional_layer, this, false);
|
||||
mPlacePageContainer.addView(addLayerView);
|
||||
}
|
||||
|
||||
private void fillPlacePageApi(MapObject mo)
|
||||
{
|
||||
mPlacePageContainer.removeAllViews();
|
||||
final View apiView = mInflater.inflate(R.layout.info_box_api, null);
|
||||
final View apiView = mInflater.inflate(R.layout.info_box_api, this, false);
|
||||
mPlacePageContainer.addView(apiView);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,28 +10,28 @@ public class ConnectionState
|
|||
public static final int CONNECTED_BY_3G = 1;
|
||||
public static final int CONNECTED_BY_WIFI = 2;
|
||||
public static final int CONNECTED_BY_WIFI_AND_3G = CONNECTED_BY_3G & CONNECTED_BY_WIFI;
|
||||
private static final String TYPE_WIFI = "WIFI";
|
||||
private static final String TYPE_MOBILE = "MOBILE";
|
||||
|
||||
public static int getState(Context c)
|
||||
private static int getState(Context c)
|
||||
{
|
||||
boolean haveConnectedWifi = false;
|
||||
boolean haveConnectedMobile = false;
|
||||
boolean isWifiConnected = false;
|
||||
boolean isMobileConnected = false;
|
||||
|
||||
ConnectivityManager cm = (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo[] netInfo = cm.getAllNetworkInfo();
|
||||
for (NetworkInfo ni : netInfo)
|
||||
{
|
||||
if (ni.getTypeName().equalsIgnoreCase("WIFI"))
|
||||
if (ni.isConnected())
|
||||
haveConnectedWifi = true;
|
||||
if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
|
||||
if (ni.isConnected())
|
||||
haveConnectedMobile = true;
|
||||
if (ni.getTypeName().equalsIgnoreCase(TYPE_WIFI) && ni.isConnected())
|
||||
isWifiConnected = true;
|
||||
if (ni.getTypeName().equalsIgnoreCase(TYPE_MOBILE) && ni.isConnected())
|
||||
isMobileConnected = true;
|
||||
}
|
||||
if (haveConnectedWifi && haveConnectedMobile)
|
||||
if (isWifiConnected && isMobileConnected)
|
||||
return CONNECTED_BY_WIFI_AND_3G;
|
||||
else if (haveConnectedMobile)
|
||||
else if (isMobileConnected)
|
||||
return CONNECTED_BY_3G;
|
||||
else if (haveConnectedWifi)
|
||||
else if (isWifiConnected)
|
||||
return CONNECTED_BY_WIFI;
|
||||
|
||||
return NOT_CONNECTED;
|
||||
|
@ -49,6 +49,6 @@ public class ConnectionState
|
|||
|
||||
public static boolean isConnected(Context c)
|
||||
{
|
||||
return !(getState(c) == NOT_CONNECTED);
|
||||
return getState(c) != NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
|
73
android/src/com/mapswithme/util/LocationUtils.java
Normal file
73
android/src/com/mapswithme/util/LocationUtils.java
Normal file
|
@ -0,0 +1,73 @@
|
|||
package com.mapswithme.util;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
|
||||
public class LocationUtils
|
||||
{
|
||||
private LocationUtils() {}
|
||||
|
||||
private static final long LOCATION_EXPIRATION_TIME_MILLIS = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
/**
|
||||
* Correct compass angles due to display orientation.
|
||||
*/
|
||||
public static void correctCompassAngles(Display display, double angles[])
|
||||
{
|
||||
double correction = 0;
|
||||
switch (display.getOrientation())
|
||||
{
|
||||
case Surface.ROTATION_90:
|
||||
correction = Math.PI / 2.0;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
correction = Math.PI;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
correction = (3.0 * Math.PI / 2.0);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < angles.length; ++i)
|
||||
{
|
||||
if (angles[i] >= 0.0)
|
||||
{
|
||||
// negative values (like -1.0) should remain negative (indicates that no direction available)
|
||||
angles[i] = correctAngle(angles[i], correction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static double correctAngle(double angle, double correction)
|
||||
{
|
||||
angle += correction;
|
||||
|
||||
final double twoPI = 2.0 * Math.PI;
|
||||
angle = angle % twoPI;
|
||||
|
||||
// normalize angle into [0, 2PI]
|
||||
if (angle < 0.0)
|
||||
angle += twoPI;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
public static double bearingToHeading(double bearing)
|
||||
{
|
||||
return correctAngle(0.0, Math.toRadians(bearing));
|
||||
}
|
||||
|
||||
public static boolean isExpired(Location l, long t)
|
||||
{
|
||||
long timeDiff;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
timeDiff = (SystemClock.elapsedRealtimeNanos() - l.getElapsedRealtimeNanos()) / 1000000;
|
||||
else
|
||||
timeDiff = System.currentTimeMillis() - t;
|
||||
return (timeDiff > LOCATION_EXPIRATION_TIME_MILLIS);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue