OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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.os.Handler; | |
14 import android.os.HandlerThread; | |
15 import android.os.Message; | |
13 import android.util.Log; | 16 import android.util.Log; |
14 | 17 |
18 import com.google.common.annotations.VisibleForTesting; | |
19 | |
15 import org.chromium.base.ActivityStatus; | 20 import org.chromium.base.ActivityStatus; |
16 import org.chromium.base.CalledByNative; | 21 import org.chromium.base.CalledByNative; |
17 import org.chromium.base.ThreadUtils; | 22 import org.chromium.base.ThreadUtils; |
18 | 23 |
19 import java.util.List; | 24 import java.util.List; |
20 import java.util.concurrent.FutureTask; | 25 import java.util.concurrent.FutureTask; |
21 | 26 |
22 /** | 27 /** |
23 * Implements the Java side of LocationProviderAndroid. | 28 * Implements the Java side of LocationProviderAndroid. |
24 * Delegates all real functionality to the inner class. | 29 * Delegates all real functionality to the inner class. |
25 * See detailed documentation on | 30 * See detailed documentation on |
26 * content/browser/geolocation/android_location_api_adapter.h. | 31 * content/browser/geolocation/android_location_api_adapter.h. |
27 * Based on android.webkit.GeolocationService.java | 32 * Based on android.webkit.GeolocationService.java |
28 */ | 33 */ |
29 class LocationProvider { | 34 public class LocationProvider { |
30 | 35 |
31 // Log tag | 36 // Log tag |
32 private static final String TAG = "LocationProvider"; | 37 private static final String TAG = "LocationProvider"; |
33 | 38 |
39 private static boolean sUseMockProvider; | |
40 | |
41 @VisibleForTesting | |
42 public static void enableMockLocationProvider() { | |
mkosiba (inactive)
2013/12/09 16:26:08
nit: I think it would be a bit cleaner if the Loca
| |
43 sUseMockProvider = true; | |
44 } | |
45 | |
46 private interface ContentLocationProvider { | |
47 public void start(boolean gpsEnabled); | |
48 public void stop(); | |
49 public boolean isRunning(); | |
50 } | |
51 | |
52 private static class MockLocationProviderImpl implements ContentLocationProv ider { | |
53 private boolean mIsRunning; | |
54 private Handler mHandler; | |
55 private static final Object mLock = new Object(); | |
56 | |
57 private static final int UPDATE_LOCATION = 100; | |
58 | |
59 public MockLocationProviderImpl() { | |
60 HandlerThread handlerThread = new HandlerThread("MockLocationProvide rImpl"); | |
61 handlerThread.start(); | |
62 mHandler = new Handler(handlerThread.getLooper()) { | |
63 @Override | |
64 public void handleMessage(Message msg) { | |
65 synchronized(mLock) { | |
66 if (msg.what == UPDATE_LOCATION) { | |
67 newLocation(); | |
68 sendEmptyMessageDelayed(UPDATE_LOCATION, 1000); | |
69 } | |
70 } | |
71 } | |
72 }; | |
73 } | |
74 | |
75 @Override | |
76 public void start(boolean gpsEnabled) { | |
77 if (mIsRunning) return; | |
78 mIsRunning = true; | |
79 synchronized (mLock) { | |
80 mHandler.sendEmptyMessage(UPDATE_LOCATION); | |
81 } | |
82 } | |
83 | |
84 @Override | |
85 public void stop() { | |
86 if (!mIsRunning) return; | |
87 mIsRunning = false; | |
88 synchronized (mLock) { | |
89 mHandler.removeMessages(UPDATE_LOCATION); | |
90 } | |
91 } | |
92 | |
93 @Override | |
94 public boolean isRunning() { | |
95 return mIsRunning; | |
96 } | |
97 | |
98 private void newLocation() { | |
99 nativeNewLocationAvailable(0, 0, System.currentTimeMillis() / 1000.0 , | |
100 false, 0, | |
101 true, 0.5, | |
102 false, 0, | |
103 false, 0); | |
104 } | |
105 }; | |
106 | |
34 /** | 107 /** |
35 * This is the core of android location provider. It is a separate class for clarity | 108 * 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 | 109 * 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. | 110 * ensures that the start/stop calls into this class are done in the UI thre ad. |
38 */ | 111 */ |
39 private static class LocationProviderImpl | 112 private static class LocationProviderImpl |
40 implements LocationListener, ActivityStatus.StateListener { | 113 implements LocationListener, ContentLocationProvider { |
41 | 114 |
42 private Context mContext; | 115 private Context mContext; |
43 private LocationManager mLocationManager; | 116 private LocationManager mLocationManager; |
44 private boolean mIsRunning; | 117 private boolean mIsRunning; |
45 private boolean mShouldRunAfterActivityResume; | |
46 private boolean mIsGpsEnabled; | |
47 | 118 |
48 LocationProviderImpl(Context context) { | 119 LocationProviderImpl(Context context) { |
49 mContext = context; | 120 mContext = context; |
50 } | 121 } |
51 | 122 |
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 /** | 123 /** |
66 * Start listening for location updates. | 124 * Start listening for location updates. |
67 * @param gpsEnabled Whether or not we're interested in high accuracy GP S. | 125 * @param gpsEnabled Whether or not we're interested in high accuracy GP S. |
68 */ | 126 */ |
69 private void start(boolean gpsEnabled) { | 127 @Override |
70 if (!mIsRunning && !mShouldRunAfterActivityResume) { | 128 public void start(boolean gpsEnabled) { |
71 // Currently idle so start listening to activity status changes. | 129 unregisterFromLocationUpdates(); |
72 ActivityStatus.registerStateListener(this); | 130 registerForLocationUpdates(gpsEnabled); |
73 } | |
74 mIsGpsEnabled = gpsEnabled; | |
75 | |
76 if (ActivityStatus.getState() != ActivityStatus.RESUMED) { | |
77 mShouldRunAfterActivityResume = true; | |
78 } else { | |
79 unregisterFromLocationUpdates(); | |
80 registerForLocationUpdates(); | |
81 } | |
82 } | 131 } |
83 | 132 |
84 /** | 133 /** |
85 * Stop listening for location updates. | 134 * Stop listening for location updates. |
86 */ | 135 */ |
87 private void stop() { | 136 @Override |
137 public void stop() { | |
88 unregisterFromLocationUpdates(); | 138 unregisterFromLocationUpdates(); |
89 ActivityStatus.unregisterStateListener(this); | |
90 mShouldRunAfterActivityResume = false; | |
91 } | 139 } |
92 | 140 |
93 /** | 141 /** |
94 * Returns true if we are currently listening for location updates, fals e if not. | 142 * Returns true if we are currently listening for location updates, fals e if not. |
95 */ | 143 */ |
96 private boolean isRunning() { | 144 @Override |
145 public boolean isRunning() { | |
97 return mIsRunning; | 146 return mIsRunning; |
98 } | 147 } |
99 | 148 |
100 @Override | 149 @Override |
101 public void onLocationChanged(Location location) { | 150 public void onLocationChanged(Location location) { |
102 // Callbacks from the system location sevice are queued to this thre ad, so it's | 151 // 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 | 152 // possible that we receive callbacks after unregistering. At this p oint, the |
104 // native object will no longer exist. | 153 // native object will no longer exist. |
105 if (mIsRunning) { | 154 if (mIsRunning) { |
106 updateNewLocation(location); | 155 updateNewLocation(location); |
(...skipping 26 matching lines...) Expand all Loading... | |
133 mLocationManager = (LocationManager) mContext.getSystemService( | 182 mLocationManager = (LocationManager) mContext.getSystemService( |
134 Context.LOCATION_SERVICE); | 183 Context.LOCATION_SERVICE); |
135 if (mLocationManager == null) { | 184 if (mLocationManager == null) { |
136 Log.e(TAG, "Could not get location manager."); | 185 Log.e(TAG, "Could not get location manager."); |
137 } | 186 } |
138 } | 187 } |
139 | 188 |
140 /** | 189 /** |
141 * Registers this object with the location service. | 190 * Registers this object with the location service. |
142 */ | 191 */ |
143 private void registerForLocationUpdates() { | 192 private void registerForLocationUpdates(boolean isGpsEnabled) { |
144 ensureLocationManagerCreated(); | 193 ensureLocationManagerCreated(); |
145 if (usePassiveOneShotLocation()) return; | 194 if (usePassiveOneShotLocation()) return; |
146 | 195 |
147 assert !mIsRunning; | 196 assert !mIsRunning; |
148 mIsRunning = true; | 197 mIsRunning = true; |
149 | 198 |
150 // We're running on the main thread. The C++ side is responsible to | 199 // 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. | 200 // bounce notifications to the Geolocation thread as they arrive in the mainLooper. |
152 try { | 201 try { |
153 Criteria criteria = new Criteria(); | 202 Criteria criteria = new Criteria(); |
154 mLocationManager.requestLocationUpdates(0, 0, criteria, this, | 203 mLocationManager.requestLocationUpdates(0, 0, criteria, this, |
155 ThreadUtils.getUiThreadLooper()); | 204 ThreadUtils.getUiThreadLooper()); |
156 if (mIsGpsEnabled) { | 205 if (isGpsEnabled) { |
157 criteria.setAccuracy(Criteria.ACCURACY_FINE); | 206 criteria.setAccuracy(Criteria.ACCURACY_FINE); |
158 mLocationManager.requestLocationUpdates(0, 0, criteria, this , | 207 mLocationManager.requestLocationUpdates(0, 0, criteria, this , |
159 ThreadUtils.getUiThreadLooper()); | 208 ThreadUtils.getUiThreadLooper()); |
160 } | 209 } |
161 } catch(SecurityException e) { | 210 } catch(SecurityException e) { |
162 Log.e(TAG, "Caught security exception registering for location u pdates from " + | 211 Log.e(TAG, "Caught security exception registering for location u pdates from " + |
163 "system. This should only happen in DumpRenderTree."); | 212 "system. This should only happen in DumpRenderTree."); |
164 } catch(IllegalArgumentException e) { | 213 } catch(IllegalArgumentException e) { |
165 Log.e(TAG, "Caught IllegalArgumentException registering for loca tion updates."); | 214 Log.e(TAG, "Caught IllegalArgumentException registering for loca tion updates."); |
166 } | 215 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
200 * in the system. | 249 * in the system. |
201 */ | 250 */ |
202 private boolean isOnlyPassiveLocationProviderEnabled() { | 251 private boolean isOnlyPassiveLocationProviderEnabled() { |
203 List<String> providers = mLocationManager.getProviders(true); | 252 List<String> providers = mLocationManager.getProviders(true); |
204 return providers != null && providers.size() == 1 | 253 return providers != null && providers.size() == 1 |
205 && providers.get(0).equals(LocationManager.PASSIVE_PROVIDER) ; | 254 && providers.get(0).equals(LocationManager.PASSIVE_PROVIDER) ; |
206 } | 255 } |
207 } | 256 } |
208 | 257 |
209 // Delegate handling the real work in the main thread. | 258 // Delegate handling the real work in the main thread. |
210 private LocationProviderImpl mImpl; | 259 private ContentLocationProvider mImpl; |
211 | 260 |
212 private LocationProvider(Context context) { | 261 private LocationProvider(Context context) { |
213 mImpl = new LocationProviderImpl(context); | 262 if (sUseMockProvider) { |
263 mImpl = new MockLocationProviderImpl(); | |
264 } else { | |
265 mImpl = new LocationProviderImpl(context); | |
266 } | |
214 } | 267 } |
215 | 268 |
216 @CalledByNative | 269 @CalledByNative |
217 static LocationProvider create(Context context) { | 270 static LocationProvider create(Context context) { |
218 return new LocationProvider(context); | 271 return new LocationProvider(context); |
219 } | 272 } |
220 | 273 |
221 /** | 274 /** |
222 * Start listening for location updates until we're told to quit. May be | 275 * Start listening for location updates until we're told to quit. May be |
223 * called in any thread. | 276 * called in any thread. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
260 | 313 |
261 // Native functions | 314 // Native functions |
262 public static native void nativeNewLocationAvailable( | 315 public static native void nativeNewLocationAvailable( |
263 double latitude, double longitude, double timeStamp, | 316 double latitude, double longitude, double timeStamp, |
264 boolean hasAltitude, double altitude, | 317 boolean hasAltitude, double altitude, |
265 boolean hasAccuracy, double accuracy, | 318 boolean hasAccuracy, double accuracy, |
266 boolean hasHeading, double heading, | 319 boolean hasHeading, double heading, |
267 boolean hasSpeed, double speed); | 320 boolean hasSpeed, double speed); |
268 public static native void nativeNewErrorAvailable(String message); | 321 public static native void nativeNewErrorAvailable(String message); |
269 } | 322 } |
OLD | NEW |