OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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; | |
16 import org.chromium.base.CalledByNative; | |
17 import org.chromium.base.ThreadUtils; | 15 import org.chromium.base.ThreadUtils; |
18 | 16 |
17 import com.google.common.annotations.VisibleForTesting; | |
18 | |
19 import java.util.List; | 19 import java.util.List; |
20 import java.util.concurrent.FutureTask; | |
21 | 20 |
22 /** | 21 public class LocationProviderFactory { |
23 * Implements the Java side of LocationProviderAndroid. | 22 private static LocationProviderImpl sProviderImpl; |
24 * Delegates all real functionality to the inner class. | |
25 * See detailed documentation on | |
26 * content/browser/geolocation/android_location_api_adapter.h. | |
27 * Based on android.webkit.GeolocationService.java | |
28 */ | |
29 class LocationProvider { | |
30 | 23 |
31 // Log tag | 24 public interface LocationProviderImpl { |
bulach
2013/12/11 13:29:27
nit: an interface can't be an Impl.. since it's sc
mkosiba (inactive)
2013/12/11 15:47:44
or LocationProviderProvider :D
benm (inactive)
2013/12/11 20:08:51
Done.
| |
32 private static final String TAG = "LocationProvider"; | 25 public void start(boolean gpsEnabled); |
26 public void stop(); | |
27 public boolean isRunning(); | |
28 } | |
29 | |
30 private LocationProviderFactory() { | |
31 } | |
32 | |
33 @VisibleForTesting | |
34 public static void setLocationProviderImpl(LocationProviderImpl provider) { | |
35 assert sProviderImpl == null; | |
36 sProviderImpl = provider; | |
37 } | |
38 | |
39 public static LocationProviderImpl get(Context context) { | |
40 if (sProviderImpl == null) { | |
41 sProviderImpl = new SystemLocationProviderImpl(context); | |
42 } | |
43 return sProviderImpl; | |
44 } | |
33 | 45 |
34 /** | 46 /** |
35 * This is the core of android location provider. It is a separate class for clarity | 47 * 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 | 48 * 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. | 49 * ensures that the start/stop calls into this class are done in the UI thre ad. |
38 */ | 50 */ |
39 private static class LocationProviderImpl | 51 private static class SystemLocationProviderImpl |
bulach
2013/12/11 15:48:39
nit: and this would be just LocationProviderImpl
benm (inactive)
2013/12/11 20:08:51
Done.
benm (inactive)
2013/12/11 20:08:51
Done.
| |
40 implements LocationListener, ActivityStatus.StateListener { | 52 implements LocationListener, LocationProviderImpl { |
53 | |
54 // Log tag | |
55 private static final String TAG = "LocationProvider"; | |
41 | 56 |
42 private Context mContext; | 57 private Context mContext; |
43 private LocationManager mLocationManager; | 58 private LocationManager mLocationManager; |
44 private boolean mIsRunning; | 59 private boolean mIsRunning; |
45 private boolean mShouldRunAfterActivityResume; | |
46 private boolean mIsGpsEnabled; | |
47 | 60 |
48 LocationProviderImpl(Context context) { | 61 SystemLocationProviderImpl(Context context) { |
49 mContext = context; | 62 mContext = context; |
50 } | 63 } |
51 | 64 |
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 /** | 65 /** |
66 * Start listening for location updates. | 66 * Start listening for location updates. |
67 * @param gpsEnabled Whether or not we're interested in high accuracy GP S. | 67 * @param gpsEnabled Whether or not we're interested in high accuracy GP S. |
68 */ | 68 */ |
69 private void start(boolean gpsEnabled) { | 69 @Override |
70 if (!mIsRunning && !mShouldRunAfterActivityResume) { | 70 public void start(boolean gpsEnabled) { |
71 // Currently idle so start listening to activity status changes. | 71 unregisterFromLocationUpdates(); |
72 ActivityStatus.registerStateListener(this); | 72 registerForLocationUpdates(gpsEnabled); |
73 } | |
74 mIsGpsEnabled = gpsEnabled; | |
75 | |
76 if (ActivityStatus.getState() != ActivityStatus.RESUMED) { | |
77 mShouldRunAfterActivityResume = true; | |
78 } else { | |
79 unregisterFromLocationUpdates(); | |
80 registerForLocationUpdates(); | |
81 } | |
82 } | 73 } |
83 | 74 |
84 /** | 75 /** |
85 * Stop listening for location updates. | 76 * Stop listening for location updates. |
86 */ | 77 */ |
87 private void stop() { | 78 @Override |
79 public void stop() { | |
88 unregisterFromLocationUpdates(); | 80 unregisterFromLocationUpdates(); |
89 ActivityStatus.unregisterStateListener(this); | |
90 mShouldRunAfterActivityResume = false; | |
91 } | 81 } |
92 | 82 |
93 /** | 83 /** |
94 * Returns true if we are currently listening for location updates, fals e if not. | 84 * Returns true if we are currently listening for location updates, fals e if not. |
95 */ | 85 */ |
96 private boolean isRunning() { | 86 @Override |
87 public boolean isRunning() { | |
97 return mIsRunning; | 88 return mIsRunning; |
98 } | 89 } |
99 | 90 |
100 @Override | 91 @Override |
101 public void onLocationChanged(Location location) { | 92 public void onLocationChanged(Location location) { |
102 // Callbacks from the system location sevice are queued to this thre ad, so it's | 93 // 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 | 94 // possible that we receive callbacks after unregistering. At this p oint, the |
104 // native object will no longer exist. | 95 // native object will no longer exist. |
105 if (mIsRunning) { | 96 if (mIsRunning) { |
106 updateNewLocation(location); | 97 updateNewLocation(location); |
107 } | 98 } |
108 } | 99 } |
109 | 100 |
110 private void updateNewLocation(Location location) { | 101 private void updateNewLocation(Location location) { |
111 nativeNewLocationAvailable(location.getLatitude(), location.getLongi tude(), | 102 LocationProvider.nativeNewLocationAvailable( |
bulach
2013/12/11 13:29:27
nit: we don't normally expose native from other cl
benm (inactive)
2013/12/11 20:08:51
Yeah, I thought it was a little odd that the nativ
| |
103 location.getLatitude(), location.getLongitude(), | |
112 location.getTime() / 1000.0, | 104 location.getTime() / 1000.0, |
113 location.hasAltitude(), location.getAltitude(), | 105 location.hasAltitude(), location.getAltitude(), |
114 location.hasAccuracy(), location.getAccuracy(), | 106 location.hasAccuracy(), location.getAccuracy(), |
115 location.hasBearing(), location.getBearing(), | 107 location.hasBearing(), location.getBearing(), |
116 location.hasSpeed(), location.getSpeed()); | 108 location.hasSpeed(), location.getSpeed()); |
117 } | 109 } |
118 | 110 |
119 @Override | 111 @Override |
120 public void onStatusChanged(String provider, int status, Bundle extras) { | 112 public void onStatusChanged(String provider, int status, Bundle extras) { |
121 } | 113 } |
(...skipping 11 matching lines...) Expand all Loading... | |
133 mLocationManager = (LocationManager) mContext.getSystemService( | 125 mLocationManager = (LocationManager) mContext.getSystemService( |
134 Context.LOCATION_SERVICE); | 126 Context.LOCATION_SERVICE); |
135 if (mLocationManager == null) { | 127 if (mLocationManager == null) { |
136 Log.e(TAG, "Could not get location manager."); | 128 Log.e(TAG, "Could not get location manager."); |
137 } | 129 } |
138 } | 130 } |
139 | 131 |
140 /** | 132 /** |
141 * Registers this object with the location service. | 133 * Registers this object with the location service. |
142 */ | 134 */ |
143 private void registerForLocationUpdates() { | 135 private void registerForLocationUpdates(boolean isGpsEnabled) { |
144 ensureLocationManagerCreated(); | 136 ensureLocationManagerCreated(); |
145 if (usePassiveOneShotLocation()) return; | 137 if (usePassiveOneShotLocation()) return; |
146 | 138 |
147 assert !mIsRunning; | 139 assert !mIsRunning; |
148 mIsRunning = true; | 140 mIsRunning = true; |
149 | 141 |
150 // We're running on the main thread. The C++ side is responsible to | 142 // 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. | 143 // bounce notifications to the Geolocation thread as they arrive in the mainLooper. |
152 try { | 144 try { |
153 Criteria criteria = new Criteria(); | 145 Criteria criteria = new Criteria(); |
154 mLocationManager.requestLocationUpdates(0, 0, criteria, this, | 146 mLocationManager.requestLocationUpdates(0, 0, criteria, this, |
155 ThreadUtils.getUiThreadLooper()); | 147 ThreadUtils.getUiThreadLooper()); |
156 if (mIsGpsEnabled) { | 148 if (isGpsEnabled) { |
157 criteria.setAccuracy(Criteria.ACCURACY_FINE); | 149 criteria.setAccuracy(Criteria.ACCURACY_FINE); |
158 mLocationManager.requestLocationUpdates(0, 0, criteria, this , | 150 mLocationManager.requestLocationUpdates(0, 0, criteria, this , |
159 ThreadUtils.getUiThreadLooper()); | 151 ThreadUtils.getUiThreadLooper()); |
160 } | 152 } |
161 } catch(SecurityException e) { | 153 } catch(SecurityException e) { |
162 Log.e(TAG, "Caught security exception registering for location u pdates from " + | 154 Log.e(TAG, "Caught security exception registering for location u pdates from " + |
163 "system. This should only happen in DumpRenderTree."); | 155 "system. This should only happen in DumpRenderTree."); |
164 } catch(IllegalArgumentException e) { | 156 } catch(IllegalArgumentException e) { |
165 Log.e(TAG, "Caught IllegalArgumentException registering for loca tion updates."); | 157 Log.e(TAG, "Caught IllegalArgumentException registering for loca tion updates."); |
166 } | 158 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 /* | 190 /* |
199 * Checks if the passive location provider is the only provider availabl e | 191 * Checks if the passive location provider is the only provider availabl e |
200 * in the system. | 192 * in the system. |
201 */ | 193 */ |
202 private boolean isOnlyPassiveLocationProviderEnabled() { | 194 private boolean isOnlyPassiveLocationProviderEnabled() { |
203 List<String> providers = mLocationManager.getProviders(true); | 195 List<String> providers = mLocationManager.getProviders(true); |
204 return providers != null && providers.size() == 1 | 196 return providers != null && providers.size() == 1 |
205 && providers.get(0).equals(LocationManager.PASSIVE_PROVIDER) ; | 197 && providers.get(0).equals(LocationManager.PASSIVE_PROVIDER) ; |
206 } | 198 } |
207 } | 199 } |
200 } | |
208 | 201 |
209 // Delegate handling the real work in the main thread. | |
210 private LocationProviderImpl mImpl; | |
211 | 202 |
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 |