package io.nlopez.smartlocation; import android.content.Context; import android.location.Location; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.google.android.gms.location.DetectedActivity; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import io.nlopez.smartlocation.activity.ActivityProvider; import io.nlopez.smartlocation.activity.config.ActivityParams; import io.nlopez.smartlocation.activity.providers.ActivityGooglePlayServicesProvider; import io.nlopez.smartlocation.geocoding.GeocodingProvider; import io.nlopez.smartlocation.geocoding.providers.AndroidGeocodingProvider; import io.nlopez.smartlocation.geofencing.GeofencingProvider; import io.nlopez.smartlocation.geofencing.model.GeofenceModel; import io.nlopez.smartlocation.geofencing.providers.GeofencingGooglePlayServicesProvider; import io.nlopez.smartlocation.location.LocationProvider; import io.nlopez.smartlocation.location.config.LocationParams; import io.nlopez.smartlocation.location.providers.LocationGooglePlayServicesWithFallbackProvider; import io.nlopez.smartlocation.location.utils.LocationState; import io.nlopez.smartlocation.utils.Logger; import io.nlopez.smartlocation.utils.LoggerFactory; /** * Managing class for SmartLocation library. */ public class SmartLocation { private Context context; private Logger logger; private boolean preInitialize; /** * Creates the SmartLocation basic instance. * * @param context execution context * @param logger logger interface * @param preInitialize TRUE (default) if we want to instantiate directly the default providers. FALSE if we want to initialize them ourselves. */ private SmartLocation(Context context, Logger logger, boolean preInitialize) { this.context = context; this.logger = logger; this.preInitialize = preInitialize; } public static SmartLocation with(Context context) { return new Builder(context).build(); } /** * @return request handler for location operations */ public LocationControl location() { return location(new LocationGooglePlayServicesWithFallbackProvider(context)); } /** * @param provider location provider we want to use * @return request handler for location operations */ public LocationControl location(LocationProvider provider) { return new LocationControl(this, provider); } /** * Builder for activity recognition. Use activity() instead. * * @return builder for activity recognition. * @deprecated */ @Deprecated public ActivityRecognitionControl activityRecognition() { return activity(); } /** * @return request handler for activity recognition */ public ActivityRecognitionControl activity() { return activity(new ActivityGooglePlayServicesProvider()); } /** * @param activityProvider activity provider we want to use * @return request handler for activity recognition */ public ActivityRecognitionControl activity(ActivityProvider activityProvider) { return new ActivityRecognitionControl(this, activityProvider); } /** * @return request handler for geofencing operations */ public GeofencingControl geofencing() { return geofencing(new GeofencingGooglePlayServicesProvider()); } /** * @param geofencingProvider geofencing provider we want to use * @return request handler for geofencing operations */ public GeofencingControl geofencing(GeofencingProvider geofencingProvider) { return new GeofencingControl(this, geofencingProvider); } /** * @return request handler for geocoding operations */ public GeocodingControl geocoding() { return geocoding(new AndroidGeocodingProvider()); } /** * @param geocodingProvider geocoding provider we want to use * @return request handler for geocoding operations */ public GeocodingControl geocoding(GeocodingProvider geocodingProvider) { return new GeocodingControl(this, geocodingProvider); } public static class Builder { private final Context context; private boolean loggingEnabled; private boolean preInitialize; public Builder(@NonNull Context context) { this.context = context; this.loggingEnabled = false; this.preInitialize = true; } public Builder logging(boolean enabled) { this.loggingEnabled = enabled; return this; } public Builder preInitialize(boolean enabled) { this.preInitialize = enabled; return this; } public SmartLocation build() { return new SmartLocation(context, LoggerFactory.buildLogger(loggingEnabled), preInitialize); } } public static class LocationControl { private static final Map<Context, LocationProvider> MAPPING = new WeakHashMap<>(); private final SmartLocation smartLocation; private LocationParams params; private LocationProvider provider; private boolean oneFix; public LocationControl(@NonNull SmartLocation smartLocation, @NonNull LocationProvider locationProvider) { this.smartLocation = smartLocation; params = LocationParams.BEST_EFFORT; oneFix = false; if (!MAPPING.containsKey(smartLocation.context)) { MAPPING.put(smartLocation.context, locationProvider); } provider = MAPPING.get(smartLocation.context); if (smartLocation.preInitialize) { provider.init(smartLocation.context, smartLocation.logger); } } public LocationControl config(@NonNull LocationParams params) { this.params = params; return this; } public LocationControl oneFix() { this.oneFix = true; return this; } public LocationControl continuous() { this.oneFix = false; return this; } public LocationState state() { return LocationState.with(smartLocation.context); } @Nullable public Location getLastLocation() { return provider.getLastLocation(); } public LocationControl get() { return this; } public void start(OnLocationUpdatedListener listener) { if (provider == null) { throw new RuntimeException("A provider must be initialized"); } provider.start(listener, params, oneFix); } public void stop() { provider.stop(); } } public static class GeocodingControl { private static final Map<Context, GeocodingProvider> MAPPING = new WeakHashMap<>(); private final SmartLocation smartLocation; private GeocodingProvider provider; private boolean directAdded = false; private boolean reverseAdded = false; public GeocodingControl(@NonNull SmartLocation smartLocation, @NonNull GeocodingProvider geocodingProvider) { this.smartLocation = smartLocation; if (!MAPPING.containsKey(smartLocation.context)) { MAPPING.put(smartLocation.context, geocodingProvider); } provider = MAPPING.get(smartLocation.context); if (smartLocation.preInitialize) { provider.init(smartLocation.context, smartLocation.logger); } } public GeocodingControl get() { return this; } public void reverse(@NonNull Location location, @NonNull OnReverseGeocodingListener reverseGeocodingListener) { add(location); start(reverseGeocodingListener); } public void direct(@NonNull String name, @NonNull OnGeocodingListener geocodingListener) { add(name); start(geocodingListener); } public GeocodingControl add(@NonNull Location location) { reverseAdded = true; provider.addLocation(location, 1); return this; } public GeocodingControl add(@NonNull Location location, int maxResults) { reverseAdded = true; provider.addLocation(location, maxResults); return this; } public GeocodingControl add(@NonNull String name) { directAdded = true; provider.addName(name, 1); return this; } public GeocodingControl add(@NonNull String name, int maxResults) { directAdded = true; provider.addName(name, maxResults); return this; } public void start(OnGeocodingListener geocodingListener) { start(geocodingListener, null); } public void start(OnReverseGeocodingListener reverseGeocodingListener) { start(null, reverseGeocodingListener); } /** * Starts the geocoder conversions, for either direct geocoding (name to location) and reverse geocoding (location to address). * * @param geocodingListener will be called for name to location queries * @param reverseGeocodingListener will be called for location to name queries */ public void start(OnGeocodingListener geocodingListener, OnReverseGeocodingListener reverseGeocodingListener) { if (provider == null) { throw new RuntimeException("A provider must be initialized"); } if (directAdded && geocodingListener == null) { smartLocation.logger.w("Some places were added for geocoding but the listener was not specified!"); } if (reverseAdded && reverseGeocodingListener == null) { smartLocation.logger.w("Some places were added for reverse geocoding but the listener was not specified!"); } provider.start(geocodingListener, reverseGeocodingListener); } /** * Cleans up after the geocoder calls. Will be needed for avoiding possible leaks in registered receivers. */ public void stop() { provider.stop(); } } public static class ActivityRecognitionControl { private static final Map<Context, ActivityProvider> MAPPING = new WeakHashMap<>(); private final SmartLocation smartLocation; private ActivityParams params; private ActivityProvider provider; public ActivityRecognitionControl(@NonNull SmartLocation smartLocation, @NonNull ActivityProvider activityProvider) { this.smartLocation = smartLocation; params = ActivityParams.NORMAL; if (!MAPPING.containsKey(smartLocation.context)) { MAPPING.put(smartLocation.context, activityProvider); } provider = MAPPING.get(smartLocation.context); if (smartLocation.preInitialize) { provider.init(smartLocation.context, smartLocation.logger); } } public ActivityRecognitionControl config(@NonNull ActivityParams params) { this.params = params; return this; } @Nullable public DetectedActivity getLastActivity() { return provider.getLastActivity(); } public ActivityRecognitionControl get() { return this; } public void start(OnActivityUpdatedListener listener) { if (provider == null) { throw new RuntimeException("A provider must be initialized"); } provider.start(listener, params); } public void stop() { provider.stop(); } } public static class GeofencingControl { private static final Map<Context, GeofencingProvider> MAPPING = new WeakHashMap<>(); private final SmartLocation smartLocation; private GeofencingProvider provider; public GeofencingControl(@NonNull SmartLocation smartLocation, @NonNull GeofencingProvider geofencingProvider) { this.smartLocation = smartLocation; if (!MAPPING.containsKey(smartLocation.context)) { MAPPING.put(smartLocation.context, geofencingProvider); } provider = MAPPING.get(smartLocation.context); if (smartLocation.preInitialize) { provider.init(smartLocation.context, smartLocation.logger); } } public GeofencingControl add(@NonNull GeofenceModel geofenceModel) { provider.addGeofence(geofenceModel); return this; } public GeofencingControl remove(@NonNull String geofenceId) { provider.removeGeofence(geofenceId); return this; } public GeofencingControl addAll(@NonNull List<GeofenceModel> geofenceModelList) { provider.addGeofences(geofenceModelList); return this; } public GeofencingControl removeAll(@NonNull List<String> geofenceIdsList) { provider.removeGeofences(geofenceIdsList); return this; } public void start(OnGeofencingTransitionListener listener) { if (provider == null) { throw new RuntimeException("A provider must be initialized"); } provider.start(listener); } public void stop() { provider.stop(); } } }