| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.content.browser; | 5 package org.chromium.content.browser; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.location.Criteria; | 8 import android.location.Criteria; |
| 9 import android.location.Location; | 9 import android.location.Location; |
| 10 import android.location.LocationListener; | 10 import android.location.LocationListener; |
| 11 import android.location.LocationManager; | 11 import android.location.LocationManager; |
| 12 import android.os.Bundle; | 12 import android.os.Bundle; |
| 13 import android.util.Log; | 13 import android.util.Log; |
| 14 | 14 |
| 15 import org.chromium.base.ActivityStatus; | 15 import com.google.common.annotations.VisibleForTesting; |
| 16 import org.chromium.base.CalledByNative; | 16 |
| 17 import org.chromium.base.ThreadUtils; | 17 import org.chromium.base.ThreadUtils; |
| 18 | 18 |
| 19 import java.util.List; | 19 import java.util.List; |
| 20 import java.util.concurrent.FutureTask; | |
| 21 | 20 |
| 22 /** | 21 /** |
| 23 * Implements the Java side of LocationProviderAndroid. | 22 * Factory to create a LocationProvider to allow us to inject |
| 24 * Delegates all real functionality to the inner class. | 23 * a mock for tests. |
| 25 * See detailed documentation on | |
| 26 * content/browser/geolocation/android_location_api_adapter.h. | |
| 27 * Based on android.webkit.GeolocationService.java | |
| 28 */ | 24 */ |
| 29 class LocationProvider { | 25 public class LocationProviderFactory { |
| 26 private static LocationProviderFactory.LocationProvider sProviderImpl; |
| 30 | 27 |
| 31 // Log tag | 28 /** |
| 32 private static final String TAG = "LocationProvider"; | 29 * LocationProviderFactory.get() returns an instance of this interface. |
| 30 */ |
| 31 public interface LocationProvider { |
| 32 public void start(boolean gpsEnabled); |
| 33 public void stop(); |
| 34 public boolean isRunning(); |
| 35 } |
| 36 |
| 37 private LocationProviderFactory() { |
| 38 } |
| 39 |
| 40 @VisibleForTesting |
| 41 public static void setLocationProviderImpl(LocationProviderFactory.LocationP
rovider provider) { |
| 42 assert sProviderImpl == null; |
| 43 sProviderImpl = provider; |
| 44 } |
| 45 |
| 46 public static LocationProvider get(Context context) { |
| 47 if (sProviderImpl == null) { |
| 48 sProviderImpl = new LocationProviderImpl(context); |
| 49 } |
| 50 return sProviderImpl; |
| 51 } |
| 33 | 52 |
| 34 /** | 53 /** |
| 35 * This is the core of android location provider. It is a separate class for
clarity | 54 * This is the core of android location provider. It is a separate class for
clarity |
| 36 * so that it can manage all processing completely in the UI thread. The con
tainer class | 55 * so that it can manage all processing completely in the UI thread. The con
tainer class |
| 37 * ensures that the start/stop calls into this class are done in the UI thre
ad. | 56 * ensures that the start/stop calls into this class are done in the UI thre
ad. |
| 38 */ | 57 */ |
| 39 private static class LocationProviderImpl | 58 private static class LocationProviderImpl |
| 40 implements LocationListener, ActivityStatus.StateListener { | 59 implements LocationListener, LocationProviderFactory.LocationProvide
r { |
| 60 |
| 61 // Log tag |
| 62 private static final String TAG = "LocationProvider"; |
| 41 | 63 |
| 42 private Context mContext; | 64 private Context mContext; |
| 43 private LocationManager mLocationManager; | 65 private LocationManager mLocationManager; |
| 44 private boolean mIsRunning; | 66 private boolean mIsRunning; |
| 45 private boolean mShouldRunAfterActivityResume; | |
| 46 private boolean mIsGpsEnabled; | |
| 47 | 67 |
| 48 LocationProviderImpl(Context context) { | 68 LocationProviderImpl(Context context) { |
| 49 mContext = context; | 69 mContext = context; |
| 50 } | 70 } |
| 51 | 71 |
| 52 @Override | |
| 53 public void onActivityStateChange(int state) { | |
| 54 if (state == ActivityStatus.PAUSED) { | |
| 55 mShouldRunAfterActivityResume |= mIsRunning; | |
| 56 unregisterFromLocationUpdates(); | |
| 57 } else if (state == ActivityStatus.RESUMED) { | |
| 58 assert !mIsRunning; | |
| 59 if (mShouldRunAfterActivityResume) { | |
| 60 registerForLocationUpdates(); | |
| 61 } | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 /** | 72 /** |
| 66 * Start listening for location updates. | 73 * Start listening for location updates. |
| 67 * @param gpsEnabled Whether or not we're interested in high accuracy GP
S. | 74 * @param gpsEnabled Whether or not we're interested in high accuracy GP
S. |
| 68 */ | 75 */ |
| 69 private void start(boolean gpsEnabled) { | 76 @Override |
| 70 if (!mIsRunning && !mShouldRunAfterActivityResume) { | 77 public void start(boolean gpsEnabled) { |
| 71 // Currently idle so start listening to activity status changes. | 78 unregisterFromLocationUpdates(); |
| 72 ActivityStatus.registerStateListener(this); | 79 registerForLocationUpdates(gpsEnabled); |
| 73 } | |
| 74 mIsGpsEnabled = gpsEnabled; | |
| 75 | |
| 76 if (ActivityStatus.getState() != ActivityStatus.RESUMED) { | |
| 77 mShouldRunAfterActivityResume = true; | |
| 78 } else { | |
| 79 unregisterFromLocationUpdates(); | |
| 80 registerForLocationUpdates(); | |
| 81 } | |
| 82 } | 80 } |
| 83 | 81 |
| 84 /** | 82 /** |
| 85 * Stop listening for location updates. | 83 * Stop listening for location updates. |
| 86 */ | 84 */ |
| 87 private void stop() { | 85 @Override |
| 86 public void stop() { |
| 88 unregisterFromLocationUpdates(); | 87 unregisterFromLocationUpdates(); |
| 89 ActivityStatus.unregisterStateListener(this); | |
| 90 mShouldRunAfterActivityResume = false; | |
| 91 } | 88 } |
| 92 | 89 |
| 93 /** | 90 /** |
| 94 * Returns true if we are currently listening for location updates, fals
e if not. | 91 * Returns true if we are currently listening for location updates, fals
e if not. |
| 95 */ | 92 */ |
| 96 private boolean isRunning() { | 93 @Override |
| 94 public boolean isRunning() { |
| 97 return mIsRunning; | 95 return mIsRunning; |
| 98 } | 96 } |
| 99 | 97 |
| 100 @Override | 98 @Override |
| 101 public void onLocationChanged(Location location) { | 99 public void onLocationChanged(Location location) { |
| 102 // Callbacks from the system location sevice are queued to this thre
ad, so it's | 100 // Callbacks from the system location sevice are queued to this thre
ad, so it's |
| 103 // possible that we receive callbacks after unregistering. At this p
oint, the | 101 // possible that we receive callbacks after unregistering. At this p
oint, the |
| 104 // native object will no longer exist. | 102 // native object will no longer exist. |
| 105 if (mIsRunning) { | 103 if (mIsRunning) { |
| 106 updateNewLocation(location); | 104 updateNewLocation(location); |
| 107 } | 105 } |
| 108 } | 106 } |
| 109 | 107 |
| 110 private void updateNewLocation(Location location) { | 108 private void updateNewLocation(Location location) { |
| 111 nativeNewLocationAvailable(location.getLatitude(), location.getLongi
tude(), | 109 LocationProviderAdapter.newLocationAvailable( |
| 110 location.getLatitude(), location.getLongitude(), |
| 112 location.getTime() / 1000.0, | 111 location.getTime() / 1000.0, |
| 113 location.hasAltitude(), location.getAltitude(), | 112 location.hasAltitude(), location.getAltitude(), |
| 114 location.hasAccuracy(), location.getAccuracy(), | 113 location.hasAccuracy(), location.getAccuracy(), |
| 115 location.hasBearing(), location.getBearing(), | 114 location.hasBearing(), location.getBearing(), |
| 116 location.hasSpeed(), location.getSpeed()); | 115 location.hasSpeed(), location.getSpeed()); |
| 117 } | 116 } |
| 118 | 117 |
| 119 @Override | 118 @Override |
| 120 public void onStatusChanged(String provider, int status, Bundle extras)
{ | 119 public void onStatusChanged(String provider, int status, Bundle extras)
{ |
| 121 } | 120 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 133 mLocationManager = (LocationManager) mContext.getSystemService( | 132 mLocationManager = (LocationManager) mContext.getSystemService( |
| 134 Context.LOCATION_SERVICE); | 133 Context.LOCATION_SERVICE); |
| 135 if (mLocationManager == null) { | 134 if (mLocationManager == null) { |
| 136 Log.e(TAG, "Could not get location manager."); | 135 Log.e(TAG, "Could not get location manager."); |
| 137 } | 136 } |
| 138 } | 137 } |
| 139 | 138 |
| 140 /** | 139 /** |
| 141 * Registers this object with the location service. | 140 * Registers this object with the location service. |
| 142 */ | 141 */ |
| 143 private void registerForLocationUpdates() { | 142 private void registerForLocationUpdates(boolean isGpsEnabled) { |
| 144 ensureLocationManagerCreated(); | 143 ensureLocationManagerCreated(); |
| 145 if (usePassiveOneShotLocation()) return; | 144 if (usePassiveOneShotLocation()) return; |
| 146 | 145 |
| 147 assert !mIsRunning; | 146 assert !mIsRunning; |
| 148 mIsRunning = true; | 147 mIsRunning = true; |
| 149 | 148 |
| 150 // We're running on the main thread. The C++ side is responsible to | 149 // We're running on the main thread. The C++ side is responsible to |
| 151 // bounce notifications to the Geolocation thread as they arrive in
the mainLooper. | 150 // bounce notifications to the Geolocation thread as they arrive in
the mainLooper. |
| 152 try { | 151 try { |
| 153 Criteria criteria = new Criteria(); | 152 Criteria criteria = new Criteria(); |
| 154 mLocationManager.requestLocationUpdates(0, 0, criteria, this, | 153 mLocationManager.requestLocationUpdates(0, 0, criteria, this, |
| 155 ThreadUtils.getUiThreadLooper()); | 154 ThreadUtils.getUiThreadLooper()); |
| 156 if (mIsGpsEnabled) { | 155 if (isGpsEnabled) { |
| 157 criteria.setAccuracy(Criteria.ACCURACY_FINE); | 156 criteria.setAccuracy(Criteria.ACCURACY_FINE); |
| 158 mLocationManager.requestLocationUpdates(0, 0, criteria, this
, | 157 mLocationManager.requestLocationUpdates(0, 0, criteria, this
, |
| 159 ThreadUtils.getUiThreadLooper()); | 158 ThreadUtils.getUiThreadLooper()); |
| 160 } | 159 } |
| 161 } catch (SecurityException e) { | 160 } catch (SecurityException e) { |
| 162 Log.e(TAG, "Caught security exception registering for location u
pdates from " + | 161 Log.e(TAG, "Caught security exception registering for location u
pdates from " + |
| 163 "system. This should only happen in DumpRenderTree."); | 162 "system. This should only happen in DumpRenderTree."); |
| 164 } catch (IllegalArgumentException e) { | 163 } catch (IllegalArgumentException e) { |
| 165 Log.e(TAG, "Caught IllegalArgumentException registering for loca
tion updates."); | 164 Log.e(TAG, "Caught IllegalArgumentException registering for loca
tion updates."); |
| 166 } | 165 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 /* | 197 /* |
| 199 * Checks if the passive location provider is the only provider availabl
e | 198 * Checks if the passive location provider is the only provider availabl
e |
| 200 * in the system. | 199 * in the system. |
| 201 */ | 200 */ |
| 202 private boolean isOnlyPassiveLocationProviderEnabled() { | 201 private boolean isOnlyPassiveLocationProviderEnabled() { |
| 203 List<String> providers = mLocationManager.getProviders(true); | 202 List<String> providers = mLocationManager.getProviders(true); |
| 204 return providers != null && providers.size() == 1 | 203 return providers != null && providers.size() == 1 |
| 205 && providers.get(0).equals(LocationManager.PASSIVE_PROVIDER)
; | 204 && providers.get(0).equals(LocationManager.PASSIVE_PROVIDER)
; |
| 206 } | 205 } |
| 207 } | 206 } |
| 207 } |
| 208 | 208 |
| 209 // Delegate handling the real work in the main thread. | |
| 210 private LocationProviderImpl mImpl; | |
| 211 | 209 |
| 212 private LocationProvider(Context context) { | |
| 213 mImpl = new LocationProviderImpl(context); | |
| 214 } | |
| 215 | |
| 216 @CalledByNative | |
| 217 static LocationProvider create(Context context) { | |
| 218 return new LocationProvider(context); | |
| 219 } | |
| 220 | |
| 221 /** | |
| 222 * Start listening for location updates until we're told to quit. May be | |
| 223 * called in any thread. | |
| 224 * @param gpsEnabled Whether or not we're interested in high accuracy GPS. | |
| 225 */ | |
| 226 @CalledByNative | |
| 227 public boolean start(final boolean gpsEnabled) { | |
| 228 FutureTask<Void> task = new FutureTask<Void>(new Runnable() { | |
| 229 @Override | |
| 230 public void run() { | |
| 231 mImpl.start(gpsEnabled); | |
| 232 } | |
| 233 }, null); | |
| 234 ThreadUtils.runOnUiThread(task); | |
| 235 return true; | |
| 236 } | |
| 237 | |
| 238 /** | |
| 239 * Stop listening for location updates. May be called in any thread. | |
| 240 */ | |
| 241 @CalledByNative | |
| 242 public void stop() { | |
| 243 FutureTask<Void> task = new FutureTask<Void>(new Runnable() { | |
| 244 @Override | |
| 245 public void run() { | |
| 246 mImpl.stop(); | |
| 247 } | |
| 248 }, null); | |
| 249 ThreadUtils.runOnUiThread(task); | |
| 250 } | |
| 251 | |
| 252 /** | |
| 253 * Returns true if we are currently listening for location updates, false if
not. | |
| 254 * Must be called only in the UI thread. | |
| 255 */ | |
| 256 public boolean isRunning() { | |
| 257 assert ThreadUtils.runningOnUiThread(); | |
| 258 return mImpl.isRunning(); | |
| 259 } | |
| 260 | |
| 261 // Native functions | |
| 262 public static native void nativeNewLocationAvailable( | |
| 263 double latitude, double longitude, double timeStamp, | |
| 264 boolean hasAltitude, double altitude, | |
| 265 boolean hasAccuracy, double accuracy, | |
| 266 boolean hasHeading, double heading, | |
| 267 boolean hasSpeed, double speed); | |
| 268 public static native void nativeNewErrorAvailable(String message); | |
| 269 } | |
| OLD | NEW |