1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.location; 18 19 import android.content.Context; 20 import android.os.IBinder; 21 import android.os.RemoteException; 22 import android.os.ServiceManager; 23 24 import com.android.internal.util.Preconditions; 25 26 import java.io.IOException; 27 import java.util.Collections; 28 import java.util.List; 29 import java.util.Locale; 30 import java.util.concurrent.CountDownLatch; 31 import java.util.concurrent.TimeUnit; 32 33 /** 34 * A class for handling geocoding and reverse geocoding. Geocoding is 35 * the process of transforming a street address or other description 36 * of a location into a (latitude, longitude) coordinate. Reverse 37 * geocoding is the process of transforming a (latitude, longitude) 38 * coordinate into a (partial) address. The amount of detail in a 39 * reverse geocoded location description may vary, for example one 40 * might contain the full street address of the closest building, while 41 * another might contain only a city name and postal code. 42 * 43 * The Geocoder class requires a backend service that is not included in 44 * the core android framework. The Geocoder query methods will return an 45 * empty list if there no backend service in the platform. Use the 46 * isPresent() method to determine whether a Geocoder implementation 47 * exists. 48 * 49 * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on 50 * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful or 51 * correct. Do not use this API for any safety-critical or regulatory compliance purpose. 52 */ 53 public final class Geocoder { 54 55 private static final long TIMEOUT_MS = 60000; 56 57 private final GeocoderParams mParams; 58 private final ILocationManager mService; 59 60 /** 61 * Returns true if the Geocoder methods getFromLocation and 62 * getFromLocationName are implemented. Lack of network 63 * connectivity may still cause these methods to return null or 64 * empty lists. 65 */ isPresent()66 public static boolean isPresent() { 67 IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE); 68 ILocationManager lm = ILocationManager.Stub.asInterface(b); 69 try { 70 return lm.geocoderIsPresent(); 71 } catch (RemoteException e) { 72 throw e.rethrowFromSystemServer(); 73 } 74 } 75 76 /** 77 * Constructs a Geocoder whose responses will be localized for the 78 * given Locale. 79 * 80 * @param context the Context of the calling Activity 81 * @param locale the desired Locale for the query results 82 * 83 * @throws NullPointerException if Locale is null 84 */ Geocoder(Context context, Locale locale)85 public Geocoder(Context context, Locale locale) { 86 mParams = new GeocoderParams(context, locale); 87 mService = ILocationManager.Stub.asInterface( 88 ServiceManager.getService(Context.LOCATION_SERVICE)); 89 } 90 91 /** 92 * Constructs a Geocoder whose responses will be localized for the 93 * default system Locale. 94 * 95 * @param context the Context of the calling Activity 96 */ Geocoder(Context context)97 public Geocoder(Context context) { 98 this(context, Locale.getDefault()); 99 } 100 101 /** 102 * Returns an array of Addresses that attempt to describe the area immediately surrounding the 103 * given latitude and longitude. The returned addresses should be localized for the locale 104 * provided to this class's constructor. Results may be obtained by means of a network lookup 105 * and this method may take some time to return, and so should not be called on the main thread. 106 * 107 * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on 108 * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful 109 * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance 110 * purposes. 111 * 112 * @param latitude the latitude a point for the search 113 * @param longitude the longitude a point for the search 114 * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended 115 * 116 * @return a list of Address objects. Returns null or empty list if no matches were 117 * found or there is no backend service available. 118 * 119 * @throws IllegalArgumentException if latitude is 120 * less than -90 or greater than 90 121 * @throws IllegalArgumentException if longitude is 122 * less than -180 or greater than 180 123 * @throws IOException if the network is unavailable or any other 124 * I/O problem occurs 125 */ getFromLocation(double latitude, double longitude, int maxResults)126 public List<Address> getFromLocation(double latitude, double longitude, int maxResults) 127 throws IOException { 128 Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude"); 129 Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "longitude"); 130 131 try { 132 GeocodeListener listener = new GeocodeListener(); 133 mService.getFromLocation(latitude, longitude, maxResults, mParams, listener); 134 return listener.getResults(); 135 } catch (RemoteException e) { 136 throw e.rethrowFromSystemServer(); 137 } 138 } 139 140 /** 141 * Returns an array of Addresses that attempt to describe the named location, which may be a 142 * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain 143 * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be 144 * localized for the locale provided to this class's constructor. Results may be obtained by 145 * means of a network lookup and this method may take some time to return, and so should not be 146 * called on the main thread. 147 * 148 * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on 149 * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful 150 * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance 151 * purposes. 152 * 153 * @param locationName a user-supplied description of a location 154 * @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended 155 * 156 * @return a list of Address objects. Returns null or empty list if no matches were 157 * found or there is no backend service available. 158 * 159 * @throws IllegalArgumentException if locationName is null 160 * @throws IOException if the network is unavailable or any other 161 * I/O problem occurs 162 */ getFromLocationName(String locationName, int maxResults)163 public List<Address> getFromLocationName(String locationName, int maxResults) throws IOException { 164 return getFromLocationName(locationName, maxResults, 0, 0, 0, 0); 165 } 166 167 /** 168 * Returns an array of Addresses that attempt to describe the named location, which may be a 169 * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain 170 * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be 171 * localized for the locale provided to this class's constructor. Results may be obtained by 172 * means of a network lookup and this method may take some time to return, and so should not be 173 * called on the main thread. 174 * 175 * <p> You may specify a bounding box for the search results by including the latitude and 176 * longitude of the lower left point and upper right point of the box. 177 * 178 * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on 179 * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful 180 * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance 181 * purposes. 182 * 183 * @param locationName a user-supplied description of a location 184 * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended 185 * @param lowerLeftLatitude the latitude of the lower left corner of the bounding box 186 * @param lowerLeftLongitude the longitude of the lower left corner of the bounding box 187 * @param upperRightLatitude the latitude of the upper right corner of the bounding box 188 * @param upperRightLongitude the longitude of the upper right corner of the bounding box 189 * 190 * @return a list of Address objects. Returns null or empty list if no matches were 191 * found or there is no backend service available. 192 * 193 * @throws IllegalArgumentException if locationName is null 194 * @throws IllegalArgumentException if any latitude is 195 * less than -90 or greater than 90 196 * @throws IllegalArgumentException if any longitude is 197 * less than -180 or greater than 180 198 * @throws IOException if the network is unavailable or any other 199 * I/O problem occurs 200 */ getFromLocationName(String locationName, int maxResults, double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude, double upperRightLongitude)201 public List<Address> getFromLocationName(String locationName, int maxResults, 202 double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude, 203 double upperRightLongitude) throws IOException { 204 Preconditions.checkArgument(locationName != null); 205 Preconditions.checkArgumentInRange(lowerLeftLatitude, -90.0, 90.0, "lowerLeftLatitude"); 206 Preconditions.checkArgumentInRange(lowerLeftLongitude, -180.0, 180.0, "lowerLeftLongitude"); 207 Preconditions.checkArgumentInRange(upperRightLatitude, -90.0, 90.0, "upperRightLatitude"); 208 Preconditions.checkArgumentInRange(upperRightLongitude, -180.0, 180.0, 209 "upperRightLongitude"); 210 211 try { 212 GeocodeListener listener = new GeocodeListener(); 213 mService.getFromLocationName(locationName, lowerLeftLatitude, lowerLeftLongitude, 214 upperRightLatitude, upperRightLongitude, maxResults, mParams, listener); 215 return listener.getResults(); 216 } catch (RemoteException e) { 217 throw e.rethrowFromSystemServer(); 218 } 219 } 220 221 private static class GeocodeListener extends IGeocodeListener.Stub { 222 private final CountDownLatch mLatch = new CountDownLatch(1); 223 224 private String mError = null; 225 private List<Address> mResults = Collections.emptyList(); 226 GeocodeListener()227 GeocodeListener() {} 228 229 @Override onResults(String error, List<Address> results)230 public void onResults(String error, List<Address> results) { 231 mError = error; 232 mResults = results; 233 mLatch.countDown(); 234 } 235 getResults()236 public List<Address> getResults() throws IOException { 237 try { 238 if (!mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 239 mError = "Service not Available"; 240 } 241 } catch (InterruptedException e) { 242 Thread.currentThread().interrupt(); 243 } 244 245 if (mError != null) { 246 throw new IOException(mError); 247 } else { 248 return mResults; 249 } 250 } 251 } 252 } 253