1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.util;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.location.Address;
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.location.Geocoder;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.location.Location;
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.location.LocationManager;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.net.ConnectivityManager;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.net.NetworkInfo;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
272b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.common.BlobCache;
282b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.ByteArrayInputStream;
30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.ByteArrayOutputStream;
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.DataInputStream;
32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.DataOutputStream;
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.io.IOException;
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.List;
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.Locale;
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class ReverseGeocoder {
387817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @SuppressWarnings("unused")
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "ReverseGeocoder";
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static final int EARTH_RADIUS_METERS = 6378137;
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static final int LAT_MIN = -90;
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static final int LAT_MAX = 90;
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static final int LON_MIN = -180;
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static final int LON_MAX = 180;
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int MAX_COUNTRY_NAME_LENGTH = 8;
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // If two points are within 20 miles of each other, use
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // "Around Palo Alto, CA" or "Around Mountain View, CA".
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // instead of directly jumping to the next level and saying
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // "California, US".
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int MAX_LOCALITY_MILE_RANGE = 20;
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String GEO_CACHE_FILE = "rev_geocoding";
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int GEO_CACHE_MAX_ENTRIES = 1000;
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int GEO_CACHE_MAX_BYTES = 500 * 1024;
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int GEO_CACHE_VERSION = 0;
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static class SetLatLong {
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // The latitude and longitude of the min latitude point.
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public double mMinLatLatitude = LAT_MAX;
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public double mMinLatLongitude;
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // The latitude and longitude of the max latitude point.
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public double mMaxLatLatitude = LAT_MIN;
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public double mMaxLatLongitude;
64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // The latitude and longitude of the min longitude point.
65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public double mMinLonLatitude;
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public double mMinLonLongitude = LON_MAX;
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // The latitude and longitude of the max longitude point.
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public double mMaxLonLatitude;
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public double mMaxLonLongitude = LON_MIN;
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private Context mContext;
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private Geocoder mGeocoder;
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private BlobCache mGeoCache;
75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private ConnectivityManager mConnectivityManager;
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static Address sCurrentAddress; // last known address
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public ReverseGeocoder(Context context) {
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mContext = context;
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGeocoder = new Geocoder(mContext);
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGeoCache = CacheManager.getCache(context, GEO_CACHE_FILE,
82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                GEO_CACHE_MAX_ENTRIES, GEO_CACHE_MAX_BYTES,
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                GEO_CACHE_VERSION);
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mConnectivityManager = (ConnectivityManager)
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                context.getSystemService(Context.CONNECTIVITY_SERVICE);
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public String computeAddress(SetLatLong set) {
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // The overall min and max latitudes and longitudes of the set.
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        double setMinLatitude = set.mMinLatLatitude;
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        double setMinLongitude = set.mMinLatLongitude;
92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        double setMaxLatitude = set.mMaxLatLatitude;
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        double setMaxLongitude = set.mMaxLatLongitude;
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (Math.abs(set.mMaxLatLatitude - set.mMinLatLatitude)
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                < Math.abs(set.mMaxLonLongitude - set.mMinLonLongitude)) {
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            setMinLatitude = set.mMinLonLatitude;
97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            setMinLongitude = set.mMinLonLongitude;
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            setMaxLatitude = set.mMaxLonLatitude;
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            setMaxLongitude = set.mMaxLonLongitude;
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Address addr1 = lookupAddress(setMinLatitude, setMinLongitude, true);
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Address addr2 = lookupAddress(setMaxLatitude, setMaxLongitude, true);
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (addr1 == null)
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            addr1 = addr2;
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (addr2 == null)
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            addr2 = addr1;
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (addr1 == null || addr2 == null) {
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Get current location, we decide the granularity of the string based
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // on this.
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        LocationManager locationManager =
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Location location = null;
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        List<String> providers = locationManager.getAllProviders();
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0; i < providers.size(); ++i) {
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String provider = providers.get(i);
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            location = (provider != null) ? locationManager.getLastKnownLocation(provider) : null;
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (location != null)
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                break;
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String currentCity = "";
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String currentAdminArea = "";
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String currentCountry = Locale.getDefault().getCountry();
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (location != null) {
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Address currentAddress = lookupAddress(
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    location.getLatitude(), location.getLongitude(), true);
129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (currentAddress == null) {
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                currentAddress = sCurrentAddress;
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                sCurrentAddress = currentAddress;
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (currentAddress != null && currentAddress.getCountryCode() != null) {
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                currentCity = checkNull(currentAddress.getLocality());
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                currentCountry = checkNull(currentAddress.getCountryCode());
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                currentAdminArea = checkNull(currentAddress.getAdminArea());
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String closestCommonLocation = null;
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String addr1Locality = checkNull(addr1.getLocality());
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String addr2Locality = checkNull(addr2.getLocality());
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String addr1AdminArea = checkNull(addr1.getAdminArea());
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String addr2AdminArea = checkNull(addr2.getAdminArea());
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String addr1CountryCode = checkNull(addr1.getCountryCode());
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String addr2CountryCode = checkNull(addr2.getCountryCode());
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (currentCity.equals(addr1Locality) || currentCity.equals(addr2Locality)) {
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String otherCity = currentCity;
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (currentCity.equals(addr1Locality)) {
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                otherCity = addr2Locality;
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (otherCity.length() == 0) {
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    otherCity = addr2AdminArea;
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    if (!currentCountry.equals(addr2CountryCode)) {
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        otherCity += " " + addr2CountryCode;
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                addr2Locality = addr1Locality;
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                addr2AdminArea = addr1AdminArea;
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                addr2CountryCode = addr1CountryCode;
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                otherCity = addr1Locality;
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (otherCity.length() == 0) {
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    otherCity = addr1AdminArea;
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    if (!currentCountry.equals(addr1CountryCode)) {
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        otherCity += " " + addr1CountryCode;
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                addr1Locality = addr2Locality;
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                addr1AdminArea = addr2AdminArea;
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                addr1CountryCode = addr2CountryCode;
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            closestCommonLocation = valueIfEqual(addr1.getAddressLine(0), addr2.getAddressLine(0));
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (closestCommonLocation != null && !("null".equals(closestCommonLocation))) {
176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (!currentCity.equals(otherCity)) {
177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    closestCommonLocation += " - " + otherCity;
178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                return closestCommonLocation;
180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Compare thoroughfare (street address) next.
183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            closestCommonLocation = valueIfEqual(addr1.getThoroughfare(), addr2.getThoroughfare());
184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (closestCommonLocation != null && !("null".equals(closestCommonLocation))) {
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                return closestCommonLocation;
186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Compare the locality.
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        closestCommonLocation = valueIfEqual(addr1Locality, addr2Locality);
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (closestCommonLocation != null && !("".equals(closestCommonLocation))) {
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String adminArea = addr1AdminArea;
193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String countryCode = addr1CountryCode;
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (adminArea != null && adminArea.length() > 0) {
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (!countryCode.equals(currentCountry)) {
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    closestCommonLocation += ", " + adminArea + " " + countryCode;
197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                } else {
198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    closestCommonLocation += ", " + adminArea;
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return closestCommonLocation;
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // If the admin area is the same as the current location, we hide it and
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // instead show the city name.
206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (currentAdminArea.equals(addr1AdminArea) && currentAdminArea.equals(addr2AdminArea)) {
207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if ("".equals(addr1Locality)) {
208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                addr1Locality = addr2Locality;
209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if ("".equals(addr2Locality)) {
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                addr2Locality = addr1Locality;
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (!"".equals(addr1Locality)) {
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (addr1Locality.equals(addr2Locality)) {
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    closestCommonLocation = addr1Locality + ", " + currentAdminArea;
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                } else {
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    closestCommonLocation = addr1Locality + " - " + addr2Locality;
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                return closestCommonLocation;
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Just choose one of the localities if within a MAX_LOCALITY_MILE_RANGE
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // mile radius.
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        float[] distanceFloat = new float[1];
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Location.distanceBetween(setMinLatitude, setMinLongitude,
227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                setMaxLatitude, setMaxLongitude, distanceFloat);
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int distance = (int) GalleryUtils.toMile(distanceFloat[0]);
229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (distance < MAX_LOCALITY_MILE_RANGE) {
230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Try each of the points and just return the first one to have a
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // valid address.
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            closestCommonLocation = getLocalityAdminForAddress(addr1, true);
233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (closestCommonLocation != null) {
234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                return closestCommonLocation;
235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            closestCommonLocation = getLocalityAdminForAddress(addr2, true);
237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (closestCommonLocation != null) {
238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                return closestCommonLocation;
239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Check the administrative area.
243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        closestCommonLocation = valueIfEqual(addr1AdminArea, addr2AdminArea);
244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (closestCommonLocation != null && !("".equals(closestCommonLocation))) {
245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String countryCode = addr1CountryCode;
246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (!countryCode.equals(currentCountry)) {
247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (countryCode != null && countryCode.length() > 0) {
248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    closestCommonLocation += " " + countryCode;
249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return closestCommonLocation;
252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Check the country codes.
255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        closestCommonLocation = valueIfEqual(addr1CountryCode, addr2CountryCode);
256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (closestCommonLocation != null && !("".equals(closestCommonLocation))) {
257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return closestCommonLocation;
258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // There is no intersection, let's choose a nicer name.
260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String addr1Country = addr1.getCountryName();
261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String addr2Country = addr2.getCountryName();
262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (addr1Country == null)
263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            addr1Country = addr1CountryCode;
264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (addr2Country == null)
265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            addr2Country = addr2CountryCode;
266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (addr1Country == null || addr2Country == null)
267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (addr1Country.length() > MAX_COUNTRY_NAME_LENGTH || addr2Country.length() > MAX_COUNTRY_NAME_LENGTH) {
269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            closestCommonLocation = addr1CountryCode + " - " + addr2CountryCode;
270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            closestCommonLocation = addr1Country + " - " + addr2Country;
272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return closestCommonLocation;
274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private String checkNull(String locality) {
277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (locality == null)
278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return "";
279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (locality.equals("null"))
280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return "";
281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return locality;
282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private String getLocalityAdminForAddress(final Address addr, final boolean approxLocation) {
285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (addr == null)
286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return "";
287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String localityAdminStr = addr.getLocality();
288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (localityAdminStr != null && !("null".equals(localityAdminStr))) {
289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (approxLocation) {
290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                // TODO: Uncomment these lines as soon as we may translations
291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                // for Res.string.around.
292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                // localityAdminStr =
293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                // mContext.getResources().getString(Res.string.around) + " " +
294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                // localityAdminStr;
295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String adminArea = addr.getAdminArea();
297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (adminArea != null && adminArea.length() > 0) {
298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                localityAdminStr += ", " + adminArea;
299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return localityAdminStr;
301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return null;
303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public Address lookupAddress(final double latitude, final double longitude,
306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            boolean useCache) {
307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            long locationKey = (long) (((latitude + LAT_MAX) * 2 * LAT_MAX
309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    + (longitude + LON_MAX)) * EARTH_RADIUS_METERS);
310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            byte[] cachedLocation = null;
311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (useCache && mGeoCache != null) {
312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                cachedLocation = mGeoCache.lookup(locationKey);
313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Address address = null;
315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (cachedLocation == null || cachedLocation.length == 0) {
317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (networkInfo == null || !networkInfo.isConnected()) {
318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    return null;
319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                List<Address> addresses = mGeocoder.getFromLocation(latitude, longitude, 1);
321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (!addresses.isEmpty()) {
322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    address = addresses.get(0);
323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    DataOutputStream dos = new DataOutputStream(bos);
325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    Locale locale = address.getLocale();
326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, locale.getLanguage());
327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, locale.getCountry());
328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, locale.getVariant());
329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getThoroughfare());
331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    int numAddressLines = address.getMaxAddressLineIndex();
332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    dos.writeInt(numAddressLines);
333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    for (int i = 0; i < numAddressLines; ++i) {
334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        writeUTF(dos, address.getAddressLine(i));
335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getFeatureName());
337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getLocality());
338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getAdminArea());
339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getSubAdminArea());
340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getCountryName());
342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getCountryCode());
343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getPostalCode());
344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getPhone());
345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    writeUTF(dos, address.getUrl());
346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    dos.flush();
348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    if (mGeoCache != null) {
349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        mGeoCache.insert(locationKey, bos.toByteArray());
350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    dos.close();
352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                // Parsing the address from the byte stream.
355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                DataInputStream dis = new DataInputStream(
356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        new ByteArrayInputStream(cachedLocation));
357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                String language = readUTF(dis);
358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                String country = readUTF(dis);
359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                String variant = readUTF(dis);
360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Locale locale = null;
361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (language != null) {
362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    if (country == null) {
363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        locale = new Locale(language);
364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    } else if (variant == null) {
365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        locale = new Locale(language, country);
366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    } else {
367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        locale = new Locale(language, country, variant);
368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (!locale.getLanguage().equals(Locale.getDefault().getLanguage())) {
371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    dis.close();
372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    return lookupAddress(latitude, longitude, false);
373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address = new Address(locale);
375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setThoroughfare(readUTF(dis));
377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                int numAddressLines = dis.readInt();
378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                for (int i = 0; i < numAddressLines; ++i) {
379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    address.setAddressLine(i, readUTF(dis));
380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setFeatureName(readUTF(dis));
382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setLocality(readUTF(dis));
383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setAdminArea(readUTF(dis));
384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setSubAdminArea(readUTF(dis));
385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setCountryName(readUTF(dis));
387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setCountryCode(readUTF(dis));
388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setPostalCode(readUTF(dis));
389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setPhone(readUTF(dis));
390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                address.setUrl(readUTF(dis));
391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                dis.close();
392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return address;
394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } catch (Exception e) {
395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Ignore.
396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return null;
398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private String valueIfEqual(String a, String b) {
401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return (a != null && b != null && a.equalsIgnoreCase(b)) ? a : null;
402f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
403f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
404f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static final void writeUTF(DataOutputStream dos, String string) throws IOException {
405f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (string == null) {
406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            dos.writeUTF("");
407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
408f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            dos.writeUTF(string);
409f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
410f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
411f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
412f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static final String readUTF(DataInputStream dis) throws IOException {
413f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String retVal = dis.readUTF();
414f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (retVal.length() == 0)
415f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return null;
416f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return retVal;
417f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
418f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
419