Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(595)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/LocationProviderFactory.java

Issue 65273002: Add a mechanism to pause and resume geolocation requests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: remove unsused CVC.isGeolocationActiveForTest API Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698