Index: chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationTracker.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationTracker.java |
index dfac566a7f743e3a4f2a0683c7d519b53f460db1..076fb175b6aec14e391a2c45f888e0f9f8e875f1 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationTracker.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationTracker.java |
@@ -4,13 +4,17 @@ |
package org.chromium.chrome.browser.omnibox.geo; |
+import android.Manifest; |
import android.content.Context; |
+import android.content.pm.PackageManager; |
import android.location.Location; |
import android.location.LocationListener; |
import android.location.LocationManager; |
import android.os.Bundle; |
import android.os.Handler; |
+import android.os.Process; |
+import org.chromium.base.ApiCompatibilityUtils; |
import org.chromium.base.ThreadUtils; |
import org.chromium.base.VisibleForTesting; |
import org.chromium.base.annotations.SuppressFBWarnings; |
@@ -24,7 +28,8 @@ import org.chromium.base.annotations.SuppressFBWarnings; |
class GeolocationTracker { |
private static SelfCancelingListener sListener; |
- private static Location sLocationForTesting; |
+ private static Location sNetworkLocationForTesting; |
+ private static Location sGpsLocationForTesting; |
private static boolean sUseLocationForTesting; |
private static class SelfCancelingListener implements LocationListener { |
@@ -78,13 +83,37 @@ class GeolocationTracker { |
} |
/** |
- * Returns the last known location from the network provider or null if none is available. |
+ * Returns the last known location or null if none is available. |
+ * |
+ * @param includeGpsFallback Whether the gps provider should also be used as a fallback. |
+ * Otherwise only the network provider will be used. |
*/ |
- static Location getLastKnownLocation(Context context) { |
- if (sUseLocationForTesting) return sLocationForTesting; |
+ static Location getLastKnownLocation(Context context, boolean includeGpsFallback) { |
+ if (sUseLocationForTesting) { |
+ return chooseLocation( |
+ sNetworkLocationForTesting, sGpsLocationForTesting, includeGpsFallback); |
+ } |
+ |
+ if (!hasPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)) { |
+ // Do not call location manager without permissions |
+ return null; |
+ } |
+ |
LocationManager locationManager = |
(LocationManager) context.getSystemService(Context.LOCATION_SERVICE); |
- return locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); |
+ Location networkLocation = |
+ locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); |
+ // If no GPS location has been request, just return the network location. For efficiency, |
+ // don't even get the GPS location. |
+ if (!includeGpsFallback) { |
+ return networkLocation; |
+ } |
+ Location gpsLocation = null; |
+ if (hasPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)) { |
+ // Only try to get GPS location when ACCESS_FINE_LOCATION is granted. |
+ gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); |
+ } |
+ return chooseLocation(networkLocation, gpsLocation, includeGpsFallback); |
} |
/** |
@@ -96,6 +125,10 @@ class GeolocationTracker { |
static void refreshLastKnownLocation(Context context, long maxAge) { |
ThreadUtils.assertOnUiThread(); |
+ if (!hasPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)) { |
+ return; |
+ } |
+ |
// We're still waiting for a location update. |
if (sListener != null) return; |
@@ -112,8 +145,30 @@ class GeolocationTracker { |
} |
@VisibleForTesting |
- static void setLocationForTesting(Location location) { |
- sLocationForTesting = location; |
+ static void setLocationForTesting( |
+ Location networkLocationForTesting, Location gpsLocationForTesting) { |
+ sNetworkLocationForTesting = networkLocationForTesting; |
+ sGpsLocationForTesting = gpsLocationForTesting; |
sUseLocationForTesting = true; |
} |
+ |
+ private static boolean hasPermission(Context context, String permission) { |
+ return ApiCompatibilityUtils.checkPermission( |
+ context, permission, Process.myPid(), Process.myUid()) |
+ == PackageManager.PERMISSION_GRANTED; |
+ } |
+ |
+ private static Location chooseLocation( |
+ Location networkLocation, Location gpsLocation, boolean includeGpsFallback) { |
+ if (!includeGpsFallback || gpsLocation == null) { |
+ return networkLocation; |
+ } |
+ |
+ if (networkLocation == null) { |
+ return gpsLocation; |
+ } |
+ |
+ // Both are not null, take the younger one. |
+ return networkLocation.getTime() > gpsLocation.getTime() ? networkLocation : gpsLocation; |
+ } |
} |