- * Default: null - * - * @param customCallbackHandler handler instance - * @return builder instance - */ - public Builder setCustomCallbackHandler(@Nullable Handler customCallbackHandler) { - this.customCallbackHandler = customCallbackHandler; - return this; - } - - /** - * Property that allows automatic retries of connection to Google Play Services when it has bean suspended. - *
- * Default: false
- *
- * @param retryOnConnectionSuspended if should we retry on connection failure
- * @return builder instance
- */
- public Builder setRetryOnConnectionSuspended(boolean retryOnConnectionSuspended) {
- this.retryOnConnectionSuspended = retryOnConnectionSuspended;
- return this;
- }
-
- /**
- * Builds configuration instance
- *
- * @return configuration instance
- */
- public ReactiveLocationProviderConfiguration build() {
- return new ReactiveLocationProviderConfiguration(this);
- }
- }
-}
diff --git a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/ReactiveLocationProviderConfiguration.kt b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/ReactiveLocationProviderConfiguration.kt
new file mode 100644
index 00000000..0af88f26
--- /dev/null
+++ b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/ReactiveLocationProviderConfiguration.kt
@@ -0,0 +1,67 @@
+package pl.charmas.android.reactivelocation2
+
+import android.os.Handler
+
+/**
+ * Configuration for location provider. Pleas use builder to create an instance.
+ */
+class ReactiveLocationProviderConfiguration private constructor(builder: Builder) {
+
+ val customCallbackHandler: Handler? = builder.customCallbackHandler
+ val isRetryOnConnectionSuspended: Boolean = builder.retryOnConnectionSuspended
+
+ class Builder {
+ var customCallbackHandler: Handler? = null
+ private set(value) {
+ field = value
+ }
+ var retryOnConnectionSuspended = false
+ private set(value) {
+ field = value
+ }
+
+ /**
+ * Allows to set custom handler on which all Google Play Services callbacks are called.
+ *
+ *
+ * Default: null
+ *
+ * @param customCallbackHandler handler instance
+ * @return builder instance
+ */
+ fun setCustomCallbackHandler(customCallbackHandler: Handler?): Builder {
+ this.customCallbackHandler = customCallbackHandler
+ return this
+ }
+
+ /**
+ * Property that allows automatic retries of connection to Google Play Services when it has bean suspended.
+ *
+ *
+ * Default: false
+ *
+ * @param retryOnConnectionSuspended if should we retry on connection failure
+ * @return builder instance
+ */
+ fun setRetryOnConnectionSuspended(retryOnConnectionSuspended: Boolean): Builder {
+ this.retryOnConnectionSuspended = retryOnConnectionSuspended
+ return this
+ }
+
+ /**
+ * Builds configuration instance
+ *
+ * @return configuration instance
+ */
+ fun build(): ReactiveLocationProviderConfiguration {
+ return ReactiveLocationProviderConfiguration(this)
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun builder(): Builder {
+ return Builder()
+ }
+ }
+}
\ No newline at end of file
diff --git a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/ReactivePlacesProvider.kt b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/ReactivePlacesProvider.kt
new file mode 100644
index 00000000..8bcdadc0
--- /dev/null
+++ b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/ReactivePlacesProvider.kt
@@ -0,0 +1,173 @@
+package pl.charmas.android.reactivelocation2
+
+import android.content.Context
+import android.graphics.Bitmap
+import androidx.annotation.IntRange
+import androidx.annotation.RequiresPermission
+import com.google.android.libraries.places.api.Places
+import com.google.android.libraries.places.api.model.AutocompletePrediction
+import com.google.android.libraries.places.api.model.PhotoMetadata
+import com.google.android.libraries.places.api.model.Place
+import com.google.android.libraries.places.api.net.FetchPhotoRequest
+import com.google.android.libraries.places.api.net.FetchPlaceRequest
+import com.google.android.libraries.places.api.net.FetchPlaceResponse
+import com.google.android.libraries.places.api.net.FindAutocompletePredictionsRequest
+import com.google.android.libraries.places.api.net.FindAutocompletePredictionsResponse
+import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest
+import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse
+import io.reactivex.Maybe
+import io.reactivex.Observable
+import pl.charmas.android.reactivelocation2.ext.errorSkip
+import pl.charmas.android.reactivelocation2.ext.mapOrEmpty
+import pl.charmas.android.reactivelocation2.ext.toMaybe
+import java.util.Collections
+
+class ReactivePlacesProvider constructor(
+ val context: Context,
+) {
+
+ private val placesClient = Places.createClient(context)
+
+ /**
+ * Returns observable that fetches current place from Places API. To flatmap and auto release
+ * buffer to {@link com.google.android.gms.location.places.PlaceLikelihood} observable use
+ * {@link DataBufferObservable}.
+ *
+ * @param placeFilter filter
+ * @return observable that emits current places buffer and completes
+ */
+ @RequiresPermission(allOf = ["android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_WIFI_STATE"])
+ fun getCurrentPlace(placeFilter: FindCurrentPlaceRequest): Maybe> {
+ return placesClient
+ .findAutocompletePredictions(result)
+ .toMaybe()
+ .map { obj: FindAutocompletePredictionsResponse -> obj.autocompletePredictions }
+ }
+
+ /**
+ * Returns observable that fetches photo metadata from the Places API using the place ID.
+ *
+ * @param placeId id for place
+ * @return observable that emits metadata buffer and completes
+ */
+ fun getPhotosByPlaceId(
+ placeId: String,
+ @IntRange(from = 1L, to = 1600L) height: Int,
+ @IntRange(from = 1L, to = 1600L) width: Int,
+ ): Maybe
> {
+ return getPlaceById(placeId, Collections.singletonList(Place.Field.PHOTO_METADATAS))
+ .mapOrEmpty { it.place.photoMetadatas }
+ .filter { it.isNotEmpty() }
+ .flatMapSingle { photoMetadatas ->
+ Observable.fromIterable(photoMetadatas)
+ .flatMapMaybe { photoMetadata ->
+ placesClient
+ .fetchPhoto(
+ FetchPhotoRequest.builder(
+ photoMetadata
+ )
+ .setMaxHeight(height)
+ .setMaxWidth(width)
+ .build()
+ )
+ .toMaybe()
+ .errorSkip()
+ }
+ .map { it.bitmap }
+ .toList()
+ }
+ .filter { it.isNotEmpty() }
+ }
+ /**
+ * Returns observable that fetches photo metadata from the Places API using the place ID.
+ *
+ * @param placeId id for place
+ * @return observable that emits metadata buffer and completes
+ */
+ fun getFirstPhotoByPlaceId(
+ placeId: String,
+ @IntRange(from = 1L, to = 1600L) height: Int,
+ @IntRange(from = 1L, to = 1600L) width: Int,
+ ): Maybe
> {
- private final Locale locale;
- private final double latitude;
- private final double longitude;
- private final int maxResults;
-
- FallbackReverseGeocodeObservable(Locale locale, double latitude, double longitude, int maxResults) {
- this.locale = locale;
- this.latitude = latitude;
- this.longitude = longitude;
- this.maxResults = maxResults;
- }
-
- @Override
- public void subscribe(ObservableEmitter
> emitter) throws Exception {
- try {
- List addresses = alternativeReverseGeocodeQuery();
- if (!emitter.isDisposed()) {
- emitter.onNext(addresses);
- emitter.onComplete();
- }
- } catch (Exception ex) {
- if (!emitter.isDisposed()) {
- emitter.onError(ex);
- }
- }
- }
-
- /**
- * This function fetches a list of addresses for the set latitude, longitude and maxResults properties from the
- * Google Geocode API (http://maps.googleapis.com/maps/api/geocode).
- *
- * @return List of addresses
- * @throws IOException In case of network problems
- * @throws JSONException In case of problems while parsing the json response from google geocode API servers
- */
- private List alternativeReverseGeocodeQuery() throws IOException, JSONException {
- URL url = new URL(String.format(Locale.ENGLISH,
- "http://maps.googleapis.com/maps/api/geocode/json?"
- + "latlng=%1$f,%2$f&sensor=true&language=%3$s",
- latitude, longitude, locale.getLanguage()
- ));
- HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
- StringBuilder stringBuilder = new StringBuilder();
- List outResult = new ArrayList<>();
-
- try {
- BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
- String line;
- while ((line = reader.readLine()) != null) {
- stringBuilder.append(line);
- }
-
- // Root json response object
- JSONObject jsonRootObject = new JSONObject(stringBuilder.toString());
-
- // No results status
- if ("ZERO_RESULTS".equalsIgnoreCase(jsonRootObject.getString("status"))) {
- return Collections.emptyList();
- }
-
- // Other non-OK responses status
- if (!"OK".equalsIgnoreCase(jsonRootObject.getString("status"))) {
- throw new RuntimeException("Wrong API response");
- }
-
- // Process results
- JSONArray results = jsonRootObject.getJSONArray("results");
- for (int i = 0; i < results.length() && i < maxResults; i++) {
- Address address = new Address(Locale.getDefault());
- String addressLineString = "";
- JSONObject sourceResult = results.getJSONObject(i);
- JSONArray addressComponents = sourceResult.getJSONArray("address_components");
-
- // Assemble address by various components
- for (int ac = 0; ac < addressComponents.length(); ac++) {
- String longNameVal = addressComponents.getJSONObject(ac).getString("long_name");
- String shortNameVal = addressComponents.getJSONObject(ac).getString("short_name");
- JSONArray acTypes = addressComponents.getJSONObject(ac).getJSONArray("types");
- String acType = acTypes.getString(0);
-
- if (!TextUtils.isEmpty(longNameVal)) {
- if (acType.equalsIgnoreCase("street_number")) {
- if (TextUtils.isEmpty(addressLineString)) {
- addressLineString = longNameVal;
- } else {
- addressLineString += " " + longNameVal;
- }
- } else if (acType.equalsIgnoreCase("route")) {
- if (TextUtils.isEmpty(addressLineString)) {
- addressLineString = longNameVal;
- } else {
- addressLineString = longNameVal + " " + addressLineString;
- }
- } else if (acType.equalsIgnoreCase("sublocality")) {
- address.setSubLocality(longNameVal);
- } else if (acType.equalsIgnoreCase("locality")) {
- address.setLocality(longNameVal);
- } else if (acType.equalsIgnoreCase("administrative_area_level_2")) {
- address.setSubAdminArea(longNameVal);
- } else if (acType.equalsIgnoreCase("administrative_area_level_1")) {
- address.setAdminArea(longNameVal);
- } else if (acType.equalsIgnoreCase("country")) {
- address.setCountryName(longNameVal);
- address.setCountryCode(shortNameVal);
- } else if (acType.equalsIgnoreCase("postal_code")) {
- address.setPostalCode(longNameVal);
- }
- }
- }
-
- // Try to get the already formatted address
- String formattedAddress = sourceResult.getString("formatted_address");
- if (!TextUtils.isEmpty(formattedAddress)) {
- String[] formattedAddressLines = formattedAddress.split(",");
-
- for (int ia = 0; ia < formattedAddressLines.length; ia++) {
- address.setAddressLine(ia, formattedAddressLines[ia].trim());
- }
- } else if (!TextUtils.isEmpty(addressLineString)) {
- // If that fails use our manually assembled formatted address
- address.setAddressLine(0, addressLineString);
- }
-
- // Finally add address to resulting set
- outResult.add(address);
- }
-
- } finally {
- urlConnection.disconnect();
- }
-
- return Collections.unmodifiableList(outResult);
- }
-}
diff --git a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/FallbackReverseGeocodeObservable.kt b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/FallbackReverseGeocodeObservable.kt
new file mode 100644
index 00000000..a5444fa0
--- /dev/null
+++ b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/FallbackReverseGeocodeObservable.kt
@@ -0,0 +1,154 @@
+package pl.charmas.android.reactivelocation2.observables.geocode
+
+import android.location.Address
+import io.reactivex.MaybeEmitter
+import io.reactivex.MaybeOnSubscribe
+import org.json.JSONException
+import org.json.JSONObject
+import java.io.BufferedReader
+import java.io.IOException
+import java.io.InputStreamReader
+import java.net.HttpURLConnection
+import java.net.URL
+import java.util.Collections
+import java.util.Locale
+
+internal class FallbackReverseGeocodeObservable(
+ private val apiKey: String,
+ private val locale: Locale,
+ private val latitude: Double,
+ private val longitude: Double,
+ private val maxResults: Int
+) : MaybeOnSubscribe
> {
+
+ override fun subscribe(emitter: MaybeEmitter
?>) {
+ try {
+ val addresses = alternativeReverseGeocodeQuery()
+ if (!emitter.isDisposed) {
+ emitter.onSuccess(addresses)
+ }
+ } catch (exception: Exception) {
+ if (!emitter.isDisposed) {
+ emitter.onError(exception)
+ }
+ }
+ }
+
+ /**
+ * This function fetches a list of addresses for the set latitude, longitude and maxResults properties from the
+ * Google Geocode API (https://maps.googleapis.com/maps/api/geocode).
+ *
+ * @return List of addresses
+ * @throws IOException In case of network problems
+ * @throws JSONException In case of problems while parsing the json response from google geocode API servers
+ */
+ @Throws(IOException::class, JSONException::class)
+ private fun alternativeReverseGeocodeQuery(): List {
+ val url = URL(
+ "https://maps.googleapis.com/maps/api/geocode/json?"
+ + "latlng=$latitude,${longitude}&sensor=true&key=$apiKey&language=${locale.language}"
+ )
+ val urlConnection = url.openConnection() as HttpURLConnection
+ val stringBuilder = StringBuilder()
+ val outResult = mutableListOf()
+ try {
+ val reader =
+ BufferedReader(InputStreamReader(urlConnection.inputStream, Charsets.UTF_8))
+ var line: String?
+ while (reader.readLine().also { line = it } != null) {
+ stringBuilder.append(line)
+ }
+
+ // Root json response object
+ val jsonRootObject = JSONObject(stringBuilder.toString())
+
+ // No results status
+ if ("ZERO_RESULTS".equals(jsonRootObject.getString("status"), ignoreCase = true)) {
+ return emptyList()
+ }
+
+ // Other non-OK responses status
+ if (!"OK".equals(jsonRootObject.getString("status"), ignoreCase = true)) {
+ throw RuntimeException("Wrong API response")
+ }
+
+ // Process results
+ val results = jsonRootObject.getJSONArray("results")
+ var i = 0
+ while (i < results.length() && i < maxResults) {
+ val address = Address(Locale.getDefault())
+ var addressLineString = ""
+ val sourceResult = results.getJSONObject(i)
+ val addressComponents = sourceResult.getJSONArray("address_components")
+
+ // Assemble address by various components
+ for (ac in 0 until addressComponents.length()) {
+ val jsonObject = addressComponents.getJSONObject(ac)
+ val longNameVal = jsonObject.getString("long_name")
+ val shortNameVal = jsonObject.getString("short_name")
+ val acTypes = jsonObject.getJSONArray("types")
+ val acType = acTypes.getString(0)
+ if (longNameVal.isNotEmpty()) {
+ if (acType.equals("street_number", ignoreCase = true)) {
+ if (addressLineString.isEmpty()) {
+ addressLineString = longNameVal
+ } else {
+ addressLineString += " $longNameVal"
+ }
+ } else if (acType.equals("route", ignoreCase = true)) {
+ addressLineString = if (addressLineString.isEmpty()) {
+ longNameVal
+ } else {
+ "$longNameVal $addressLineString"
+ }
+ } else if (acType.equals("sublocality", ignoreCase = true)) {
+ address.subLocality = longNameVal
+ } else if (acType.equals("locality", ignoreCase = true)) {
+ address.locality = longNameVal
+ } else if (acType.equals(
+ "administrative_area_level_2",
+ ignoreCase = true
+ )
+ ) {
+ address.subAdminArea = longNameVal
+ } else if (acType.equals(
+ "administrative_area_level_1",
+ ignoreCase = true
+ )
+ ) {
+ address.adminArea = longNameVal
+ } else if (acType.equals("country", ignoreCase = true)) {
+ address.countryName = longNameVal
+ address.countryCode = shortNameVal
+ } else if (acType.equals("postal_code", ignoreCase = true)) {
+ address.postalCode = longNameVal
+ }
+ }
+ }
+
+ // Try to get the already formatted address
+ val formattedAddress = sourceResult.getString("formatted_address")
+ if (formattedAddress.isNotEmpty()) {
+ val formattedAddressLines =
+ formattedAddress.split(",".toRegex()).toTypedArray()
+ for (ia in formattedAddressLines.indices) {
+ address.setAddressLine(
+ ia,
+ formattedAddressLines[ia].trim { it <= ' ' }
+ )
+ }
+ } else if (addressLineString.isNotEmpty()) {
+ // If that fails use our manually assembled formatted address
+ address.setAddressLine(0, addressLineString)
+ }
+
+ // Finally add address to resulting set
+ outResult.add(address)
+ i++
+ }
+ } finally {
+ urlConnection.disconnect()
+ }
+ return Collections.unmodifiableList(outResult)
+ }
+}
\ No newline at end of file
diff --git a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/GeocodeMaybe.kt b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/GeocodeMaybe.kt
new file mode 100644
index 00000000..f5e68eff
--- /dev/null
+++ b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/GeocodeMaybe.kt
@@ -0,0 +1,73 @@
+package pl.charmas.android.reactivelocation2.observables.geocode
+
+import android.content.Context
+import android.location.Address
+import android.location.Geocoder
+import com.google.android.gms.maps.model.LatLngBounds
+import io.reactivex.Maybe
+import io.reactivex.MaybeEmitter
+import io.reactivex.MaybeOnSubscribe
+import pl.charmas.android.reactivelocation2.observables.MaybeFactory
+import pl.charmas.android.reactivelocation2.observables.ObservableFactory
+import java.io.IOException
+import java.util.Locale
+
+class GeocodeMaybe private constructor(
+ private val ctx: Context,
+ private val locationName: String,
+ private val maxResults: Int,
+ private val bounds: LatLngBounds? = null,
+ private val locale: Locale
+) : MaybeOnSubscribe
> {
+
+ @Throws(Exception::class)
+ override fun subscribe(emitter: MaybeEmitter
>) {
+ val geoCoder = createGeocoder()
+ try {
+ val result = getAddresses(geoCoder)
+ if (!emitter.isDisposed) {
+ emitter.onSuccess(result)
+ }
+ } catch (e: IOException) {
+ if (!emitter.isDisposed) {
+ emitter.onError(e)
+ }
+ }
+ }
+
+ @Throws(IOException::class)
+ private fun getAddresses(geocoder: Geocoder): List {
+ return if (bounds != null) {
+ geocoder.getFromLocationName(
+ locationName,
+ maxResults,
+ bounds.southwest.latitude,
+ bounds.southwest.longitude,
+ bounds.northeast.latitude,
+ bounds.northeast.longitude
+ )
+ } else {
+ geocoder.getFromLocationName(locationName, maxResults)
+ }
+ }
+
+ private fun createGeocoder(): Geocoder {
+ return Geocoder(ctx, locale)
+ }
+
+ companion object {
+ fun create(
+ ctx: Context,
+ factory: MaybeFactory,
+ locationName: String,
+ maxResults: Int,
+ bounds: LatLngBounds? = null,
+ locale: Locale
+ ): Maybe
> {
+ return factory.create(
+ GeocodeMaybe(ctx, locationName, maxResults, bounds, locale)
+ )
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/GeocodeObservable.java b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/GeocodeObservable.java
deleted file mode 100644
index e74f1fc8..00000000
--- a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/GeocodeObservable.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package pl.charmas.android.reactivelocation2.observables.geocode;
-
-import android.content.Context;
-import android.location.Address;
-import android.location.Geocoder;
-import android.support.annotation.NonNull;
-
-import com.google.android.gms.maps.model.LatLngBounds;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Locale;
-
-import io.reactivex.Observable;
-import io.reactivex.ObservableEmitter;
-import io.reactivex.ObservableOnSubscribe;
-import pl.charmas.android.reactivelocation2.observables.ObservableFactory;
-
-public class GeocodeObservable implements ObservableOnSubscribe
> {
- private final Context ctx;
- private final String locationName;
- private final int maxResults;
- private final LatLngBounds bounds;
- private final Locale locale;
-
- public static Observable
> createObservable(Context ctx, ObservableFactory factory, String locationName, int maxResults, LatLngBounds bounds, Locale locale) {
- return factory.createObservable(new GeocodeObservable(ctx, locationName, maxResults, bounds, locale));
- }
-
- private GeocodeObservable(Context ctx, String locationName, int maxResults, LatLngBounds bounds, Locale locale) {
- this.ctx = ctx;
- this.locationName = locationName;
- this.maxResults = maxResults;
- this.bounds = bounds;
- this.locale = locale;
- }
-
- @Override
- public void subscribe(ObservableEmitter
> emitter) throws Exception {
- Geocoder geocoder = createGeocoder();
- try {
- List result = getAddresses(geocoder);
- if (!emitter.isDisposed()) {
- emitter.onNext(result);
- emitter.onComplete();
- }
- } catch (IOException e) {
- if (!emitter.isDisposed()) {
- emitter.onError(e);
- }
- }
- }
-
- private List getAddresses(Geocoder geocoder) throws IOException {
- List result;
- if (bounds != null) {
- result = geocoder.getFromLocationName(locationName, maxResults, bounds.southwest.latitude, bounds.southwest.longitude, bounds.northeast.latitude, bounds.northeast.longitude);
- } else {
- result = geocoder.getFromLocationName(locationName, maxResults);
- }
- return result;
- }
-
- @NonNull
- private Geocoder createGeocoder() {
- if (locale != null) return new Geocoder(ctx, locale);
- return new Geocoder(ctx);
- }
-}
diff --git a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/ReverseGeocodeObservable.java b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/ReverseGeocodeObservable.java
deleted file mode 100644
index bbcccf5f..00000000
--- a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/ReverseGeocodeObservable.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package pl.charmas.android.reactivelocation2.observables.geocode;
-
-import android.content.Context;
-import android.location.Address;
-import android.location.Geocoder;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Locale;
-
-import io.reactivex.Observable;
-import io.reactivex.ObservableEmitter;
-import io.reactivex.ObservableOnSubscribe;
-import io.reactivex.schedulers.Schedulers;
-import pl.charmas.android.reactivelocation2.observables.ObservableEmitterWrapper;
-import pl.charmas.android.reactivelocation2.observables.ObservableFactory;
-
-
-public class ReverseGeocodeObservable implements ObservableOnSubscribe
> {
- private final Context ctx;
- private final Locale locale;
- private final double latitude;
- private final double longitude;
- private final int maxResults;
-
- public static Observable
> createObservable(Context ctx, ObservableFactory factory, Locale locale, double latitude, double longitude, int maxResults) {
- return factory.createObservable(new ReverseGeocodeObservable(ctx, locale, latitude, longitude, maxResults));
- }
-
- private ReverseGeocodeObservable(Context ctx, Locale locale, double latitude, double longitude, int maxResults) {
- this.ctx = ctx;
- this.latitude = latitude;
- this.longitude = longitude;
- this.maxResults = maxResults;
- this.locale = locale;
- }
-
- @Override
- public void subscribe(ObservableEmitter
> emitter) throws Exception {
- Geocoder geocoder = new Geocoder(ctx, locale);
- try {
- List addresses = geocoder.getFromLocation(latitude, longitude, maxResults);
- if (!emitter.isDisposed()) {
- emitter.onNext(addresses);
- emitter.onComplete();
- }
- } catch (IOException e) {
- // If it's a service not available error try a different approach using google web api
- if (!emitter.isDisposed()) {
- Observable
- .create(new FallbackReverseGeocodeObservable(locale, latitude, longitude, maxResults))
- .subscribeOn(Schedulers.io())
- .subscribe(new ObservableEmitterWrapper<>(emitter));
- }
- }
- }
-}
diff --git a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/ReverseGeocodeObservable.kt b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/ReverseGeocodeObservable.kt
new file mode 100644
index 00000000..c19b91d9
--- /dev/null
+++ b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geocode/ReverseGeocodeObservable.kt
@@ -0,0 +1,64 @@
+package pl.charmas.android.reactivelocation2.observables.geocode
+
+import android.content.Context
+import android.location.Address
+import android.location.Geocoder
+import io.reactivex.Maybe
+import io.reactivex.MaybeEmitter
+import io.reactivex.MaybeOnSubscribe
+import io.reactivex.schedulers.Schedulers
+import pl.charmas.android.reactivelocation2.observables.MaybeEmitterWrapper
+import pl.charmas.android.reactivelocation2.observables.MaybeFactory
+import java.io.IOException
+import java.util.Locale
+
+class ReverseGeocodeObservable private constructor(
+ private val ctx: Context,
+ private val locale: Locale,
+ private val apiKey: String,
+ private val latitude: Double,
+ private val longitude: Double,
+ private val maxResults: Int
+) : MaybeOnSubscribe
> {
+
+ override fun subscribe(emitter: MaybeEmitter
>) {
+ val geoCoder = Geocoder(ctx, locale)
+ try {
+ val addresses = geoCoder.getFromLocation(latitude, longitude, maxResults)
+ if (!emitter.isDisposed) {
+ emitter.onSuccess(addresses)
+ }
+ } catch (e: IOException) {
+ // If it's a service not available error try a different approach using google web api
+ if (!emitter.isDisposed) {
+ Maybe.create(
+ FallbackReverseGeocodeObservable(
+ apiKey,
+ locale,
+ latitude,
+ longitude,
+ maxResults
+ )
+ )
+ .subscribeOn(Schedulers.io())
+ .subscribe(MaybeEmitterWrapper(emitter))
+ }
+ }
+ }
+
+ companion object {
+ fun create(
+ ctx: Context,
+ apiKey: String,
+ factory: MaybeFactory,
+ locale: Locale,
+ latitude: Double,
+ longitude: Double,
+ maxResults: Int
+ ): Maybe
> {
+ return factory.create(
+ ReverseGeocodeObservable(ctx, locale, apiKey, latitude, longitude, maxResults)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geofence/AddGeofenceMaybeOnSubscribe.kt b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geofence/AddGeofenceMaybeOnSubscribe.kt
new file mode 100644
index 00000000..f086f299
--- /dev/null
+++ b/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/geofence/AddGeofenceMaybeOnSubscribe.kt
@@ -0,0 +1,55 @@
+package pl.charmas.android.reactivelocation2.observables.geofence
+
+import android.app.PendingIntent
+import androidx.annotation.RequiresPermission
+import com.google.android.gms.common.api.GoogleApiClient
+import com.google.android.gms.location.GeofencingClient
+import com.google.android.gms.location.GeofencingRequest
+import io.reactivex.Maybe
+import io.reactivex.MaybeEmitter
+import pl.charmas.android.reactivelocation2.observables.BaseLocationMaybeOnSubscribe
+import pl.charmas.android.reactivelocation2.observables.MaybeContext
+import pl.charmas.android.reactivelocation2.observables.MaybeFactory
+
+class AddGeofenceMaybeOnSubscribe private constructor(
+ ctx: MaybeContext,
+ private val request: GeofencingRequest,
+ private val geofenceTransitionPendingIntent: PendingIntent,
+ private val geofencingClient: GeofencingClient
+) : BaseLocationMaybeOnSubscribe