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
17package android.location;
18
19import java.util.HashMap;
20import java.util.Locale;
21import java.util.Map;
22import java.util.Set;
23
24import android.os.Bundle;
25import android.os.Parcel;
26import android.os.Parcelable;
27
28/**
29 * A class representing an Address, i.e, a set of Strings describing a location.
30 *
31 * The addres format is a simplified version of xAL (eXtensible Address Language)
32 * http://www.oasis-open.org/committees/ciq/ciq.html#6
33 */
34public 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     */
63    public Address(Locale locale) {
64        mLocale = locale;
65    }
66
67    /**
68     * Returns the Locale associated with this address.
69     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
199    public String getThoroughfare() {
200        return mThoroughfare;
201    }
202
203    /**
204     * Sets the thoroughfare name of the address, which may be null.
205     */
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     */
214    public String getSubThoroughfare() {
215        return mSubThoroughfare;
216    }
217
218    /**
219     * Sets the sub-thoroughfare name of the address, which may be null.
220     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
312    public void setLatitude(double latitude) {
313        mLatitude = latitude;
314        mHasLatitude = true;
315    }
316
317    /**
318     * Removes any latitude associated with this address.
319     */
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     */
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     */
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     */
349    public void setLongitude(double longitude) {
350        mLongitude = longitude;
351        mHasLongitude = true;
352    }
353
354    /**
355     * Removes any longitude associated with this address.
356     */
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 latitude.
367     */
368    public String getPhone() {
369        return mPhone;
370    }
371
372    /**
373     * Sets the phone number associated with this address.
374     */
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     */
383    public String getUrl() {
384        return mUrl;
385    }
386
387    /**
388     * Sets the public URL associated with this address.
389     */
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     */
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     */
417    public void setExtras(Bundle extras) {
418        mExtras = (extras == null) ? null : new Bundle(extras);
419    }
420
421    @Override
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 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
529    public int describeContents() {
530        return (mExtras != null) ? mExtras.describeContents() : 0;
531    }
532
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