LocationBasedCountryDetector.java revision a58a8751b4c2ce457f0082a0baaee61312d56195
1a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao/* 2a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Copyright (C) 2010 The Android Open Source Project 3a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * 4a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Licensed under the Apache License, Version 2.0 (the "License"); 5a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * you may not use this file except in compliance with the License. 6a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * You may obtain a copy of the License at 7a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * 8a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * http://www.apache.org/licenses/LICENSE-2.0 9a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * 10a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Unless required by applicable law or agreed to in writing, software 11a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * distributed under the License is distributed on an "AS IS" BASIS, 12a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * See the License for the specific language governing permissions and 14a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * limitations under the License 15a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 16a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 17a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taopackage com.android.server.location; 18a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 19a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport java.io.IOException; 20a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport java.util.ArrayList; 21a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport java.util.List; 22a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport java.util.Timer; 23a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport java.util.TimerTask; 24a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 25a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.content.Context; 26a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.Address; 27a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.Country; 28a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.Geocoder; 29a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.Location; 30a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.LocationListener; 31a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.LocationManager; 32a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.os.Bundle; 33a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.util.Slog; 34a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 35a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao/** 36a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * This class detects which country the user currently is in through the enabled 37a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * location providers and the GeoCoder 38a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p> 39a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Use {@link #detectCountry} to start querying. If the location can not be 40a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * resolved within the given time, the last known location will be used to get 41a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * the user country through the GeoCoder. The IllegalStateException will be 42a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * thrown if there is a ongoing query. 43a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p> 44a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * The current query can be stopped by {@link #stop()} 45a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * 46a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * @hide 47a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 48a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taopublic class LocationBasedCountryDetector extends CountryDetectorBase { 49a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao private final static String TAG = "LocationBasedCountryDetector"; 50a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao private final static long QUERY_LOCATION_TIMEOUT = 1000 * 60 * 5; // 5 mins 51a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 52a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 53a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Used for canceling location query 54a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 55a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao protected Timer mTimer; 56a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 57a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 58a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * The thread to query the country from the GeoCoder. 59a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 60a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao protected Thread mQueryThread; 61a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao protected List<LocationListener> mLocationListeners; 62a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 63a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao private LocationManager mLocationManager; 64a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao private List<String> mEnabledProviders; 65a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 66a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao public LocationBasedCountryDetector(Context ctx) { 67a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao super(ctx); 68a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mLocationManager = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE); 69a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 70a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 71a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 72a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * @return the ISO 3166-1 two letters country code from the location 73a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 74a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao protected String getCountryFromLocation(Location location) { 75a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao String country = null; 76a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao Geocoder geoCoder = new Geocoder(mContext); 77a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao try { 78a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao List<Address> addresses = geoCoder.getFromLocation( 79a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao location.getLatitude(), location.getLongitude(), 1); 80a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (addresses != null && addresses.size() > 0) { 81a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao country = addresses.get(0).getCountryCode(); 82a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 83a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } catch (IOException e) { 84a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao Slog.w(TAG, "Exception occurs when getting country from location"); 85a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 86a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao return country; 87a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 88a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 89a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 90a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Register the listeners with the location providers 91a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 92a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao protected void registerEnabledProviders(List<LocationListener> listeners) { 93a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao int total = listeners.size(); 94a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao for (int i = 0; i< total; i++) { 95a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mLocationManager.requestLocationUpdates( 96a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mEnabledProviders.get(i), 0, 0, listeners.get(i)); 97a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 98a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 99a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 100a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 101a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Unregister the listeners with the location providers 102a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 103a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao protected void unregisterProviders(List<LocationListener> listeners) { 104a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao for (LocationListener listener : listeners) { 105a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mLocationManager.removeUpdates(listener); 106a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 107a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 108a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 109a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 110a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * @return the last known location from all providers 111a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 112a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao protected Location getLastKnownLocation() { 113a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao List<String> providers = mLocationManager.getAllProviders(); 114a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao Location bestLocation = null; 115a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao for (String provider : providers) { 116a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao Location lastKnownLocation = mLocationManager.getLastKnownLocation(provider); 117a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (lastKnownLocation != null) { 118a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (bestLocation == null || bestLocation.getTime() < lastKnownLocation.getTime()) { 119a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao bestLocation = lastKnownLocation; 120a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 121a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 122a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 123a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao return bestLocation; 124a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 125a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 126a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 127a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * @return the timeout for querying the location. 128a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 129a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao protected long getQueryLocationTimeout() { 130a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao return QUERY_LOCATION_TIMEOUT; 131a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 132a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 133a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 134a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * @return the total number of enabled location providers 135a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 136a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao protected int getTotalEnabledProviders() { 137a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (mEnabledProviders == null) { 138a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mEnabledProviders = mLocationManager.getProviders(true); 139a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 140a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao return mEnabledProviders.size(); 141a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 142a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 143a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 144a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Start detecting the country. 145a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p> 146a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Queries the location from all location providers, then starts a thread to query the 147a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * country from GeoCoder. 148a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 149a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao @Override 150a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao public synchronized Country detectCountry() { 151a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (mLocationListeners != null) { 152a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao throw new IllegalStateException(); 153a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 154a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao // Request the location from all enabled providers. 155a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao int totalProviders = getTotalEnabledProviders(); 156a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (totalProviders > 0) { 157a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mLocationListeners = new ArrayList<LocationListener>(totalProviders); 158a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao for (int i = 0; i < totalProviders; i++) { 159a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao LocationListener listener = new LocationListener () { 160a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao public void onLocationChanged(Location location) { 161a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (location != null) { 162a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao LocationBasedCountryDetector.this.stop(); 163a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao queryCountryCode(location); 164a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 165a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 166a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao public void onProviderDisabled(String provider) { 167a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 168a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao public void onProviderEnabled(String provider) { 169a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 170a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao public void onStatusChanged(String provider, int status, Bundle extras) { 171a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 172a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao }; 173a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mLocationListeners.add(listener); 174a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 175a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao registerEnabledProviders(mLocationListeners); 176a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mTimer = new Timer(); 177a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mTimer.schedule(new TimerTask() { 178a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao @Override 179a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao public void run() { 180a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mTimer = null; 181a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao LocationBasedCountryDetector.this.stop(); 182a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao // Looks like no provider could provide the location, let's try the last 183a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao // known location. 184a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao queryCountryCode(getLastKnownLocation()); 185a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 186a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao }, getQueryLocationTimeout()); 187a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } else { 188a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao // There is no provider enabled. 189a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao queryCountryCode(getLastKnownLocation()); 190a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 191a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao return mDetectedCountry; 192a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 193a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 194a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 195a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Stop the current query without notifying the listener. 196a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 197a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao @Override 198a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao public synchronized void stop() { 199a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (mLocationListeners != null) { 200a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao unregisterProviders(mLocationListeners); 201a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mLocationListeners = null; 202a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 203a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (mTimer != null) { 204a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mTimer.cancel(); 205a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mTimer = null; 206a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 207a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 208a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao 209a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao /** 210a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Start a new thread to query the country from Geocoder. 211a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */ 212a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao private synchronized void queryCountryCode(final Location location) { 213a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (location == null) { 214a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao notifyListener(null); 215a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao return; 216a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 217a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (mQueryThread != null) return; 218a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mQueryThread = new Thread(new Runnable() { 219a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao public void run() { 220a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao String countryIso = null; 221a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (location != null) { 222a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao countryIso = getCountryFromLocation(location); 223a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 224a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao if (countryIso != null) { 225a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mDetectedCountry = new Country(countryIso, Country.COUNTRY_SOURCE_LOCATION); 226a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } else { 227a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mDetectedCountry = null; 228a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 229a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao notifyListener(mDetectedCountry); 230a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mQueryThread = null; 231a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 232a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao }); 233a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao mQueryThread.start(); 234a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao } 235a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao} 236