1 /* 2 * Copyright (C) 2010 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 package com.android.server.location; 17 18 import android.location.Country; 19 import android.location.CountryListener; 20 import android.location.Location; 21 import android.location.LocationListener; 22 import android.location.LocationManager; 23 import android.test.AndroidTestCase; 24 25 import java.util.Arrays; 26 import java.util.HashMap; 27 import java.util.HashSet; 28 import java.util.List; 29 import java.util.Map; 30 import java.util.Map.Entry; 31 import java.util.Set; 32 import java.util.Timer; 33 34 public class LocationBasedCountryDetectorTest extends AndroidTestCase { 35 private static final List<String> sEnabledProviders = Arrays.asList( 36 LocationManager.GPS_PROVIDER, LocationManager.PASSIVE_PROVIDER); 37 private class TestCountryDetector extends LocationBasedCountryDetector { 38 public static final int TOTAL_PROVIDERS = 2; 39 protected Object countryFoundLocker = new Object(); 40 protected boolean notifyCountry = false; 41 private final Location mLocation; 42 private final String mCountry; 43 private final long mQueryLocationTimeout; 44 private Map<String, LocationListener> mListeners; 45 46 public TestCountryDetector(String country, String provider) { 47 this(country, provider, 1000 * 60 * 5); 48 } 49 50 public TestCountryDetector(String country, String provider, long queryLocationTimeout) { 51 super(getContext()); 52 mCountry = country; 53 mLocation = new Location(provider); 54 mQueryLocationTimeout = queryLocationTimeout; 55 mListeners = new HashMap<String, LocationListener>(); 56 } 57 58 @Override 59 protected String getCountryFromLocation(Location location) { 60 synchronized (countryFoundLocker) { 61 if (!notifyCountry) { 62 try { 63 countryFoundLocker.wait(); 64 } catch (InterruptedException e) { 65 } 66 } 67 } 68 if (mLocation.getProvider().endsWith(location.getProvider())) { 69 return mCountry; 70 } else { 71 return null; 72 } 73 } 74 75 @Override 76 protected Location getLastKnownLocation() { 77 return mLocation; 78 } 79 80 private Set<String> mAcceptableProviders; 81 82 public void setAcceptableProvider(Set<String> acceptableProviders) { 83 mAcceptableProviders = acceptableProviders; 84 } 85 86 @Override 87 protected boolean isAcceptableProvider(String provider) { 88 if (mAcceptableProviders != null) { 89 return mAcceptableProviders.contains(provider); 90 } else { 91 return true; 92 } 93 } 94 95 @Override 96 protected void registerListener(String provider, LocationListener listener) { 97 assertNotNull(provider); 98 mListeners.put(provider, listener); 99 } 100 101 @Override 102 protected void unregisterListener(LocationListener listener) { 103 for (Entry<String, LocationListener> entry : mListeners.entrySet()) { 104 if (entry.getValue().equals(listener)) { 105 mListeners.remove(entry.getKey()); 106 return; 107 } 108 } 109 fail("Not registered"); 110 } 111 112 public Map<String, LocationListener> getListeners() { 113 return mListeners; 114 } 115 116 @Override 117 protected long getQueryLocationTimeout() { 118 return mQueryLocationTimeout; 119 } 120 121 @Override 122 protected List<String> getEnabledProviders() { 123 return sEnabledProviders; 124 } 125 126 public void notifyLocationFound() { 127 // Listener could be removed in the notification. 128 LocationListener[] listeners = new LocationListener[mListeners.size()]; 129 mLocationListeners.toArray(listeners); 130 for (LocationListener listener :listeners) { 131 listener.onLocationChanged(mLocation); 132 } 133 } 134 135 public int getListenersCount() { 136 return mListeners.size(); 137 } 138 139 public void notifyCountryFound() { 140 synchronized (countryFoundLocker) { 141 notifyCountry = true; 142 countryFoundLocker.notify(); 143 } 144 } 145 146 public Timer getTimer() { 147 return mTimer; 148 } 149 150 public Thread getQueryThread() { 151 return mQueryThread; 152 } 153 } 154 155 private class CountryListenerImpl implements CountryListener { 156 private boolean mNotified; 157 private String mCountryCode; 158 public void onCountryDetected(Country country) { 159 mNotified = true; 160 if (country != null) { 161 mCountryCode = country.getCountryIso(); 162 } 163 } 164 165 public boolean notified() { 166 return mNotified; 167 } 168 169 public String getCountry() { 170 return mCountryCode; 171 } 172 } 173 174 public void testFindingCountry() { 175 testFindingCountryCommon(null); 176 } 177 178 public void testFindingCountryWithAcceptableProvider() { 179 testFindingCountryCommon(new HashSet<String>(Arrays.asList("passive"))); 180 } 181 182 private void testFindingCountryCommon(Set<String> acceptableProviders) { 183 final String country = "us"; 184 final String provider = "Good"; 185 CountryListenerImpl countryListener = new CountryListenerImpl(); 186 TestCountryDetector detector = new TestCountryDetector(country, provider); 187 188 if (acceptableProviders != null) { 189 detector.setAcceptableProvider(acceptableProviders); 190 } 191 192 detector.setCountryListener(countryListener); 193 detector.detectCountry(); 194 195 if (acceptableProviders != null) { 196 assertEquals(acceptableProviders.size(), detector.getListenersCount()); 197 Map<String, LocationListener> listeners = detector.getListeners(); 198 for (String acceptableProvider : acceptableProviders) { 199 assertTrue(listeners.containsKey(acceptableProvider)); 200 } 201 } else { 202 assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount()); 203 } 204 205 detector.notifyLocationFound(); 206 // All listeners should be unregistered 207 assertEquals(0, detector.getListenersCount()); 208 assertNull(detector.getTimer()); 209 Thread queryThread = waitForQueryThreadLaunched(detector); 210 detector.notifyCountryFound(); 211 // Wait for query thread ending 212 waitForThreadEnding(queryThread); 213 // QueryThread should be set to NULL 214 assertNull(detector.getQueryThread()); 215 assertTrue(countryListener.notified()); 216 assertEquals("us", countryListener.getCountry().toLowerCase()); 217 } 218 219 public void testFindingCountryCancelled() { 220 final String country = "us"; 221 final String provider = "Good"; 222 CountryListenerImpl countryListener = new CountryListenerImpl(); 223 TestCountryDetector detector = new TestCountryDetector(country, provider); 224 detector.setCountryListener(countryListener); 225 detector.detectCountry(); 226 assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount()); 227 detector.notifyLocationFound(); 228 // All listeners should be unregistered 229 assertEquals(0, detector.getListenersCount()); 230 // The time should be stopped 231 assertNull(detector.getTimer()); 232 Thread queryThread = waitForQueryThreadLaunched(detector); 233 detector.stop(); 234 // There is no way to stop the thread, let's test it could be stopped, after get country 235 detector.notifyCountryFound(); 236 // Wait for query thread ending 237 waitForThreadEnding(queryThread); 238 // QueryThread should be set to NULL 239 assertNull(detector.getQueryThread()); 240 assertTrue(countryListener.notified()); 241 assertEquals("us", countryListener.getCountry().toLowerCase()); 242 } 243 244 public void testFindingLocationCancelled() { 245 final String country = "us"; 246 final String provider = "Good"; 247 CountryListenerImpl countryListener = new CountryListenerImpl(); 248 TestCountryDetector detector = new TestCountryDetector(country, provider); 249 detector.setCountryListener(countryListener); 250 detector.detectCountry(); 251 assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount()); 252 detector.stop(); 253 // All listeners should be unregistered 254 assertEquals(0, detector.getListenersCount()); 255 // The time should be stopped 256 assertNull(detector.getTimer()); 257 // QueryThread should still be NULL 258 assertNull(detector.getQueryThread()); 259 assertFalse(countryListener.notified()); 260 } 261 262 public void testFindingLocationFailed() { 263 final String country = "us"; 264 final String provider = "Good"; 265 long timeout = 1000; 266 TestCountryDetector detector = new TestCountryDetector(country, provider, timeout) { 267 @Override 268 protected Location getLastKnownLocation() { 269 return null; 270 } 271 }; 272 CountryListenerImpl countryListener = new CountryListenerImpl(); 273 detector.setCountryListener(countryListener); 274 detector.detectCountry(); 275 assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount()); 276 waitForTimerReset(detector); 277 // All listeners should be unregistered 278 assertEquals(0, detector.getListenersCount()); 279 // QueryThread should still be NULL 280 assertNull(detector.getQueryThread()); 281 assertTrue(countryListener.notified()); 282 assertNull(countryListener.getCountry()); 283 } 284 285 public void testFindingCountryFailed() { 286 final String country = "us"; 287 final String provider = "Good"; 288 TestCountryDetector detector = new TestCountryDetector(country, provider) { 289 @Override 290 protected String getCountryFromLocation(Location location) { 291 synchronized (countryFoundLocker) { 292 if (! notifyCountry) { 293 try { 294 countryFoundLocker.wait(); 295 } catch (InterruptedException e) { 296 } 297 } 298 } 299 // We didn't find country. 300 return null; 301 } 302 }; 303 CountryListenerImpl countryListener = new CountryListenerImpl(); 304 detector.setCountryListener(countryListener); 305 detector.detectCountry(); 306 assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount()); 307 detector.notifyLocationFound(); 308 // All listeners should be unregistered 309 assertEquals(0, detector.getListenersCount()); 310 assertNull(detector.getTimer()); 311 Thread queryThread = waitForQueryThreadLaunched(detector); 312 detector.notifyCountryFound(); 313 // Wait for query thread ending 314 waitForThreadEnding(queryThread); 315 // QueryThread should be set to NULL 316 assertNull(detector.getQueryThread()); 317 // CountryListener should be notified 318 assertTrue(countryListener.notified()); 319 assertNull(countryListener.getCountry()); 320 } 321 322 public void testFindingCountryWithLastKnownLocation() { 323 final String country = "us"; 324 final String provider = "Good"; 325 long timeout = 1000; 326 TestCountryDetector detector = new TestCountryDetector(country, provider, timeout); 327 CountryListenerImpl countryListener = new CountryListenerImpl(); 328 detector.setCountryListener(countryListener); 329 detector.detectCountry(); 330 assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount()); 331 waitForTimerReset(detector); 332 // All listeners should be unregistered 333 assertEquals(0, detector.getListenersCount()); 334 Thread queryThread = waitForQueryThreadLaunched(detector); 335 detector.notifyCountryFound(); 336 // Wait for query thread ending 337 waitForThreadEnding(queryThread); 338 // QueryThread should be set to NULL 339 assertNull(detector.getQueryThread()); 340 // CountryListener should be notified 341 assertTrue(countryListener.notified()); 342 assertEquals("us", countryListener.getCountry().toLowerCase()); 343 } 344 345 private void waitForTimerReset(TestCountryDetector detector) { 346 int count = 5; 347 long interval = 1000; 348 try { 349 while (count-- > 0 && detector.getTimer() != null) { 350 Thread.sleep(interval); 351 } 352 } catch (InterruptedException e) { 353 } 354 Timer timer = detector.getTimer(); 355 assertTrue(timer == null); 356 } 357 358 private void waitForThreadEnding(Thread thread) { 359 try { 360 thread.join(5000); 361 } catch (InterruptedException e) { 362 e.printStackTrace(); 363 } 364 } 365 366 private Thread waitForQueryThreadLaunched(TestCountryDetector detector) { 367 int count = 5; 368 long interval = 1000; 369 try { 370 while (count-- > 0 && detector.getQueryThread() == null) { 371 Thread.sleep(interval); 372 } 373 } catch (InterruptedException e) { 374 } 375 Thread thread = detector.getQueryThread(); 376 assertTrue(thread != null); 377 return thread; 378 } 379 } 380