diff options
author | vng <viktor.govako@gmail.com> | 2013-09-18 19:51:37 +0400 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 02:02:09 +0300 |
commit | db29320ae8bc371b50d923bed6b1286dfba5d0a7 (patch) | |
tree | 22032c77744c01d9a69af8a0dd3d2cc26e3a66a3 | |
parent | 40c4e677ef0c7154edee3a005c61cf0b6fee4cf9 (diff) |
[android] Use Location.getElapsedRealtimeNanos() for API level >= 17.
4 files changed, 121 insertions, 78 deletions
diff --git a/android/src/com/mapswithme/maps/location/LocationService.java b/android/src/com/mapswithme/maps/location/LocationService.java index 75500d5793..d615d11b69 100644 --- a/android/src/com/mapswithme/maps/location/LocationService.java +++ b/android/src/com/mapswithme/maps/location/LocationService.java @@ -16,7 +16,6 @@ import android.location.LocationListener; import android.location.LocationManager; import android.net.wifi.WifiManager; import android.os.Bundle; -import android.util.Log; import android.view.Display; import android.view.Surface; @@ -24,14 +23,12 @@ import com.mapswithme.maps.MWMApplication; import com.mapswithme.util.ConnectionState; import com.mapswithme.util.LocationUtils; import com.mapswithme.util.log.Logger; -import com.mapswithme.util.log.StubLogger; +import com.mapswithme.util.log.SimpleLogger; public class LocationService implements LocationListener, SensorEventListener, WifiLocation.Listener { - private static final String TAG = "LocationService"; - - private Logger mLogger = StubLogger.get();//SimpleLogger.get(this.toString()); + private Logger mLogger = SimpleLogger.get(this.toString()); /// These constants should correspond to values defined in platform/location.hpp /// Leave 0-value as no any error. @@ -69,7 +66,6 @@ public class LocationService implements LocationListener, SensorEventListener, W public LocationService(MWMApplication application) { - mLogger.d("Creating locserivice"); mApplication = application; mLocationManager = (LocationManager) mApplication.getSystemService(Context.LOCATION_SERVICE); @@ -121,7 +117,7 @@ public class LocationService implements LocationListener, SensorEventListener, W public void startUpdate(Listener observer) { - mLogger.d("Start update", observer); + mLogger.d("Start update for listener: ", observer); mObservers.add(observer); @@ -130,11 +126,11 @@ public class LocationService implements LocationListener, SensorEventListener, W mIsGPSOff = false; List<String> providers = getFilteredProviders(); - Log.d(TAG, "Enabled providers count = " + providers.size()); + mLogger.d("Enabled providers count = ", providers.size()); startWifiLocationUpdate(); - if ((providers.size() == 0) && (mWifiScanner == null)) + if (providers.size() == 0 && mWifiScanner == null) observer.onLocationError(ERROR_DENIED); else { @@ -142,7 +138,8 @@ public class LocationService implements LocationListener, SensorEventListener, W for (String provider : providers) { - Log.d(TAG, "Connected to provider = " + provider); + mLogger.d("Connected to provider = ", provider); + // Half of a second is more than enough, I think ... mLocationManager.requestLocationUpdates(provider, 500, 0, this); } @@ -155,7 +152,9 @@ public class LocationService implements LocationListener, SensorEventListener, W if (notExpiredLocations.size() > 0) { final Location newestLocation = LocationUtils.getNewestLocation(notExpiredLocations); + mLogger.d("Last newest location: ", newestLocation); final Location mostAccurateLocation = LocationUtils.getMostAccurateLocation(notExpiredLocations); + mLogger.d("Last accurate location: ", mostAccurateLocation); if (LocationUtils.isFirstOneBetterLocation(newestLocation, mostAccurateLocation)) lastKnownLocation = newestLocation; @@ -163,19 +162,19 @@ public class LocationService implements LocationListener, SensorEventListener, W lastKnownLocation = mostAccurateLocation; } - if (mLastLocation != null && LocationUtils.isFirstOneBetterLocation(mLastLocation, lastKnownLocation)) + if (LocationUtils.isNotExpired(mLastLocation) && + LocationUtils.isFirstOneBetterLocation(mLastLocation, lastKnownLocation)) + { lastKnownLocation = mLastLocation; - // ### location chosen + } // Pass last known location only in the end of all registerListener // in case, when we want to disconnect in listener. if (lastKnownLocation != null) { - //mark location with current time - lastKnownLocation.setTime(System.currentTimeMillis()); + LocationUtils.hackLocationTime(lastKnownLocation); emitLocation(lastKnownLocation); } - } if (mIsGPSOff) @@ -236,22 +235,23 @@ public class LocationService implements LocationListener, SensorEventListener, W public void stopUpdate(Listener observer) { - mLogger.d("Stop update", observer); + mLogger.d("Stop update for listener: ", observer); mObservers.remove(observer); - stopWifiLocationUpdate(); - // Stop only if no more observers are subscribed if (mObservers.size() == 0) { + stopWifiLocationUpdate(); + mLocationManager.removeUpdates(this); + if (mSensorManager != null) mSensorManager.unregisterListener(this); //mLastLocation = null; - // reset current parameters to force initialize in the next startUpdate + // Reset current parameters to force initialize in the next startUpdate mMagneticField = null; mDrivingHeading = -1.0; mIsActive = false; @@ -259,18 +259,15 @@ public class LocationService implements LocationListener, SensorEventListener, W } private static final long MAXTIME_CALC_DIRECTIONS = 1000 * 10; - private static final long LOCATION_EXPIRATION_TIME = 5 * 60 * 1000; /* 5 minutes*/ private List<Location> getAllNotExpiredLocations(List<String> providers) { List<Location> locations = new ArrayList<Location>(providers.size()); - - for (String prov : providers) + for (String pr : providers) { - Location loc = mLocationManager.getLastKnownLocation(prov); - final long timeNow = System.currentTimeMillis(); - if (loc != null && ((timeNow - loc.getTime()) <= LOCATION_EXPIRATION_TIME)) - locations.add(loc); + final Location l = mLocationManager.getLastKnownLocation(pr); + if (LocationUtils.isNotExpired(l)) + locations.add(l); } return locations; @@ -293,6 +290,8 @@ public class LocationService implements LocationListener, SensorEventListener, W private void emitLocation(Location l) { + mLogger.d("Location accepted: ", l); + mLastLocation = l; notifyLocationUpdated(l); } @@ -303,13 +302,13 @@ public class LocationService implements LocationListener, SensorEventListener, W @Override public void onLocationChanged(Location l) { - mLogger.d("Location changed", l); + mLogger.d("Location changed: ", l); + // Completely ignore locations without lat and lon - if (l.getAccuracy() <= 0.) + if (l.getAccuracy() <= 0.0) return; - // hack to avoid time zone troubles - l.setTime(System.currentTimeMillis()); + LocationUtils.hackLocationTime(l); if (LocationUtils.isFirstOneBetterLocation(l, mLastLocation)) { final long timeNow = System.currentTimeMillis(); @@ -471,25 +470,24 @@ public class LocationService implements LocationListener, SensorEventListener, W @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { - //Log.d(TAG, "Compass accuracy changed to " + String.valueOf(accuracy)); } @Override public void onProviderDisabled(String provider) { - Log.d(TAG, "Disabled location provider: " + provider); + mLogger.d("Disabled location provider: ", provider); } @Override public void onProviderEnabled(String provider) { - Log.d(TAG, "Enabled location provider: " + provider); + mLogger.d("Enabled location provider: ", provider); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { - Log.d(TAG, String.format("Status changed for location provider: %s to %d", provider, status)); + mLogger.d("Status changed for location provider: ", provider, status); } @Override diff --git a/android/src/com/mapswithme/maps/location/WifiLocation.java b/android/src/com/mapswithme/maps/location/WifiLocation.java index e261a63a8e..fffe27b2ca 100644 --- a/android/src/com/mapswithme/maps/location/WifiLocation.java +++ b/android/src/com/mapswithme/maps/location/WifiLocation.java @@ -1,6 +1,4 @@ package com.mapswithme.maps.location; -import com.mapswithme.util.statistics.Statistics; - import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; @@ -20,6 +18,9 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; import android.os.AsyncTask; +import com.mapswithme.util.LocationUtils; +import com.mapswithme.util.statistics.Statistics; + public class WifiLocation extends BroadcastReceiver { private static final String MWM_GEOLOCATION_SERVER = "http://geolocation.server/"; @@ -29,7 +30,6 @@ public class WifiLocation extends BroadcastReceiver public void onWifiLocationUpdated(Location l); } - // @TODO support multiple listeners private Listener mObserver = null; private WifiManager mWifi = null; @@ -40,8 +40,7 @@ public class WifiLocation extends BroadcastReceiver { } - // @TODO support multiple listeners - // Returns true if was started successfully + /// @return true if was started successfully. public boolean startScan(Context context, Listener l) { mObserver = l; @@ -113,7 +112,7 @@ public class WifiLocation extends BroadcastReceiver if (mLocationManager == null) mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); - Location l = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); + final Location l = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (l != null) { if (wifiHeaderAdded) @@ -162,8 +161,8 @@ public class WifiLocation extends BroadcastReceiver protected void onPostExecute(Boolean result) { // Notify event should be called on UI thread - if (mObserver != null && this.mLocation != null) - mObserver.onWifiLocationUpdated(this.mLocation); + if (mObserver != null && mLocation != null) + mObserver.onWifiLocationUpdated(mLocation); } @Override @@ -196,7 +195,7 @@ public class WifiLocation extends BroadcastReceiver mLocation.setAccuracy((float) acc); mLocation.setLatitude(lat); mLocation.setLongitude(lon); - mLocation.setTime(java.lang.System.currentTimeMillis()); + LocationUtils.setLocationCurrentTime(mLocation); wr.close(); rd.close(); diff --git a/android/src/com/mapswithme/util/LocationUtils.java b/android/src/com/mapswithme/util/LocationUtils.java index 9a8e8dfa8b..85ec818bd7 100644 --- a/android/src/com/mapswithme/util/LocationUtils.java +++ b/android/src/com/mapswithme/util/LocationUtils.java @@ -1,18 +1,62 @@ package com.mapswithme.util; -import android.location.Location; - import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import android.annotation.SuppressLint; +import android.location.Location; +import android.os.SystemClock; + /** * Locations utils from {@link http://developer.android.com/guide/topics/location/strategies.html} * Partly modified and suited for MWM. */ public class LocationUtils { - private static final int TWO_MINUTES = 1000 * 60 * 2; + private static final int TWO_MINUTES = 2 * 60 * 1000; + private static final long LOCATION_EXPIRATION_TIME = 5 * 60 * 1000; + + @SuppressLint("NewApi") + public static boolean isNotExpired(Location l) + { + if (l != null) + { + long timeDiff; + if (Utils.apiEqualOrGreaterThan(17)) + timeDiff = (SystemClock.elapsedRealtimeNanos() - l.getElapsedRealtimeNanos()) / 1000000; + else + timeDiff = System.currentTimeMillis() - l.getTime(); + return (timeDiff <= LOCATION_EXPIRATION_TIME); + } + return false; + } + + @SuppressLint("NewApi") + public static long timeDiffMillis(Location l1, Location l2) + { + if (Utils.apiEqualOrGreaterThan(17)) + return (l1.getElapsedRealtimeNanos() - l2.getElapsedRealtimeNanos()) / 1000000; + else + return (l1.getTime() - l2.getTime()); + } + + @SuppressLint("NewApi") + public static void setLocationCurrentTime(Location l) + { + if (Utils.apiEqualOrGreaterThan(17)) + l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + l.setTime(System.currentTimeMillis()); + } + + /// Call this function before comparing or after getting location to + /// avoid troubles with invalid system time. + @SuppressLint("NewApi") + public static void hackLocationTime(Location l) + { + if (Utils.apiLowerThan(17)) + l.setTime(System.currentTimeMillis()); + } /** Determines whether one Location reading is better than the current Location fix * @param firstLoc The new Location that you want to evaluate @@ -20,47 +64,51 @@ public class LocationUtils */ public static boolean isFirstOneBetterLocation(Location firstLoc, Location secondLoc) { + if (firstLoc == null) + return false; if (secondLoc == null) - { - // A new location is always better than no location return true; - } // Check whether the new location fix is newer or older - long timeDelta = firstLoc.getTime() - secondLoc.getTime(); - boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; - boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; - boolean isNewer = timeDelta > 0; - - // If it's been more than two minutes since the current location, use the new location - // because the user has likely moved - if (isSignificantlyNewer) + final long timeDelta = timeDiffMillis(firstLoc, secondLoc); + + // If it's been more than two minutes since the current location, + // use the new location because the user has likely moved + if (timeDelta > TWO_MINUTES) { + // significantly newer return true; - // If the new location is more than two minutes older, it must be worse } - else if (isSignificantlyOlder) + else if (timeDelta < -TWO_MINUTES) + { + // significantly older return false; + } // Check whether the new location fix is more or less accurate - int accuracyDelta = (int) (firstLoc.getAccuracy() - secondLoc.getAccuracy()); - // Relative diff, not absolute - boolean almostAsAccurate = Math.abs(accuracyDelta) <= 0.1*secondLoc.getAccuracy(); - - boolean isMoreAccurate = accuracyDelta < 0; - boolean isSignificantlyLessAccurate = accuracyDelta > 200; - - // Check if the old and new location are from the same provider - boolean isFromSameProvider = isSameProvider(firstLoc.getProvider(), - secondLoc.getProvider()); + final float accuracyDelta = firstLoc.getAccuracy() - secondLoc.getAccuracy(); + // Relative difference, not absolute + final boolean almostAsAccurate = Math.abs(accuracyDelta) <= 0.1*secondLoc.getAccuracy(); // Determine location quality using a combination of timeliness and accuracy - if (isMoreAccurate) + final boolean isNewer = timeDelta > 0; + if (accuracyDelta < 0) + { + // more accurate and has the same time order return true; + } else if (isNewer && almostAsAccurate) + { + // newer and has the same accuracy order return true; - else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) + } + else if (isNewer && accuracyDelta <= 200 && + isSameProvider(firstLoc.getProvider(), secondLoc.getProvider())) + { + // not significantly less accurate and from the same provider return true; + } + return false; } @@ -85,8 +133,7 @@ public class LocationUtils @Override public int compare(Location lhs, Location rhs) { - final float deltaAcc = rhs.getAccuracy() - lhs.getAccuracy(); - return (int) (1 * Math.signum(deltaAcc)); + return (int) (1 * Math.signum(rhs.getAccuracy() - lhs.getAccuracy())); } }; @@ -100,8 +147,7 @@ public class LocationUtils @Override public int compare(Location lhs, Location rhs) { - final long deltaTime = lhs.getTime() - rhs.getTime(); - return (int) (1 * Math.signum(deltaTime)); + return (int) (1 * Math.signum(timeDiffMillis(lhs, rhs))); } }; diff --git a/android/src/com/mapswithme/util/log/SimpleLogger.java b/android/src/com/mapswithme/util/log/SimpleLogger.java index 131bb394c4..cafc4ca5cf 100644 --- a/android/src/com/mapswithme/util/log/SimpleLogger.java +++ b/android/src/com/mapswithme/util/log/SimpleLogger.java @@ -34,9 +34,9 @@ public class SimpleLogger extends Logger private static String join(Object ... args) { - return TextUtils.join(",", args); + return (args != null ? TextUtils.join(", ", args) : ""); } - private SimpleLogger() {}; - private SimpleLogger(String tag) { super(tag); }; + private SimpleLogger() {} + private SimpleLogger(String tag) { super(tag); } } |