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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/LocationProvider.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: Add new test case, fix a bug :) 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) 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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698