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 java.util.HashMap;
20 import java.util.Locale;
21 import java.util.Map;
22 import java.util.Set;
23 
24 import android.os.Bundle;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 /**
29  * A class representing an Address, i.e, a set of Strings describing a location.
30  *
31  * The address format is a simplified version of xAL (eXtensible Address Language)
32  * http://www.oasis-open.org/committees/ciq/ciq.html#6
33  */
34 public class Address implements Parcelable {
35 
36     private Locale mLocale;
37 
38     private String mFeatureName;
39     private HashMap<Integer, String> mAddressLines;
40     private int mMaxAddressLineIndex = -1;
41     private String mAdminArea;
42     private String mSubAdminArea;
43     private String mLocality;
44     private String mSubLocality;
45     private String mThoroughfare;
46     private String mSubThoroughfare;
47     private String mPremises;
48     private String mPostalCode;
49     private String mCountryCode;
50     private String mCountryName;
51     private double mLatitude;
52     private double mLongitude;
53     private boolean mHasLatitude = false;
54     private boolean mHasLongitude = false;
55     private String mPhone;
56     private String mUrl;
57     private Bundle mExtras = null;
58 
59     /**
60      * Constructs a new Address object set to the given Locale and with all
61      * other fields initialized to null or false.
62      */
Address(Locale locale)63     public Address(Locale locale) {
64         mLocale = locale;
65     }
66 
67     /**
68      * Returns the Locale associated with this address.
69      */
getLocale()70     public Locale getLocale() {
71         return mLocale;
72     }
73 
74     /**
75      * Returns the largest index currently in use to specify an address line.
76      * If no address lines are specified, -1 is returned.
77      */
getMaxAddressLineIndex()78     public int getMaxAddressLineIndex() {
79         return mMaxAddressLineIndex;
80     }
81 
82     /**
83      * Returns a line of the address numbered by the given index
84      * (starting at 0), or null if no such line is present.
85      *
86      * @throws IllegalArgumentException if index < 0
87      */
getAddressLine(int index)88     public String getAddressLine(int index) {
89         if (index < 0) {
90             throw new IllegalArgumentException("index = " + index + " < 0");
91         }
92         return mAddressLines == null? null :  mAddressLines.get(index);
93     }
94 
95     /**
96      * Sets the line of the address numbered by index (starting at 0) to the
97      * given String, which may be null.
98      *
99      * @throws IllegalArgumentException if index < 0
100      */
setAddressLine(int index, String line)101     public void setAddressLine(int index, String line) {
102         if (index < 0) {
103             throw new IllegalArgumentException("index = " + index + " < 0");
104         }
105         if (mAddressLines == null) {
106             mAddressLines = new HashMap<Integer, String>();
107         }
108         mAddressLines.put(index, line);
109 
110         if (line == null) {
111             // We've eliminated a line, recompute the max index
112             mMaxAddressLineIndex = -1;
113             for (Integer i : mAddressLines.keySet()) {
114                 mMaxAddressLineIndex = Math.max(mMaxAddressLineIndex, i);
115             }
116         } else {
117             mMaxAddressLineIndex = Math.max(mMaxAddressLineIndex, index);
118         }
119     }
120 
121     /**
122      * Returns the feature name of the address, for example, "Golden Gate Bridge", or null
123      * if it is unknown
124      */
getFeatureName()125     public String getFeatureName() {
126         return mFeatureName;
127     }
128 
129     /**
130      * Sets the feature name of the address to the given String, which may be null
131      */
setFeatureName(String featureName)132     public void setFeatureName(String featureName) {
133         mFeatureName = featureName;
134     }
135 
136     /**
137      * Returns the administrative area name of the address, for example, "CA", or null if
138      * it is unknown
139      */
getAdminArea()140     public String getAdminArea() {
141         return mAdminArea;
142     }
143 
144     /**
145      * Sets the administrative area name of the address to the given String, which may be null
146      */
setAdminArea(String adminArea)147     public void setAdminArea(String adminArea) {
148         this.mAdminArea = adminArea;
149     }
150 
151     /**
152      * Returns the sub-administrative area name of the address, for example, "Santa Clara County",
153      * or null if it is unknown
154      */
getSubAdminArea()155     public String getSubAdminArea() {
156         return mSubAdminArea;
157     }
158 
159     /**
160      * Sets the sub-administrative area name of the address to the given String, which may be null
161      */
setSubAdminArea(String subAdminArea)162     public void setSubAdminArea(String subAdminArea) {
163         this.mSubAdminArea = subAdminArea;
164     }
165 
166     /**
167      * Returns the locality of the address, for example "Mountain View", or null if it is unknown.
168      */
getLocality()169     public String getLocality() {
170         return mLocality;
171     }
172 
173     /**
174      * Sets the locality of the address to the given String, which may be null.
175      */
setLocality(String locality)176     public void setLocality(String locality) {
177         mLocality = locality;
178     }
179 
180     /**
181      * Returns the sub-locality of the address, or null if it is unknown.
182      * For example, this may correspond to the neighborhood of the locality.
183      */
getSubLocality()184     public String getSubLocality() {
185         return mSubLocality;
186     }
187 
188     /**
189      * Sets the sub-locality of the address to the given String, which may be null.
190      */
setSubLocality(String sublocality)191     public void setSubLocality(String sublocality) {
192         mSubLocality = sublocality;
193     }
194 
195     /**
196      * Returns the thoroughfare name of the address, for example, "1600 Ampitheater Parkway",
197      * which may be null
198      */
getThoroughfare()199     public String getThoroughfare() {
200         return mThoroughfare;
201     }
202 
203     /**
204      * Sets the thoroughfare name of the address, which may be null.
205      */
setThoroughfare(String thoroughfare)206     public void setThoroughfare(String thoroughfare) {
207         this.mThoroughfare = thoroughfare;
208     }
209 
210     /**
211      * Returns the sub-thoroughfare name of the address, which may be null.
212      * This may correspond to the street number of the address.
213      */
getSubThoroughfare()214     public String getSubThoroughfare() {
215         return mSubThoroughfare;
216     }
217 
218     /**
219      * Sets the sub-thoroughfare name of the address, which may be null.
220      */
setSubThoroughfare(String subthoroughfare)221     public void setSubThoroughfare(String subthoroughfare) {
222         this.mSubThoroughfare = subthoroughfare;
223     }
224 
225     /**
226      * Returns the premises of the address, or null if it is unknown.
227      */
getPremises()228     public String getPremises() {
229         return mPremises;
230     }
231 
232     /**
233      * Sets the premises of the address to the given String, which may be null.
234      */
setPremises(String premises)235     public void setPremises(String premises) {
236         mPremises = premises;
237     }
238 
239     /**
240      * Returns the postal code of the address, for example "94110",
241      * or null if it is unknown.
242      */
getPostalCode()243     public String getPostalCode() {
244         return mPostalCode;
245     }
246 
247     /**
248      * Sets the postal code of the address to the given String, which may
249      * be null.
250      */
setPostalCode(String postalCode)251     public void setPostalCode(String postalCode) {
252         mPostalCode = postalCode;
253     }
254 
255     /**
256      * Returns the country code of the address, for example "US",
257      * or null if it is unknown.
258      */
getCountryCode()259     public String getCountryCode() {
260         return mCountryCode;
261     }
262 
263     /**
264      * Sets the country code of the address to the given String, which may
265      * be null.
266      */
setCountryCode(String countryCode)267     public void setCountryCode(String countryCode) {
268         mCountryCode = countryCode;
269     }
270 
271     /**
272      * Returns the localized country name of the address, for example "Iceland",
273      * or null if it is unknown.
274      */
getCountryName()275     public String getCountryName() {
276         return mCountryName;
277     }
278 
279     /**
280      * Sets the country name of the address to the given String, which may
281      * be null.
282      */
setCountryName(String countryName)283     public void setCountryName(String countryName) {
284         mCountryName = countryName;
285     }
286 
287     /**
288      * Returns true if a latitude has been assigned to this Address,
289      * false otherwise.
290      */
hasLatitude()291     public boolean hasLatitude() {
292         return mHasLatitude;
293     }
294 
295     /**
296      * Returns the latitude of the address if known.
297      *
298      * @throws IllegalStateException if this Address has not been assigned
299      * a latitude.
300      */
getLatitude()301     public double getLatitude() {
302         if (mHasLatitude) {
303             return mLatitude;
304         } else {
305             throw new IllegalStateException();
306         }
307     }
308 
309     /**
310      * Sets the latitude associated with this address.
311      */
setLatitude(double latitude)312     public void setLatitude(double latitude) {
313         mLatitude = latitude;
314         mHasLatitude = true;
315     }
316 
317     /**
318      * Removes any latitude associated with this address.
319      */
clearLatitude()320     public void clearLatitude() {
321         mHasLatitude = false;
322     }
323 
324     /**
325      * Returns true if a longitude has been assigned to this Address,
326      * false otherwise.
327      */
hasLongitude()328     public boolean hasLongitude() {
329         return mHasLongitude;
330     }
331 
332     /**
333      * Returns the longitude of the address if known.
334      *
335      * @throws IllegalStateException if this Address has not been assigned
336      * a longitude.
337      */
getLongitude()338     public double getLongitude() {
339         if (mHasLongitude) {
340             return mLongitude;
341         } else {
342             throw new IllegalStateException();
343         }
344     }
345 
346     /**
347      * Sets the longitude associated with this address.
348      */
setLongitude(double longitude)349     public void setLongitude(double longitude) {
350         mLongitude = longitude;
351         mHasLongitude = true;
352     }
353 
354     /**
355      * Removes any longitude associated with this address.
356      */
clearLongitude()357     public void clearLongitude() {
358         mHasLongitude = false;
359     }
360 
361     /**
362      * Returns the phone number of the address if known,
363      * or null if it is unknown.
364      *
365      * @throws IllegalStateException if this Address has not been assigned
366      * a phone number.
367      */
getPhone()368     public String getPhone() {
369         return mPhone;
370     }
371 
372     /**
373      * Sets the phone number associated with this address.
374      */
setPhone(String phone)375     public void setPhone(String phone) {
376         mPhone = phone;
377     }
378 
379     /**
380      * Returns the public URL for the address if known,
381      * or null if it is unknown.
382      */
getUrl()383     public String getUrl() {
384         return mUrl;
385     }
386 
387     /**
388      * Sets the public URL associated with this address.
389      */
setUrl(String Url)390     public void setUrl(String Url) {
391         mUrl = Url;
392     }
393 
394     /**
395      * Returns additional provider-specific information about the
396      * address as a Bundle.  The keys and values are determined
397      * by the provider.  If no additional information is available,
398      * null is returned.
399      *
400      * <!--
401      * <p> A number of common key/value pairs are listed
402      * below. Providers that use any of the keys on this list must
403      * provide the corresponding value as described below.
404      *
405      * <ul>
406      * </ul>
407      * -->
408      */
getExtras()409     public Bundle getExtras() {
410         return mExtras;
411     }
412 
413     /**
414      * Sets the extra information associated with this fix to the
415      * given Bundle.
416      */
setExtras(Bundle extras)417     public void setExtras(Bundle extras) {
418         mExtras = (extras == null) ? null : new Bundle(extras);
419     }
420 
421     @Override
toString()422     public String toString() {
423         StringBuilder sb = new StringBuilder();
424         sb.append("Address[addressLines=[");
425         for (int i = 0; i <= mMaxAddressLineIndex; i++) {
426             if (i > 0) {
427                 sb.append(',');
428             }
429             sb.append(i);
430             sb.append(':');
431             String line = mAddressLines.get(i);
432             if (line == null) {
433                 sb.append("null");
434             } else {
435                 sb.append('\"');
436                 sb.append(line);
437                 sb.append('\"');
438             }
439         }
440         sb.append(']');
441         sb.append(",feature=");
442         sb.append(mFeatureName);
443         sb.append(",admin=");
444         sb.append(mAdminArea);
445         sb.append(",sub-admin=");
446         sb.append(mSubAdminArea);
447         sb.append(",locality=");
448         sb.append(mLocality);
449         sb.append(",thoroughfare=");
450         sb.append(mThoroughfare);
451         sb.append(",postalCode=");
452         sb.append(mPostalCode);
453         sb.append(",countryCode=");
454         sb.append(mCountryCode);
455         sb.append(",countryName=");
456         sb.append(mCountryName);
457         sb.append(",hasLatitude=");
458         sb.append(mHasLatitude);
459         sb.append(",latitude=");
460         sb.append(mLatitude);
461         sb.append(",hasLongitude=");
462         sb.append(mHasLongitude);
463         sb.append(",longitude=");
464         sb.append(mLongitude);
465         sb.append(",phone=");
466         sb.append(mPhone);
467         sb.append(",url=");
468         sb.append(mUrl);
469         sb.append(",extras=");
470         sb.append(mExtras);
471         sb.append(']');
472         return sb.toString();
473     }
474 
475     public static final @android.annotation.NonNull Parcelable.Creator<Address> CREATOR =
476         new Parcelable.Creator<Address>() {
477         public Address createFromParcel(Parcel in) {
478             String language = in.readString();
479             String country = in.readString();
480             Locale locale = country.length() > 0 ?
481                 new Locale(language, country) :
482                 new Locale(language);
483             Address a = new Address(locale);
484 
485             int N = in.readInt();
486             if (N > 0) {
487                 a.mAddressLines = new HashMap<Integer, String>(N);
488                 for (int i = 0; i < N; i++) {
489                     int index = in.readInt();
490                     String line = in.readString();
491                     a.mAddressLines.put(index, line);
492                     a.mMaxAddressLineIndex =
493                         Math.max(a.mMaxAddressLineIndex, index);
494                 }
495             } else {
496                 a.mAddressLines = null;
497                 a.mMaxAddressLineIndex = -1;
498             }
499             a.mFeatureName = in.readString();
500             a.mAdminArea = in.readString();
501             a.mSubAdminArea = in.readString();
502             a.mLocality = in.readString();
503             a.mSubLocality = in.readString();
504             a.mThoroughfare = in.readString();
505             a.mSubThoroughfare = in.readString();
506             a.mPremises = in.readString();
507             a.mPostalCode = in.readString();
508             a.mCountryCode = in.readString();
509             a.mCountryName = in.readString();
510             a.mHasLatitude = in.readInt() == 0 ? false : true;
511             if (a.mHasLatitude) {
512                 a.mLatitude = in.readDouble();
513             }
514             a.mHasLongitude = in.readInt() == 0 ? false : true;
515             if (a.mHasLongitude) {
516                 a.mLongitude = in.readDouble();
517             }
518             a.mPhone = in.readString();
519             a.mUrl = in.readString();
520             a.mExtras = in.readBundle();
521             return a;
522         }
523 
524         public Address[] newArray(int size) {
525             return new Address[size];
526         }
527     };
528 
describeContents()529     public int describeContents() {
530         return (mExtras != null) ? mExtras.describeContents() : 0;
531     }
532 
writeToParcel(Parcel parcel, int flags)533     public void writeToParcel(Parcel parcel, int flags) {
534         parcel.writeString(mLocale.getLanguage());
535         parcel.writeString(mLocale.getCountry());
536         if (mAddressLines == null) {
537             parcel.writeInt(0);
538         } else {
539             Set<Map.Entry<Integer, String>> entries = mAddressLines.entrySet();
540             parcel.writeInt(entries.size());
541             for (Map.Entry<Integer, String> e : entries) {
542                 parcel.writeInt(e.getKey());
543                 parcel.writeString(e.getValue());
544             }
545         }
546         parcel.writeString(mFeatureName);
547         parcel.writeString(mAdminArea);
548         parcel.writeString(mSubAdminArea);
549         parcel.writeString(mLocality);
550         parcel.writeString(mSubLocality);
551         parcel.writeString(mThoroughfare);
552         parcel.writeString(mSubThoroughfare);
553         parcel.writeString(mPremises);
554         parcel.writeString(mPostalCode);
555         parcel.writeString(mCountryCode);
556         parcel.writeString(mCountryName);
557         parcel.writeInt(mHasLatitude ? 1 : 0);
558         if (mHasLatitude) {
559             parcel.writeDouble(mLatitude);
560         }
561         parcel.writeInt(mHasLongitude ? 1 : 0);
562         if (mHasLongitude){
563             parcel.writeDouble(mLongitude);
564         }
565         parcel.writeString(mPhone);
566         parcel.writeString(mUrl);
567         parcel.writeBundle(mExtras);
568     }
569 }
570