Merge "Use passive provider for location based country detection"

This commit is contained in:
Daisuke Miyakawa
2011-04-28 16:19:23 -07:00
committed by Android (Google) Code Review
4 changed files with 164 additions and 71 deletions

View File

@@ -1310,7 +1310,7 @@ public class LocationManager {
* @param listener GPS status listener object to register
*
* @return true if the listener was successfully added
*
*
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
*/
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
@@ -1434,7 +1434,7 @@ public class LocationManager {
return false;
}
}
/**
* Used by NetInitiatedActivity to report user response
* for network initiated GPS fix requests.
@@ -1449,5 +1449,5 @@ public class LocationManager {
return false;
}
}
}

View File

@@ -56,6 +56,7 @@ import java.util.TimerTask;
public class ComprehensiveCountryDetector extends CountryDetectorBase {
private final static String TAG = "ComprehensiveCountryDetector";
/* package */ static final boolean DEBUG = false;
/**
* The refresh interval when the location based country was used
@@ -90,7 +91,9 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase {
* The listener for receiving the notification from LocationBasedCountryDetector.
*/
private CountryListener mLocationBasedCountryDetectionListener = new CountryListener() {
@Override
public void onCountryDetected(Country country) {
if (DEBUG) Slog.d(TAG, "Country detected via LocationBasedCountryDetector");
mCountryFromLocation = country;
// Don't start the LocationBasedCountryDetector.
detectCountry(true, false);
@@ -206,6 +209,7 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase {
protected void runAfterDetectionAsync(final Country country, final Country detectedCountry,
final boolean notifyChange, final boolean startLocationBasedDetection) {
mHandler.post(new Runnable() {
@Override
public void run() {
runAfterDetection(
country, detectedCountry, notifyChange, startLocationBasedDetection);
@@ -233,9 +237,20 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase {
if (notifyChange) {
notifyIfCountryChanged(country, detectedCountry);
}
if (DEBUG) {
Slog.d(TAG, "startLocationBasedDetection=" + startLocationBasedDetection
+ " detectCountry=" + (detectedCountry == null ? null :
"(source: " + detectedCountry.getSource()
+ ", countryISO: " + detectedCountry.getCountryIso() + ")")
+ " isAirplaneModeOff()=" + isAirplaneModeOff()
+ " mListener=" + mListener
+ " isGeoCoderImplemnted()=" + isGeoCoderImplemented());
}
if (startLocationBasedDetection && (detectedCountry == null
|| detectedCountry.getSource() > Country.COUNTRY_SOURCE_LOCATION)
&& isAirplaneModeOff() && mListener != null && isGeoCoderImplemented()) {
if (DEBUG) Slog.d(TAG, "run startLocationBasedDetector()");
// Start finding location when the source is less reliable than the
// location and the airplane mode is off (as geocoder will not
// work).
@@ -266,12 +281,20 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase {
if (mLocationBasedCountryDetector != null) {
return;
}
if (DEBUG) {
Slog.d(TAG, "starts LocationBasedDetector to detect Country code via Location info "
+ "(e.g. GPS)");
}
mLocationBasedCountryDetector = createLocationBasedCountryDetector();
mLocationBasedCountryDetector.setCountryListener(listener);
mLocationBasedCountryDetector.detectCountry();
}
private synchronized void stopLocationBasedDetector() {
if (DEBUG) {
Slog.d(TAG, "tries to stop LocationBasedDetector "
+ "(current detector: " + mLocationBasedCountryDetector + ")");
}
if (mLocationBasedCountryDetector != null) {
mLocationBasedCountryDetector.stop();
mLocationBasedCountryDetector = null;
@@ -305,10 +328,17 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase {
*/
private synchronized void scheduleLocationRefresh() {
if (mLocationRefreshTimer != null) return;
if (DEBUG) {
Slog.d(TAG, "start periodic location refresh timer. Interval: "
+ LOCATION_REFRESH_INTERVAL);
}
mLocationRefreshTimer = new Timer();
mLocationRefreshTimer.schedule(new TimerTask() {
@Override
public void run() {
if (DEBUG) {
Slog.d(TAG, "periodic location refresh event. Starts detecting Country code");
}
mLocationRefreshTimer = null;
detectCountry(false, true);
}

View File

@@ -16,12 +16,6 @@
package com.android.server.location;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.location.Address;
import android.location.Country;
@@ -32,6 +26,12 @@ import android.location.LocationManager;
import android.os.Bundle;
import android.util.Slog;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
/**
* This class detects which country the user currently is in through the enabled
* location providers and the GeoCoder
@@ -86,24 +86,23 @@ public class LocationBasedCountryDetector extends CountryDetectorBase {
return country;
}
/**
* Register the listeners with the location providers
*/
protected void registerEnabledProviders(List<LocationListener> listeners) {
int total = listeners.size();
for (int i = 0; i< total; i++) {
mLocationManager.requestLocationUpdates(
mEnabledProviders.get(i), 0, 0, listeners.get(i));
}
protected boolean isAcceptableProvider(String provider) {
// We don't want to actively initiate a location fix here (with gps or network providers).
return LocationManager.PASSIVE_PROVIDER.equals(provider);
}
/**
* Unregister the listeners with the location providers
* Register a listener with a provider name
*/
protected void unregisterProviders(List<LocationListener> listeners) {
for (LocationListener listener : listeners) {
mLocationManager.removeUpdates(listener);
}
protected void registerListener(String provider, LocationListener listener) {
mLocationManager.requestLocationUpdates(provider, 0, 0, listener);
}
/**
* Unregister an already registered listener
*/
protected void unregisterListener(LocationListener listener) {
mLocationManager.removeUpdates(listener);
}
/**
@@ -130,14 +129,11 @@ public class LocationBasedCountryDetector extends CountryDetectorBase {
return QUERY_LOCATION_TIMEOUT;
}
/**
* @return the total number of enabled location providers
*/
protected int getTotalEnabledProviders() {
protected List<String> getEnabledProviders() {
if (mEnabledProviders == null) {
mEnabledProviders = mLocationManager.getProviders(true);
}
return mEnabledProviders.size();
return mEnabledProviders;
}
/**
@@ -152,27 +148,36 @@ public class LocationBasedCountryDetector extends CountryDetectorBase {
throw new IllegalStateException();
}
// Request the location from all enabled providers.
int totalProviders = getTotalEnabledProviders();
List<String> enabledProviders = getEnabledProviders();
int totalProviders = enabledProviders.size();
if (totalProviders > 0) {
mLocationListeners = new ArrayList<LocationListener>(totalProviders);
for (int i = 0; i < totalProviders; i++) {
LocationListener listener = new LocationListener () {
public void onLocationChanged(Location location) {
if (location != null) {
LocationBasedCountryDetector.this.stop();
queryCountryCode(location);
String provider = enabledProviders.get(i);
if (isAcceptableProvider(provider)) {
LocationListener listener = new LocationListener () {
@Override
public void onLocationChanged(Location location) {
if (location != null) {
LocationBasedCountryDetector.this.stop();
queryCountryCode(location);
}
}
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
mLocationListeners.add(listener);
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
mLocationListeners.add(listener);
registerListener(provider, listener);
}
}
registerEnabledProviders(mLocationListeners);
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
@@ -197,7 +202,9 @@ public class LocationBasedCountryDetector extends CountryDetectorBase {
@Override
public synchronized void stop() {
if (mLocationListeners != null) {
unregisterProviders(mLocationListeners);
for (LocationListener listener : mLocationListeners) {
unregisterListener(listener);
}
mLocationListeners = null;
}
if (mTimer != null) {
@@ -216,6 +223,7 @@ public class LocationBasedCountryDetector extends CountryDetectorBase {
}
if (mQueryThread != null) return;
mQueryThread = new Thread(new Runnable() {
@Override
public void run() {
String countryIso = null;
if (location != null) {

View File

@@ -15,17 +15,25 @@
*/
package com.android.server.location;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import android.location.Country;
import android.location.CountryListener;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.test.AndroidTestCase;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Timer;
public class LocationBasedCountryDetectorTest extends AndroidTestCase {
private static final List<String> sEnabledProviders = Arrays.asList(
LocationManager.GPS_PROVIDER, LocationManager.PASSIVE_PROVIDER);
private class TestCountryDetector extends LocationBasedCountryDetector {
public static final int TOTAL_PROVIDERS = 2;
protected Object countryFoundLocker = new Object();
@@ -33,7 +41,7 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase {
private final Location mLocation;
private final String mCountry;
private final long mQueryLocationTimeout;
private List<LocationListener> mListeners;
private Map<String, LocationListener> mListeners;
public TestCountryDetector(String country, String provider) {
this(country, provider, 1000 * 60 * 5);
@@ -44,7 +52,7 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase {
mCountry = country;
mLocation = new Location(provider);
mQueryLocationTimeout = queryLocationTimeout;
mListeners = new ArrayList<LocationListener>();
mListeners = new HashMap<String, LocationListener>();
}
@Override
@@ -69,26 +77,50 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase {
return mLocation;
}
@Override
protected void registerEnabledProviders(List<LocationListener> listeners) {
mListeners.addAll(listeners);
private Set<String> mAcceptableProviders;
public void setAcceptableProvider(Set<String> acceptableProviders) {
mAcceptableProviders = acceptableProviders;
}
@Override
protected void unregisterProviders(List<LocationListener> listeners) {
for (LocationListener listener : mLocationListeners) {
assertTrue(mListeners.remove(listener));
protected boolean isAcceptableProvider(String provider) {
if (mAcceptableProviders != null) {
return mAcceptableProviders.contains(provider);
} else {
return true;
}
}
@Override
protected void registerListener(String provider, LocationListener listener) {
assertNotNull(provider);
mListeners.put(provider, listener);
}
@Override
protected void unregisterListener(LocationListener listener) {
for (Entry<String, LocationListener> entry : mListeners.entrySet()) {
if (entry.getValue().equals(listener)) {
mListeners.remove(entry.getKey());
return;
}
}
fail("Not registered");
}
public Map<String, LocationListener> getListeners() {
return mListeners;
}
@Override
protected long getQueryLocationTimeout() {
return mQueryLocationTimeout;
}
@Override
protected int getTotalEnabledProviders() {
return TOTAL_PROVIDERS;
protected List<String> getEnabledProviders() {
return sEnabledProviders;
}
public void notifyLocationFound() {
@@ -140,16 +172,39 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase {
}
public void testFindingCountry() {
testFindingCountryCommon(null);
}
public void testFindingCountryWithAcceptableProvider() {
testFindingCountryCommon(new HashSet<String>(Arrays.asList("passive")));
}
private void testFindingCountryCommon(Set<String> acceptableProviders) {
final String country = "us";
final String provider = "Good";
CountryListenerImpl countryListener = new CountryListenerImpl();
TestCountryDetector detector = new TestCountryDetector(country, provider);
if (acceptableProviders != null) {
detector.setAcceptableProvider(acceptableProviders);
}
detector.setCountryListener(countryListener);
detector.detectCountry();
assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
if (acceptableProviders != null) {
assertEquals(acceptableProviders.size(), detector.getListenersCount());
Map<String, LocationListener> listeners = detector.getListeners();
for (String acceptableProvider : acceptableProviders) {
assertTrue(listeners.containsKey(acceptableProvider));
}
} else {
assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
}
detector.notifyLocationFound();
// All listeners should be unregistered
assertEquals(detector.getListenersCount(), 0);
assertEquals(0, detector.getListenersCount());
assertNull(detector.getTimer());
Thread queryThread = waitForQueryThreadLaunched(detector);
detector.notifyCountryFound();
@@ -168,10 +223,10 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase {
TestCountryDetector detector = new TestCountryDetector(country, provider);
detector.setCountryListener(countryListener);
detector.detectCountry();
assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
detector.notifyLocationFound();
// All listeners should be unregistered
assertEquals(detector.getListenersCount(), 0);
assertEquals(0, detector.getListenersCount());
// The time should be stopped
assertNull(detector.getTimer());
Thread queryThread = waitForQueryThreadLaunched(detector);
@@ -193,10 +248,10 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase {
TestCountryDetector detector = new TestCountryDetector(country, provider);
detector.setCountryListener(countryListener);
detector.detectCountry();
assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
detector.stop();
// All listeners should be unregistered
assertEquals(detector.getListenersCount(), 0);
assertEquals(0, detector.getListenersCount());
// The time should be stopped
assertNull(detector.getTimer());
// QueryThread should still be NULL
@@ -217,10 +272,10 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase {
CountryListenerImpl countryListener = new CountryListenerImpl();
detector.setCountryListener(countryListener);
detector.detectCountry();
assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
waitForTimerReset(detector);
// All listeners should be unregistered
assertEquals(detector.getListenersCount(), 0);
assertEquals(0, detector.getListenersCount());
// QueryThread should still be NULL
assertNull(detector.getQueryThread());
assertTrue(countryListener.notified());
@@ -248,10 +303,10 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase {
CountryListenerImpl countryListener = new CountryListenerImpl();
detector.setCountryListener(countryListener);
detector.detectCountry();
assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
detector.notifyLocationFound();
// All listeners should be unregistered
assertEquals(detector.getListenersCount(), 0);
assertEquals(0, detector.getListenersCount());
assertNull(detector.getTimer());
Thread queryThread = waitForQueryThreadLaunched(detector);
detector.notifyCountryFound();
@@ -272,10 +327,10 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase {
CountryListenerImpl countryListener = new CountryListenerImpl();
detector.setCountryListener(countryListener);
detector.detectCountry();
assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
waitForTimerReset(detector);
// All listeners should be unregistered
assertEquals(detector.getListenersCount(), 0);
assertEquals(0, detector.getListenersCount());
Thread queryThread = waitForQueryThreadLaunched(detector);
detector.notifyCountryFound();
// Wait for query thread ending