Skip to content

Commit 09d0827

Browse files
author
Langston Smith
authored
Added user location button to Places Plugin's PlacePickerActivity (#994)
1 parent c6f43b3 commit 09d0827

File tree

8 files changed

+233
-70
lines changed

8 files changed

+233
-70
lines changed

app/src/main/java/com/mapbox/mapboxsdk/plugins/testapp/activity/places/PickerLauncherActivity.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,21 @@ class PickerLauncherActivity : AppCompatActivity() {
2828
else getString(R.string.reverse_geocoding_disabled)
2929
}
3030

31+
userLocationSwitch.text = getString(R.string.user_location_button_disabled)
32+
userLocationSwitch.setOnCheckedChangeListener { compoundButton, checked ->
33+
userLocationSwitch.text = if (checked)
34+
getString(R.string.user_location_button_enabled)
35+
else getString(R.string.user_location_button_disabled)
36+
}
37+
3138
fabLocationPicker.setOnClickListener { _ ->
3239
Mapbox.getAccessToken()?.let {
3340
startActivityForResult(
3441
PlacePicker.IntentBuilder()
3542
.accessToken(it)
3643
.placeOptions(PlacePickerOptions.builder()
3744
.includeReverseGeocode(reverseGeocodingSwitch.isChecked)
45+
.includeDeviceLocationButton(userLocationSwitch.isChecked)
3846
.statingCameraPosition(CameraPosition.Builder()
3947
.target(LatLng(40.7544, -73.9862))
4048
.zoom(16.0)

app/src/main/res/layout/activity_picker_launcher.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@
2121
app:layout_constraintStart_toStartOf="parent"
2222
app:layout_constraintTop_toBottomOf="@+id/textView"/>
2323

24+
<Switch
25+
android:id="@+id/userLocationSwitch"
26+
android:layout_width="wrap_content"
27+
android:layout_height="22dp"
28+
android:layout_marginStart="8dp"
29+
android:layout_marginLeft="8dp"
30+
android:layout_marginEnd="8dp"
31+
android:layout_marginRight="8dp"
32+
android:layout_marginBottom="8dp"
33+
app:layout_constraintBottom_toTopOf="@+id/reverseGeocodingSwitch"
34+
app:layout_constraintEnd_toEndOf="parent"
35+
app:layout_constraintHorizontal_bias="0.5"
36+
app:layout_constraintStart_toStartOf="parent"
37+
app:layout_constraintTop_toBottomOf="@+id/textView" />
38+
2439
<TextView
2540
android:id="@+id/textView"
2641
android:layout_width="0dp"

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
<string name="detailed_description_place_picker">Example shows how to launch the Place Picker using the Floating action button and receiving a result in onActivityResult.</string>
6565
<string name="reverse_geocoding_enabled">Reverse geocoding enabled</string>
6666
<string name="reverse_geocoding_disabled">Reverse geocoding disabled</string>
67+
<string name="user_location_button_enabled">User location button enabled</string>
68+
<string name="user_location_button_disabled">User location button disabled</string>
6769

6870
<!-- Misc -->
6971
<string name="min_zoom_textview">Min zoom: %1$d</string>

plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/model/PlacePickerOptions.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ public abstract class PlacePickerOptions implements BasePlaceOptions, Parcelable
3535

3636
public abstract boolean includeReverseGeocode();
3737

38+
public abstract boolean includeDeviceLocationButton();
39+
3840
public static Builder builder() {
3941
return new AutoValue_PlacePickerOptions.Builder()
40-
.includeReverseGeocode(true);
42+
.includeReverseGeocode(true)
43+
.includeDeviceLocationButton(false);
4144
}
4245

4346
@AutoValue.Builder
@@ -59,6 +62,10 @@ public Builder geocodingTypes(@NonNull @GeocodingTypeCriteria String... geocodin
5962
public abstract Builder statingCameraPosition(@NonNull CameraPosition cameraPosition);
6063

6164
/**
65+
* Determine whether to include a bottom sheet in the PlacePickerActivity to display
66+
* geocoding information associated with coordinates at the center of the map. A new
67+
* geocoding call is made every time the map is moved when true is passed through
68+
* includeReverseGeocode().
6269
*
6370
* @param includeReverseGeocode whether or not to make a reverse geocoding call to
6471
* retrieve and display information associated with
@@ -68,6 +75,18 @@ public Builder geocodingTypes(@NonNull @GeocodingTypeCriteria String... geocodin
6875
*/
6976
public abstract Builder includeReverseGeocode(boolean includeReverseGeocode);
7077

78+
/**
79+
* Determine whether an Android-system Floating Action Button is included in
80+
* the PlacePickerActivity UI. Clicking on this Floating Action Button will
81+
* move the map camera to the device's location. False is the default if
82+
* this method isn't used in building the PlacePickerOptions object.
83+
*
84+
* @param includeDeviceLocationButton
85+
*
86+
* @return this builder instance for chaining options together
87+
*/
88+
public abstract Builder includeDeviceLocationButton(boolean includeDeviceLocationButton);
89+
7190
public abstract PlacePickerOptions build();
7291
}
7392
}

plugin-places/src/main/java/com/mapbox/mapboxsdk/plugins/places/picker/ui/PlacePickerActivity.java

Lines changed: 119 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import android.arch.lifecycle.Observer;
44
import android.arch.lifecycle.ViewModelProviders;
55
import android.content.Intent;
6+
import android.location.Location;
67
import android.os.Bundle;
78
import android.support.annotation.NonNull;
89
import android.support.annotation.Nullable;
@@ -15,12 +16,20 @@
1516
import android.view.Window;
1617
import android.view.animation.OvershootInterpolator;
1718
import android.widget.ImageView;
19+
import android.widget.Toast;
1820

1921
import com.google.gson.JsonObject;
22+
import com.mapbox.android.core.permissions.PermissionsListener;
23+
import com.mapbox.android.core.permissions.PermissionsManager;
2024
import com.mapbox.api.geocoding.v5.models.CarmenFeature;
2125
import com.mapbox.geojson.Point;
26+
import com.mapbox.mapboxsdk.camera.CameraPosition;
2227
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
2328
import com.mapbox.mapboxsdk.geometry.LatLng;
29+
import com.mapbox.mapboxsdk.location.LocationComponent;
30+
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions;
31+
import com.mapbox.mapboxsdk.location.modes.CameraMode;
32+
import com.mapbox.mapboxsdk.location.modes.RenderMode;
2433
import com.mapbox.mapboxsdk.maps.MapView;
2534
import com.mapbox.mapboxsdk.maps.MapboxMap;
2635
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
@@ -33,6 +42,7 @@
3342
import com.mapbox.mapboxsdk.plugins.places.picker.model.PlacePickerOptions;
3443
import com.mapbox.mapboxsdk.plugins.places.picker.viewmodel.PlacePickerViewModel;
3544

45+
import java.util.List;
3646
import java.util.Locale;
3747

3848
import timber.log.Timber;
@@ -46,8 +56,10 @@
4656
* @since 0.2.0
4757
*/
4858
public class PlacePickerActivity extends AppCompatActivity implements OnMapReadyCallback,
49-
MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraIdleListener, Observer<CarmenFeature> {
59+
MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraIdleListener, Observer<CarmenFeature>,
60+
PermissionsListener {
5061

62+
private PermissionsManager permissionsManager;
5163
CurrentPlaceSelectionBottomSheet bottomSheet;
5264
CarmenFeature carmenFeature;
5365
private PlacePickerViewModel viewModel;
@@ -56,6 +68,7 @@ public class PlacePickerActivity extends AppCompatActivity implements OnMapReady
5668
private MapboxMap mapboxMap;
5769
private String accessToken;
5870
private MapView mapView;
71+
private FloatingActionButton userLocationButton;
5972
private boolean includeReverseGeocode;
6073

6174
@Override
@@ -105,6 +118,12 @@ private void bindViews() {
105118
mapView = findViewById(R.id.map_view);
106119
bottomSheet = findViewById(R.id.mapbox_plugins_picker_bottom_sheet);
107120
markerImage = findViewById(R.id.mapbox_plugins_image_view_marker);
121+
userLocationButton = findViewById(R.id.user_location_button);
122+
}
123+
124+
private void bindListeners() {
125+
PlacePickerActivity.this.mapboxMap.addOnCameraMoveStartedListener(PlacePickerActivity.this);
126+
PlacePickerActivity.this.mapboxMap.addOnCameraIdleListener(PlacePickerActivity.this);
108127
}
109128

110129
private void customizeViews() {
@@ -123,25 +142,85 @@ public void onMapReady(final MapboxMap mapboxMap) {
123142
mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
124143
@Override
125144
public void onStyleLoaded(@NonNull Style style) {
126-
if (options != null) {
127-
if (options.startingBounds() != null) {
128-
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(options.startingBounds(), 0));
129-
} else if (options.statingCameraPosition() != null) {
130-
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(options.statingCameraPosition()));
131-
}
132-
}
133-
145+
adjustCameraBasedOnOptions();
134146
if (includeReverseGeocode) {
135-
// Initialize with the markers current location information.
147+
// Initialize with the marker's current coordinates.
136148
makeReverseGeocodingSearch();
137149
}
150+
bindListeners();
138151

139-
PlacePickerActivity.this.mapboxMap.addOnCameraMoveStartedListener(PlacePickerActivity.this);
140-
PlacePickerActivity.this.mapboxMap.addOnCameraIdleListener(PlacePickerActivity.this);
152+
if (options != null && options.includeDeviceLocationButton()) {
153+
enableLocationComponent(style);
154+
} else {
155+
userLocationButton.hide();
156+
}
141157
}
142158
});
143159
}
144160

161+
private void adjustCameraBasedOnOptions() {
162+
if (options != null) {
163+
if (options.startingBounds() != null) {
164+
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(options.startingBounds(), 0));
165+
} else if (options.statingCameraPosition() != null) {
166+
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(options.statingCameraPosition()));
167+
}
168+
}
169+
}
170+
171+
@SuppressWarnings( {"MissingPermission"})
172+
private void enableLocationComponent(@NonNull Style loadedMapStyle) {
173+
// Check if permissions are enabled and if not request
174+
if (PermissionsManager.areLocationPermissionsGranted(this)) {
175+
176+
// Get an instance of the component
177+
LocationComponent locationComponent = mapboxMap.getLocationComponent();
178+
179+
// Activate with options
180+
locationComponent.activateLocationComponent(
181+
LocationComponentActivationOptions.builder(this, loadedMapStyle).build());
182+
183+
// Enable to make component visible
184+
locationComponent.setLocationComponentEnabled(true);
185+
186+
// Set the component's camera mode
187+
locationComponent.setCameraMode(CameraMode.NONE);
188+
189+
// Set the component's render mode
190+
locationComponent.setRenderMode(RenderMode.NORMAL);
191+
192+
addUserLocationButton();
193+
} else {
194+
permissionsManager = new PermissionsManager(this);
195+
permissionsManager.requestLocationPermissions(this);
196+
}
197+
}
198+
199+
@Override
200+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
201+
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
202+
}
203+
204+
@Override
205+
public void onExplanationNeeded(List<String> permissionsToExplain) {
206+
Toast.makeText(this, R.string.mapbox_plugins_place_picker_user_location_permission_explanation,
207+
Toast.LENGTH_LONG).show();
208+
}
209+
210+
@Override
211+
public void onPermissionResult(boolean granted) {
212+
if (granted) {
213+
mapboxMap.getStyle(new Style.OnStyleLoaded() {
214+
@Override
215+
public void onStyleLoaded(@NonNull Style style) {
216+
if (options != null && options.includeDeviceLocationButton()) {
217+
enableLocationComponent(style);
218+
}
219+
}
220+
});
221+
}
222+
}
223+
145224
@Override
146225
public void onCameraMoveStarted(int reason) {
147226
Timber.v("Map camera has begun moving.");
@@ -185,8 +264,8 @@ private void makeReverseGeocodingSearch() {
185264
LatLng latLng = mapboxMap.getCameraPosition().target;
186265
if (latLng != null) {
187266
viewModel.reverseGeocode(
188-
Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()),
189-
accessToken, options
267+
Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()),
268+
accessToken, options
190269
);
191270
}
192271
}
@@ -207,6 +286,32 @@ public void onClick(View view) {
207286
});
208287
}
209288

289+
/**
290+
* Bind the device location Floating Action Button to this activity's UI and move the
291+
* map camera if the button's clicked.
292+
*/
293+
private void addUserLocationButton() {
294+
userLocationButton.show();
295+
userLocationButton.setOnClickListener(new View.OnClickListener() {
296+
@Override
297+
public void onClick(View view) {
298+
if (mapboxMap.getLocationComponent().getLastKnownLocation() != null) {
299+
Location lastKnownLocation = mapboxMap.getLocationComponent().getLastKnownLocation();
300+
mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(
301+
new CameraPosition.Builder()
302+
.target(new LatLng(lastKnownLocation.getLatitude(),
303+
lastKnownLocation.getLongitude()))
304+
.zoom(17.5)
305+
.build()
306+
),1400);
307+
} else {
308+
Toast.makeText(PlacePickerActivity.this,
309+
getString(R.string.mapbox_plugins_place_picker_user_location_not_found), Toast.LENGTH_SHORT).show();
310+
}
311+
}
312+
});
313+
}
314+
210315
void placeSelected() {
211316
Intent returningIntent = new Intent();
212317
if (includeReverseGeocode) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24.0"
5+
android:viewportHeight="24.0">
6+
<path
7+
android:fillColor="#606060"
8+
android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06C6.83,3.52 3.52,6.83 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L23,13v-2h-2.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
9+
</vector>

0 commit comments

Comments
 (0)