• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 com.android.tv.common.util;
18 
19 import android.Manifest;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.location.Address;
23 import android.location.Geocoder;
24 import android.location.Location;
25 import android.location.LocationListener;
26 import android.location.LocationManager;
27 import android.os.Bundle;
28 import android.support.annotation.NonNull;
29 import android.text.TextUtils;
30 import android.util.Log;
31 import com.android.tv.common.BuildConfig;
32 
33 
34 
35 
36 import java.io.IOException;
37 import java.util.Collections;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Set;
42 
43 /** A utility class to get the current location. */
44 public class LocationUtils {
45     private static final String TAG = "LocationUtils";
46     private static final boolean DEBUG = false;
47 
48     private static final Set<OnUpdateAddressListener> sOnUpdateAddressListeners =
49             Collections.synchronizedSet(new HashSet<>());
50 
51     private static Context sApplicationContext;
52     private static Address sAddress;
53     private static String sCountry;
54     private static IOException sError;
55 
56     /** Checks the current location. */
getCurrentAddress(Context context)57     public static synchronized Address getCurrentAddress(Context context)
58             throws IOException, SecurityException {
59         if (sAddress != null) {
60             return sAddress;
61         }
62         if (sError != null) {
63             throw sError;
64         }
65         if (sApplicationContext == null) {
66             sApplicationContext = context.getApplicationContext();
67         }
68         LocationUtilsHelper.startLocationUpdates();
69         return null;
70     }
71 
72     /** The listener used when address is updated. */
73     public interface OnUpdateAddressListener {
74         /**
75          * Called when address is updated.
76          *
77          * This listener is removed when this method returns true.
78          *
79          * @return {@code true} if the job has been finished and the listener needs to be removed;
80          *         {@code false} otherwise.
81          */
onUpdateAddress(Address address)82         boolean onUpdateAddress(Address address);
83     }
84 
85     /**
86      * Add an {@link OnUpdateAddressListener} instance.
87      *
88      * Note that the listener is removed automatically when
89      * {@link OnUpdateAddressListener#onUpdateAddress(Address)} is called and returns {@code true}.
90      */
addOnUpdateAddressListener(OnUpdateAddressListener listener)91     public static void addOnUpdateAddressListener(OnUpdateAddressListener listener) {
92         sOnUpdateAddressListeners.add(listener);
93     }
94 
95     /**
96      * Remove an {@link OnUpdateAddressListener} instance if it exists.
97      *
98      * Note that the listener will be removed automatically when
99      * {@link OnUpdateAddressListener#onUpdateAddress(Address)} is called and returns {@code true}.
100      */
removeOnUpdateAddressListener(OnUpdateAddressListener listener)101     public static void removeOnUpdateAddressListener(OnUpdateAddressListener listener) {
102         sOnUpdateAddressListeners.remove(listener);
103     }
104 
105     /** Returns the current country. */
106     @NonNull
getCurrentCountry(Context context)107     public static synchronized String getCurrentCountry(Context context) {
108         if (sCountry != null) {
109             return sCountry;
110         }
111         if (TextUtils.isEmpty(sCountry)) {
112             sCountry = context.getResources().getConfiguration().locale.getCountry();
113         }
114         return sCountry;
115     }
116 
updateAddress(Location location)117     private static void updateAddress(Location location) {
118         if (DEBUG) Log.d(TAG, "Updating address with " + location);
119         if (location == null) {
120             return;
121         }
122         Geocoder geocoder = new Geocoder(sApplicationContext, Locale.getDefault());
123         try {
124             List<Address> addresses =
125                     geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
126             if (addresses != null && !addresses.isEmpty()) {
127                 sAddress = addresses.get(0);
128                 if (DEBUG) Log.d(TAG, "Got " + sAddress);
129                 try {
130                     PostalCodeUtils.updatePostalCode(sApplicationContext);
131                 } catch (Exception e) {
132                     // Do nothing
133                 }
134                 Set<OnUpdateAddressListener> listenersToRemove = new HashSet<>();
135                 synchronized (sOnUpdateAddressListeners) {
136                     for (OnUpdateAddressListener listener : sOnUpdateAddressListeners) {
137                         if (listener.onUpdateAddress(sAddress)) {
138                             listenersToRemove.add(listener);
139                         }
140                     }
141                     for (OnUpdateAddressListener listener : listenersToRemove) {
142                         removeOnUpdateAddressListener(listener);
143                     }
144                 }
145             } else {
146                 if (DEBUG) Log.d(TAG, "No address returned");
147             }
148             sError = null;
149         } catch (IOException e) {
150             Log.w(TAG, "Error in updating address", e);
151             sError = e;
152         }
153     }
154 
LocationUtils()155     private LocationUtils() {}
156 
157     private static class LocationUtilsHelper {
158         private static final LocationListener LOCATION_LISTENER =
159                 new LocationListener() {
160                     @Override
161                     public void onLocationChanged(Location location) {
162                         updateAddress(location);
163                     }
164 
165                     @Override
166                     public void onStatusChanged(String provider, int status, Bundle extras) {}
167 
168                     @Override
169                     public void onProviderEnabled(String provider) {}
170 
171                     @Override
172                     public void onProviderDisabled(String provider) {}
173                 };
174 
175         private static LocationManager sLocationManager;
176 
startLocationUpdates()177         public static void startLocationUpdates() {
178             if (sLocationManager == null) {
179                 sLocationManager =
180                         (LocationManager)
181                                 sApplicationContext.getSystemService(Context.LOCATION_SERVICE);
182                 try {
183                     sLocationManager.requestLocationUpdates(
184                             LocationManager.NETWORK_PROVIDER, 1000, 10, LOCATION_LISTENER, null);
185                 } catch (SecurityException e) {
186                     // Enables requesting the location updates again.
187                     sLocationManager = null;
188                     throw e;
189                 }
190             }
191         }
192     }
193 }
194