listenerRegistrations = entry.getValue();
+ for (int i = listenerRegistrations.size() - 1; i >= 0; i--) {
+ LocationListener listener = listenerRegistrations.get(i).listener;
+ if(removedLocationListeners.contains(listener)) {
+ listenerRegistrations.remove(i);
+ }
+ }
+ }
+ }
+
+ @Implementation
+ public void removeUpdates(PendingIntent pendingIntent) {
+ while (requestLocationUdpateCriteriaPendingIntents.remove(pendingIntent) != null);
+ while (requestLocationUdpateProviderPendingIntents.remove(pendingIntent) != null);
+ }
+
+ public boolean hasGpsStatusListener(Listener listener) {
+ return gpsStatusListeners.contains(listener);
+ }
+
+ /**
+ * Non-Android accessor.
+ *
+ *
+ * Gets the criteria value used in the last call to {@link #getBestProvider(android.location.Criteria, boolean)}
+ *
+ * @return the criteria used to find the best provider
+ */
+ public Criteria getLastBestProviderCriteria() {
+ return lastBestProviderCriteria;
+ }
+
+ /**
+ * Non-Android accessor.
+ *
+ *
+ * Gets the enabled value used in the last call to {@link #getBestProvider(android.location.Criteria, boolean)}
+ *
+ * @return the enabled value used to find the best provider
+ */
+ public boolean getLastBestProviderEnabledOnly() {
+ return lastBestProviderEnabled;
+ }
+
+ /**
+ * Sets the value to return from {@link #getBestProvider(android.location.Criteria, boolean)} for the given
+ * {@code provider}
+ *
+ * @param provider name of the provider who should be considered best
+ * @param enabled Enabled
+ * @param criteria List of criteria
+ * @throws Exception if provider is not known
+ * @return false If provider is not enabled but it is supposed to be set as the best enabled provider don't set it, otherwise true
+ */
+ public boolean setBestProvider(String provider, boolean enabled, List criteria) throws Exception {
+ if (!getAllProviders().contains(provider)) {
+ throw new IllegalStateException("Best provider is not a known provider");
+ }
+ // If provider is not enabled but it is supposed to be set as the best enabled provider don't set it.
+ for (String prvdr : providersEnabled.keySet()) {
+ if (provider.equals(prvdr) && providersEnabled.get(prvdr).enabled != enabled) {
return false;
- }
-
- @Implementation
- public List getAllProviders() {
- Set allKnownProviders = new LinkedHashSet<>(providersEnabled.keySet());
- allKnownProviders.add(LocationManager.GPS_PROVIDER);
- allKnownProviders.add(LocationManager.NETWORK_PROVIDER);
- allKnownProviders.add(LocationManager.PASSIVE_PROVIDER);
-
- return new ArrayList<>(allKnownProviders);
- }
-
- /**
- * Sets the value to return from {@link #isProviderEnabled(String)} for the given {@code
- * provider}
- *
- * @param provider
- * name of the provider whose status to set
- * @param isEnabled
- * whether that provider should appear enabled
- */
- public void setProviderEnabled(String provider, boolean isEnabled) {
- setProviderEnabled(provider, isEnabled, null);
- }
-
- public void setProviderEnabled(String provider, boolean isEnabled, List criteria) {
- LocationProviderEntry providerEntry = providersEnabled.get(provider);
- if (providerEntry == null) {
- providerEntry = new LocationProviderEntry();
- }
- providerEntry.enabled = isEnabled;
- providerEntry.criteria = criteria;
- providersEnabled.put(provider, providerEntry);
- List locationUpdateListeners = new ArrayList<>(
- getRequestLocationUpdateListeners());
- for (LocationListener locationUpdateListener : locationUpdateListeners) {
- if (isEnabled) {
- locationUpdateListener.onProviderEnabled(provider);
- } else {
- locationUpdateListener.onProviderDisabled(provider);
- }
- }
- // Send intent to notify about provider status
- final Intent intent = new Intent();
- intent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, isEnabled);
- ShadowApplication.getInstance().sendBroadcast(intent);
- Set requestLocationUdpatePendingIntentSet =
- requestLocationUdpateCriteriaPendingIntents.keySet();
- for (PendingIntent requestLocationUdpatePendingIntent :
- requestLocationUdpatePendingIntentSet) {
- try {
- requestLocationUdpatePendingIntent.send();
- } catch (PendingIntent.CanceledException e) {
- requestLocationUdpateCriteriaPendingIntents
- .remove(requestLocationUdpatePendingIntent);
- }
- }
- // if this provider gets disabled and it was the best active provider, then it's not anymore
- if (provider.equals(bestEnabledProvider) && !isEnabled) {
- bestEnabledProvider = null;
- }
- }
-
- @Implementation
- public List getProviders(boolean enabledOnly) {
- ArrayList enabledProviders = new ArrayList<>();
- for (String provider : getAllProviders()) {
- if (!enabledOnly || providersEnabled.get(provider) != null) {
- enabledProviders.add(provider);
- }
- }
- return enabledProviders;
- }
-
- @Implementation
- public Location getLastKnownLocation(String provider) {
- return lastKnownLocations.get(provider);
- }
-
- @Implementation
- public boolean addGpsStatusListener(GpsStatus.Listener listener) {
- if (!gpsStatusListeners.contains(listener)) {
- gpsStatusListeners.add(listener);
- }
- return true;
- }
-
- @Implementation
- public void removeGpsStatusListener(GpsStatus.Listener listener) {
- gpsStatusListeners.remove(listener);
- }
-
- @Implementation
- public String getBestProvider(Criteria criteria, boolean enabled) {
- lastBestProviderCriteria = criteria;
- lastBestProviderEnabled = enabled;
-
- if (criteria == null) {
- return getBestProviderWithNoCriteria(enabled);
- }
-
- return getBestProviderWithCriteria(criteria, enabled);
- }
-
- private String getBestProviderWithCriteria(Criteria criteria, boolean enabled) {
- List providers = getProviders(enabled);
- int powerRequirement = criteria.getPowerRequirement();
- int accuracy = criteria.getAccuracy();
- for (String provider : providers) {
- LocationProviderEntry locationProviderEntry = providersEnabled.get(provider);
- if (locationProviderEntry == null) {
- continue;
- }
- List criteriaList = locationProviderEntry.getValue();
- if (criteriaList == null) {
- continue;
- }
- for (Criteria criteriaListItem : criteriaList) {
- if (criteria.equals(criteriaListItem)) {
- return provider;
- } else if (criteriaListItem.getAccuracy() == accuracy) {
- return provider;
- } else if (criteriaListItem.getPowerRequirement() == powerRequirement) {
- return provider;
- }
- }
- }
- // TODO: these conditions are incomplete
- for (String provider : providers) {
- if (provider.equals(LocationManager.NETWORK_PROVIDER) && (accuracy ==
- Criteria.ACCURACY_COARSE || powerRequirement == Criteria.POWER_LOW)) {
- return provider;
- } else if (provider.equals(LocationManager.GPS_PROVIDER) && accuracy ==
- Criteria.ACCURACY_FINE && powerRequirement != Criteria.POWER_LOW) {
- return provider;
- }
- }
-
- // No enabled provider found with the desired criteria, then return the the first registered
- // provider(?)
- return providers.isEmpty() ? null : providers.get(0);
- }
-
- private String getBestProviderWithNoCriteria(boolean enabled) {
- List providers = getProviders(enabled);
-
- if (enabled && bestEnabledProvider != null) {
- return bestEnabledProvider;
- } else if (bestDisabledProvider != null) {
- return bestDisabledProvider;
- } else if (providers.contains(LocationManager.GPS_PROVIDER)) {
- return LocationManager.GPS_PROVIDER;
- } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
- return LocationManager.NETWORK_PROVIDER;
- }
- return null;
- }
-
- @Implementation
- public void requestLocationUpdates(String provider, long minTime, float minDistance,
- LocationListener listener) {
- addLocationListener(provider, listener, minTime, minDistance);
- }
-
- private void addLocationListener(String provider, LocationListener listener, long minTime,
- float minDistance) {
- List providerListeners = locationListeners.get(provider);
- if (providerListeners == null) {
- providerListeners = new ArrayList<>();
- locationListeners.put(provider, providerListeners);
- }
- ListenerRegistration registrationToAdd = new ListenerRegistration(provider,
- minTime, minDistance, copyOf(getLastKnownLocation(provider)), listener);
- for (ListenerRegistration registration : providerListeners) {
- if (registration.equals(registrationToAdd)) {
- providerListeners.remove(registration);
- break;
- }
- }
- providerListeners.add(registrationToAdd);
-
- }
-
- @Implementation
- public void requestLocationUpdates(String provider, long minTime, float minDistance,
- LocationListener listener, Looper looper) {
- addLocationListener(provider, listener, minTime, minDistance);
- }
-
- @Implementation
- public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
- PendingIntent pendingIntent) {
- if (pendingIntent == null) {
- throw new IllegalStateException("Intent must not be null");
- }
- if (getBestProvider(criteria, true) == null) {
- throw new IllegalArgumentException("no providers found for criteria");
- }
- requestLocationUdpateCriteriaPendingIntents.put(pendingIntent, criteria);
- }
-
- @Implementation
- public void requestLocationUpdates(String provider, long minTime, float minDistance,
- PendingIntent pendingIntent) {
- if (pendingIntent == null) {
- throw new IllegalStateException("Intent must not be null");
- }
- if (!providersEnabled.containsKey(provider)) {
- throw new IllegalArgumentException("no providers found");
- }
-
- requestLocationUdpateProviderPendingIntents.put(pendingIntent, provider);
- }
-
- @Implementation
- public void removeUpdates(LocationListener listener) {
- removedLocationListeners.add(listener);
- }
-
- private void cleanupRemovedLocationListeners() {
- for (Map.Entry> entry : locationListeners.entrySet()) {
- List listenerRegistrations = entry.getValue();
- for (int i = listenerRegistrations.size() - 1; i >= 0; i--) {
- LocationListener listener = listenerRegistrations.get(i).listener;
- if (removedLocationListeners.contains(listener)) {
- listenerRegistrations.remove(i);
- }
- }
- }
- }
-
- @Implementation
- public void removeUpdates(PendingIntent pendingIntent) {
- while (requestLocationUdpateCriteriaPendingIntents.containsKey(pendingIntent)) {
- requestLocationUdpateCriteriaPendingIntents.remove(pendingIntent);
- }
- while (requestLocationUdpateProviderPendingIntents.containsKey(pendingIntent)) {
- requestLocationUdpateProviderPendingIntents.remove(pendingIntent);
- }
- }
-
- public boolean hasGpsStatusListener(GpsStatus.Listener listener) {
- return gpsStatusListeners.contains(listener);
- }
-
- /**
- * Non-Android accessor.
- *
- *
- * Gets the criteria value used in the last call to {@link #getBestProvider(
- * android.location.Criteria, boolean)}
- *
- * @return the criteria used to find the best provider
- */
- public Criteria getLastBestProviderCriteria() {
- return lastBestProviderCriteria;
- }
-
- /**
- * Non-Android accessor.
- *
- *
- * Gets the enabled value used in the last call to {@link #getBestProvider(
- * android.location.Criteria, boolean)}
- *
- * @return the enabled value used to find the best provider
- */
- public boolean getLastBestProviderEnabledOnly() {
- return lastBestProviderEnabled;
- }
-
- /**
- * Sets the value to return from {@link #getBestProvider(android.location.Criteria, boolean)}
- * for the given
- * {@code provider}
- *
- * @param provider name of the provider who should be considered best
- * @param enabled Enabled
- * @param criteria List of criteria
- * @throws Exception if provider is not known
- * @return false If provider is not enabled but it is supposed to be set as the best enabled
- * provider don't set it, otherwise true
- */
- public boolean setBestProvider(String provider, boolean enabled, List criteria)
- throws Exception {
- if (!getAllProviders().contains(provider)) {
- throw new IllegalStateException("Best provider is not a known provider");
- }
- // If provider is not enabled but it is supposed to be set as the best enabled provider
- // don't set it.
- for (String prvdr : providersEnabled.keySet()) {
- if (provider.equals(prvdr) && providersEnabled.get(prvdr).enabled != enabled) {
- return false;
- }
- }
-
- if (enabled) {
- bestEnabledProvider = provider;
- if (provider.equals(bestDisabledProvider)) {
- bestDisabledProvider = null;
- }
- } else {
- bestDisabledProvider = provider;
- if (provider.equals(bestEnabledProvider)) {
- bestEnabledProvider = null;
- }
- }
- if (criteria == null) {
- return true;
- }
- LocationProviderEntry entry;
- if (!providersEnabled.containsKey(provider)) {
- entry = new LocationProviderEntry();
- entry.enabled = enabled;
- entry.criteria = criteria;
- } else {
- entry = providersEnabled.get(provider);
- }
- providersEnabled.put(provider, entry);
-
- return true;
- }
-
- public boolean setBestProvider(String provider, boolean enabled) throws Exception {
- return setBestProvider(provider, enabled, null);
- }
-
- /**
- * Sets the value to return from {@link #getLastKnownLocation(String)} for the given {@code
- * provider}
- *
- * @param provider
- * name of the provider whose location to set
- * @param location
- * the last known location for the provider
- */
- public void setLastKnownLocation(String provider, Location location) {
- lastKnownLocations.put(provider, location);
- }
-
- /**
- * Non-Android accessor.
- *
- * @return lastRequestedLocationUpdatesLocationListener
- */
- public List getRequestLocationUpdateListeners() {
- cleanupRemovedLocationListeners();
- List all = new ArrayList<>();
- for (Map.Entry> entry : locationListeners.entrySet()) {
- for (ListenerRegistration reg : entry.getValue()) {
- all.add(reg.listener);
- }
- }
-
- return all;
- }
-
- public void simulateLocation(Location location) {
- cleanupRemovedLocationListeners();
- setLastKnownLocation(location.getProvider(), location);
-
- List providerListeners = locationListeners.get(
- location.getProvider());
- if (providerListeners == null) {
- return;
- }
-
- for (ListenerRegistration listenerReg : providerListeners) {
- if (listenerReg.lastSeenLocation != null && location != null) {
- float distanceChange = distanceBetween(location, listenerReg.lastSeenLocation);
- boolean withinMinDistance = distanceChange < listenerReg.minDistance;
- boolean exceededMinTime = location.getTime() - listenerReg.lastSeenTime >
- listenerReg.minTime;
- if (withinMinDistance || !exceededMinTime) {
- continue;
- }
- }
- listenerReg.lastSeenLocation = copyOf(location);
- listenerReg.lastSeenTime = location == null ? 0 : location.getTime();
- listenerReg.listener.onLocationChanged(copyOf(location));
- }
- cleanupRemovedLocationListeners();
- }
-
- private Location copyOf(Location location) {
- if (location == null) {
- return null;
- }
- Location copy = new Location(location);
- copy.setAccuracy(location.getAccuracy());
- copy.setAltitude(location.getAltitude());
- copy.setBearing(location.getBearing());
- copy.setExtras(location.getExtras());
- copy.setLatitude(location.getLatitude());
- copy.setLongitude(location.getLongitude());
- copy.setProvider(location.getProvider());
- copy.setSpeed(location.getSpeed());
- copy.setTime(location.getTime());
- return copy;
- }
-
- /**
- * Returns the distance between the two locations in meters.
- * Adapted from: http://stackoverflow.com/questions/837872/calculate-distance-in-meters-when-
- * you-know-longitude-and-latitude-in-java
- */
- private static float distanceBetween(Location location1, Location location2) {
- double earthRadius = 3958.75;
- double latDifference = Math.toRadians(location2.getLatitude() - location1.getLatitude());
- double lonDifference = Math.toRadians(location2.getLongitude() - location2.getLongitude());
- double a = Math.sin(latDifference / 2) * Math.sin(latDifference / 2) +
- Math.cos(Math.toRadians(location1.getLatitude())) * Math.cos(Math.toRadians(
- location2.getLatitude())) *
- Math.sin(lonDifference / 2) * Math.sin(lonDifference / 2);
- double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- double dist = Math.abs(earthRadius * c);
-
- int meterConversion = 1609;
-
- return new Float(dist * meterConversion);
- }
-
- public Map getRequestLocationUdpateCriteriaPendingIntents() {
- return requestLocationUdpateCriteriaPendingIntents;
- }
-
- public Map getRequestLocationUdpateProviderPendingIntents() {
- return requestLocationUdpateProviderPendingIntents;
- }
-
- public Collection getProvidersForListener(LocationListener listener) {
- cleanupRemovedLocationListeners();
- Set providers = new HashSet<>();
- for (List listenerRegistrations : locationListeners.values()) {
- for (ListenerRegistration listenerRegistration : listenerRegistrations) {
- if (listenerRegistration.listener == listener) {
- providers.add(listenerRegistration.provider);
- }
- }
- }
- return providers;
- }
-
- @Implementation
- public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
- }
-
- private final class LocationProviderEntry implements Map.Entry> {
- private Boolean enabled;
- private List criteria;
-
- @Override
- public Boolean getKey() {
- return enabled;
- }
-
- @Override
- public List getValue() {
- return criteria;
- }
-
- @Override
- public List setValue(List criteria) {
- List oldCriteria = this.criteria;
- this.criteria = criteria;
- return oldCriteria;
- }
- }
-
+ }
+ }
+
+ if (enabled) {
+ bestEnabledProvider = provider;
+ if (provider.equals(bestDisabledProvider)) {
+ bestDisabledProvider = null;
+ }
+ } else {
+ bestDisabledProvider = provider;
+ if (provider.equals(bestEnabledProvider)) {
+ bestEnabledProvider = null;
+ }
+ }
+ if (criteria == null) {
+ return true;
+ }
+ LocationProviderEntry entry;
+ if (!providersEnabled.containsKey(provider)) {
+ entry = new LocationProviderEntry();
+ entry.enabled = enabled;
+ entry.criteria = criteria;
+ } else {
+ entry = providersEnabled.get(provider);
+ }
+ providersEnabled.put(provider, entry);
+
+ return true;
+ }
+
+ public boolean setBestProvider(String provider, boolean enabled) throws Exception {
+ return setBestProvider(provider, enabled, null);
+ }
+
+ /**
+ * Sets the value to return from {@link #getLastKnownLocation(String)} for the given {@code provider}
+ *
+ * @param provider
+ * name of the provider whose location to set
+ * @param location
+ * the last known location for the provider
+ */
+ public void setLastKnownLocation(String provider, Location location) {
+ lastKnownLocations.put(provider, location);
+ }
+
+ /**
+ * Non-Android accessor.
+ *
+ * @return lastRequestedLocationUpdatesLocationListener
+ */
+ public List getRequestLocationUpdateListeners() {
+ cleanupRemovedLocationListeners();
+ List all = new ArrayList<>();
+ for (Map.Entry> entry : locationListeners.entrySet()) {
+ for (ListenerRegistration reg : entry.getValue()) {
+ all.add(reg.listener);
+ }
+ }
+
+ return all;
+ }
+
+ public void simulateLocation(Location location) {
+ cleanupRemovedLocationListeners();
+ setLastKnownLocation(location.getProvider(), location);
+
+ List providerListeners = locationListeners.get(
+ location.getProvider());
+ if (providerListeners == null) return;
+
+ for (ListenerRegistration listenerReg : providerListeners) {
+ if(listenerReg.lastSeenLocation != null && location != null) {
+ float distanceChange = distanceBetween(location, listenerReg.lastSeenLocation);
+ boolean withinMinDistance = distanceChange < listenerReg.minDistance;
+ boolean exceededMinTime = location.getTime() - listenerReg.lastSeenTime > listenerReg.minTime;
+ if (withinMinDistance || !exceededMinTime) continue;
+ }
+ listenerReg.lastSeenLocation = copyOf(location);
+ listenerReg.lastSeenTime = location == null ? 0 : location.getTime();
+ listenerReg.listener.onLocationChanged(copyOf(location));
+ }
+ cleanupRemovedLocationListeners();
+ }
+
+ private Location copyOf(Location location) {
+ if (location == null) return null;
+ Location copy = new Location(location);
+ copy.setAccuracy(location.getAccuracy());
+ copy.setAltitude(location.getAltitude());
+ copy.setBearing(location.getBearing());
+ copy.setExtras(location.getExtras());
+ copy.setLatitude(location.getLatitude());
+ copy.setLongitude(location.getLongitude());
+ copy.setProvider(location.getProvider());
+ copy.setSpeed(location.getSpeed());
+ copy.setTime(location.getTime());
+ return copy;
+ }
+
+ /**
+ * Returns the distance between the two locations in meters.
+ * Adapted from: http://stackoverflow.com/questions/837872/calculate-distance-in-meters-when-you-know-longitude-and-latitude-in-java
+ */
+ private static float distanceBetween(Location location1, Location location2) {
+ double earthRadius = 3958.75;
+ double latDifference = Math.toRadians(location2.getLatitude() - location1.getLatitude());
+ double lonDifference = Math.toRadians(location2.getLongitude() - location2.getLongitude());
+ double a = Math.sin(latDifference/2) * Math.sin(latDifference/2) +
+ Math.cos(Math.toRadians(location1.getLatitude())) * Math.cos(Math.toRadians(location2.getLatitude())) *
+ Math.sin(lonDifference/2) * Math.sin(lonDifference/2);
+ double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
+ double dist = Math.abs(earthRadius * c);
+
+ int meterConversion = 1609;
+
+ return new Float(dist * meterConversion);
+ }
+
+ public Map getRequestLocationUdpateCriteriaPendingIntents() {
+ return requestLocationUdpateCriteriaPendingIntents;
+ }
+
+ public Map getRequestLocationUdpateProviderPendingIntents() {
+ return requestLocationUdpateProviderPendingIntents;
+ }
+
+ public Collection getProvidersForListener(LocationListener listener) {
+ cleanupRemovedLocationListeners();
+ Set providers = new HashSet<>();
+ for (List listenerRegistrations : locationListeners.values()) {
+ for (ListenerRegistration listenerRegistration : listenerRegistrations) {
+ if (listenerRegistration.listener == listener) {
+ providers.add(listenerRegistration.provider);
+ }
+ }
+ }
+ return providers;
+ }
+
+ @Implementation
+ public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
+ }
+
+ final private class LocationProviderEntry implements Map.Entry> {
+ private Boolean enabled;
+ private List criteria;
+
+ @Override
+ public Boolean getKey() {
+ return enabled;
+ }
+
+ @Override
+ public List getValue() {
+ return criteria;
+ }
+
+ @Override
+ public List setValue(List criteria) {
+ List oldCriteria = this.criteria;
+ this.criteria = criteria;
+ return oldCriteria;
+ }
+ }
}