From d2f016e3b7142ab3d98f6013e21fd553b39f66cb Mon Sep 17 00:00:00 2001 From: vng Date: Sat, 14 Sep 2013 14:36:54 +0300 Subject: [PATCH] [yopme] Integrate LocationRequester (smart single location update) into BackScreenActivity. --- .../location/LocationRequester.java | 99 ++++++++++++++++--- .../mapswithme/yopme/BackscreenActivity.java | 55 +++-------- .../src/com/mapswithme/yopme/util/Utils.java | 61 ------------ 3 files changed, 102 insertions(+), 113 deletions(-) diff --git a/android/YoPme/src/com/mapswithme/location/LocationRequester.java b/android/YoPme/src/com/mapswithme/location/LocationRequester.java index 2282aa5a60..fb95b766be 100644 --- a/android/YoPme/src/com/mapswithme/location/LocationRequester.java +++ b/android/YoPme/src/com/mapswithme/location/LocationRequester.java @@ -2,10 +2,10 @@ package com.mapswithme.location; import android.app.PendingIntent; import android.content.Context; +import android.location.Location; import android.location.LocationManager; import android.os.Handler; import android.os.Message; -import android.util.Log; public class LocationRequester implements Handler.Callback { @@ -30,12 +30,83 @@ public class LocationRequester implements Handler.Callback mDelayedEventsHandler = new Handler(this); } - public boolean requestSingleUpdate(PendingIntent pi) + private static final int TWO_MINUTES = 1000 * 60 * 2; + + /** Checks whether two providers are the same */ + private static boolean isSameProvider(String provider1, String provider2) { + if (provider1 == null) + return provider2 == null; + else + return provider1.equals(provider2); + } + + /** Determines whether one Location reading is better than the current Location fix + * @param firstLoc The new Location that you want to evaluate + * @param secondLoc The current Location fix, to which you want to compare the new one + */ + public static boolean isFirstOneBetterLocation(Location firstLoc, Location secondLoc) + { + if (secondLoc == null) + { + // A new location is always better than no location + return true; + } + + // Check whether the new location fix is newer or older + final long timeDelta = (firstLoc.getElapsedRealtimeNanos() - secondLoc.getElapsedRealtimeNanos())/1000; + final boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; + final boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; + final 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) + { + return true; + // If the new location is more than two minutes older, it must be worse + } + else if (isSignificantlyOlder) + return false; + + // Check whether the new location fix is more or less accurate + final int accuracyDelta = (int) (firstLoc.getAccuracy() - secondLoc.getAccuracy()); + // Relative diff, not absolute + final boolean almostAsAccurate = Math.abs(accuracyDelta) <= 0.1*secondLoc.getAccuracy(); + + final boolean isMoreAccurate = accuracyDelta < 0; + final boolean isSignificantlyLessAccurate = accuracyDelta > 200; + + // Check if the old and new location are from the same provider + final boolean isFromSameProvider = isSameProvider(firstLoc.getProvider(), + secondLoc.getProvider()); + + // Determine location quality using a combination of timeliness and accuracy + if (isMoreAccurate) + return true; + else if (isNewer && almostAsAccurate) + return true; + else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) + return true; return false; } - public boolean requestSingleUpdate(PendingIntent pi, long maxTimeToDeliver) + public Location getLastLocation() + { + Location res = null; + for (final String provider : mEnabledProviders) + { + if (mLocationManager.isProviderEnabled(provider)) + { + final Location l = mLocationManager.getLastKnownLocation(provider); + if (isFirstOneBetterLocation(l, res)) + res = l; + } + } + return res; + } + + public void requestSingleUpdate(PendingIntent pi, long delayMillis) { if (mEnabledProviders.length > 0) { @@ -45,12 +116,18 @@ public class LocationRequester implements Handler.Callback mLocationManager.requestSingleUpdate(provider, pi); } - if (maxTimeToDeliver > 0) - postRequestCancelation(pi, maxTimeToDeliver); - - return true; + if (delayMillis > 0) + postRequestCancelation(pi, delayMillis); + } + } + + public void requestLocationUpdates(long minTime, float minDistance, PendingIntent pi) + { + for (final String provider : mEnabledProviders) + { + if (mLocationManager.isProviderEnabled(provider)) + mLocationManager.requestLocationUpdates(provider, minTime, minDistance, pi); } - return false; } public void removeUpdates(PendingIntent pi) @@ -58,14 +135,12 @@ public class LocationRequester implements Handler.Callback mLocationManager.removeUpdates(pi); } - private void postRequestCancelation(PendingIntent pi, long maxTimeToDeliver) + private void postRequestCancelation(PendingIntent pi, long delayMillis) { final Message msg = mDelayedEventsHandler.obtainMessage(WHAT_LOCATION_REQUEST_CANCELATION); msg.obj = pi; - mDelayedEventsHandler.sendMessageDelayed(msg, maxTimeToDeliver); - - Log.d(TAG, "Posted request cancelation for " + pi + "in " + maxTimeToDeliver + "ms"); + mDelayedEventsHandler.sendMessageDelayed(msg, delayMillis); } @Override diff --git a/android/YoPme/src/com/mapswithme/yopme/BackscreenActivity.java b/android/YoPme/src/com/mapswithme/yopme/BackscreenActivity.java index e867e52ed0..d4e97641de 100644 --- a/android/YoPme/src/com/mapswithme/yopme/BackscreenActivity.java +++ b/android/YoPme/src/com/mapswithme/yopme/BackscreenActivity.java @@ -17,11 +17,11 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.preference.PreferenceManager; -import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import com.mapswithme.location.LocationRequester; import com.mapswithme.maps.api.MWMPoint; import com.mapswithme.yopme.map.MapData; import com.mapswithme.yopme.map.MapDataProvider; @@ -68,7 +68,7 @@ public class BackscreenActivity extends BSActivity protected View mPoiInfo; protected MapDataProvider mMapDataProvider; - private LocationManager mLocationManager; + private LocationRequester mLocationManager; private final Runnable mInvalidateDrawable = new Runnable() { @@ -104,7 +104,7 @@ public class BackscreenActivity extends BSActivity setUpView(); - mLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); + mLocationManager = new LocationRequester(this); } @Override @@ -136,8 +136,6 @@ public class BackscreenActivity extends BSActivity mMode = (Mode) savedInstanceState.getSerializable(EXTRA_MODE); mLocation = (Location) savedInstanceState.getParcelable(EXTRA_LOCATION); mZoomLevel = savedInstanceState.getDouble(EXTRA_ZOOM); - - Log.d(TAG, "State restored."); } @Override @@ -149,8 +147,6 @@ public class BackscreenActivity extends BSActivity outState.putSerializable(EXTRA_MODE, mMode); outState.putParcelable(EXTRA_LOCATION, mLocation); outState.putDouble(EXTRA_ZOOM, mZoomLevel); - - Log.d(TAG, "State saved."); } @Override @@ -192,7 +188,8 @@ public class BackscreenActivity extends BSActivity mZoomLevel = intent.getDoubleExtra(EXTRA_ZOOM, MapDataProvider.COMFORT_ZOOM); updateData(); - hideWaitMessage(); + invalidate(); + requestLocationUpdate(); } } @@ -247,36 +244,20 @@ public class BackscreenActivity extends BSActivity .getString(getString(R.string.pref_loc_update), YopmePreference.LOCATION_UPDATE_DEFAULT); final long updateInterval = Long.parseLong(updateIntervalStr); - final String[] providers = { - LocationManager.GPS_PROVIDER, - LocationManager.NETWORK_PROVIDER, - LocationManager.PASSIVE_PROVIDER, - }; - final PendingIntent pi = getLocationPendingIntent(this); - // before requesting updates try to get last known in the first try if (mLocation == null) { - for (final String provider : providers) - if (mLocationManager.isProviderEnabled(provider)) - { - final Location lastLocation = mLocationManager.getLastKnownLocation(provider); - if (lastLocation != null) - onLocationUpdate(lastLocation); - } + final Location l = mLocationManager.getLastLocation(); + if (l != null) + onLocationUpdate(l); } // then listen to updates - for (final String provider : providers) - { - if (mLocationManager.isProviderEnabled(provider)) - { - if (updateInterval == -1) - mLocationManager.requestSingleUpdate(provider, pi); - else - mLocationManager.requestLocationUpdates(provider, updateInterval*1000, 0, pi); - } - } + final PendingIntent pi = getLocationPendingIntent(this); + if (updateInterval == -1) + mLocationManager.requestSingleUpdate(pi, 60*1000); + else + mLocationManager.requestLocationUpdates(updateInterval*1000, 5.0f, pi); if (mMode == Mode.LOCATION && mLocation == null) showWaitMessage(getString(R.string.wait_msg)); @@ -284,12 +265,11 @@ public class BackscreenActivity extends BSActivity private void onLocationUpdate(Location location) { - if (Utils.isFirstOneBetterLocation(location, mLocation)) + if (LocationRequester.isFirstOneBetterLocation(location, mLocation)) mLocation = location; else return; - hideWaitMessage(); updateData(); invalidate(); } @@ -298,15 +278,11 @@ public class BackscreenActivity extends BSActivity { mWaitMessage.setText(msg); mWaitScreen.setVisibility(View.VISIBLE); - - invalidate(); } private void hideWaitMessage() { mWaitScreen.setVisibility(View.GONE); - - invalidate(); } private final static NumberFormat df = DecimalFormat.getInstance(); @@ -360,7 +336,6 @@ public class BackscreenActivity extends BSActivity { mPoiInfo.setVisibility(View.VISIBLE); - if (mLocation != null) data = mMapDataProvider.getPOIData(mPoint, mZoomLevel, true, mLocation.getLatitude(), mLocation.getLongitude()); else @@ -380,7 +355,7 @@ public class BackscreenActivity extends BSActivity if (mBitmap == null) { - // this means we dont have this map + // this means we don't have this map showWaitMessage(getString(R.string.error_map_is_absent)); return; } diff --git a/android/YoPme/src/com/mapswithme/yopme/util/Utils.java b/android/YoPme/src/com/mapswithme/yopme/util/Utils.java index b01967337d..36ebd1c0da 100644 --- a/android/YoPme/src/com/mapswithme/yopme/util/Utils.java +++ b/android/YoPme/src/com/mapswithme/yopme/util/Utils.java @@ -7,7 +7,6 @@ import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.text.MessageFormat; -import android.location.Location; import android.util.Log; public class Utils @@ -46,65 +45,5 @@ public class Utils } } - private static final int TWO_MINUTES = 1000 * 60 * 2; - /** Determines whether one Location reading is better than the current Location fix - * @param firstLoc The new Location that you want to evaluate - * @param secondLoc The current Location fix, to which you want to compare the new one - */ - public static boolean isFirstOneBetterLocation(Location firstLoc, Location secondLoc) - { - if (secondLoc == null) - { - // A new location is always better than no location - return true; - } - - // Check whether the new location fix is newer or older - final long timeDelta = (firstLoc.getElapsedRealtimeNanos() - secondLoc.getElapsedRealtimeNanos())/1000; - final boolean isSignificantlyNewer = timeDelta > TWO_MINUTES; - final boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; - final 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) - { - return true; - // If the new location is more than two minutes older, it must be worse - } - else if (isSignificantlyOlder) - return false; - - // Check whether the new location fix is more or less accurate - final int accuracyDelta = (int) (firstLoc.getAccuracy() - secondLoc.getAccuracy()); - // Relative diff, not absolute - final boolean almostAsAccurate = Math.abs(accuracyDelta) <= 0.1*secondLoc.getAccuracy(); - - final boolean isMoreAccurate = accuracyDelta < 0; - final boolean isSignificantlyLessAccurate = accuracyDelta > 200; - - // Check if the old and new location are from the same provider - final boolean isFromSameProvider = isSameProvider(firstLoc.getProvider(), - secondLoc.getProvider()); - - // Determine location quality using a combination of timeliness and accuracy - if (isMoreAccurate) - return true; - else if (isNewer && almostAsAccurate) - return true; - else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) - return true; - return false; - } - - /** Checks whether two providers are the same */ - public static boolean isSameProvider(String provider1, String provider2) - { - if (provider1 == null) - return provider2 == null; - else - return provider1.equals(provider2); - } - private Utils() {} }