19 | * Warning: Values emitted by this observable are mutable and owned by the host 20 | * {@code TextView} and thus are not safe to cache or delay reading (such as by observing 21 | * on a different thread). If you want to cache or delay reading the items emitted then you must 22 | * map values through a function which calls {@link String#valueOf} or 23 | * {@link CharSequence#toString() .toString()} to create a copy. 24 | *
25 | * Warning: The created observable keeps a strong reference to {@code view}. Unsubscribe 26 | * to free this reference. 27 | *
28 | * Note: A value will be emitted immediately on subscribe.
29 | */
30 | @CheckResult
31 | @NonNull
32 | public static Observable
37 | * Default: null
38 | *
39 | * @param customCallbackHandler handler instance
40 | * @return builder instance
41 | */
42 | public Builder setCustomCallbackHandler(@Nullable Handler customCallbackHandler) {
43 | this.customCallbackHandler = customCallbackHandler;
44 | return this;
45 | }
46 |
47 | /**
48 | * Property that allows automatic retries of connection to Google Play Services when it has bean suspended.
49 | *
50 | * Default: false
51 | *
52 | * @param retryOnConnectionSuspended if should we retry on connection failure
53 | * @return builder instance
54 | */
55 | public Builder setRetryOnConnectionSuspended(boolean retryOnConnectionSuspended) {
56 | this.retryOnConnectionSuspended = retryOnConnectionSuspended;
57 | return this;
58 | }
59 |
60 | /**
61 | * Builds configuration instance
62 | *
63 | * @return configuration instance
64 | */
65 | public ReactiveLocationProviderConfiguration build() {
66 | return new ReactiveLocationProviderConfiguration(this);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/observables/location/AddLocationIntentUpdatesObservableOnSubscribe.java:
--------------------------------------------------------------------------------
1 | package pl.charmas.android.reactivelocation2.observables.location;
2 |
3 | import android.app.PendingIntent;
4 | import android.support.annotation.NonNull;
5 |
6 | import com.google.android.gms.common.api.GoogleApiClient;
7 | import com.google.android.gms.common.api.ResultCallback;
8 | import com.google.android.gms.common.api.Status;
9 | import com.google.android.gms.location.LocationRequest;
10 | import com.google.android.gms.location.LocationServices;
11 |
12 | import io.reactivex.Observable;
13 | import io.reactivex.ObservableEmitter;
14 | import pl.charmas.android.reactivelocation2.observables.BaseLocationObservableOnSubscribe;
15 | import pl.charmas.android.reactivelocation2.observables.ObservableContext;
16 | import pl.charmas.android.reactivelocation2.observables.ObservableFactory;
17 | import pl.charmas.android.reactivelocation2.observables.StatusException;
18 |
19 |
20 | @SuppressWarnings("MissingPermission")
21 | public class AddLocationIntentUpdatesObservableOnSubscribe extends BaseLocationObservableOnSubscribe> {
20 | private final Context ctx;
21 | private final Locale locale;
22 | private final double latitude;
23 | private final double longitude;
24 | private final int maxResults;
25 |
26 | public static Observable
> createObservable(Context ctx, ObservableFactory factory, Locale locale, double latitude, double longitude, int maxResults) {
27 | return factory.createObservable(new ReverseGeocodeObservable(ctx, locale, latitude, longitude, maxResults));
28 | }
29 |
30 | private ReverseGeocodeObservable(Context ctx, Locale locale, double latitude, double longitude, int maxResults) {
31 | this.ctx = ctx;
32 | this.latitude = latitude;
33 | this.longitude = longitude;
34 | this.maxResults = maxResults;
35 | this.locale = locale;
36 | }
37 |
38 | @Override
39 | public void subscribe(ObservableEmitter
> emitter) throws Exception {
40 | Geocoder geocoder = new Geocoder(ctx, locale);
41 | try {
42 | List addresses = geocoder.getFromLocation(latitude, longitude, maxResults);
43 | if (!emitter.isDisposed()) {
44 | emitter.onNext(addresses);
45 | emitter.onComplete();
46 | }
47 | } catch (IOException e) {
48 | // If it's a service not available error try a different approach using google web api
49 | if (!emitter.isDisposed()) {
50 | Observable
51 | .create(new FallbackReverseGeocodeObservable(locale, latitude, longitude, maxResults))
52 | .subscribeOn(Schedulers.io())
53 | .subscribe(new ObservableEmitterWrapper<>(emitter));
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/android-reactive-location/src/main/java/pl/charmas/android/reactivelocation2/ReactiveLocationProviderConfiguration.java:
--------------------------------------------------------------------------------
1 | package pl.charmas.android.reactivelocation2;
2 |
3 | import android.os.Handler;
4 | import android.support.annotation.Nullable;
5 |
6 | /**
7 | * Configuration for location provider. Pleas use builder to create an instance.
8 | */
9 | public class ReactiveLocationProviderConfiguration {
10 | private final Handler customCallbackHandler;
11 | private final boolean retryOnConnectionSuspended;
12 |
13 | private ReactiveLocationProviderConfiguration(Builder builder) {
14 | this.customCallbackHandler = builder.customCallbackHandler;
15 | this.retryOnConnectionSuspended = builder.retryOnConnectionSuspended;
16 | }
17 |
18 | public Handler getCustomCallbackHandler() {
19 | return customCallbackHandler;
20 | }
21 |
22 | public boolean isRetryOnConnectionSuspended() {
23 | return retryOnConnectionSuspended;
24 | }
25 |
26 | public static Builder builder() {
27 | return new Builder();
28 | }
29 |
30 | public static class Builder {
31 | private Handler customCallbackHandler = null;
32 | private boolean retryOnConnectionSuspended = false;
33 |
34 | /**
35 | * Allows to set custom handler on which all Google Play Services callbacks are called.
36 | *
> {
20 | private final Context ctx;
21 | private final String locationName;
22 | private final int maxResults;
23 | private final LatLngBounds bounds;
24 | private final Locale locale;
25 |
26 | public static Observable
> createObservable(Context ctx, ObservableFactory factory, String locationName, int maxResults, LatLngBounds bounds, Locale locale) {
27 | return factory.createObservable(new GeocodeObservable(ctx, locationName, maxResults, bounds, locale));
28 | }
29 |
30 | private GeocodeObservable(Context ctx, String locationName, int maxResults, LatLngBounds bounds, Locale locale) {
31 | this.ctx = ctx;
32 | this.locationName = locationName;
33 | this.maxResults = maxResults;
34 | this.bounds = bounds;
35 | this.locale = locale;
36 | }
37 |
38 | @Override
39 | public void subscribe(ObservableEmitter
> emitter) throws Exception {
40 | Geocoder geocoder = createGeocoder();
41 | try {
42 | List result = getAddresses(geocoder);
43 | if (!emitter.isDisposed()) {
44 | emitter.onNext(result);
45 | emitter.onComplete();
46 | }
47 | } catch (IOException e) {
48 | if (!emitter.isDisposed()) {
49 | emitter.onError(e);
50 | }
51 | }
52 | }
53 |
54 | private List getAddresses(Geocoder geocoder) throws IOException {
55 | List result;
56 | if (bounds != null) {
57 | result = geocoder.getFromLocationName(locationName, maxResults, bounds.southwest.latitude, bounds.southwest.longitude, bounds.northeast.latitude, bounds.northeast.longitude);
58 | } else {
59 | result = geocoder.getFromLocationName(locationName, maxResults);
60 | }
61 | return result;
62 | }
63 |
64 | @NonNull
65 | private Geocoder createGeocoder() {
66 | if (locale != null) return new Geocoder(ctx, locale);
67 | return new Geocoder(ctx);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/sample/src/main/java/pl/charmas/android/reactivelocation2/sample/utils/TextViewTextOnSubscribe.java:
--------------------------------------------------------------------------------
1 | package pl.charmas.android.reactivelocation2.sample.utils;
2 |
3 | import android.os.Looper;
4 | import android.text.Editable;
5 | import android.text.TextWatcher;
6 | import android.widget.TextView;
7 |
8 | import java.util.concurrent.atomic.AtomicBoolean;
9 |
10 | import io.reactivex.ObservableEmitter;
11 | import io.reactivex.ObservableOnSubscribe;
12 | import io.reactivex.android.schedulers.AndroidSchedulers;
13 | import io.reactivex.disposables.Disposable;
14 |
15 | class TextViewTextOnSubscribe implements ObservableOnSubscribe
> {
24 | private final Locale locale;
25 | private final double latitude;
26 | private final double longitude;
27 | private final int maxResults;
28 |
29 | FallbackReverseGeocodeObservable(Locale locale, double latitude, double longitude, int maxResults) {
30 | this.locale = locale;
31 | this.latitude = latitude;
32 | this.longitude = longitude;
33 | this.maxResults = maxResults;
34 | }
35 |
36 | @Override
37 | public void subscribe(ObservableEmitter
> emitter) throws Exception {
38 | try {
39 | List addresses = alternativeReverseGeocodeQuery();
40 | if (!emitter.isDisposed()) {
41 | emitter.onNext(addresses);
42 | emitter.onComplete();
43 | }
44 | } catch (Exception ex) {
45 | if (!emitter.isDisposed()) {
46 | emitter.onError(ex);
47 | }
48 | }
49 | }
50 |
51 | /**
52 | * This function fetches a list of addresses for the set latitude, longitude and maxResults properties from the
53 | * Google Geocode API (http://maps.googleapis.com/maps/api/geocode).
54 | *
55 | * @return List of addresses
56 | * @throws IOException In case of network problems
57 | * @throws JSONException In case of problems while parsing the json response from google geocode API servers
58 | */
59 | private List alternativeReverseGeocodeQuery() throws IOException, JSONException {
60 | URL url = new URL(String.format(Locale.ENGLISH,
61 | "http://maps.googleapis.com/maps/api/geocode/json?"
62 | + "latlng=%1$f,%2$f&sensor=true&language=%3$s",
63 | latitude, longitude, locale.getLanguage()
64 | ));
65 | HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
66 | StringBuilder stringBuilder = new StringBuilder();
67 | List outResult = new ArrayList<>();
68 |
69 | try {
70 | BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
71 | String line;
72 | while ((line = reader.readLine()) != null) {
73 | stringBuilder.append(line);
74 | }
75 |
76 | // Root json response object
77 | JSONObject jsonRootObject = new JSONObject(stringBuilder.toString());
78 |
79 | // No results status
80 | if ("ZERO_RESULTS".equalsIgnoreCase(jsonRootObject.getString("status"))) {
81 | return Collections.emptyList();
82 | }
83 |
84 | // Other non-OK responses status
85 | if (!"OK".equalsIgnoreCase(jsonRootObject.getString("status"))) {
86 | throw new RuntimeException("Wrong API response");
87 | }
88 |
89 | // Process results
90 | JSONArray results = jsonRootObject.getJSONArray("results");
91 | for (int i = 0; i < results.length() && i < maxResults; i++) {
92 | Address address = new Address(Locale.getDefault());
93 | String addressLineString = "";
94 | JSONObject sourceResult = results.getJSONObject(i);
95 | JSONArray addressComponents = sourceResult.getJSONArray("address_components");
96 |
97 | // Assemble address by various components
98 | for (int ac = 0; ac < addressComponents.length(); ac++) {
99 | String longNameVal = addressComponents.getJSONObject(ac).getString("long_name");
100 | String shortNameVal = addressComponents.getJSONObject(ac).getString("short_name");
101 | JSONArray acTypes = addressComponents.getJSONObject(ac).getJSONArray("types");
102 | String acType = acTypes.getString(0);
103 |
104 | if (!TextUtils.isEmpty(longNameVal)) {
105 | if (acType.equalsIgnoreCase("street_number")) {
106 | if (TextUtils.isEmpty(addressLineString)) {
107 | addressLineString = longNameVal;
108 | } else {
109 | addressLineString += " " + longNameVal;
110 | }
111 | } else if (acType.equalsIgnoreCase("route")) {
112 | if (TextUtils.isEmpty(addressLineString)) {
113 | addressLineString = longNameVal;
114 | } else {
115 | addressLineString = longNameVal + " " + addressLineString;
116 | }
117 | } else if (acType.equalsIgnoreCase("sublocality")) {
118 | address.setSubLocality(longNameVal);
119 | } else if (acType.equalsIgnoreCase("locality")) {
120 | address.setLocality(longNameVal);
121 | } else if (acType.equalsIgnoreCase("administrative_area_level_2")) {
122 | address.setSubAdminArea(longNameVal);
123 | } else if (acType.equalsIgnoreCase("administrative_area_level_1")) {
124 | address.setAdminArea(longNameVal);
125 | } else if (acType.equalsIgnoreCase("country")) {
126 | address.setCountryName(longNameVal);
127 | address.setCountryCode(shortNameVal);
128 | } else if (acType.equalsIgnoreCase("postal_code")) {
129 | address.setPostalCode(longNameVal);
130 | }
131 | }
132 | }
133 |
134 | // Try to get the already formatted address
135 | String formattedAddress = sourceResult.getString("formatted_address");
136 | if (!TextUtils.isEmpty(formattedAddress)) {
137 | String[] formattedAddressLines = formattedAddress.split(",");
138 |
139 | for (int ia = 0; ia < formattedAddressLines.length; ia++) {
140 | address.setAddressLine(ia, formattedAddressLines[ia].trim());
141 | }
142 | } else if (!TextUtils.isEmpty(addressLineString)) {
143 | // If that fails use our manually assembled formatted address
144 | address.setAddressLine(0, addressLineString);
145 | }
146 |
147 | // Finally add address to resulting set
148 | outResult.add(address);
149 | }
150 |
151 | } finally {
152 | urlConnection.disconnect();
153 | }
154 |
155 | return Collections.unmodifiableList(outResult);
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/sample/src/main/java/pl/charmas/android/reactivelocation2/sample/PlacesActivity.java:
--------------------------------------------------------------------------------
1 | package pl.charmas.android.reactivelocation2.sample;
2 |
3 | import android.location.Location;
4 | import android.os.Bundle;
5 | import android.text.TextUtils;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.widget.AdapterView;
9 | import android.widget.ArrayAdapter;
10 | import android.widget.EditText;
11 | import android.widget.ListView;
12 | import android.widget.TextView;
13 |
14 | import com.google.android.gms.location.places.AutocompletePrediction;
15 | import com.google.android.gms.location.places.AutocompletePredictionBuffer;
16 | import com.google.android.gms.location.places.PlaceLikelihood;
17 | import com.google.android.gms.location.places.PlaceLikelihoodBuffer;
18 | import com.google.android.gms.maps.model.LatLng;
19 | import com.google.android.gms.maps.model.LatLngBounds;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 | import java.util.concurrent.TimeUnit;
24 |
25 | import io.reactivex.Observable;
26 | import io.reactivex.disposables.CompositeDisposable;
27 | import io.reactivex.functions.BiFunction;
28 | import io.reactivex.functions.Consumer;
29 | import io.reactivex.functions.Function;
30 | import io.reactivex.functions.Predicate;
31 | import pl.charmas.android.reactivelocation2.ReactiveLocationProvider;
32 | import pl.charmas.android.reactivelocation2.sample.utils.RxTextView;
33 |
34 | import static pl.charmas.android.reactivelocation2.sample.utils.UnsubscribeIfPresent.dispose;
35 |
36 | public class PlacesActivity extends BaseActivity {
37 |
38 | private TextView currentPlaceView;
39 | private EditText queryView;
40 | private ListView placeSuggestionsList;
41 | private ReactiveLocationProvider reactiveLocationProvider;
42 | private CompositeDisposable compositeDisposable;
43 |
44 | @Override
45 | protected void onCreate(Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | setContentView(R.layout.activity_places);
48 | currentPlaceView = (TextView) findViewById(R.id.current_place_view);
49 | queryView = (EditText) findViewById(R.id.place_query_view);
50 | placeSuggestionsList = (ListView) findViewById(R.id.place_suggestions_list);
51 | placeSuggestionsList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
52 | @Override
53 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
54 | AutocompleteInfo info = (AutocompleteInfo) parent.getAdapter().getItem(position);
55 | startActivity(PlacesResultActivity.getStartIntent(PlacesActivity.this, info.id));
56 | }
57 | });
58 |
59 | reactiveLocationProvider = new ReactiveLocationProvider(this);
60 | }
61 |
62 | @Override
63 | protected void onLocationPermissionGranted() {
64 | compositeDisposable = new CompositeDisposable();
65 | compositeDisposable.add(
66 | reactiveLocationProvider.getCurrentPlace(null)
67 | .subscribe(new Consumer
> reverseGeocodeObservable = locationProvider
111 | .getReverseGeocodeObservable(location.getLatitude(), location.getLongitude(), MAX_ADDRESSES);
112 |
113 | reverseGeocodeObservable
114 | .subscribeOn(Schedulers.io()) // use I/O thread to query for addresses
115 | .observeOn(AndroidSchedulers.mainThread()) // return result in main android thread to manipulate UI
116 | .subscribe(...);
117 | ```
118 |
119 | ### Geocode location
120 |
121 | Do you need address for a text search query?
122 |
123 | ```java
124 | Observable
> geocodeObservable = locationProvider
125 | .getGeocodeObservable(String userQuery, MAX_ADDRESSES);
126 |
127 | geocodeObservable
128 | .subscribeOn(Schedulers.io())
129 | .observeOn(AndroidSchedulers.mainThread())
130 | .subscribe(...);
131 | ```
132 |
133 | ### Managing geofences
134 |
135 | For geofence management use `addGeofences` and `removeGeofences` methods.
136 |
137 | ### Checking location settings though location settings API
138 |
139 | To get ```LocationSettingsResponse``` for your ```LocationRequest``` check
140 | out ```ReactiveLocationProvider.checkLocationSettings()``` method. Sample
141 | usage can be found in **sample** project in ```MainActivity``` class.
142 |
143 | ### Connecting to Google Play Services API
144 |
145 | If you just need managed connection to Play Services API
146 | use ```ReactiveLocationProvider.getGoogleApiClientObservable()```.
147 | On subscription it will connect to the API.
148 | Unsubscription will close the connection.
149 |
150 | ### Creating observable from PendingResult
151 |
152 | If you are manually using Google Play Services and you are dealing with
153 | ```PendingResult``` you can easily transform them to observables with
154 | ```ReactiveLocationProvider.fromPendingResult()``` method.
155 |
156 | ### Transforming buffers to observable
157 |
158 | To transform any buffer to observable and autorelease it on unsubscription
159 | use ```DataBufferObservable.from()``` method. It will let you easily flatMap
160 | such data as ```PlaceLikelihoodBuffer``` or ```AutocompletePredictionBuffer```
161 | from Places API. For usage example see ```PlacesActivity``` sample.
162 |
163 | ### Places API
164 |
165 | You can fetch current place or place suggestions using:
166 |
167 | * ```ReactiveLocationProvider.getCurrentPlace()```
168 | * ```ReactiveLocationProvider.getPlaceAutocompletePredictions()```
169 | * ```ReactiveLocationProvider.getPlaceById()```
170 |
171 | For more info see sample project and ```PlacesActivity```.
172 |
173 | ### Cooler examples
174 |
175 | Do you need location with certain accuracy but don't want to wait for it more than 4 sec? No problem.
176 |
177 | ```java
178 | LocationRequest req = LocationRequest.create()
179 | .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
180 | .setExpirationDuration(TimeUnit.SECONDS.toMillis(LOCATION_TIMEOUT_IN_SECONDS))
181 | .setInterval(LOCATION_UPDATE_INTERVAL);
182 |
183 | Observable
> apply(Location location) {
117 | return locationProvider.getReverseGeocodeObservable(location.getLatitude(), location.getLongitude(), 1);
118 | }
119 | })
120 | .map(new Function
, Address>() {
121 | @Override
122 | public Address apply(List addresses) {
123 | return addresses != null && !addresses.isEmpty() ? addresses.get(0) : null;
124 | }
125 | })
126 | .map(new AddressToStringFunc())
127 | .subscribeOn(Schedulers.io())
128 | .observeOn(AndroidSchedulers.mainThread());
129 |
130 | activityObservable = locationProvider
131 | .getDetectedActivity(50)
132 | .observeOn(AndroidSchedulers.mainThread());
133 | }
134 |
135 | @Override
136 | protected void onLocationPermissionGranted() {
137 | lastKnownLocationDisposable = lastKnownLocationObservable
138 | .map(new LocationToStringFunc())
139 | .subscribe(new DisplayTextOnViewAction(lastKnownLocationView), new ErrorHandler());
140 |
141 | updatableLocationDisposable = locationUpdatesObservable
142 | .map(new LocationToStringFunc())
143 | .map(new Function
> getReverseGeocodeObservable(double lat, double lng, int maxResults) {
204 | return ReverseGeocodeObservable.createObservable(ctx.getContext(), factory, Locale.getDefault(), lat, lng, maxResults);
205 | }
206 |
207 | /**
208 | * Creates observable that translates latitude and longitude to list of possible addresses using
209 | * included Geocoder class. In case geocoder fails with IOException("Service not Available") fallback
210 | * decoder is used using google web api. You should subscribe for this observable on I/O thread.
211 | * The stream finishes after address list is available.
212 | *
213 | * @param locale locale for address language
214 | * @param lat latitude
215 | * @param lng longitude
216 | * @param maxResults maximal number of results you are interested in
217 | * @return observable that serves list of address based on location
218 | */
219 | public Observable
> getReverseGeocodeObservable(Locale locale, double lat, double lng, int maxResults) {
220 | return ReverseGeocodeObservable.createObservable(ctx.getContext(), factory, locale, lat, lng, maxResults);
221 | }
222 |
223 | /**
224 | * Creates observable that translates a street address or other description into a list of
225 | * possible addresses using included Geocoder class. You should subscribe for this
226 | * observable on I/O thread.
227 | * The stream finishes after address list is available.
228 | *
229 | * @param locationName a user-supplied description of a location
230 | * @param maxResults max number of results you are interested in
231 | * @return observable that serves list of address based on location name
232 | */
233 | public Observable
> getGeocodeObservable(String locationName, int maxResults) {
234 | return getGeocodeObservable(locationName, maxResults, null);
235 | }
236 |
237 | /**
238 | * Creates geocoder with default Locale.
239 | *
240 | * @see ReactiveLocationProvider#getGeocodeObservable(String, int, LatLngBounds, Locale)
241 | */
242 | public Observable
> getGeocodeObservable(String locationName, int maxResults, LatLngBounds bounds) {
243 | return getGeocodeObservable(locationName, maxResults, bounds, null);
244 | }
245 |
246 | /**
247 | * Creates observable that translates a street address or other description into a list of
248 | * possible addresses using included Geocoder class. You should subscribe for this
249 | * observable on I/O thread.
250 | * The stream finishes after address list is available.
251 | *
252 | * You may specify a bounding box for the search results.
253 | *
254 | * @param locationName a user-supplied description of a location
255 | * @param maxResults max number of results you are interested in
256 | * @param bounds restricts the results to geographical bounds. May be null
257 | * @param locale locale passed to geocoder
258 | * @return observable that serves list of address based on location name
259 | */
260 | public Observable
> getGeocodeObservable(String locationName, int maxResults, LatLngBounds bounds, Locale locale) {
261 | return GeocodeObservable.createObservable(ctx.getContext(), factory, locationName, maxResults, bounds, locale);
262 | }
263 |
264 | /**
265 | * Creates observable that adds request and completes when the action is done.
266 | *
267 | * Observable can report {@link pl.charmas.android.reactivelocation2.observables.GoogleAPIConnectionException}
268 | * when there are trouble connecting with Google Play Services.
269 | *
270 | * In case of unsuccessful status {@link pl.charmas.android.reactivelocation2.observables.StatusException} is delivered.
271 | *
272 | * Other exceptions will be reported that can be thrown on {@link com.google.android.gms.location.GeofencingApi#addGeofences(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.GeofencingRequest, android.app.PendingIntent)}
273 | *
274 | * @param geofenceTransitionPendingIntent pending intent to register on geofence transition
275 | * @param request list of request to add
276 | * @return observable that adds request
277 | */
278 | @RequiresPermission("android.permission.ACCESS_FINE_LOCATION")
279 | public Observable